Skip to content

Commit c8d2b22

Browse files
committed
Modified GCDWebServerMultiPart to allow duplicate control names
1 parent f7d6da5 commit c8d2b22

4 files changed

Lines changed: 64 additions & 30 deletions

File tree

GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@
3333
*/
3434
@interface GCDWebServerMultiPart : NSObject
3535

36+
/**
37+
* Returns the control name retrieved from the part headers.
38+
*/
39+
@property(nonatomic, readonly) NSString* controlName;
40+
3641
/**
3742
* Returns the content type retrieved from the part headers or "text/plain"
3843
* if not available (per HTTP specifications).
@@ -100,18 +105,28 @@
100105
* Returns the argument parts from the multipart encoded form as
101106
* name / GCDWebServerMultiPartArgument pairs.
102107
*/
103-
@property(nonatomic, readonly) NSDictionary* arguments;
108+
@property(nonatomic, readonly) NSArray* arguments;
104109

105110
/**
106111
* Returns the files parts from the multipart encoded form as
107112
* name / GCDWebServerMultiPartFile pairs.
108113
*/
109-
@property(nonatomic, readonly) NSDictionary* files;
114+
@property(nonatomic, readonly) NSArray* files;
110115

111116
/**
112117
* Returns the MIME type for multipart encoded forms
113118
* i.e. "multipart/form-data".
114119
*/
115120
+ (NSString*)mimeType;
116121

122+
/**
123+
* Returns the first argument for a given control name or nil if not found.
124+
*/
125+
- (GCDWebServerMultiPartArgument*)firstArgumentForControlName:(NSString*)name;
126+
127+
/**
128+
* Returns the first file for a given control name or nil if not found.
129+
*/
130+
- (GCDWebServerMultiPartFile*)firstFileForControlName:(NSString*)name;
131+
117132
@end

GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
} ParserState;
3939

4040
@interface GCDWebServerMIMEStreamParser : NSObject
41-
- (instancetype)initWithBoundary:(NSString*)boundary arguments:(NSMutableDictionary*)arguments files:(NSMutableDictionary*)files;
41+
- (instancetype)initWithBoundary:(NSString*)boundary arguments:(NSMutableArray*)arguments files:(NSMutableArray*)files;
4242
- (BOOL)appendData:(NSData*)data;
4343
- (BOOL)isAtEnd;
4444
@end
@@ -49,24 +49,27 @@ - (BOOL)isAtEnd;
4949

5050
@interface GCDWebServerMultiPart () {
5151
@private
52+
NSString* _controlName;
5253
NSString* _contentType;
5354
NSString* _mimeType;
5455
}
5556
@end
5657

5758
@implementation GCDWebServerMultiPart
5859

59-
@synthesize contentType=_contentType, mimeType=_mimeType;
60+
@synthesize controlName=_controlName, contentType=_contentType, mimeType=_mimeType;
6061

61-
- (id)initWithContentType:(NSString*)contentType {
62+
- (id)initWithControlName:(NSString*)name contentType:(NSString*)type {
6263
if ((self = [super init])) {
63-
_contentType = [contentType copy];
64+
_controlName = [name copy];
65+
_contentType = [type copy];
6466
_mimeType = ARC_RETAIN(GCDWebServerTruncateHeaderValue(_contentType));
6567
}
6668
return self;
6769
}
6870

6971
- (void)dealloc {
72+
ARC_RELEASE(_controlName);
7073
ARC_RELEASE(_contentType);
7174
ARC_RELEASE(_mimeType);
7275

@@ -86,8 +89,8 @@ @implementation GCDWebServerMultiPartArgument
8689

8790
@synthesize data=_data, string=_string;
8891

89-
- (id)initWithContentType:(NSString*)contentType data:(NSData*)data {
90-
if ((self = [super initWithContentType:contentType])) {
92+
- (id)initWithControlName:(NSString*)name contentType:(NSString*)type data:(NSData*)data {
93+
if ((self = [super initWithControlName:name contentType:type])) {
9194
_data = ARC_RETAIN(data);
9295

9396
if ([self.contentType hasPrefix:@"text/"]) {
@@ -122,8 +125,8 @@ @implementation GCDWebServerMultiPartFile
122125

123126
@synthesize fileName=_fileName, temporaryPath=_temporaryPath;
124127

125-
- (id)initWithContentType:(NSString*)contentType fileName:(NSString*)fileName temporaryPath:(NSString*)temporaryPath {
126-
if ((self = [super initWithContentType:contentType])) {
128+
- (id)initWithControlName:(NSString*)name contentType:(NSString*)type fileName:(NSString*)fileName temporaryPath:(NSString*)temporaryPath {
129+
if ((self = [super initWithControlName:name contentType:type])) {
127130
_fileName = [fileName copy];
128131
_temporaryPath = [temporaryPath copy];
129132
}
@@ -150,8 +153,8 @@ @interface GCDWebServerMIMEStreamParser () {
150153
NSData* _boundary;
151154
ParserState _state;
152155
NSMutableData* _data;
153-
NSMutableDictionary* _arguments;
154-
NSMutableDictionary* _files;
156+
NSMutableArray* _arguments;
157+
NSMutableArray* _files;
155158

156159
NSString* _controlName;
157160
NSString* _fileName;
@@ -178,7 +181,7 @@ + (void)initialize {
178181
}
179182
}
180183

181-
- (instancetype)initWithBoundary:(NSString*)boundary arguments:(NSMutableDictionary*)arguments files:(NSMutableDictionary*)files {
184+
- (instancetype)initWithBoundary:(NSString*)boundary arguments:(NSMutableArray*)arguments files:(NSMutableArray*)files {
182185
NSData* data = boundary.length ? [[NSString stringWithFormat:@"--%@", boundary] dataUsingEncoding:NSASCIIStringEncoding] : nil;
183186
if (data == nil) {
184187
DNOT_REACHED();
@@ -294,8 +297,8 @@ - (BOOL)_parseData {
294297
if (result == (ssize_t)dataLength) {
295298
if (close(_tmpFile) == 0) {
296299
_tmpFile = 0;
297-
GCDWebServerMultiPartFile* file = [[GCDWebServerMultiPartFile alloc] initWithContentType:_contentType fileName:_fileName temporaryPath:_tmpPath];
298-
[_files setObject:file forKey:_controlName];
300+
GCDWebServerMultiPartFile* file = [[GCDWebServerMultiPartFile alloc] initWithControlName:_controlName contentType:_contentType fileName:_fileName temporaryPath:_tmpPath];
301+
[_files addObject:file];
299302
ARC_RELEASE(file);
300303
} else {
301304
DNOT_REACHED();
@@ -309,8 +312,8 @@ - (BOOL)_parseData {
309312
_tmpPath = nil;
310313
} else {
311314
NSData* data = [[NSData alloc] initWithBytes:(void*)dataBytes length:dataLength];
312-
GCDWebServerMultiPartArgument* argument = [[GCDWebServerMultiPartArgument alloc] initWithContentType:_contentType data:data];
313-
[_arguments setObject:argument forKey:_controlName];
315+
GCDWebServerMultiPartArgument* argument = [[GCDWebServerMultiPartArgument alloc] initWithControlName:_controlName contentType:_contentType data:data];
316+
[_arguments addObject:argument];
314317
ARC_RELEASE(argument);
315318
ARC_RELEASE(data);
316319
}
@@ -356,8 +359,8 @@ - (BOOL)isAtEnd {
356359
@interface GCDWebServerMultiPartFormRequest () {
357360
@private
358361
GCDWebServerMIMEStreamParser* _parser;
359-
NSMutableDictionary* _arguments;
360-
NSMutableDictionary* _files;
362+
NSMutableArray* _arguments;
363+
NSMutableArray* _files;
361364
}
362365
@end
363366

@@ -371,8 +374,8 @@ + (NSString*)mimeType {
371374

372375
- (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDictionary*)headers path:(NSString*)path query:(NSDictionary*)query {
373376
if ((self = [super initWithMethod:method url:url headers:headers path:path query:query])) {
374-
_arguments = [[NSMutableDictionary alloc] init];
375-
_files = [[NSMutableDictionary alloc] init];
377+
_arguments = [[NSMutableArray alloc] init];
378+
_files = [[NSMutableArray alloc] init];
376379
}
377380
return self;
378381
}
@@ -413,21 +416,37 @@ - (BOOL)close:(NSError**)error {
413416
return YES;
414417
}
415418

419+
- (GCDWebServerMultiPartArgument*)firstArgumentForControlName:(NSString*)name {
420+
for (GCDWebServerMultiPartArgument* argument in _arguments) {
421+
if ([argument.controlName isEqualToString:name]) {
422+
return argument;
423+
}
424+
}
425+
return nil;
426+
}
427+
428+
- (GCDWebServerMultiPartFile*)firstFileForControlName:(NSString*)name {
429+
for (GCDWebServerMultiPartFile* file in _files) {
430+
if ([file.controlName isEqualToString:name]) {
431+
return file;
432+
}
433+
}
434+
return nil;
435+
}
436+
416437
- (NSString*)description {
417438
NSMutableString* description = [NSMutableString stringWithString:[super description]];
418439
if (_arguments.count) {
419440
[description appendString:@"\n"];
420-
for (NSString* key in [[_arguments allKeys] sortedArrayUsingSelector:@selector(compare:)]) {
421-
GCDWebServerMultiPartArgument* argument = [_arguments objectForKey:key];
422-
[description appendFormat:@"\n%@ (%@)\n", key, argument.contentType];
441+
for (GCDWebServerMultiPartArgument* argument in _arguments) {
442+
[description appendFormat:@"\n%@ (%@)\n", argument.controlName, argument.contentType];
423443
[description appendString:GCDWebServerDescribeData(argument.data, argument.contentType)];
424444
}
425445
}
426446
if (_files.count) {
427447
[description appendString:@"\n"];
428-
for (NSString* key in [[_files allKeys] sortedArrayUsingSelector:@selector(compare:)]) {
429-
GCDWebServerMultiPartFile* file = [_files objectForKey:key];
430-
[description appendFormat:@"\n%@ (%@): %@\n{%@}", key, file.contentType, file.fileName, file.temporaryPath];
448+
for (GCDWebServerMultiPartFile* file in _files) {
449+
[description appendFormat:@"\n%@ (%@): %@\n{%@}", file.controlName, file.contentType, file.fileName, file.temporaryPath];
431450
}
432451
}
433452
return description;

GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
@interface GCDWebServerURLEncodedFormRequest : GCDWebServerDataRequest
3636

3737
/**
38-
* Returns the unescaped names and values for the URL encoded form.
38+
* Returns the unescaped control names and values for the URL encoded form.
3939
*
4040
* The text encoding used to interpret the data is extracted from the
4141
* "Content-Type" header or defaults to UTF-8.

GCDWebUploader/GCDWebUploader.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,11 +154,11 @@ - (GCDWebServerResponse*)uploadFile:(GCDWebServerMultiPartFormRequest*)request {
154154
NSRange range = [[request.headers objectForKey:@"Accept"] rangeOfString:@"application/json" options:NSCaseInsensitiveSearch];
155155
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)
156156

157-
GCDWebServerMultiPartFile* file = [request.files objectForKey:@"files[]"];
157+
GCDWebServerMultiPartFile* file = [request firstFileForControlName:@"files[]"];
158158
if ((!_allowHidden && [file.fileName hasPrefix:@"."]) || ![self _checkFileExtension:file.fileName]) {
159159
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Uploaded file name \"%@\" is not allowed", file.fileName];
160160
}
161-
NSString* relativePath = [(GCDWebServerMultiPartArgument*)[request.arguments objectForKey:@"path"] string];
161+
NSString* relativePath = [[request firstArgumentForControlName:@"path"] string];
162162
NSString* absolutePath = [self _uniquePathForPath:[[_uploadDirectory stringByAppendingPathComponent:relativePath] stringByAppendingPathComponent:file.fileName]];
163163

164164
if (![self shouldUploadFileAtPath:absolutePath withTemporaryFile:file.temporaryPath]) {

0 commit comments

Comments
 (0)