]> err.no Git - sope/blob - sope-appserver/NGObjWeb/NGHttp/NGHttpHeaderFields.m
fixed makefiles to search FHS locations at the last resort
[sope] / sope-appserver / NGObjWeb / NGHttp / NGHttpHeaderFields.m
1 /*
2   Copyright (C) 2000-2003 SKYRIX Software AG
3
4   This file is part of OGo
5
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
9   later version.
10
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.
15
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
19   02111-1307, USA.
20 */
21 // $Id$
22
23 #include "common.h"
24 #include "NGHttpHeaderFields.h"
25
26 @implementation NGHttpHostHeaderField
27
28 - (id)initWithString:(NSString *)_value {
29   if ([_value length] < 1) {
30     NSLog(@"invalid value for HTTP host header field ..");
31     self = AUTORELEASE(self);
32     return nil;
33   }
34   
35   if ((self = [super init])) {
36     NSRange rng = [_value rangeOfString:@":"];
37
38     if (rng.length == 0) {
39       self->hostName = [_value copyWithZone:[self zone]];
40       self->port     = -1;
41     }
42     else {
43       self->hostName = [[_value substringToIndex:rng.location] retain];
44       self->port     = [[_value substringFromIndex:(rng.location + rng.length)]
45                                 intValue];
46     }
47   }
48   return self;
49 }
50
51 #if !LIB_FOUNDATION_BOEHM_GC
52 - (void)dealloc {
53   RELEASE(self->hostName);
54   [super dealloc];
55 }
56 #endif
57
58 // accessors
59
60 - (NSString *)hostName {
61   return self->hostName;
62 }
63 - (int)port {
64   return self->port;
65 }
66
67 // advanced conversions
68
69 - (NGInternetSocketAddress *)socketAddress {
70   return [NGInternetSocketAddress addressWithPort:[self port]
71                                   onHost:[self hostName]];
72 }
73 - (NSHost *)host {
74   return [NSHost hostWithName:[self hostName]];
75 }
76
77 /* description */
78
79 - (NSString *)stringValue {
80   if (self->port > 0) {
81     return [NSString stringWithFormat:@"%s:%i",
82                        [self->hostName cString], self->port];
83   }
84   else
85     return self->hostName;
86 }
87
88 - (NSString *)description {
89   return [NSString stringWithFormat:@"<HostField[0x%08X]: host=%@ port=%i>",
90                      self, [self hostName], [self port]];
91 }
92
93 @end /* NGHttpHostHeaderField */
94
95 @implementation NGHttpCharsetHeaderField
96
97 - (id)init {
98   return [self initWithString:nil];
99 }
100
101 - (id)initWithArray:(NSArray *)_charsetArray {
102   if ([_charsetArray count] < 1) {
103     NSLog(@"invalid value for HTTP charset header field ..");
104     self = AUTORELEASE(self);
105     return nil;
106   }
107
108   if ((self = [super init])) {
109     self->charsets = RETAIN(_charsetArray);
110     NSAssert([self->charsets count] >= 1, @"no content in array ..");
111
112     self->containsWildcard = [self->charsets containsObject:@"*"];
113   }
114   return self;
115 }
116 - (id)initWithString:(NSString *)_value {
117   if ([_value length] < 1) {
118     NSLog(@"invalid value for HTTP charset header field ..");
119     self = AUTORELEASE(self);
120     return nil;
121   }
122
123   return [self initWithArray:[_value componentsSeparatedByString:@","]];
124 }
125
126 #if !LIB_FOUNDATION_BOEHM_GC
127 - (void)dealloc {
128   RELEASE(self->charsets);
129   [super dealloc];
130 }
131 #endif
132
133 // accessors
134
135 - (NSEnumerator *)charsets {
136   return [self->charsets objectEnumerator];
137 }
138 - (BOOL)containsCharset:(NSString *)_setName {
139   if (self->containsWildcard)
140     return YES;
141   else
142     return [self->charsets containsObject:_setName];
143 }
144
145 /* description */
146
147 - (NSString *)stringValue {
148   NSMutableString *str = [[NSMutableString allocWithZone:[self zone]] init];
149   int  cnt, count = [self->charsets count];
150
151   for (cnt = 0; cnt < count; cnt++) {
152     if (cnt != 0) [str appendString:@","];
153     [str appendString:[self->charsets objectAtIndex:cnt]];
154   }
155   return AUTORELEASE(str);
156 }
157
158 - (NSString *)description {
159   return [NSString stringWithFormat:@"<HttpCharset[0x%08X]: %@>",
160                      self, self->charsets];
161 }
162
163 @end /* NGHttpCharsetHeaderField */
164
165 @implementation NGHttpTypeSetHeaderField
166
167 - (id)init {
168   return [self initWithArray:nil];
169 }
170
171 - (id)initWithArray:(NSArray *)_typeArray {
172   if ([_typeArray count] < 1) {
173     NSLog(@"invalid value for HTTP charset header field ..");
174     self = AUTORELEASE(self);
175     return nil;
176   }
177
178   if ((self = [super init])) {
179     self->types = RETAIN(_typeArray);
180     NSAssert([self->types count] >= 1, @"no content in array ..");
181   }
182   return self;
183 }
184
185 #if !LIB_FOUNDATION_BOEHM_GC
186 - (void)dealloc {
187   RELEASE(self->types); self->types = nil;
188   [super dealloc];
189 }
190 #endif
191
192 // accessors
193
194 - (NSEnumerator *)types {
195   return [self->types objectEnumerator];
196 }
197 - (BOOL)containsMimeType:(NGMimeType *)_type {
198   return [self->types containsObject:_type];
199 }
200
201 /* description */
202
203 - (NSString *)stringValue {
204   NSMutableString *str;
205   int  cnt, count;
206
207   str = [[NSMutableString allocWithZone:[self zone]] init];
208   count = [self->types count];
209
210   for (cnt = 0; cnt < count; cnt++) {
211     if (cnt != 0) [str appendString:@", "];
212     [str appendString:[[self->types objectAtIndex:cnt] stringValue]];
213   }
214   return AUTORELEASE(str);
215 }
216
217 - (NSString *)description {
218   return [NSString stringWithFormat:@"<HttpMimeTypes[0x%08X]: %@>",
219                      self, self->types];
220 }
221
222 @end /* NGHttpTypeSetHeaderField */
223
224 @implementation NGHttpLanguageSetHeaderField
225
226 - (id)init {
227   return [self initWithArray:nil];
228 }
229
230 - (id)initWithArray:(NSArray *)_languageArray {
231   if ([_languageArray count] < 1) {
232     NSLog(@"invalid value for HTTP charset header field ..");
233     self = AUTORELEASE(self);
234     return nil;
235   }
236
237   if ((self = [super init])) {
238     self->languages = RETAIN(_languageArray);
239     NSAssert([self->languages count] >= 1, @"no content in array ..");
240   }
241   return self;
242 }
243
244 #if !LIB_FOUNDATION_BOEHM_GC
245 - (void)dealloc {
246   RELEASE(self->languages); self->languages = nil;
247   [super dealloc];
248 }
249 #endif
250
251 // accessors
252
253 - (NSEnumerator *)languages {
254   return [self->languages objectEnumerator];
255 }
256 - (BOOL)containsLanguage:(NSString *)_language {
257   return [self->languages containsObject:_language];
258 }
259
260 /* description */
261
262 - (NSString *)stringValue {
263   NSMutableString *str = [[NSMutableString allocWithZone:[self zone]] init];
264   int  cnt, count = [self->languages count];
265
266   for (cnt = 0; cnt < count; cnt++) {
267     if (cnt != 0) [str appendString:@", "];
268     [str appendString:[self->languages objectAtIndex:cnt]];
269   }
270   return AUTORELEASE(str);
271 }
272
273 - (NSString *)description {
274   return [NSString stringWithFormat:@"<HttpLanguages[0x%08X]: %@>",
275                      self, self->languages];
276 }
277
278 @end /* NGHttpLanguageSetHeaderField */
279
280 @implementation NGHttpUserAgent
281
282 static void _parseUserAgent(NGHttpUserAgent *self) {
283   [self->browser release]; self->browser = nil;
284
285   if ([self->value hasPrefix:@"Mozilla"]) {
286     // Mozilla Browser or compatible
287     NSRange r;
288     int idx, av, iv;
289
290     r = [self->value rangeOfString:@"/"];
291     idx = r.location;
292     if (r.length > 0) {
293       NSString *tmp;
294
295       tmp = [self->value substringFromIndex:(idx + 1)];
296       r   = [tmp rangeOfString:@" "];
297       idx = r.location;
298       if (r.length > 0)
299         tmp = [tmp substringToIndex:idx];
300
301       self->browser = @"Mozilla";
302
303       sscanf([tmp cString], "%i.%i", &av, &iv);
304       self->majorVersion = av;
305       self->minorVersion = iv;
306
307       if (idx != NSNotFound) {
308         r = [self->value rangeOfString:@"MSIE "];
309         idx = r.location;
310         if (r.length > 0) {
311           tmp = [self->value substringFromIndex:(idx + 5)];
312           self->browser = @"MSIE";
313
314           sscanf([tmp cString], "%i.%i", &av, &iv);
315           self->majorVersion = av;
316           self->minorVersion = iv;
317         }
318       }
319       return;
320     }
321   }
322 }
323
324 - (id)initWithString:(NSString *)_value {
325   if ((self = [super init])) {
326     self->value = [_value copyWithZone:[self zone]];
327     _parseUserAgent(self);
328   }
329   return self;
330 }
331
332 - (void)dealloc {
333   [self->browser release];
334   [self->value   release];
335   [super dealloc];
336 }
337
338 /* browsers */
339
340 - (BOOL)isMozilla {
341   return [self->browser isEqualToString:@"Mozilla"];
342 }
343 - (BOOL)isInternetExplorer {
344   return [self->browser isEqualToString:@"MSIE"];
345 }
346
347 - (int)majorVersion {
348   return self->majorVersion;
349 }
350 - (int)minorVersion {
351   return self->minorVersion;
352 }
353
354 /* description */
355
356 - (NSString *)stringValue {
357   return self->value;
358 }
359
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];
366 }
367
368 @end /* NGHttpUserAgent */
369
370 @implementation NGHttpConnectionHeaderField
371
372 - (id)initWithString:(NSString *)_value {
373   NSString *s;
374   
375   s = [_value lowercaseString];
376
377   if ([s rangeOfString:@"keep-alive"].length > 0) {
378     if ((self = [super init])) {
379       self->keepAlive = YES;
380     }
381     return self;
382   }
383   else if ([s rangeOfString:@"close"].length > 0) {
384     if ((self = [super init])) {
385       self->close = YES;
386     }
387     return self;
388   }
389   else if ([s rangeOfString:@"te"].length > 0) {
390     if ((self = [super init])) {
391       self->isTE = YES;
392     }
393     return self;
394   }
395   else {
396     NSLog(@"WARNING(%s): cannot parse HTTP connection header value: '%@'",
397           __PRETTY_FUNCTION__, _value);
398     self = AUTORELEASE(self);
399     return [_value copy];
400   }
401 }
402
403 /* accessors */
404
405 - (BOOL)keepAlive {
406   return self->keepAlive;
407 }
408 - (BOOL)close {
409   return self->close;
410 }
411
412 /* description */
413
414 - (NSString *)stringValue {
415   if (self->close)
416     return @"close";
417   if (self->keepAlive)
418     return @"Keep-Alive";
419   if (self->isTE)
420     return @"TE";
421
422   return nil;
423 }
424
425 - (NSString *)description {
426   return [NSString stringWithFormat:
427                      @"<HttpConnection[0x%08X]: keepAlive=%s close=%s TE=%s>",
428                      self,
429                      self->keepAlive ? "yes" : "no",
430                      self->close     ? "yes" : "no",
431                      self->isTE      ? "yes" : "no"
432   ];
433 }
434
435 @end /* NGHttpConnectionHeaderField */
436
437 // authorization
438
439 @interface NGConcreteHttpBasicCredentials : NGHttpCredentials
440 {
441   NSString *user;
442   NSString *password;
443 }
444
445 @end
446
447 @interface NGHttpCredentials(PrivateMethods)
448 - (id)initWithScheme:(NSString *)_scheme credentials:(NSData *)_credentials;
449 @end
450
451 @implementation NGHttpCredentials
452
453 + (id)credentialsWithString:(NSString *)_cred {
454   NSRange rng;
455   NSString *lscheme;
456   NSData   *cred;
457   
458   if ([_cred length] == 0)
459     return nil;
460   rng = [_cred rangeOfString:@" "];
461   if (rng.length <= 0)
462     return nil;
463
464   lscheme = [_cred substringToIndex:rng.location];
465   cred    = [[_cred substringFromIndex:(rng.location + 1)]
466                     dataUsingEncoding:NSISOLatin1StringEncoding];
467   
468   return [self credentialsWithScheme:lscheme credentials:cred];
469 }
470
471 + (id)credentialsWithScheme:(NSString *)_scheme
472   credentials:(NSData *)_credentials
473 {
474   if ([_scheme caseInsensitiveCompare:@"basic"] == NSOrderedSame) {
475     return [[[NGConcreteHttpBasicCredentials alloc]
476                                              initWithScheme:_scheme
477                                              credentials:_credentials]
478                                              autorelease];
479   }
480
481   return [[[self alloc] initWithScheme:_scheme
482                         credentials:_credentials] autorelease];
483 }
484
485 - (id)initWithScheme:(NSString *)_scheme credentials:(NSData *)_credentials {
486   if ((self = [super init])) {
487     self->scheme      = [_scheme      copy];
488     self->credentials = [_credentials copy];
489   }
490   return self;
491 }
492 - (id)init {
493   return [self initWithScheme:@"basic" credentials:nil];
494 }
495
496 - (void)dealloc {
497   [self->scheme      release];
498   [self->credentials release];
499   [super dealloc];
500 }
501
502 /* accessors */
503
504 - (NSString *)scheme {
505   return self->scheme;
506 }
507
508 - (NSData *)credentials {
509   return self->credentials;
510 }
511
512 - (NSString *)userName {
513 #if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY
514   // TODO: raise exception
515   return nil;
516 #else
517   return [self subclassResponsibility:_cmd];
518 #endif
519 }
520 - (NSString *)password {
521 #if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY
522   // TODO: raise exception
523   return nil;
524 #else
525   return [self subclassResponsibility:_cmd];
526 #endif
527 }
528
529 /* description */
530
531 - (NSString *)stringValue {
532   NSMutableString *str;
533   
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]]];
539   return str;
540 }
541
542 - (NSString *)description {
543   return [NSString stringWithFormat:@"<%@[0x%08X]: %@>",
544                      NSStringFromClass([self class]), self,
545                      [self stringValue]];
546 }
547
548 @end /* NGHttpCredentials */
549
550 @implementation NGConcreteHttpBasicCredentials
551
552 - (id)initWithScheme:(NSString *)_scheme credentials:(NSData *)_credentials {
553   if ((self = [super initWithScheme:_scheme credentials:_credentials])) {
554     NSData *data = [_credentials dataByDecodingBase64];
555
556     if (data) {
557       char *str   = (char *)[data bytes];
558       int  len    = [data length];
559       char *start = str;
560
561       while ((*str != '\0') && (*str != ':') && (len > 0)) {
562         str++;
563         len--;
564       }
565       self->user = 
566         [[NSString alloc] initWithCString:start length:(str - start)];
567       // skip ':'
568       str++; len--;
569       
570       if (len > 0) {
571         self->password = [[NSString alloc] initWithCString:str length:len];
572       }
573
574       //NSLog(@"decoded user %@ password %@", self->user, self->password);
575     }
576     else
577       NSLog(@"ERROR: could not decode credentials (invalid base64 encoding)");
578   }
579   return self;
580 }
581
582 - (void)dealloc {
583   [self->user     release];
584   [self->password release];
585   [super dealloc];
586 }
587
588 /* accessors */
589
590 - (NSString *)userName {
591   return self->user;
592 }
593 - (NSString *)password {
594   return self->password;
595 }
596
597 /* description */
598
599 - (NSString *)description {
600   return [NSString stringWithFormat:
601                      @"<BasicCredentials[0x%08X]: user=%@ hasPassword=%s>",
602                      self,
603                      [self userName],
604                      self->password ? "yes" : "no"
605                    ];
606 }
607
608 @end /* NGConcreteHttpBasicCredentials */
609
610 @implementation NGHttpChallenge
611
612 + (id)basicChallengeWithRealm:(NSString *)_realm {
613   return [[[self alloc] initWithScheme:@"basic" realm:_realm] autorelease];
614 }
615
616 - (id)initWithScheme:(NSString *)_scheme realm:(NSString *)_realm {
617   if ((self = [super init])) {
618     self->scheme     = [_scheme copy];
619     self->parameters = [[NSMutableDictionary alloc] init];
620
621     if (_realm)
622       [(NSMutableDictionary *)self->parameters setObject:_realm forKey:@"realm"];
623   }
624   return self;
625 }
626 - (id)init {
627   return [self initWithScheme:@"basic" realm:@"NGHttp"];
628 }
629
630 - (void)dealloc {
631   [self->scheme     release];
632   [self->parameters release];
633   [super dealloc];
634 }
635
636 /* accessors */
637
638 - (NSString *)scheme {
639   return self->scheme;
640 }
641
642 - (void)setRealm:(NSString *)_realm {
643   [(NSMutableDictionary *)self->parameters setObject:_realm forKey:@"realm"];
644 }
645 - (NSString *)realm {
646   return [self->parameters objectForKey:@"realm"];
647 }
648
649 /* description */
650
651 - (NSString *)stringValue {
652   NSMutableString *str;
653   NSEnumerator    *keys;
654   NSString        *key  = nil;
655
656   str  = [NSMutableString stringWithCapacity:128];
657   keys = [self->parameters keyEnumerator];
658   [str appendString:self->scheme];
659   
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:@"\""];
666   }
667
668   return str;
669 }
670
671 - (NSString *)description {
672   return [NSString stringWithFormat:@"<%@[0x%08X]: %@>",
673                      NSStringFromClass([self class]), self,
674                      [self stringValue]];
675 }
676
677 @end /* NGHttpChallenge */