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
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>
29 @interface WORequest(NGSupport)
30 - (void)_setHttpRequest:(NGHttpRequest *)_request;
33 @implementation NGHttpRequest(WOSupport)
35 static Class NSArrayClass = Nil;
37 - (id)initWithWORequest:(WORequest *)_request {
40 hm = [NGHashMap hashMapWithDictionary:[_request headers]];
42 self = [self initWithMethod:[_request method]
45 version:[_request httpVersion]];
46 [self setBody:[_request content]];
48 /* transfer cookies */
49 if ([[_request cookies] count] > 0)
50 [self warnWithFormat:@"cannot transfer cookies to NGHttpRequest yet !"];
52 /* transfer headers !!! */
57 - (WORequest *)woRequest {
58 NSAutoreleasePool *pool;
60 NSDictionary *woHeaders;
62 pool = [[NSAutoreleasePool alloc] init];
66 request = [[WORequest alloc]
67 initWithMethod:[self methodName]
69 httpVersion:[self httpVersion]
71 content:[self woContent]
73 request = [request autorelease];
75 [request _setHttpRequest:self];
82 cs = [[self woCookies] objectEnumerator];
83 while ((cookie = [cs nextObject]))
84 [request addCookie:cookie];
92 if (NSArrayClass == Nil)
93 NSArrayClass = [NSArray class];
95 keys = [self headerFieldNames];
96 while ((key = [keys nextObject])) {
100 values = [self valuesOfHeaderFieldWithName:key];
101 while ((value = [values nextObject])) {
102 if ([value isKindOfClass:NSArrayClass]) {
105 ev2 = [value objectEnumerator];
106 while ((value = [ev2 nextObject])) {
107 value = [value stringValue];
108 [request appendHeader:value forKey:key];
112 value = [value stringValue];
113 [request appendHeader:value forKey:key];
119 request = [request retain];
120 [pool release]; pool = nil;
122 return [request autorelease];
127 - (NSArray *)woHeaderKeys {
128 NSMutableArray *keys;
132 keys = [[NSMutableArray alloc] init];
133 ekeys = [self headerFieldNames];
135 while ((key = [ekeys nextObject]))
136 [keys addObject:key];
138 return [keys autorelease];
141 - (NSString *)woHeaderForKey:(NSString *)_key {
142 return [[[self valuesOfHeaderFieldWithName:_key]
147 - (NSArray *)woHeadersForKey:(NSString *)_key {
148 NSMutableArray *vals;
150 NSString *value = nil;
152 vals = [NSMutableArray arrayWithCapacity:2];
153 evals = [self valuesOfHeaderFieldWithName:_key];
155 while ((value = [evals nextObject])) {
156 if ((value = [value stringValue]))
157 [vals addObject:value];
165 - (void)_addHTTPCookie:(id)_cookie to:(NSMutableArray *)_a {
166 static Class NGHttpCookieClass = Nil;
167 static Class WOCookieClass = Nil;
174 if (NGHttpCookieClass == Nil) NGHttpCookieClass = [NGHttpCookie class];
175 if (WOCookieClass == Nil) WOCookieClass = NSClassFromString(@"WOCookie");
177 if (![_cookie isKindOfClass:NGHttpCookieClass]) {
178 static NGHttpCookieFieldParser *cookieParser = nil;
180 if (cookieParser == nil)
181 cookieParser = [[NGHttpCookieFieldParser alloc] init];
183 _cookie = [_cookie stringValue];
184 _cookie = [_cookie dataUsingEncoding:NSISOLatin1StringEncoding];
185 _cookie = [cookieParser parseValue:_cookie ofHeaderField:@"cookie"];
188 if ([_cookie isKindOfClass:[NSArray class]]) {
191 _cookie = [_cookie objectEnumerator];
193 while ((singleCookie = [_cookie nextObject]))
194 [self _addHTTPCookie:singleCookie to:_a];
198 cookieValue = [_cookie value];
199 if ([cookieValue isKindOfClass:[NSArray class]]) {
200 if ([cookieValue count] == 0)
202 else if ([cookieValue count] == 1)
203 cookieValue = [[cookieValue objectAtIndex:0] stringValue];
206 @"got %d values for cookie '%@', using first only: %@",
208 [_cookie cookieName],
209 [cookieValue componentsJoinedByString:@","]];
210 cookieValue = [[cookieValue objectAtIndex:0] stringValue];
214 cookieValue = [cookieValue stringValue];
216 cookie = [WOCookieClass cookieWithName:[_cookie cookieName]
219 domain:[_cookie domainName]
220 expires:[_cookie expireDate]
221 isSecure:[_cookie needsSecureChannel]];
225 [_a addObject:cookie];
228 - (NSArray *)woCookies {
229 NSMutableArray *womCookies;
231 NSEnumerator *mcookies;
234 if (NSArrayClass == Nil) NSArrayClass = [NSArray class];
236 womCookies = [NSMutableArray arrayWithCapacity:8];
238 mcookies = [self valuesOfHeaderFieldWithName:@"cookie"];
239 while ((cookie = [mcookies nextObject])) {
240 if ([cookie isKindOfClass:NSArrayClass]) {
243 cookie = [cookie objectEnumerator];
245 while ((singleCookie = [cookie nextObject]))
246 [self _addHTTPCookie:singleCookie to:womCookies];
251 [self _addHTTPCookie:cookie to:womCookies];
254 woCookies = [womCookies copy];
255 return [woCookies autorelease];
260 - (NSData *)woContent {
261 NGMimePartGenerator *gen;
264 if ((content = [self body]) == nil) {
269 if ([content isKindOfClass:[NSData class]])
272 if (![content conformsToProtocol:@protocol(NGMimePart)])
273 return [[content stringValue] dataUsingEncoding:NSASCIIStringEncoding];
275 gen = [[NGMimePartGenerator alloc] init];
276 content = [gen generateMimeFromPart:content];
281 /* form parameters */
283 static NGMimeType *multipartFormData = nil;
284 static Class DispClass = Nil;
286 - (id)_decodeMultiPartFormDataContent {
287 NGMutableHashMap *formContent;
288 NGMimeMultipartBody *ebody;
292 if (DispClass == Nil)
293 DispClass = [NGMimeContentDispositionHeaderField class];
296 if (![ebody isKindOfClass:[NGMimeMultipartBody class]]) {
297 [self errorWithFormat:
298 @"form-data parser expected MultipartBody, got %@", ebody];
299 return [[NGHashMap alloc] init];
302 parts = [ebody parts];
303 count = [parts count];
305 [self debugWithFormat:@"%s: %i parts %@", __PRETTY_FUNCTION__,
308 formContent = [[NGMutableHashMap alloc] init];
309 for (i = 0; i < count; i++) {
310 NGMimeContentDispositionHeaderField *disposition;
311 id<NGMimePart> bodyPart;
315 bodyPart = [parts objectAtIndex:i];
317 [[bodyPart valuesOfHeaderFieldWithName:@"content-disposition"]nextObject];
319 if (disposition == nil) {
320 [self errorWithFormat:
321 @"did not find content disposition in form part %@", bodyPart];
325 /* morph to disposition field in case it's unparsed ... */
326 if (![disposition isKindOfClass:DispClass]) {
328 [[DispClass alloc] initWithString:[disposition stringValue]];
329 [disposition autorelease];
332 name = [disposition name];
333 partBody = [bodyPart body];
336 [(NGMutableHashMap *)formContent addObject:partBody forKey:name];
341 - (NGHashMap *)_decodeFormContentURLParameters:(id)formContent {
342 /* all this sounds expensive ;-) */
346 const char *p = uribuf;
349 if ((s = [self uri]) == nil)
351 if ([s rangeOfString:@"?"].length == 0)
354 urilen = [s cStringLength];
355 p = uribuf = malloc(urilen + 4);
356 [s getCString:uribuf]; // UNICODE?
358 if ((p = index(p, '?')) == NULL) {
359 if (uribuf) free(uribuf);
364 map = NGDecodeUrlFormParameters(p, strlen(p));
365 if (uribuf) free(uribuf); uribuf = NULL; p = NULL;
369 if (formContent == nil)
372 map = [map autorelease]; // NGDecodeUrlFormParameters returns a retained map!
374 if ([formContent isKindOfClass:[NGHashMap class]]) {
379 formContent = [[NGMutableHashMap alloc] initWithHashMap:tmp];
382 keys = [map keyEnumerator];
383 while ((key = [keys nextObject])) {
384 NSEnumerator *values;
387 values = [map objectEnumeratorForKey:key];
388 while ((value = [values nextObject]))
389 [formContent addObject:value forKey:key];
392 else if ([formContent isKindOfClass:[NSDictionary class]]) {
397 formContent = [[NGMutableHashMap alloc] initWithDictionary:tmp];
400 keys = [map keyEnumerator];
401 while ((key = [keys nextObject])) {
402 NSEnumerator *values;
405 values = [map objectEnumeratorForKey:key];
406 while ((value = [values nextObject]))
407 [formContent addObject:value forKey:key];
413 - (NGHashMap *)formParameters {
416 if (multipartFormData == nil) {
417 multipartFormData = [NGMimeType mimeType:@"multipart/form-data"];
418 multipartFormData = [multipartFormData retain];
421 if ([[self methodName] isEqualToString:@"POST"]) {
422 NGMimeType *contentType = [self contentType];
425 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 */