2 Copyright (C) 2000-2003 SKYRIX Software AG
4 This file is part of OGo
6 OGo 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 OGo 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 OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 #include "NGHttpHeaderFields.h"
26 @implementation NGHttpHostHeaderField
28 - (id)initWithString:(NSString *)_value {
29 if ([_value length] < 1) {
30 NSLog(@"invalid value for HTTP host header field ..");
31 self = AUTORELEASE(self);
35 if ((self = [super init])) {
36 NSRange rng = [_value rangeOfString:@":"];
38 if (rng.length == 0) {
39 self->hostName = [_value copyWithZone:[self zone]];
43 self->hostName = [[_value substringToIndex:rng.location] retain];
44 self->port = [[_value substringFromIndex:(rng.location + rng.length)]
51 #if !LIB_FOUNDATION_BOEHM_GC
53 RELEASE(self->hostName);
60 - (NSString *)hostName {
61 return self->hostName;
67 // advanced conversions
69 - (NGInternetSocketAddress *)socketAddress {
70 return [NGInternetSocketAddress addressWithPort:[self port]
71 onHost:[self hostName]];
74 return [NSHost hostWithName:[self hostName]];
79 - (NSString *)stringValue {
81 return [NSString stringWithFormat:@"%s:%i",
82 [self->hostName cString], self->port];
85 return self->hostName;
88 - (NSString *)description {
89 return [NSString stringWithFormat:@"<HostField[0x%08X]: host=%@ port=%i>",
90 self, [self hostName], [self port]];
93 @end /* NGHttpHostHeaderField */
95 @implementation NGHttpCharsetHeaderField
98 return [self initWithString:nil];
101 - (id)initWithArray:(NSArray *)_charsetArray {
102 if ([_charsetArray count] < 1) {
103 NSLog(@"invalid value for HTTP charset header field ..");
104 self = AUTORELEASE(self);
108 if ((self = [super init])) {
109 self->charsets = RETAIN(_charsetArray);
110 NSAssert([self->charsets count] >= 1, @"no content in array ..");
112 self->containsWildcard = [self->charsets containsObject:@"*"];
116 - (id)initWithString:(NSString *)_value {
117 if ([_value length] < 1) {
118 NSLog(@"invalid value for HTTP charset header field ..");
119 self = AUTORELEASE(self);
123 return [self initWithArray:[_value componentsSeparatedByString:@","]];
126 #if !LIB_FOUNDATION_BOEHM_GC
128 RELEASE(self->charsets);
135 - (NSEnumerator *)charsets {
136 return [self->charsets objectEnumerator];
138 - (BOOL)containsCharset:(NSString *)_setName {
139 if (self->containsWildcard)
142 return [self->charsets containsObject:_setName];
147 - (NSString *)stringValue {
148 NSMutableString *str = [[NSMutableString allocWithZone:[self zone]] init];
149 int cnt, count = [self->charsets count];
151 for (cnt = 0; cnt < count; cnt++) {
152 if (cnt != 0) [str appendString:@","];
153 [str appendString:[self->charsets objectAtIndex:cnt]];
155 return AUTORELEASE(str);
158 - (NSString *)description {
159 return [NSString stringWithFormat:@"<HttpCharset[0x%08X]: %@>",
160 self, self->charsets];
163 @end /* NGHttpCharsetHeaderField */
165 @implementation NGHttpTypeSetHeaderField
168 return [self initWithArray:nil];
171 - (id)initWithArray:(NSArray *)_typeArray {
172 if ([_typeArray count] < 1) {
173 NSLog(@"invalid value for HTTP charset header field ..");
174 self = AUTORELEASE(self);
178 if ((self = [super init])) {
179 self->types = RETAIN(_typeArray);
180 NSAssert([self->types count] >= 1, @"no content in array ..");
185 #if !LIB_FOUNDATION_BOEHM_GC
187 RELEASE(self->types); self->types = nil;
194 - (NSEnumerator *)types {
195 return [self->types objectEnumerator];
197 - (BOOL)containsMimeType:(NGMimeType *)_type {
198 return [self->types containsObject:_type];
203 - (NSString *)stringValue {
204 NSMutableString *str;
207 str = [[NSMutableString allocWithZone:[self zone]] init];
208 count = [self->types count];
210 for (cnt = 0; cnt < count; cnt++) {
211 if (cnt != 0) [str appendString:@", "];
212 [str appendString:[[self->types objectAtIndex:cnt] stringValue]];
214 return AUTORELEASE(str);
217 - (NSString *)description {
218 return [NSString stringWithFormat:@"<HttpMimeTypes[0x%08X]: %@>",
222 @end /* NGHttpTypeSetHeaderField */
224 @implementation NGHttpLanguageSetHeaderField
227 return [self initWithArray:nil];
230 - (id)initWithArray:(NSArray *)_languageArray {
231 if ([_languageArray count] < 1) {
232 NSLog(@"invalid value for HTTP charset header field ..");
233 self = AUTORELEASE(self);
237 if ((self = [super init])) {
238 self->languages = RETAIN(_languageArray);
239 NSAssert([self->languages count] >= 1, @"no content in array ..");
244 #if !LIB_FOUNDATION_BOEHM_GC
246 RELEASE(self->languages); self->languages = nil;
253 - (NSEnumerator *)languages {
254 return [self->languages objectEnumerator];
256 - (BOOL)containsLanguage:(NSString *)_language {
257 return [self->languages containsObject:_language];
262 - (NSString *)stringValue {
263 NSMutableString *str = [[NSMutableString allocWithZone:[self zone]] init];
264 int cnt, count = [self->languages count];
266 for (cnt = 0; cnt < count; cnt++) {
267 if (cnt != 0) [str appendString:@", "];
268 [str appendString:[self->languages objectAtIndex:cnt]];
270 return AUTORELEASE(str);
273 - (NSString *)description {
274 return [NSString stringWithFormat:@"<HttpLanguages[0x%08X]: %@>",
275 self, self->languages];
278 @end /* NGHttpLanguageSetHeaderField */
280 @implementation NGHttpUserAgent
282 static void _parseUserAgent(NGHttpUserAgent *self) {
283 [self->browser release]; self->browser = nil;
285 if ([self->value hasPrefix:@"Mozilla"]) {
286 // Mozilla Browser or compatible
290 r = [self->value rangeOfString:@"/"];
295 tmp = [self->value substringFromIndex:(idx + 1)];
296 r = [tmp rangeOfString:@" "];
299 tmp = [tmp substringToIndex:idx];
301 self->browser = @"Mozilla";
303 sscanf([tmp cString], "%i.%i", &av, &iv);
304 self->majorVersion = av;
305 self->minorVersion = iv;
307 if (idx != NSNotFound) {
308 r = [self->value rangeOfString:@"MSIE "];
311 tmp = [self->value substringFromIndex:(idx + 5)];
312 self->browser = @"MSIE";
314 sscanf([tmp cString], "%i.%i", &av, &iv);
315 self->majorVersion = av;
316 self->minorVersion = iv;
324 - (id)initWithString:(NSString *)_value {
325 if ((self = [super init])) {
326 self->value = [_value copyWithZone:[self zone]];
327 _parseUserAgent(self);
333 [self->browser release];
334 [self->value release];
341 return [self->browser isEqualToString:@"Mozilla"];
343 - (BOOL)isInternetExplorer {
344 return [self->browser isEqualToString:@"MSIE"];
347 - (int)majorVersion {
348 return self->majorVersion;
350 - (int)minorVersion {
351 return self->minorVersion;
356 - (NSString *)stringValue {
360 - (NSString *)description {
361 return [NSString stringWithFormat:
362 @"<HttpUserAgent[0x%08X]: %@ "
363 @"(detected=%@, major=%i, minor=%i)>",
364 self, self->value, self->browser,
365 self->majorVersion, self->minorVersion];
368 @end /* NGHttpUserAgent */
370 @implementation NGHttpConnectionHeaderField
372 - (id)initWithString:(NSString *)_value {
375 s = [_value lowercaseString];
377 if ([s rangeOfString:@"keep-alive"].length > 0) {
378 if ((self = [super init])) {
379 self->keepAlive = YES;
383 else if ([s rangeOfString:@"close"].length > 0) {
384 if ((self = [super init])) {
389 else if ([s rangeOfString:@"te"].length > 0) {
390 if ((self = [super init])) {
396 NSLog(@"WARNING(%s): cannot parse HTTP connection header value: '%@'",
397 __PRETTY_FUNCTION__, _value);
398 self = AUTORELEASE(self);
399 return [_value copy];
406 return self->keepAlive;
414 - (NSString *)stringValue {
418 return @"Keep-Alive";
425 - (NSString *)description {
426 return [NSString stringWithFormat:
427 @"<HttpConnection[0x%08X]: keepAlive=%s close=%s TE=%s>",
429 self->keepAlive ? "yes" : "no",
430 self->close ? "yes" : "no",
431 self->isTE ? "yes" : "no"
435 @end /* NGHttpConnectionHeaderField */
439 @interface NGConcreteHttpBasicCredentials : NGHttpCredentials
447 @interface NGHttpCredentials(PrivateMethods)
448 - (id)initWithScheme:(NSString *)_scheme credentials:(NSData *)_credentials;
451 @implementation NGHttpCredentials
453 + (id)credentialsWithString:(NSString *)_cred {
458 if ([_cred length] == 0)
460 rng = [_cred rangeOfString:@" "];
464 lscheme = [_cred substringToIndex:rng.location];
465 cred = [[_cred substringFromIndex:(rng.location + 1)]
466 dataUsingEncoding:NSISOLatin1StringEncoding];
468 return [self credentialsWithScheme:lscheme credentials:cred];
471 + (id)credentialsWithScheme:(NSString *)_scheme
472 credentials:(NSData *)_credentials
474 if ([_scheme caseInsensitiveCompare:@"basic"] == NSOrderedSame) {
475 return [[[NGConcreteHttpBasicCredentials alloc]
476 initWithScheme:_scheme
477 credentials:_credentials]
481 return [[[self alloc] initWithScheme:_scheme
482 credentials:_credentials] autorelease];
485 - (id)initWithScheme:(NSString *)_scheme credentials:(NSData *)_credentials {
486 if ((self = [super init])) {
487 self->scheme = [_scheme copy];
488 self->credentials = [_credentials copy];
493 return [self initWithScheme:@"basic" credentials:nil];
497 [self->scheme release];
498 [self->credentials release];
504 - (NSString *)scheme {
508 - (NSData *)credentials {
509 return self->credentials;
512 - (NSString *)userName {
513 #if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY
514 // TODO: raise exception
517 return [self subclassResponsibility:_cmd];
520 - (NSString *)password {
521 #if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY
522 // TODO: raise exception
525 return [self subclassResponsibility:_cmd];
531 - (NSString *)stringValue {
532 NSMutableString *str;
534 str = [NSMutableString stringWithCapacity:64];
535 [str appendString:self->scheme];
536 [str appendString:@" "];
537 [str appendString:[NSString stringWithCString:[self->credentials bytes]
538 length:[self->credentials length]]];
542 - (NSString *)description {
543 return [NSString stringWithFormat:@"<%@[0x%08X]: %@>",
544 NSStringFromClass([self class]), self,
548 @end /* NGHttpCredentials */
550 @implementation NGConcreteHttpBasicCredentials
552 - (id)initWithScheme:(NSString *)_scheme credentials:(NSData *)_credentials {
553 if ((self = [super initWithScheme:_scheme credentials:_credentials])) {
554 NSData *data = [_credentials dataByDecodingBase64];
557 char *str = (char *)[data bytes];
558 int len = [data length];
561 while ((*str != '\0') && (*str != ':') && (len > 0)) {
566 [[NSString alloc] initWithCString:start length:(str - start)];
571 self->password = [[NSString alloc] initWithCString:str length:len];
574 //NSLog(@"decoded user %@ password %@", self->user, self->password);
577 NSLog(@"ERROR: could not decode credentials (invalid base64 encoding)");
583 [self->user release];
584 [self->password release];
590 - (NSString *)userName {
593 - (NSString *)password {
594 return self->password;
599 - (NSString *)description {
600 return [NSString stringWithFormat:
601 @"<BasicCredentials[0x%08X]: user=%@ hasPassword=%s>",
604 self->password ? "yes" : "no"
608 @end /* NGConcreteHttpBasicCredentials */
610 @implementation NGHttpChallenge
612 + (id)basicChallengeWithRealm:(NSString *)_realm {
613 return [[[self alloc] initWithScheme:@"basic" realm:_realm] autorelease];
616 - (id)initWithScheme:(NSString *)_scheme realm:(NSString *)_realm {
617 if ((self = [super init])) {
618 self->scheme = [_scheme copy];
619 self->parameters = [[NSMutableDictionary alloc] init];
622 [(NSMutableDictionary *)self->parameters setObject:_realm forKey:@"realm"];
627 return [self initWithScheme:@"basic" realm:@"NGHttp"];
631 [self->scheme release];
632 [self->parameters release];
638 - (NSString *)scheme {
642 - (void)setRealm:(NSString *)_realm {
643 [(NSMutableDictionary *)self->parameters setObject:_realm forKey:@"realm"];
645 - (NSString *)realm {
646 return [self->parameters objectForKey:@"realm"];
651 - (NSString *)stringValue {
652 NSMutableString *str;
656 str = [NSMutableString stringWithCapacity:128];
657 keys = [self->parameters keyEnumerator];
658 [str appendString:self->scheme];
660 while ((key = [keys nextObject])) {
661 [str appendString:@" "];
662 [str appendString:key];
663 [str appendString:@"=\""];
664 [str appendString:[[self->parameters objectForKey:key] stringValue]];
665 [str appendString:@"\""];
671 - (NSString *)description {
672 return [NSString stringWithFormat:@"<%@[0x%08X]: %@>",
673 NSStringFromClass([self class]), self,
677 @end /* NGHttpChallenge */