]> err.no Git - sope/blob - sope-appserver/NGObjWeb/NGHttp+WO.m
fixed gstep-base compile warnings
[sope] / sope-appserver / NGObjWeb / NGHttp+WO.m
1 /*
2   Copyright (C) 2000-2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
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
9   later version.
10
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.
15
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
19   02111-1307, USA.
20 */
21
22 #include "NGHttp+WO.h"
23 #include <NGHttp/NGHttp.h>
24 #include <NGObjWeb/WOCookie.h>
25 #include <NGObjWeb/WORequest.h>
26 #include <NGMime/NGMime.h>
27 #include "common.h"
28 #include <string.h>
29
30 @interface WORequest(NGSupport)
31 - (void)_setHttpRequest:(NGHttpRequest *)_request;
32 @end
33
34 @implementation NGHttpRequest(WOSupport)
35
36 static Class NSArrayClass = Nil;
37
38 - (id)initWithWORequest:(WORequest *)_request {
39   NGHashMap *hm;
40   
41   hm = [NGHashMap hashMapWithDictionary:[_request headers]];
42     
43   self = [self initWithMethod:[_request method]
44                uri:[_request uri]
45                header:hm
46                version:[_request httpVersion]];
47   [self setBody:[_request content]];
48   
49   /* transfer cookies */
50   if ([[_request cookies] count] > 0)
51     [self warnWithFormat:@"cannot transfer cookies to NGHttpRequest yet !"];
52
53   /* transfer headers !!! */
54   
55   return self;
56 }
57
58 - (WORequest *)woRequest {
59   NSAutoreleasePool *pool;
60   WORequest    *request;
61   NSDictionary *woHeaders;
62
63   pool = [[NSAutoreleasePool alloc] init];
64   
65   woHeaders = nil;
66   
67   request = [[WORequest alloc]
68                         initWithMethod:[self methodName]
69                         uri:[self uri]
70                         httpVersion:[self httpVersion]
71                         headers:woHeaders
72                         content:[self woContent]
73                         userInfo:nil];
74   request = [request autorelease];
75   
76   [request _setHttpRequest:self];
77   
78   /* process cookies */
79   {
80     NSEnumerator *cs;
81     WOCookie *cookie;
82     
83     cs = [[self woCookies] objectEnumerator];
84     while ((cookie = [cs nextObject]))
85       [request addCookie:cookie];
86   }
87   
88   /* process headers */
89   {
90     NSEnumerator *keys;
91     NSString *key;
92
93     if (NSArrayClass == Nil)
94       NSArrayClass = [NSArray class];
95     
96     keys = [self headerFieldNames];
97     while ((key = [keys nextObject])) {
98       NSEnumerator *values;
99       id value;
100       
101       values = [self valuesOfHeaderFieldWithName:key];
102       while ((value = [values nextObject])) {
103         if ([value isKindOfClass:NSArrayClass]) {
104           NSEnumerator *ev2;
105
106           ev2 = [value objectEnumerator];
107           while ((value = [ev2 nextObject])) {
108             value = [value stringValue];
109             [request appendHeader:value forKey:key];
110           }
111         }
112         else {
113           value = [value stringValue];
114           [request appendHeader:value forKey:key];
115         }
116       }
117     }
118   }
119   
120   request = [request retain];
121   [pool release]; pool = nil;
122   
123   return [request autorelease];
124 }
125
126 /* headers */
127
128 - (NSArray *)woHeaderKeys {
129   NSMutableArray *keys;
130   NSEnumerator   *ekeys;
131   NSString       *key   = nil;
132   
133   keys  = [[NSMutableArray alloc] init];
134   ekeys = [self headerFieldNames];
135   
136   while ((key = [ekeys nextObject]))
137     [keys addObject:key];
138   
139   return [keys autorelease];
140 }
141
142 - (NSString *)woHeaderForKey:(NSString *)_key {
143   return [[[self valuesOfHeaderFieldWithName:_key]
144                  nextObject]
145                  stringValue];
146 }
147
148 - (NSArray *)woHeadersForKey:(NSString *)_key {
149   NSMutableArray *vals;
150   NSEnumerator   *evals;
151   NSString       *value = nil;
152
153   vals  = [NSMutableArray arrayWithCapacity:2];
154   evals = [self valuesOfHeaderFieldWithName:_key];
155   
156   while ((value = [evals nextObject])) {
157     if ((value = [value stringValue]))
158       [vals addObject:value];
159   }
160
161   return vals;
162 }
163
164 /* cookies */
165
166 - (void)_addHTTPCookie:(id)_cookie to:(NSMutableArray *)_a {
167   static Class NGHttpCookieClass = Nil;
168   static Class WOCookieClass = Nil;
169   WOCookie *cookie;
170   id cookieValue;
171   
172   if (_cookie == nil)
173     return;
174   
175   if (NGHttpCookieClass == Nil) NGHttpCookieClass = [NGHttpCookie class];
176   if (WOCookieClass     == Nil) WOCookieClass = NSClassFromString(@"WOCookie");
177
178   if (![_cookie isKindOfClass:NGHttpCookieClass]) {
179     static NGHttpCookieFieldParser *cookieParser = nil;
180           
181     if (cookieParser == nil)
182       cookieParser = [[NGHttpCookieFieldParser alloc] init];
183           
184     _cookie = [_cookie stringValue];
185     _cookie = [_cookie dataUsingEncoding:NSISOLatin1StringEncoding];
186     _cookie = [cookieParser parseValue:_cookie ofHeaderField:@"cookie"];
187   }
188   
189   if ([_cookie isKindOfClass:[NSArray class]]) {
190     id singleCookie;
191       
192     _cookie = [_cookie objectEnumerator];
193     
194     while ((singleCookie = [_cookie nextObject]))
195       [self _addHTTPCookie:singleCookie to:_a];
196     return;
197   }
198
199   cookieValue = [(NGHttpCookie *)_cookie value];
200   if ([cookieValue isKindOfClass:[NSArray class]]) {
201     if ([cookieValue count] == 0)
202       cookieValue = @"";
203     else if ([cookieValue count] == 1)
204       cookieValue = [[cookieValue objectAtIndex:0] stringValue];
205     else {
206       [self logWithFormat:
207               @"got %d values for cookie '%@', using first only: %@",
208               [cookieValue count],
209               [_cookie cookieName], 
210               [cookieValue componentsJoinedByString:@","]];
211       cookieValue = [[cookieValue objectAtIndex:0] stringValue];
212     }
213   }
214   else
215     cookieValue = [cookieValue stringValue];
216     
217   cookie = [WOCookieClass cookieWithName:[_cookie cookieName]
218                           value:cookieValue
219                           path:[_cookie path]
220                           domain:[_cookie domainName]
221                           expires:[_cookie expireDate]
222                           isSecure:[_cookie needsSecureChannel]];
223   
224   /* WOMessage */
225   if (cookie != nil)
226     [_a addObject:cookie];
227 }
228
229 - (NSArray *)woCookies {
230   NSMutableArray *womCookies;
231   NSArray        *woCookies;
232   NSEnumerator   *mcookies;
233   id             cookie;
234
235   if (NSArrayClass == Nil) NSArrayClass = [NSArray class];
236   
237   womCookies = [NSMutableArray arrayWithCapacity:8];
238   
239   mcookies = [self valuesOfHeaderFieldWithName:@"cookie"];
240   while ((cookie = [mcookies nextObject])) {
241     if ([cookie isKindOfClass:NSArrayClass]) {
242       id singleCookie;
243       
244       cookie = [cookie objectEnumerator];
245       
246       while ((singleCookie = [cookie nextObject]))
247         [self _addHTTPCookie:singleCookie to:womCookies];
248       
249       continue;
250     }
251     
252     [self _addHTTPCookie:cookie to:womCookies];
253   }
254   
255   woCookies = [womCookies copy];
256   return [woCookies autorelease];
257 }
258
259 /* content */
260
261 - (NSData *)woContent {
262   NGMimePartGenerator *gen;
263   id content;
264   
265   if ((content = [self body]) == nil) {
266     /* no body */
267     return nil;
268   }
269   
270   if ([content isKindOfClass:[NSData class]])
271     return content;
272   
273   if (![content conformsToProtocol:@protocol(NGMimePart)])
274     return [[content stringValue] dataUsingEncoding:NSASCIIStringEncoding];
275   
276   gen  = [[NGMimePartGenerator alloc] init];
277   content = [gen generateMimeFromPart:content];
278   [gen release];
279   return content;
280 }
281
282 /* form parameters */
283
284 static NGMimeType *multipartFormData = nil;
285 static Class      DispClass = Nil;
286
287 - (id)_decodeMultiPartFormDataContent {
288   NGMutableHashMap    *formContent;
289   NGMimeMultipartBody *ebody;
290   NSArray             *parts;
291   unsigned            i, count;
292
293   if (DispClass == Nil)
294     DispClass = [NGMimeContentDispositionHeaderField class];
295   
296   ebody = [self body];
297   if (![ebody isKindOfClass:[NGMimeMultipartBody class]]) {
298     [self errorWithFormat:
299             @"form-data parser expected MultipartBody, got %@", ebody];
300     return [[NGHashMap alloc] init];
301   }
302   
303   parts = [ebody parts];
304   count = [parts count];
305   
306   [self debugWithFormat:@"%s:   %i parts %@", __PRETTY_FUNCTION__, 
307           count, parts];
308   
309   formContent = [[NGMutableHashMap alloc] init];
310   for (i = 0; i < count; i++) {
311     NGMimeContentDispositionHeaderField *disposition;
312     id<NGMimePart> bodyPart;
313     NSString *name;
314     id       partBody;
315           
316     bodyPart = [parts objectAtIndex:i];
317     disposition =
318       [[bodyPart valuesOfHeaderFieldWithName:@"content-disposition"]nextObject];
319           
320     if (disposition == nil) {
321       [self errorWithFormat:
322               @"did not find content disposition in form part %@", bodyPart];
323       continue;
324     }
325
326     /* morph to disposition field in case it's unparsed ... */
327     if (![disposition isKindOfClass:DispClass]) {
328               disposition =
329                 [[DispClass alloc] initWithString:[disposition stringValue]];
330               [disposition autorelease];
331     }
332             
333     name     = [disposition name];
334     partBody = [bodyPart body];
335     
336     if (partBody)
337       [(NGMutableHashMap *)formContent addObject:partBody forKey:name];
338   }
339   return formContent;
340 }
341
342 - (NGHashMap *)_decodeFormContentURLParameters:(id)formContent {
343   /* all this sounds expensive ;-) */
344   NSString   *s;
345   unsigned   urilen;
346   char       *uribuf;
347   const char *p = uribuf;
348   NGHashMap  *map;
349   
350   if ((s = [self uri]) == nil)
351     return formContent;
352   if ([s rangeOfString:@"?"].length == 0)
353     return formContent;
354   
355   urilen = [s cStringLength];
356   p = uribuf = malloc(urilen + 4);
357   [s getCString:uribuf]; // UNICODE?
358   
359   if ((p = index(p, '?')) == NULL) {
360     if (uribuf) free(uribuf);
361     return formContent;
362   }
363   
364   p++; // skip the '?'
365   map = NGDecodeUrlFormParameters((unsigned char *)p, strlen((char *)p));
366   if (uribuf != NULL) free(uribuf); uribuf = NULL; p = NULL;
367   
368   if (map == nil) 
369     return formContent;
370   if (formContent == nil)
371     return map;
372   
373   map = [map autorelease]; // NGDecodeUrlFormParameters returns a retained map!
374   
375   if ([formContent isKindOfClass:[NGHashMap class]]) {
376     NSEnumerator *keys;
377     id key, tmp;
378   
379     tmp = formContent;
380     formContent =  [[NGMutableHashMap alloc] initWithHashMap:tmp];
381     [tmp release];
382   
383     keys = [map keyEnumerator];
384     while ((key = [keys nextObject])) {
385       NSEnumerator *values;
386       id value;
387             
388       values = [map objectEnumeratorForKey:key];
389       while ((value = [values nextObject]))
390         [formContent addObject:value forKey:key];
391     }
392   }
393   else if ([formContent isKindOfClass:[NSDictionary class]]) {
394     NSEnumerator *keys;
395     id key, tmp;
396           
397     tmp = formContent;
398     formContent = [[NGMutableHashMap alloc] initWithDictionary:tmp];
399     [tmp release];
400   
401     keys = [map keyEnumerator];
402     while ((key = [keys nextObject])) {
403       NSEnumerator *values;
404       id value;
405   
406       values = [map objectEnumeratorForKey:key];
407       while ((value = [values nextObject]))
408         [formContent addObject:value forKey:key];
409     }
410   }
411   return formContent;
412 }
413
414 - (NGHashMap *)formParameters {
415   id formContent;
416   
417   if (multipartFormData == nil) {
418     multipartFormData = [NGMimeType mimeType:@"multipart/form-data"];
419     multipartFormData = [multipartFormData retain];
420   }
421   
422   if ([[self methodName] isEqualToString:@"POST"]) {
423     NGMimeType *contentType = [self contentType];
424     
425 #if 0
426     NSLog(@"%s: process POST, ctype %@", __PRETTY_FUNCTION__, contentType);
427 #endif
428     
429     formContent = [contentType hasSameType:multipartFormData]
430       ? [self _decodeMultiPartFormDataContent]
431       : [[self body] retain];
432   }
433   else
434     formContent = nil;
435   
436   /* decode URL parameters */
437   formContent = [self _decodeFormContentURLParameters:formContent];
438   
439   return [formContent autorelease];
440 }
441
442 @end /* NGHttpRequest */