mirror of
https://github.com/swisspol/GCDWebServer.git
synced 2026-04-24 00:00:04 +08:00
Modified GCDWebServerMultiPart to allow duplicate control names
This commit is contained in:
@@ -33,6 +33,11 @@
|
|||||||
*/
|
*/
|
||||||
@interface GCDWebServerMultiPart : NSObject
|
@interface GCDWebServerMultiPart : NSObject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the control name retrieved from the part headers.
|
||||||
|
*/
|
||||||
|
@property(nonatomic, readonly) NSString* controlName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the content type retrieved from the part headers or "text/plain"
|
* Returns the content type retrieved from the part headers or "text/plain"
|
||||||
* if not available (per HTTP specifications).
|
* if not available (per HTTP specifications).
|
||||||
@@ -100,13 +105,13 @@
|
|||||||
* Returns the argument parts from the multipart encoded form as
|
* Returns the argument parts from the multipart encoded form as
|
||||||
* name / GCDWebServerMultiPartArgument pairs.
|
* name / GCDWebServerMultiPartArgument pairs.
|
||||||
*/
|
*/
|
||||||
@property(nonatomic, readonly) NSDictionary* arguments;
|
@property(nonatomic, readonly) NSArray* arguments;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the files parts from the multipart encoded form as
|
* Returns the files parts from the multipart encoded form as
|
||||||
* name / GCDWebServerMultiPartFile pairs.
|
* name / GCDWebServerMultiPartFile pairs.
|
||||||
*/
|
*/
|
||||||
@property(nonatomic, readonly) NSDictionary* files;
|
@property(nonatomic, readonly) NSArray* files;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the MIME type for multipart encoded forms
|
* Returns the MIME type for multipart encoded forms
|
||||||
@@ -114,4 +119,14 @@
|
|||||||
*/
|
*/
|
||||||
+ (NSString*)mimeType;
|
+ (NSString*)mimeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first argument for a given control name or nil if not found.
|
||||||
|
*/
|
||||||
|
- (GCDWebServerMultiPartArgument*)firstArgumentForControlName:(NSString*)name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first file for a given control name or nil if not found.
|
||||||
|
*/
|
||||||
|
- (GCDWebServerMultiPartFile*)firstFileForControlName:(NSString*)name;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ typedef enum {
|
|||||||
} ParserState;
|
} ParserState;
|
||||||
|
|
||||||
@interface GCDWebServerMIMEStreamParser : NSObject
|
@interface GCDWebServerMIMEStreamParser : NSObject
|
||||||
- (instancetype)initWithBoundary:(NSString*)boundary arguments:(NSMutableDictionary*)arguments files:(NSMutableDictionary*)files;
|
- (instancetype)initWithBoundary:(NSString*)boundary arguments:(NSMutableArray*)arguments files:(NSMutableArray*)files;
|
||||||
- (BOOL)appendData:(NSData*)data;
|
- (BOOL)appendData:(NSData*)data;
|
||||||
- (BOOL)isAtEnd;
|
- (BOOL)isAtEnd;
|
||||||
@end
|
@end
|
||||||
@@ -49,6 +49,7 @@ static NSData* _dashNewlineData = nil;
|
|||||||
|
|
||||||
@interface GCDWebServerMultiPart () {
|
@interface GCDWebServerMultiPart () {
|
||||||
@private
|
@private
|
||||||
|
NSString* _controlName;
|
||||||
NSString* _contentType;
|
NSString* _contentType;
|
||||||
NSString* _mimeType;
|
NSString* _mimeType;
|
||||||
}
|
}
|
||||||
@@ -56,17 +57,19 @@ static NSData* _dashNewlineData = nil;
|
|||||||
|
|
||||||
@implementation GCDWebServerMultiPart
|
@implementation GCDWebServerMultiPart
|
||||||
|
|
||||||
@synthesize contentType=_contentType, mimeType=_mimeType;
|
@synthesize controlName=_controlName, contentType=_contentType, mimeType=_mimeType;
|
||||||
|
|
||||||
- (id)initWithContentType:(NSString*)contentType {
|
- (id)initWithControlName:(NSString*)name contentType:(NSString*)type {
|
||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
_contentType = [contentType copy];
|
_controlName = [name copy];
|
||||||
|
_contentType = [type copy];
|
||||||
_mimeType = ARC_RETAIN(GCDWebServerTruncateHeaderValue(_contentType));
|
_mimeType = ARC_RETAIN(GCDWebServerTruncateHeaderValue(_contentType));
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
|
ARC_RELEASE(_controlName);
|
||||||
ARC_RELEASE(_contentType);
|
ARC_RELEASE(_contentType);
|
||||||
ARC_RELEASE(_mimeType);
|
ARC_RELEASE(_mimeType);
|
||||||
|
|
||||||
@@ -86,8 +89,8 @@ static NSData* _dashNewlineData = nil;
|
|||||||
|
|
||||||
@synthesize data=_data, string=_string;
|
@synthesize data=_data, string=_string;
|
||||||
|
|
||||||
- (id)initWithContentType:(NSString*)contentType data:(NSData*)data {
|
- (id)initWithControlName:(NSString*)name contentType:(NSString*)type data:(NSData*)data {
|
||||||
if ((self = [super initWithContentType:contentType])) {
|
if ((self = [super initWithControlName:name contentType:type])) {
|
||||||
_data = ARC_RETAIN(data);
|
_data = ARC_RETAIN(data);
|
||||||
|
|
||||||
if ([self.contentType hasPrefix:@"text/"]) {
|
if ([self.contentType hasPrefix:@"text/"]) {
|
||||||
@@ -122,8 +125,8 @@ static NSData* _dashNewlineData = nil;
|
|||||||
|
|
||||||
@synthesize fileName=_fileName, temporaryPath=_temporaryPath;
|
@synthesize fileName=_fileName, temporaryPath=_temporaryPath;
|
||||||
|
|
||||||
- (id)initWithContentType:(NSString*)contentType fileName:(NSString*)fileName temporaryPath:(NSString*)temporaryPath {
|
- (id)initWithControlName:(NSString*)name contentType:(NSString*)type fileName:(NSString*)fileName temporaryPath:(NSString*)temporaryPath {
|
||||||
if ((self = [super initWithContentType:contentType])) {
|
if ((self = [super initWithControlName:name contentType:type])) {
|
||||||
_fileName = [fileName copy];
|
_fileName = [fileName copy];
|
||||||
_temporaryPath = [temporaryPath copy];
|
_temporaryPath = [temporaryPath copy];
|
||||||
}
|
}
|
||||||
@@ -150,8 +153,8 @@ static NSData* _dashNewlineData = nil;
|
|||||||
NSData* _boundary;
|
NSData* _boundary;
|
||||||
ParserState _state;
|
ParserState _state;
|
||||||
NSMutableData* _data;
|
NSMutableData* _data;
|
||||||
NSMutableDictionary* _arguments;
|
NSMutableArray* _arguments;
|
||||||
NSMutableDictionary* _files;
|
NSMutableArray* _files;
|
||||||
|
|
||||||
NSString* _controlName;
|
NSString* _controlName;
|
||||||
NSString* _fileName;
|
NSString* _fileName;
|
||||||
@@ -178,7 +181,7 @@ static NSData* _dashNewlineData = nil;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithBoundary:(NSString*)boundary arguments:(NSMutableDictionary*)arguments files:(NSMutableDictionary*)files {
|
- (instancetype)initWithBoundary:(NSString*)boundary arguments:(NSMutableArray*)arguments files:(NSMutableArray*)files {
|
||||||
NSData* data = boundary.length ? [[NSString stringWithFormat:@"--%@", boundary] dataUsingEncoding:NSASCIIStringEncoding] : nil;
|
NSData* data = boundary.length ? [[NSString stringWithFormat:@"--%@", boundary] dataUsingEncoding:NSASCIIStringEncoding] : nil;
|
||||||
if (data == nil) {
|
if (data == nil) {
|
||||||
DNOT_REACHED();
|
DNOT_REACHED();
|
||||||
@@ -294,8 +297,8 @@ static NSData* _dashNewlineData = nil;
|
|||||||
if (result == (ssize_t)dataLength) {
|
if (result == (ssize_t)dataLength) {
|
||||||
if (close(_tmpFile) == 0) {
|
if (close(_tmpFile) == 0) {
|
||||||
_tmpFile = 0;
|
_tmpFile = 0;
|
||||||
GCDWebServerMultiPartFile* file = [[GCDWebServerMultiPartFile alloc] initWithContentType:_contentType fileName:_fileName temporaryPath:_tmpPath];
|
GCDWebServerMultiPartFile* file = [[GCDWebServerMultiPartFile alloc] initWithControlName:_controlName contentType:_contentType fileName:_fileName temporaryPath:_tmpPath];
|
||||||
[_files setObject:file forKey:_controlName];
|
[_files addObject:file];
|
||||||
ARC_RELEASE(file);
|
ARC_RELEASE(file);
|
||||||
} else {
|
} else {
|
||||||
DNOT_REACHED();
|
DNOT_REACHED();
|
||||||
@@ -309,8 +312,8 @@ static NSData* _dashNewlineData = nil;
|
|||||||
_tmpPath = nil;
|
_tmpPath = nil;
|
||||||
} else {
|
} else {
|
||||||
NSData* data = [[NSData alloc] initWithBytes:(void*)dataBytes length:dataLength];
|
NSData* data = [[NSData alloc] initWithBytes:(void*)dataBytes length:dataLength];
|
||||||
GCDWebServerMultiPartArgument* argument = [[GCDWebServerMultiPartArgument alloc] initWithContentType:_contentType data:data];
|
GCDWebServerMultiPartArgument* argument = [[GCDWebServerMultiPartArgument alloc] initWithControlName:_controlName contentType:_contentType data:data];
|
||||||
[_arguments setObject:argument forKey:_controlName];
|
[_arguments addObject:argument];
|
||||||
ARC_RELEASE(argument);
|
ARC_RELEASE(argument);
|
||||||
ARC_RELEASE(data);
|
ARC_RELEASE(data);
|
||||||
}
|
}
|
||||||
@@ -356,8 +359,8 @@ static NSData* _dashNewlineData = nil;
|
|||||||
@interface GCDWebServerMultiPartFormRequest () {
|
@interface GCDWebServerMultiPartFormRequest () {
|
||||||
@private
|
@private
|
||||||
GCDWebServerMIMEStreamParser* _parser;
|
GCDWebServerMIMEStreamParser* _parser;
|
||||||
NSMutableDictionary* _arguments;
|
NSMutableArray* _arguments;
|
||||||
NSMutableDictionary* _files;
|
NSMutableArray* _files;
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@@ -371,8 +374,8 @@ static NSData* _dashNewlineData = nil;
|
|||||||
|
|
||||||
- (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDictionary*)headers path:(NSString*)path query:(NSDictionary*)query {
|
- (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDictionary*)headers path:(NSString*)path query:(NSDictionary*)query {
|
||||||
if ((self = [super initWithMethod:method url:url headers:headers path:path query:query])) {
|
if ((self = [super initWithMethod:method url:url headers:headers path:path query:query])) {
|
||||||
_arguments = [[NSMutableDictionary alloc] init];
|
_arguments = [[NSMutableArray alloc] init];
|
||||||
_files = [[NSMutableDictionary alloc] init];
|
_files = [[NSMutableArray alloc] init];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@@ -413,21 +416,37 @@ static NSData* _dashNewlineData = nil;
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (GCDWebServerMultiPartArgument*)firstArgumentForControlName:(NSString*)name {
|
||||||
|
for (GCDWebServerMultiPartArgument* argument in _arguments) {
|
||||||
|
if ([argument.controlName isEqualToString:name]) {
|
||||||
|
return argument;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (GCDWebServerMultiPartFile*)firstFileForControlName:(NSString*)name {
|
||||||
|
for (GCDWebServerMultiPartFile* file in _files) {
|
||||||
|
if ([file.controlName isEqualToString:name]) {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
- (NSString*)description {
|
- (NSString*)description {
|
||||||
NSMutableString* description = [NSMutableString stringWithString:[super description]];
|
NSMutableString* description = [NSMutableString stringWithString:[super description]];
|
||||||
if (_arguments.count) {
|
if (_arguments.count) {
|
||||||
[description appendString:@"\n"];
|
[description appendString:@"\n"];
|
||||||
for (NSString* key in [[_arguments allKeys] sortedArrayUsingSelector:@selector(compare:)]) {
|
for (GCDWebServerMultiPartArgument* argument in _arguments) {
|
||||||
GCDWebServerMultiPartArgument* argument = [_arguments objectForKey:key];
|
[description appendFormat:@"\n%@ (%@)\n", argument.controlName, argument.contentType];
|
||||||
[description appendFormat:@"\n%@ (%@)\n", key, argument.contentType];
|
|
||||||
[description appendString:GCDWebServerDescribeData(argument.data, argument.contentType)];
|
[description appendString:GCDWebServerDescribeData(argument.data, argument.contentType)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_files.count) {
|
if (_files.count) {
|
||||||
[description appendString:@"\n"];
|
[description appendString:@"\n"];
|
||||||
for (NSString* key in [[_files allKeys] sortedArrayUsingSelector:@selector(compare:)]) {
|
for (GCDWebServerMultiPartFile* file in _files) {
|
||||||
GCDWebServerMultiPartFile* file = [_files objectForKey:key];
|
[description appendFormat:@"\n%@ (%@): %@\n{%@}", file.controlName, file.contentType, file.fileName, file.temporaryPath];
|
||||||
[description appendFormat:@"\n%@ (%@): %@\n{%@}", key, file.contentType, file.fileName, file.temporaryPath];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return description;
|
return description;
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
@interface GCDWebServerURLEncodedFormRequest : GCDWebServerDataRequest
|
@interface GCDWebServerURLEncodedFormRequest : GCDWebServerDataRequest
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the unescaped names and values for the URL encoded form.
|
* Returns the unescaped control names and values for the URL encoded form.
|
||||||
*
|
*
|
||||||
* The text encoding used to interpret the data is extracted from the
|
* The text encoding used to interpret the data is extracted from the
|
||||||
* "Content-Type" header or defaults to UTF-8.
|
* "Content-Type" header or defaults to UTF-8.
|
||||||
|
|||||||
@@ -154,11 +154,11 @@
|
|||||||
NSRange range = [[request.headers objectForKey:@"Accept"] rangeOfString:@"application/json" options:NSCaseInsensitiveSearch];
|
NSRange range = [[request.headers objectForKey:@"Accept"] rangeOfString:@"application/json" options:NSCaseInsensitiveSearch];
|
||||||
NSString* contentType = (range.location != NSNotFound ? @"application/json" : @"text/plain; charset=utf-8"); // Required when using iFrame transport (see https://github.com/blueimp/jQuery-File-Upload/wiki/Setup)
|
NSString* contentType = (range.location != NSNotFound ? @"application/json" : @"text/plain; charset=utf-8"); // Required when using iFrame transport (see https://github.com/blueimp/jQuery-File-Upload/wiki/Setup)
|
||||||
|
|
||||||
GCDWebServerMultiPartFile* file = [request.files objectForKey:@"files[]"];
|
GCDWebServerMultiPartFile* file = [request firstFileForControlName:@"files[]"];
|
||||||
if ((!_allowHidden && [file.fileName hasPrefix:@"."]) || ![self _checkFileExtension:file.fileName]) {
|
if ((!_allowHidden && [file.fileName hasPrefix:@"."]) || ![self _checkFileExtension:file.fileName]) {
|
||||||
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Uploaded file name \"%@\" is not allowed", file.fileName];
|
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Uploaded file name \"%@\" is not allowed", file.fileName];
|
||||||
}
|
}
|
||||||
NSString* relativePath = [(GCDWebServerMultiPartArgument*)[request.arguments objectForKey:@"path"] string];
|
NSString* relativePath = [[request firstArgumentForControlName:@"path"] string];
|
||||||
NSString* absolutePath = [self _uniquePathForPath:[[_uploadDirectory stringByAppendingPathComponent:relativePath] stringByAppendingPathComponent:file.fileName]];
|
NSString* absolutePath = [self _uniquePathForPath:[[_uploadDirectory stringByAppendingPathComponent:relativePath] stringByAppendingPathComponent:file.fileName]];
|
||||||
|
|
||||||
if (![self shouldUploadFileAtPath:absolutePath withTemporaryFile:file.temporaryPath]) {
|
if (![self shouldUploadFileAtPath:absolutePath withTemporaryFile:file.temporaryPath]) {
|
||||||
|
|||||||
Reference in New Issue
Block a user