| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 | 
#import "MultipartMessageHeaderField.h"#import "HTTPLogging.h"//-----------------------------------------------------------------#pragma mark log level#ifdef DEBUGstatic const int httpLogLevel = HTTP_LOG_LEVEL_WARN;#elsestatic const int httpLogLevel = HTTP_LOG_LEVEL_WARN;#endif// helpersint findChar(const char* str,NSUInteger length, char c);NSString* extractParamValue(const char* bytes, NSUInteger length, NSStringEncoding encoding);//-----------------------------------------------------------------// interface MultipartMessageHeaderField (private)//-----------------------------------------------------------------@interface MultipartMessageHeaderField (private)-(BOOL) parseHeaderValueBytes:(char*) bytes length:(NSUInteger) length encoding:(NSStringEncoding) encoding;@end//-----------------------------------------------------------------// implementation MultipartMessageHeaderField//-----------------------------------------------------------------@implementation MultipartMessageHeaderField@synthesize name,value,params;- (id) initWithData:(NSData *)data contentEncoding:(NSStringEncoding)encoding {	params = [[NSMutableDictionary alloc] initWithCapacity:1];	char* bytes = (char*)data.bytes;	NSUInteger length = data.length;	int separatorOffset = findChar(bytes, length, ':');	if( (-1 == separatorOffset) || (separatorOffset >= length-2) ) {		HTTPLogError(@"MultipartFormDataParser: Bad format.No colon in field header.");		// tear down		return nil;	}		// header name is always ascii encoded;	name = [[NSString alloc] initWithBytes: bytes length: separatorOffset encoding: NSASCIIStringEncoding];	if( nil == name ) {		HTTPLogError(@"MultipartFormDataParser: Bad MIME header name.");		// tear down		return nil;			}		// skip the separator and the next ' ' symbol	bytes += separatorOffset + 2;	length -= separatorOffset + 2;	separatorOffset = findChar(bytes, length, ';');	if( separatorOffset == -1 ) {		// couldn't find ';', means we don't have extra params here. 		value = [[NSString alloc] initWithBytes:bytes length: length encoding:encoding];		if( nil == value ) {			HTTPLogError(@"MultipartFormDataParser: Bad MIME header value for header name: '%@'",name);			// tear down			return nil;				}		return self;	}		value = [[NSString alloc] initWithBytes:bytes length: separatorOffset encoding:encoding];	HTTPLogVerbose(@"MultipartFormDataParser: Processing  header field '%@' : '%@'",name,value);	// skipe the separator and the next ' ' symbol	bytes += separatorOffset + 2;	length -= separatorOffset + 2;	// parse the "params" part of the header	if( ![self parseHeaderValueBytes:bytes length:length encoding:encoding] ) {		NSString* paramsStr = [[NSString alloc] initWithBytes:bytes length:length encoding:NSASCIIStringEncoding];		HTTPLogError(@"MultipartFormDataParser: Bad params for header with name '%@' and value '%@'",name,value);		HTTPLogError(@"MultipartFormDataParser: Params str: %@",paramsStr);		return nil;			}	return self;}-(BOOL) parseHeaderValueBytes:(char*) bytes length:(NSUInteger) length encoding:(NSStringEncoding) encoding {	int offset = 0;	NSString* currentParam = nil;	BOOL insideQuote = NO;	while( offset < length ) {		if( bytes[offset] == '\"' ) {			if( !offset || bytes[offset-1] != '\\' ) {			   insideQuote = !insideQuote;			}		}		// skip quoted symbols		if( insideQuote ) {			++ offset;			continue; 		}		if( bytes[offset] == '=' ) {			if( currentParam ) {				// found '=' before terminating previous param.				return NO;			}			currentParam = [[NSString alloc] initWithBytes:bytes length:offset encoding:NSASCIIStringEncoding];			bytes+=offset + 1;			length -= offset + 1;			offset = 0;			continue;		}		if( bytes[offset] == ';' ) {			if( !currentParam ) {				// found ; before stating '='.				HTTPLogError(@"MultipartFormDataParser: Unexpected ';' when parsing header");				return NO;			}			NSString* paramValue = extractParamValue(bytes, offset,encoding);			 if( nil == paramValue ) {				HTTPLogWarn(@"MultipartFormDataParser: Failed to exctract paramValue for key %@ in header %@",currentParam,name);			}			else {#ifdef DEBUG				if( [params objectForKey:currentParam] ) {					HTTPLogWarn(@"MultipartFormDataParser: param %@ mentioned more then once in header %@",currentParam,name);				}#endif				[params setObject:paramValue forKey:currentParam];				HTTPLogVerbose(@"MultipartFormDataParser: header param: %@ = %@",currentParam,paramValue);			}			currentParam = nil;			// ';' separator has ' ' following, skip them.			bytes+=offset + 2;			length -= offset + 2;			offset = 0;		}		++ offset;	}	// add last param	if( insideQuote ) {		HTTPLogWarn(@"MultipartFormDataParser: unterminated quote in header %@",name);//		return YES;	}	if( currentParam ) {		NSString* paramValue = extractParamValue(bytes, length, encoding);		if( nil == paramValue ) {			HTTPLogError(@"MultipartFormDataParser: Failed to exctract paramValue for key %@ in header %@",currentParam,name);		}#ifdef DEBUG		if( [params objectForKey:currentParam] ) {			HTTPLogWarn(@"MultipartFormDataParser: param %@ mentioned more then once in one header",currentParam);		}#endif		[params setObject:paramValue forKey:currentParam];		HTTPLogVerbose(@"MultipartFormDataParser: header param: %@ = %@",currentParam,paramValue);		currentParam = nil;	}		return YES;}- (NSString *)description {	return [NSString stringWithFormat:@"%@:%@\n params: %@",name,value,params];}@endint findChar(const char* str, NSUInteger length, char c) {	int offset = 0;	while( offset < length ) {		if( str[offset] == c )			return offset;		++ offset;	}	return -1;}NSString* extractParamValue(const char* bytes, NSUInteger length, NSStringEncoding encoding) {	if( !length ) 		return nil;	NSMutableString* value = nil;		if( bytes[0] == '"' ) {		// values may be quoted. Strip the quotes to get what we need.		value = [[NSMutableString alloc] initWithBytes:bytes + 1 length: length - 2 encoding:encoding]; 	}	else {		value = [[NSMutableString alloc] initWithBytes:bytes length: length encoding:encoding];	}	// restore escaped symbols	NSRange range= [value rangeOfString:@"\\"];	while ( range.length ) {		[value deleteCharactersInRange:range];		range.location ++;		range = [value rangeOfString:@"\\" options:NSLiteralSearch range: range];	}	return value;}
 |