Index: src/OFHTTPRequest.m ================================================================== --- src/OFHTTPRequest.m +++ src/OFHTTPRequest.m @@ -38,11 +38,11 @@ #import "macros.h" Class of_http_request_tls_socket_class = Nil; static OF_INLINE void -normalize_key(OFString *key) +normalizeKey(OFString *key) { uint8_t *str = (uint8_t*)[key UTF8String]; BOOL firstLetter = YES; while (*str != '\0') { @@ -193,10 +193,11 @@ OFDataArray *data; OFEnumerator *keyEnumerator, *objectEnumerator; OFString *key, *object, *contentLengthHeader; int status; const char *type = NULL; + BOOL chunked; char *buffer; size_t bytesReceived; if (![scheme isEqual: @"http"] && ![scheme isEqual: @"https"]) @throw [OFUnsupportedProtocolException exceptionWithClass: isa @@ -235,14 +236,14 @@ if ([(path = [URL path]) isEqual: @""]) path = @"/"; if ([URL query] != nil) - [sock writeFormat: @"%s %@?%@ HTTP/1.0\r\n", + [sock writeFormat: @"%s %@?%@ HTTP/1.1\r\n", type, path, [URL query]]; else - [sock writeFormat: @"%s %@ HTTP/1.0\r\n", type, path]; + [sock writeFormat: @"%s %@ HTTP/1.1\r\n", type, path]; if ([URL port] == 80) [sock writeFormat: @"Host: %@\r\n", [URL host]]; else [sock writeFormat: @"Host: %@:%d\r\n", [URL host], @@ -273,14 +274,10 @@ [sock setBuffersWrites: NO]; if (requestType == OF_HTTP_REQUEST_TYPE_POST) [sock writeString: queryString]; - /* - * We also need to check for HTTP/1.1 since Apache always declares the - * reply to be HTTP/1.1. - */ line = [sock readLine]; if (![line hasPrefix: @"HTTP/1.0 "] && ![line hasPrefix: @"HTTP/1.1 "]) @throw [OFInvalidServerReplyException exceptionWithClass: isa]; status = (int)[[line substringWithRange: of_range(9, 3)] decimalValue]; @@ -298,11 +295,11 @@ @throw [OFInvalidServerReplyException exceptionWithClass: isa]; key = [OFString stringWithUTF8String: line_c length: tmp - line_c]; - normalize_key(key); + normalizeKey(key); do { tmp++; } while (*tmp == ' '); @@ -350,29 +347,80 @@ [delegate request: self didReceiveHeaders: serverHeaders withStatusCode: status]; data = (storesData ? [OFDataArray dataArray] : nil); + chunked = [[serverHeaders objectForKey: @"Transfer-Encoding"] + isEqual: @"chunked"]; buffer = [self allocMemoryWithSize: of_pagesize]; bytesReceived = 0; @try { - size_t len; - - while ((len = [sock readNBytes: of_pagesize - intoBuffer: buffer]) > 0) { - [delegate request: self - didReceiveData: buffer - withLength: len]; - - bytesReceived += len; - [data addNItems: len - fromCArray: buffer]; - } + OFAutoreleasePool *pool2 = [[OFAutoreleasePool alloc] init]; + + if (chunked) { + for (;;) { + size_t pos, toRead; + + line = [sock readLine]; + + pos = [line + indexOfFirstOccurrenceOfString: @";"]; + if (pos != OF_INVALID_INDEX) + line = [line substringWithRange: + of_range(0, pos)]; + + toRead = (size_t)[line hexadecimalValue]; + if (toRead == 0) + break; + + while (toRead > 0) { + size_t length = (toRead < of_pagesize + ? toRead : of_pagesize); + + length = [sock readNBytes: length + intoBuffer: buffer]; + + [delegate request: self + didReceiveData: buffer + withLength: length]; + + bytesReceived += length; + [data addNItems: length + fromCArray: buffer]; + + toRead -= length; + } + + if (![[sock readLine] isEqual: @""]) + @throw [OFInvalidServerReplyException + exceptionWithClass: isa]; + + [pool2 releaseObjects]; + } + } else { + size_t length; + + while ((length = [sock readNBytes: of_pagesize + intoBuffer: buffer]) > 0) { + [delegate request: self + didReceiveData: buffer + withLength: length]; + [pool2 releaseObjects]; + + bytesReceived += length; + [data addNItems: length + fromCArray: buffer]; + } + } + + [pool2 release]; } @finally { [self freeMemory: buffer]; } + + [sock close]; if ((contentLengthHeader = [serverHeaders objectForKey: @"Content-Length"]) != nil) { intmax_t cl = [contentLengthHeader decimalValue]; Index: tests/OFHTTPRequestTests.m ================================================================== --- tests/OFHTTPRequestTests.m +++ tests/OFHTTPRequestTests.m @@ -57,11 +57,11 @@ [cond signal]; [cond unlock]; client = [listener accept]; - if (![[client readLine] isEqual: @"GET /foo HTTP/1.0"]) + if (![[client readLine] isEqual: @"GET /foo HTTP/1.1"]) assert(0); if (![[client readLine] isEqual: [OFString stringWithFormat: @"Host: 127.0.0.1:%" @PRIu16, port]]) assert(0); @@ -70,11 +70,11 @@ assert(0); if (![[client readLine] isEqual: @""]) assert(0); - [client writeString: @"HTTP/1.0 200 OK\r\n" + [client writeString: @"HTTP/1.1 200 OK\r\n" @"cONTeNT-lENgTH: 7\r\n" @"\r\n" @"foo\n" @"bar"]; [client close];