Index: src/OFDataArray.m ================================================================== --- src/OFDataArray.m +++ src/OFDataArray.m @@ -187,58 +187,54 @@ #endif - initWithContentsOfURL: (OFURL*)URL { void *pool; -#ifdef OF_HAVE_SOCKETS - OFHTTPClient *client; - OFHTTPRequest *request; - OFHTTPResponse *response; - OFDictionary *headers; - OFString *contentLength; -#endif + OFString *scheme; #ifdef OF_HAVE_FILES Class c = [self class]; #endif [self release]; pool = objc_autoreleasePoolPush(); - if ([[URL scheme] isEqual: @"file"]) { + scheme = [URL scheme]; + #ifdef OF_HAVE_FILES + if ([scheme isEqual: @"file"]) self = [[c alloc] initWithContentsOfFile: [URL path]]; - objc_autoreleasePoolPop(pool); - return self; -#else - @throw [OFUnsupportedProtocolException exceptionWithURL: URL]; + else #endif - } - #ifdef OF_HAVE_SOCKETS - client = [OFHTTPClient client]; - request = [OFHTTPRequest requestWithURL: URL]; - response = [client performRequest: request]; - - if ([response statusCode] != 200) - @throw [OFHTTPRequestFailedException - exceptionWithRequest: request - response: response]; - - /* - * TODO: This can be optimized by allocating a data array with the - * capacity from the Content-Length header. - */ - self = [[response readDataArrayTillEndOfStream] retain]; - - headers = [response headers]; - if ((contentLength = [headers objectForKey: @"Content-Length"]) != nil) - if ([self count] != (size_t)[contentLength decimalValue]) - @throw [OFTruncatedDataException exception]; -#else - @throw [OFUnsupportedProtocolException exceptionWithURL: URL]; + if ([scheme isEqual: @"http"] || [scheme isEqual: @"https"]) { + OFHTTPClient *client = [OFHTTPClient client]; + OFHTTPRequest *request = [OFHTTPRequest requestWithURL: URL]; + OFHTTPResponse *response = [client performRequest: request]; + OFDictionary *headers; + OFString *contentLength; + + if ([response statusCode] != 200) + @throw [OFHTTPRequestFailedException + exceptionWithRequest: request + response: response]; + + /* + * TODO: This can be optimized by allocating a data array with + * the capacity from the Content-Length header. + */ + self = [[response readDataArrayTillEndOfStream] retain]; + + headers = [response headers]; + if ((contentLength = + [headers objectForKey: @"Content-Length"]) != nil) + if ([self count] != + (size_t)[contentLength decimalValue]) + @throw [OFTruncatedDataException exception]; + } else #endif + @throw [OFUnsupportedProtocolException exceptionWithURL: URL]; objc_autoreleasePoolPop(pool); return self; } Index: src/OFHTTPClient.m ================================================================== --- src/OFHTTPClient.m +++ src/OFHTTPClient.m @@ -559,15 +559,16 @@ _socket = [socket retain]; _lastURL = [URL copy]; _lastResponse = [response retain]; } + /* FIXME: Case-insensitive check of redirect's scheme */ if (redirects > 0 && (status == 301 || status == 302 || status == 303 || status == 307) && (redirect = [serverHeaders objectForKey: @"Location"]) != nil && (_insecureRedirectsAllowed || [scheme isEqual: @"http"] || - ![redirect hasPrefix: @"http://"])) { + [redirect hasPrefix: @"https://"])) { OFURL *newURL; bool follow; newURL = [OFURL URLWithString: redirect relativeToURL: URL]; Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -876,81 +876,78 @@ - initWithContentsOfURL: (OFURL*)URL encoding: (of_string_encoding_t)encoding { void *pool; -#ifdef OF_HAVE_SOCKETS - OFHTTPClient *client; - OFHTTPRequest *request; - OFHTTPResponse *response; - OFDictionary *headers; - OFString *contentType, *contentLength; - OFDataArray *data; -#endif + OFString *scheme; #ifdef OF_HAVE_FILES Class c = [self class]; #endif [self release]; pool = objc_autoreleasePoolPush(); - if ([[URL scheme] isEqual: @"file"]) { + scheme = [URL scheme]; + #ifdef OF_HAVE_FILES + if ([scheme isEqual: @"file"]) { if (encoding == OF_STRING_ENCODING_AUTODETECT) encoding = OF_STRING_ENCODING_UTF_8; self = [[c alloc] initWithContentsOfFile: [URL path] encoding: encoding]; - objc_autoreleasePoolPop(pool); - return self; -#else - @throw [OFUnsupportedProtocolException exceptionWithURL: URL]; -#endif - } - -#ifdef OF_HAVE_SOCKETS - client = [OFHTTPClient client]; - request = [OFHTTPRequest requestWithURL: URL]; - response = [client performRequest: request]; - - if ([response statusCode] != 200) - @throw [OFHTTPRequestFailedException - exceptionWithRequest: request - response: response]; - - headers = [response headers]; - - if (encoding == OF_STRING_ENCODING_AUTODETECT && - (contentType = [headers objectForKey: @"Content-Type"]) != nil) { - contentType = [contentType lowercaseString]; - - if ([contentType hasSuffix: @"charset=utf-8"]) - encoding = OF_STRING_ENCODING_UTF_8; - if ([contentType hasSuffix: @"charset=iso-8859-1"]) - encoding = OF_STRING_ENCODING_ISO_8859_1; - if ([contentType hasSuffix: @"charset=iso-8859-15"]) - encoding = OF_STRING_ENCODING_ISO_8859_15; - if ([contentType hasSuffix: @"charset=windows-1252"]) - encoding = OF_STRING_ENCODING_WINDOWS_1252; - } - - if (encoding == OF_STRING_ENCODING_AUTODETECT) - encoding = OF_STRING_ENCODING_UTF_8; - - data = [response readDataArrayTillEndOfStream]; - - if ((contentLength = [headers objectForKey: @"Content-Length"]) != nil) - if ([data count] != (size_t)[contentLength decimalValue]) - @throw [OFTruncatedDataException exception]; - - self = [[c alloc] initWithCString: (char*)[data items] - encoding: encoding - length: [data count]]; -#else - @throw [OFUnsupportedProtocolException exceptionWithURL: URL]; -#endif + } else +#endif +#ifdef OF_HAVE_SOCKETS + if ([scheme isEqual: @"http"] || [scheme isEqual: @"https"]) { + OFHTTPClient *client = [OFHTTPClient client]; + OFHTTPRequest *request = [OFHTTPRequest requestWithURL: URL]; + OFHTTPResponse *response = [client performRequest: request]; + OFDictionary *headers; + OFString *contentType, *contentLength; + OFDataArray *data; + + if ([response statusCode] != 200) + @throw [OFHTTPRequestFailedException + exceptionWithRequest: request + response: response]; + + headers = [response headers]; + + if (encoding == OF_STRING_ENCODING_AUTODETECT && + (contentType = [headers + objectForKey: @"Content-Type"]) != nil) { + contentType = [contentType lowercaseString]; + + if ([contentType hasSuffix: @"charset=utf-8"]) + encoding = OF_STRING_ENCODING_UTF_8; + if ([contentType hasSuffix: @"charset=iso-8859-1"]) + encoding = OF_STRING_ENCODING_ISO_8859_1; + if ([contentType hasSuffix: @"charset=iso-8859-15"]) + encoding = OF_STRING_ENCODING_ISO_8859_15; + if ([contentType hasSuffix: @"charset=windows-1252"]) + encoding = OF_STRING_ENCODING_WINDOWS_1252; + } + + if (encoding == OF_STRING_ENCODING_AUTODETECT) + encoding = OF_STRING_ENCODING_UTF_8; + + data = [response readDataArrayTillEndOfStream]; + + if ((contentLength = [headers + objectForKey: @"Content-Length"]) != nil) + if ([data count] != + (size_t)[contentLength decimalValue]) + @throw [OFTruncatedDataException exception]; + + self = [[c alloc] initWithCString: (char*)[data items] + encoding: encoding + length: [data count]]; + } else +#endif + @throw [OFUnsupportedProtocolException exception]; objc_autoreleasePoolPop(pool); return self; } Index: src/OFURL.m ================================================================== --- src/OFURL.m +++ src/OFURL.m @@ -16,10 +16,11 @@ #include "config.h" #include #include +#include #import "OFURL.h" #import "OFString.h" #import "OFArray.h" #import "OFXMLElement.h" @@ -55,28 +56,32 @@ @try { char *tmp, *tmp2; if ((UTF8String2 = of_strdup([string UTF8String])) == NULL) @throw [OFOutOfMemoryException - exceptionWithRequestedSize: [string - UTF8StringLength]]; + exceptionWithRequestedSize: + [string UTF8StringLength]]; UTF8String = UTF8String2; - if (!strncmp(UTF8String, "file://", 7)) { - _scheme = @"file"; + if ((tmp = strstr(UTF8String, "://")) == NULL) + @throw [OFInvalidFormatException exception]; + + for (tmp2 = UTF8String; tmp2 < tmp; tmp2++) + *tmp2 = tolower((int)*tmp2); + + _scheme = [[OFString alloc] + initWithUTF8String: UTF8String + length: tmp - UTF8String]; + + UTF8String = tmp + 3; + + if ([_scheme isEqual: @"file"]) { _path = [[OFString alloc] - initWithUTF8String: UTF8String + 7]; + initWithUTF8String: UTF8String]; return self; - } else if (!strncmp(UTF8String, "http://", 7)) { - _scheme = @"http"; - UTF8String += 7; - } else if (!strncmp(UTF8String, "https://", 8)) { - _scheme = @"https"; - UTF8String += 8; - } else - @throw [OFInvalidFormatException exception]; + } if ((tmp = strchr(UTF8String, '/')) != NULL) { *tmp = '\0'; tmp++; } @@ -118,24 +123,21 @@ if ([portString decimalValue] > 65535) @throw [OFInvalidFormatException exception]; _port = [portString decimalValue]; - if (_port == 0) - _port = 80; - objc_autoreleasePoolPop(pool); } else { _host = [[OFString alloc] initWithUTF8String: UTF8String]; if ([_scheme isEqual: @"http"]) _port = 80; else if ([_scheme isEqual: @"https"]) _port = 443; - else - OF_ENSURE(0); + else if ([_scheme isEqual: @"ftp"]) + _port = 21; } if ((UTF8String = tmp) != NULL) { if ((tmp = strchr(UTF8String, '#')) != NULL) { *tmp = '\0'; @@ -364,13 +366,10 @@ OF_GETTER(_scheme, true) } - (void)setScheme: (OFString*)scheme { - if (![scheme isEqual: @"http"] && ![scheme isEqual: @"https"]) - @throw [OFInvalidArgumentException exception]; - OF_SETTER(_scheme, scheme, true, 1) } - (OFString*)host { @@ -417,14 +416,10 @@ OF_GETTER(_path, true) } - (void)setPath: (OFString*)path { - if (([_scheme isEqual: @"http"] || [_scheme isEqual: @"https"]) && - ![path hasPrefix: @"/"]) - @throw [OFInvalidArgumentException exception]; - OF_SETTER(_path, path, true, 1) } - (OFString*)parameters { @@ -475,11 +470,12 @@ if (_host != nil) [ret appendString: _host]; if (([_scheme isEqual: @"http"] && _port != 80) || - ([_scheme isEqual: @"https"] && _port != 443)) + ([_scheme isEqual: @"https"] && _port != 443) || + ([_scheme isEqual: @"ftp"] && _port != 21)) [ret appendFormat: @":%u", _port]; if (_path != nil) [ret appendFormat: @"/%@", _path]; Index: tests/OFURLTests.m ================================================================== --- tests/OFURLTests.m +++ tests/OFURLTests.m @@ -74,18 +74,15 @@ [[u1 fragment] isEqual: @"f"] && [u4 fragment] == nil) TEST(@"-[copy]", R(u4 = [[u1 copy] autorelease])) TEST(@"-[isEqual:]", [u1 isEqual: u4] && ![u2 isEqual: u3] && - [[OFURL URLWithString: @"http://bar/"] isEqual: u3]) + [[OFURL URLWithString: @"HTTP://bar/"] isEqual: u3]) TEST(@"-[hash:]", [u1 hash] == [u4 hash] && [u2 hash] != [u3 hash]) EXPECT_EXCEPTION(@"Detection of invalid format", OFInvalidFormatException, [OFURL URLWithString: @"http"]) - EXPECT_EXCEPTION(@"Detection of invalid scheme", - OFInvalidFormatException, [OFURL URLWithString: @"foo://"]) - [pool drain]; } @end