2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #import "NGHttpHeaderFieldParser.h"
24 #import "NGHttpHeaderFields.h"
25 #import "NGHttpCookie.h"
27 static Class NSArrayClass = Nil;
29 @implementation NGHttpStringHeaderFieldParser
31 - (id)parseValue:(id)_data ofHeaderField:(NSString *)_field {
33 const unsigned char *src = NULL;
34 NGHttpHostHeaderField *value = nil;
37 if ([_data isKindOfClass:[NSData class]]) {
39 src = (unsigned char *)[_data bytes];
42 len = [_data cStringLength];
43 src = [_data cString];
47 NSLog(@"WARNING: empty value for header field %@ ..", _field);
52 // strip leading spaces
53 while (isRfc822_LWSP(*src) && (len > 0)) {
58 str = [[NSString alloc] initWithCString:src length:len];
59 NSAssert(str, @"string allocation failed ..");
61 if ([_field isEqualToString:@"host"])
62 value = [[NGHttpHostHeaderField alloc] initWithString:str];
63 else if ([_field isEqualToString:@"user-agent"])
64 value = [[NGHttpUserAgent alloc] initWithString:str];
65 else if ([_field isEqualToString:@"connection"])
66 value = [[NGHttpConnectionHeaderField alloc] initWithString:str];
70 RELEASE(str); str = nil;
72 return AUTORELEASE(value);
75 @end /* NGHttpStringHeaderFieldParser */
77 @implementation NGHttpCredentialsFieldParser
79 - (id)parseValue:(id)_data ofHeaderField:(NSString *)_field {
81 const unsigned char *src = NULL;
82 NSString *scheme = nil;
85 if ([_data isKindOfClass:[NSData class]]) {
87 src = (unsigned char *)[_data bytes];
90 len = [_data cStringLength];
91 src = [_data cString];
95 NSLog(@"WARNING: empty value for header field %@ ..", _field);
99 // strip leading spaces
100 while (isRfc822_LWSP(*src) && (len > 0)) {
105 NSLog(@"WARNING: empty value for header field %@ ..", _field);
111 const unsigned char *start = src;
113 while (!isRfc822_LWSP(*src) && (len > 0)) {
117 scheme = [NSString stringWithCString:start length:(src - start)];
121 while (isRfc822_LWSP(*src) && (len > 0)) {
126 NSLog(@"WARNING: invalid credentials header field %@ .. (missing credentials)",
132 data = [NSData dataWithBytes:src length:len];
134 return [NGHttpCredentials credentialsWithScheme:[scheme lowercaseString]
138 @end /* NGHttpCredentialsFieldParser */
140 @implementation NGHttpStringArrayHeaderFieldParser
142 - (id)initWithSplitChar:(unsigned char)_c {
143 if ((self = [super init])) {
144 self->splitChar = _c;
149 return [self initWithSplitChar:','];
152 - (id)parseValuePart:(const char *)_b length:(unsigned)_len
155 return [[NSString allocWithZone:_zone]
156 initWithCString:_b length:_len];
159 - (id)parseValue:(id)_data ofHeaderField:(NSString *)_field {
161 const unsigned char *src = NULL;
162 NSMutableArray *array = nil;
164 if ([_data isKindOfClass:[NSData class]]) {
165 len = [_data length];
166 src = (unsigned char *)[_data bytes];
169 len = [_data cStringLength];
170 src = [_data cString];
175 NSLog(@"WARNING: empty value for header field %@ ..", _field);
181 NSLog(@"field %@ is %@",
183 [[NSString alloc] initWithData:_data encoding:NSASCIIStringEncoding]);
187 array = [NSMutableArray arrayWithCapacity:16];
188 NSAssert(array, @"array allocation failed ..");
190 const unsigned char *startPos = NULL;
192 // strip leading spaces
193 while ((*src != '\0') && isRfc822_LWSP(*src) && (len > 0)) {
202 while ((*src != self->splitChar) && !isRfc822_LWSP(*src) && (len > 0)) {
207 if (src > startPos) {
211 partLen = (src - startPos);
213 NSLog(@"field %@: current len=%i %s(%i)", _field, len, startPos, partLen);
216 part = [self parseValuePart:startPos
220 [array addObject:part];
221 RELEASE(part); part = nil;
226 if (isRfc822_LWSP(*src)) { // skip until splitchar or to len ..
227 while ((*src != '\0') && (*src != self->splitChar) && (len > 0)) {
232 else if (*src == self->splitChar) { // skip ','
238 while ((*src != '\0') && (len > 0));
243 @end /* NGHttpStringArrayHeaderFieldParser */
245 @implementation NGHttpCharsetHeaderFieldParser
247 - (id)parseValue:(NSData *)_data ofHeaderField:(NSString *)_field {
250 value = [super parseValue:_data ofHeaderField:_field];
252 if (NSArrayClass == Nil)
253 NSArrayClass = [NSArray class];
255 NSAssert([value isKindOfClass:NSArrayClass], @"invalid value ..");
257 value = [[NGHttpCharsetHeaderField alloc] initWithArray:value];
258 value = AUTORELEASE(value);
263 @end /* NGHttpCharsetHeaderFieldParser */
265 @implementation NGHttpTypeArrayHeaderFieldParser
267 - (id)parseValuePart:(const char *)_b length:(unsigned)_len zone:(NSZone *)_zone {
268 NSString *typeString = [[NSString alloc] initWithCString:_b length:_len];
269 NGMimeType *type = nil;
271 type = typeString ? [NGMimeType mimeType:typeString] : nil;
277 - (id)parseValue:(id)_data ofHeaderField:(NSString *)_field {
280 value = [super parseValue:_data ofHeaderField:_field];
282 if (NSArrayClass == Nil)
283 NSArrayClass = [NSArray class];
285 NSAssert([value isKindOfClass:NSArrayClass], @"invalid value ..");
287 value = [[NGHttpTypeSetHeaderField alloc] initWithArray:value];
288 value = AUTORELEASE(value);
293 @end /* NGHttpTypeArrayHeaderFieldParser */
295 @implementation NGHttpLanguageArrayHeaderFieldParser
297 - (id)parseValue:(id)_data ofHeaderField:(NSString *)_field {
300 value = [super parseValue:_data ofHeaderField:_field];
302 if (NSArrayClass == Nil)
303 NSArrayClass = [NSArray class];
305 NSAssert([value isKindOfClass:NSArrayClass], @"invalid value ..");
307 value = [[NGHttpLanguageSetHeaderField alloc] initWithArray:value];
308 value = AUTORELEASE(value);
313 @end /* NGHttpLanguageArrayHeaderFieldParser */
315 @implementation NGHttpCookieFieldParser
318 return [self initWithSplitChar:';'];
320 - (id)initWithSplitChar:(unsigned char)_splitChar {
321 if ((self = [super initWithSplitChar:_splitChar])) {
322 self->fetchedCookies = NSCreateMapTable(NSObjectMapKeyCallBacks,
323 NSObjectMapValueCallBacks,
325 self->isRunning = NO;
326 self->foundInvalidPairs = NO;
331 #if !LIB_FOUNDATION_BOEHM_GC
333 if (self->fetchedCookies) {
334 NSFreeMapTable(self->fetchedCookies);
335 self->fetchedCookies = NULL;
341 - (id)parseValuePart:(const char *)_bytes length:(unsigned)_len
344 NGHttpCookie *cookie = nil;
347 for (pos = 0, toGo = _len; (toGo > 0) && (_bytes[pos] != '='); toGo--, pos++)
351 NSString *name = nil;
352 NSString *value = nil;
354 // NSLog(@"pos=%i toGo=%i", pos, toGo);
356 name = [[NSString allocWithZone:_z]
357 initWithCString:_bytes
359 value = [[NSString allocWithZone:_z]
360 initWithCString:&(_bytes[pos + 1])
363 //NSLog(@"pair='%@'", [NSString stringWithCString:_bytes length:_len]);
364 //NSLog(@"name='%@' value='%@'", name, value);
367 NSLog(@"ERROR: invalid cookie pair missing name: %@",
368 [NSString stringWithCString:_bytes length:_len]);
373 else if (value == nil) {
374 NSLog(@"ERROR: invalid cookie pair missing value (name=%@): %@",
376 [NSString stringWithCString:_bytes length:_len]);
382 cookie = (id)NSMapGet(self->fetchedCookies, name);
385 [cookie addAdditionalValue:[value stringByUnescapingURL]];
389 cookie = [[NGHttpCookie allocWithZone:_z]
390 initWithName:[name stringByUnescapingURL]
391 value:[value stringByUnescapingURL]];
392 NSMapInsert(self->fetchedCookies, name, cookie);
396 RELEASE(name); name = nil;
397 RELEASE(value); value = nil;
401 NSLog(@"ERROR(%s:%i): invalid cookie pair: %@",
402 __PRETTY_FUNCTION__, __LINE__,
403 [NSString stringWithCString:_bytes length:_len]);
404 self->foundInvalidPairs = YES;
410 - (id)parseValue:(id)_data ofHeaderField:(NSString *)_field {
413 if (NSArrayClass == Nil)
414 NSArrayClass = [NSArray class];
416 NSAssert(self->isRunning == NO, @"parser used in multiple threads !");
417 self->foundInvalidPairs = NO;
420 NSLog(@"cookie: field %@ is %@",
422 [[NSString alloc] initWithData:_data encoding:NSUTF8StringEncoding]);
425 self->isRunning = YES; // semi-lock
427 value = [super parseValue:_data ofHeaderField:_field];
428 NSResetMapTable(self->fetchedCookies);
430 self->isRunning = NO; // semi-unlock
432 if (self->foundInvalidPairs) {
436 if ([_data isKindOfClass:[NSData class]])
437 s = [[NSString alloc] initWithData:_data encoding:NSASCIIStringEncoding];
441 NSLog(@"ERROR(%s:%i): got invalid cookie pairs for field %@ data %@.",
442 __PRETTY_FUNCTION__, __LINE__,
450 NSAssert1([value isKindOfClass:NSArrayClass],
451 @"invalid value '%@' ..", value);
453 //value = [[NGHttpTypeSetHeaderField alloc] initWithArray:value];
454 //AUTORELEASE(value);
459 @end /* NGHttpCookieFieldParser */
461 @implementation NGMimeHeaderFieldParserSet(HttpFieldParserSet)
463 static NGMimeHeaderFieldParserSet *httpSet = nil;
465 static inline void NGRegisterParser(NSString *_field, NSString *_parserClass) {
466 id parser = [[NSClassFromString(_parserClass) alloc] init];
469 [httpSet setParser:parser forField:_field];
474 NSLog(@"WARNING: did not find header field parser %@", _parserClass);
478 + (id)defaultHttpHeaderFieldParserSet {
479 if (httpSet == nil) {
482 httpSet = [[self alloc] initWithParseSet:
483 [NGMimeHeaderFieldParserSet defaultRfc822HeaderFieldParserSet]];
485 parser = [[NGHttpStringHeaderFieldParser alloc] init];
486 [httpSet setParser:parser forField:@"host"];
487 [httpSet setParser:parser forField:@"user-agent"];
488 [httpSet setParser:parser forField:@"connection"];
489 RELEASE(parser); parser = nil;
491 NGRegisterParser(@"accept-charset", @"NGHttpCharsetHeaderFieldParser");
492 NGRegisterParser(@"accept-language", @"NGHttpLanguageArrayHeaderFieldParser");
493 NGRegisterParser(@"accept", @"NGHttpTypeArrayHeaderFieldParser");
494 NGRegisterParser(@"accept-encoding", @"NGHttpStringArrayHeaderFieldParser");
495 NGRegisterParser(@"cookie", @"NGHttpCookieFieldParser");
496 NGRegisterParser(@"authorization", @"NGHttpCredentialsFieldParser");
501 @end /* NGMimeHeaderFieldParserSet(HttpFieldParserSet) */