diff --git a/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h b/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h index 043014e..2463ca2 100644 --- a/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h +++ b/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h @@ -33,6 +33,11 @@ */ @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" * if not available (per HTTP specifications). @@ -100,13 +105,13 @@ * Returns the argument parts from the multipart encoded form as * name / GCDWebServerMultiPartArgument pairs. */ -@property(nonatomic, readonly) NSDictionary* arguments; +@property(nonatomic, readonly) NSArray* arguments; /** * Returns the files parts from the multipart encoded form as * name / GCDWebServerMultiPartFile pairs. */ -@property(nonatomic, readonly) NSDictionary* files; +@property(nonatomic, readonly) NSArray* files; /** * Returns the MIME type for multipart encoded forms @@ -114,4 +119,14 @@ */ + (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 diff --git a/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m b/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m index 3dd8224..7420bac 100644 --- a/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m +++ b/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m @@ -38,7 +38,7 @@ typedef enum { } ParserState; @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)isAtEnd; @end @@ -49,6 +49,7 @@ static NSData* _dashNewlineData = nil; @interface GCDWebServerMultiPart () { @private + NSString* _controlName; NSString* _contentType; NSString* _mimeType; } @@ -56,17 +57,19 @@ static NSData* _dashNewlineData = nil; @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])) { - _contentType = [contentType copy]; + _controlName = [name copy]; + _contentType = [type copy]; _mimeType = ARC_RETAIN(GCDWebServerTruncateHeaderValue(_contentType)); } return self; } - (void)dealloc { + ARC_RELEASE(_controlName); ARC_RELEASE(_contentType); ARC_RELEASE(_mimeType); @@ -86,8 +89,8 @@ static NSData* _dashNewlineData = nil; @synthesize data=_data, string=_string; -- (id)initWithContentType:(NSString*)contentType data:(NSData*)data { - if ((self = [super initWithContentType:contentType])) { +- (id)initWithControlName:(NSString*)name contentType:(NSString*)type data:(NSData*)data { + if ((self = [super initWithControlName:name contentType:type])) { _data = ARC_RETAIN(data); if ([self.contentType hasPrefix:@"text/"]) { @@ -122,8 +125,8 @@ static NSData* _dashNewlineData = nil; @synthesize fileName=_fileName, temporaryPath=_temporaryPath; -- (id)initWithContentType:(NSString*)contentType fileName:(NSString*)fileName temporaryPath:(NSString*)temporaryPath { - if ((self = [super initWithContentType:contentType])) { +- (id)initWithControlName:(NSString*)name contentType:(NSString*)type fileName:(NSString*)fileName temporaryPath:(NSString*)temporaryPath { + if ((self = [super initWithControlName:name contentType:type])) { _fileName = [fileName copy]; _temporaryPath = [temporaryPath copy]; } @@ -150,8 +153,8 @@ static NSData* _dashNewlineData = nil; NSData* _boundary; ParserState _state; NSMutableData* _data; - NSMutableDictionary* _arguments; - NSMutableDictionary* _files; + NSMutableArray* _arguments; + NSMutableArray* _files; NSString* _controlName; 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; if (data == nil) { DNOT_REACHED(); @@ -294,8 +297,8 @@ static NSData* _dashNewlineData = nil; if (result == (ssize_t)dataLength) { if (close(_tmpFile) == 0) { _tmpFile = 0; - GCDWebServerMultiPartFile* file = [[GCDWebServerMultiPartFile alloc] initWithContentType:_contentType fileName:_fileName temporaryPath:_tmpPath]; - [_files setObject:file forKey:_controlName]; + GCDWebServerMultiPartFile* file = [[GCDWebServerMultiPartFile alloc] initWithControlName:_controlName contentType:_contentType fileName:_fileName temporaryPath:_tmpPath]; + [_files addObject:file]; ARC_RELEASE(file); } else { DNOT_REACHED(); @@ -309,8 +312,8 @@ static NSData* _dashNewlineData = nil; _tmpPath = nil; } else { NSData* data = [[NSData alloc] initWithBytes:(void*)dataBytes length:dataLength]; - GCDWebServerMultiPartArgument* argument = [[GCDWebServerMultiPartArgument alloc] initWithContentType:_contentType data:data]; - [_arguments setObject:argument forKey:_controlName]; + GCDWebServerMultiPartArgument* argument = [[GCDWebServerMultiPartArgument alloc] initWithControlName:_controlName contentType:_contentType data:data]; + [_arguments addObject:argument]; ARC_RELEASE(argument); ARC_RELEASE(data); } @@ -356,8 +359,8 @@ static NSData* _dashNewlineData = nil; @interface GCDWebServerMultiPartFormRequest () { @private GCDWebServerMIMEStreamParser* _parser; - NSMutableDictionary* _arguments; - NSMutableDictionary* _files; + NSMutableArray* _arguments; + NSMutableArray* _files; } @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 { if ((self = [super initWithMethod:method url:url headers:headers path:path query:query])) { - _arguments = [[NSMutableDictionary alloc] init]; - _files = [[NSMutableDictionary alloc] init]; + _arguments = [[NSMutableArray alloc] init]; + _files = [[NSMutableArray alloc] init]; } return self; } @@ -413,21 +416,37 @@ static NSData* _dashNewlineData = nil; 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 { NSMutableString* description = [NSMutableString stringWithString:[super description]]; if (_arguments.count) { [description appendString:@"\n"]; - for (NSString* key in [[_arguments allKeys] sortedArrayUsingSelector:@selector(compare:)]) { - GCDWebServerMultiPartArgument* argument = [_arguments objectForKey:key]; - [description appendFormat:@"\n%@ (%@)\n", key, argument.contentType]; + for (GCDWebServerMultiPartArgument* argument in _arguments) { + [description appendFormat:@"\n%@ (%@)\n", argument.controlName, argument.contentType]; [description appendString:GCDWebServerDescribeData(argument.data, argument.contentType)]; } } if (_files.count) { [description appendString:@"\n"]; - for (NSString* key in [[_files allKeys] sortedArrayUsingSelector:@selector(compare:)]) { - GCDWebServerMultiPartFile* file = [_files objectForKey:key]; - [description appendFormat:@"\n%@ (%@): %@\n{%@}", key, file.contentType, file.fileName, file.temporaryPath]; + for (GCDWebServerMultiPartFile* file in _files) { + [description appendFormat:@"\n%@ (%@): %@\n{%@}", file.controlName, file.contentType, file.fileName, file.temporaryPath]; } } return description; diff --git a/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h b/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h index edb858f..e36eac3 100644 --- a/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h +++ b/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h @@ -35,7 +35,7 @@ @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 * "Content-Type" header or defaults to UTF-8. diff --git a/GCDWebUploader/GCDWebUploader.m b/GCDWebUploader/GCDWebUploader.m index c25e28e..56eb6da 100644 --- a/GCDWebUploader/GCDWebUploader.m +++ b/GCDWebUploader/GCDWebUploader.m @@ -154,11 +154,11 @@ 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) - GCDWebServerMultiPartFile* file = [request.files objectForKey:@"files[]"]; + GCDWebServerMultiPartFile* file = [request firstFileForControlName:@"files[]"]; if ((!_allowHidden && [file.fileName hasPrefix:@"."]) || ![self _checkFileExtension: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]]; if (![self shouldUploadFileAtPath:absolutePath withTemporaryFile:file.temporaryPath]) {