2 Copyright (C) 2000-2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
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
23 #include "NGHttp+WO.h"
24 #include <NGHttp/NGHttp.h>
25 #include <NGObjWeb/WOCookie.h>
26 #include <NGObjWeb/WORequest.h>
27 #include <NGMime/NGMime.h>
30 @interface WORequest(NGSupport)
31 - (void)_setHttpRequest:(NGHttpRequest *)_request;
34 @implementation NGHttpRequest(WOSupport)
36 static Class NSArrayClass = Nil;
38 - (id)initWithWORequest:(WORequest *)_request {
41 hm = [NGHashMap hashMapWithDictionary:[_request headers]];
43 self = [self initWithMethod:[_request method]
46 version:[_request httpVersion]];
47 [self setBody:[_request content]];
49 /* transfer cookies */
50 if ([[_request cookies] count] > 0)
51 NSLog(@"WARNING: cannot transfer cookies to NGHttpRequest yet !");
53 /* transfer headers !!! */
58 - (WORequest *)woRequest {
59 NSAutoreleasePool *pool;
61 NSDictionary *woHeaders;
63 pool = [[NSAutoreleasePool alloc] init];
67 request = [[WORequest alloc]
68 initWithMethod:[self methodName]
70 httpVersion:[self httpVersion]
72 content:[self woContent]
74 request = [request autorelease];
76 [request _setHttpRequest:self];
83 cs = [[self woCookies] objectEnumerator];
84 while ((cookie = [cs nextObject]))
85 [request addCookie:cookie];
93 if (NSArrayClass == Nil)
94 NSArrayClass = [NSArray class];
96 keys = [self headerFieldNames];
97 while ((key = [keys nextObject])) {
101 values = [self valuesOfHeaderFieldWithName:key];
102 while ((value = [values nextObject])) {
103 if ([value isKindOfClass:NSArrayClass]) {
106 ev2 = [value objectEnumerator];
107 while ((value = [ev2 nextObject])) {
108 value = [value stringValue];
109 [request appendHeader:value forKey:key];
113 value = [value stringValue];
114 [request appendHeader:value forKey:key];
120 request = [request retain];
121 [pool release]; pool = nil;
123 return [request autorelease];
128 - (NSArray *)woHeaderKeys {
129 NSMutableArray *keys;
133 keys = [[NSMutableArray alloc] init];
134 ekeys = [self headerFieldNames];
136 while ((key = [ekeys nextObject]))
137 [keys addObject:key];
139 return [keys autorelease];
142 - (NSString *)woHeaderForKey:(NSString *)_key {
143 return [[[self valuesOfHeaderFieldWithName:_key]
148 - (NSArray *)woHeadersForKey:(NSString *)_key {
149 NSMutableArray *vals;
151 NSString *value = nil;
153 vals = [NSMutableArray arrayWithCapacity:2];
154 evals = [self valuesOfHeaderFieldWithName:_key];
156 while ((value = [evals nextObject])) {
157 if ((value = [value stringValue]))
158 [vals addObject:value];
166 - (void)_addHTTPCookie:(id)_cookie to:(NSMutableArray *)_a {
167 static Class NGHttpCookieClass = Nil;
168 static Class WOCookieClass = Nil;
175 if (NGHttpCookieClass == Nil) NGHttpCookieClass = [NGHttpCookie class];
176 if (WOCookieClass == Nil) WOCookieClass = NSClassFromString(@"WOCookie");
178 if (![_cookie isKindOfClass:NGHttpCookieClass]) {
179 static NGHttpCookieFieldParser *cookieParser = nil;
181 if (cookieParser == nil)
182 cookieParser = [[NGHttpCookieFieldParser alloc] init];
184 _cookie = [_cookie stringValue];
185 _cookie = [_cookie dataUsingEncoding:NSISOLatin1StringEncoding];
186 _cookie = [cookieParser parseValue:_cookie ofHeaderField:@"cookie"];
189 if ([_cookie isKindOfClass:[NSArray class]]) {
192 _cookie = [_cookie objectEnumerator];
194 while ((singleCookie = [_cookie nextObject]))
195 [self _addHTTPCookie:singleCookie to:_a];
200 cookieValue = [_cookie value];
201 if ([cookieValue isKindOfClass:[NSArray class]]) {
202 if ([cookieValue count] == 0)
204 else if ([cookieValue count] == 1)
205 cookieValue = [[cookieValue objectAtIndex:0] stringValue];
208 @"got %i values for cookie '%@', using first only.",
210 [_cookie cookieName]];
211 cookieValue = [[cookieValue objectAtIndex:0] stringValue];
215 cookieValue = [cookieValue stringValue];
217 cookie = [WOCookieClass cookieWithName:[_cookie cookieName]
220 domain:[_cookie domainName]
221 expires:[_cookie expireDate]
222 isSecure:[_cookie needsSecureChannel]];
226 [_a addObject:cookie];
229 - (NSArray *)woCookies {
230 NSMutableArray *womCookies;
232 NSEnumerator *mcookies;
235 if (NSArrayClass == Nil) NSArrayClass = [NSArray class];
237 womCookies = [NSMutableArray arrayWithCapacity:8];
239 mcookies = [self valuesOfHeaderFieldWithName:@"cookie"];
240 while ((cookie = [mcookies nextObject])) {
241 if ([cookie isKindOfClass:NSArrayClass]) {
244 cookie = [cookie objectEnumerator];
246 while ((singleCookie = [cookie nextObject]))
247 [self _addHTTPCookie:singleCookie to:womCookies];
252 [self _addHTTPCookie:cookie to:womCookies];
255 woCookies = [womCookies copy];
256 return [woCookies autorelease];
261 - (NSData *)woContent {
262 NGMimePartGenerator *gen;
265 if ((content = [self body]) == nil) {
270 if ([content isKindOfClass:[NSData class]])
273 if (![content conformsToProtocol:@protocol(NGMimePart)])
274 return [[content stringValue] dataUsingEncoding:NSASCIIStringEncoding];
276 gen = [[NGMimePartGenerator alloc] init];
277 content = [gen generateMimeFromPart:content];
282 /* form parameters */
284 static NGMimeType *multipartFormData = nil;
285 static Class DispClass = Nil;
287 - (id)_decodeMultiPartFormDataContent {
288 NGMutableHashMap *formContent;
289 NGMimeMultipartBody *ebody;
293 if (DispClass == Nil)
294 DispClass = [NGMimeContentDispositionHeaderField class];
297 if (![ebody isKindOfClass:[NGMimeMultipartBody class]]) {
299 @"ERROR: form-data parser expected MultipartBody, got %@", ebody];
300 return [[NGHashMap alloc] init];
303 parts = [ebody parts];
304 count = [parts count];
306 [self debugWithFormat:@"%s: %i parts %@", __PRETTY_FUNCTION__,
309 formContent = [[NGMutableHashMap alloc] init];
310 for (i = 0; i < count; i++) {
311 NGMimeContentDispositionHeaderField *disposition;
312 id<NGMimePart> bodyPart;
316 bodyPart = [parts objectAtIndex:i];
318 [[bodyPart valuesOfHeaderFieldWithName:@"content-disposition"]nextObject];
320 if (disposition == nil) {
322 @"ERROR: did not find content disposition in form part %@",
327 /* morph to disposition field in case it's unparsed ... */
328 if (![disposition isKindOfClass:DispClass]) {
330 [[DispClass alloc] initWithString:[disposition stringValue]];
331 [disposition autorelease];
334 name = [disposition name];
335 partBody = [bodyPart body];
338 [(NGMutableHashMap *)formContent addObject:partBody forKey:name];
343 - (NGHashMap *)_decodeFormContentURLParameters:(id)formContent {
344 /* all this sounds expensive ;-) */
348 const char *p = uribuf;
351 if ((s = [self uri]) == nil)
353 if ([s rangeOfString:@"?"].length == 0)
356 urilen = [s cStringLength];
357 p = uribuf = malloc(urilen + 4);
358 [s getCString:uribuf]; // UNICODE?
360 if ((p = index(p, '?')) == NULL) {
361 if (uribuf) free(uribuf);
366 map = NGDecodeUrlFormParameters(p, strlen(p));
367 if (uribuf) free(uribuf); uribuf = NULL; p = NULL;
371 if (formContent == nil)
374 map = [map autorelease]; // NGDecodeUrlFormParameters returns a retained map!
376 if ([formContent isKindOfClass:[NGHashMap class]]) {
381 formContent = [[NGMutableHashMap alloc] initWithHashMap:tmp];
384 keys = [map keyEnumerator];
385 while ((key = [keys nextObject])) {
386 NSEnumerator *values;
389 values = [map objectEnumeratorForKey:key];
390 while ((value = [values nextObject]))
391 [formContent addObject:value forKey:key];
394 else if ([formContent isKindOfClass:[NSDictionary class]]) {
399 formContent = [[NGMutableHashMap alloc] initWithDictionary:tmp];
402 keys = [map keyEnumerator];
403 while ((key = [keys nextObject])) {
404 NSEnumerator *values;
407 values = [map objectEnumeratorForKey:key];
408 while ((value = [values nextObject]))
409 [formContent addObject:value forKey:key];
415 - (NGHashMap *)formParameters {
418 if (multipartFormData == nil) {
419 multipartFormData = [NGMimeType mimeType:@"multipart/form-data"];
420 multipartFormData = [multipartFormData retain];
423 if ([[self methodName] isEqualToString:@"POST"]) {
424 NGMimeType *contentType = [self contentType];
426 //NSLog(@"%s: process POST, ctype %@", __PRETTY_FUNCTION__, contentType);
428 formContent = [contentType hasSameType:multipartFormData]
429 ? [self _decodeMultiPartFormDataContent]
430 : [[self body] retain];
435 /* decode URL parameters */
436 formContent = [self _decodeFormContentURLParameters:formContent];
438 return [formContent autorelease];
441 @end /* NGHttpRequest */