Index: src/OFHTTPServer.m ================================================================== --- src/OFHTTPServer.m +++ src/OFHTTPServer.m @@ -663,14 +663,14 @@ path = [_path substringWithRange: of_range(0, pos)]; query = [_path substringWithRange: of_range(pos + 1, [_path length] - pos - 1)]; - [URL setPath: path]; - [URL setQuery: query]; + [URL setURLEncodedPath: path]; + [URL setURLEncodedQuery: query]; } else - [URL setPath: _path]; + [URL setURLEncodedPath: _path]; [URL makeImmutable]; request = [OFHTTPRequest requestWithURL: URL]; [request setMethod: _method]; Index: src/OFMutableURL.h ================================================================== --- src/OFMutableURL.h +++ src/OFMutableURL.h @@ -27,15 +27,33 @@ /*! * The scheme part of the URL. */ @property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *scheme; +/*! + * The scheme part of the URL in URL-encoded form. + * + * Setting this retains the original URL-encoding used - if more characters + * than necessary are URL-encoded, it is kept this way. + */ +@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) + OFString *URLEncodedScheme; + /*! * The host part of the URL. */ @property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *host; +/*! + * The host part of the URL in URL-encoded form. + * + * Setting this retains the original URL-encoding used - if more characters + * than necessary are URL-encoded, it is kept this way. + */ +@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) + OFString *URLEncodedHost; + /*! * The port part of the URL. */ @property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFNumber *port; @@ -42,20 +60,47 @@ /*! * The user part of the URL. */ @property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *user; +/*! + * The user part of the URL in URL-encoded form. + * + * Setting this retains the original URL-encoding used - if more characters + * than necessary are URL-encoded, it is kept this way. + */ +@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) + OFString *URLEncodedUser; + /*! * The password part of the URL. */ @property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *password; +/*! + * The password part of the URL in URL-encoded form. + * + * Setting this retains the original URL-encoding used - if more characters + * than necessary are URL-encoded, it is kept this way. + */ +@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) + OFString *URLEncodedPassword; + /*! * The path part of the URL. */ @property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *path; +/*! + * The path part of the URL in URL-encoded form. + * + * Setting this retains the original URL-encoding used - if more characters + * than necessary are URL-encoded, it is kept this way. + */ +@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) + OFString *URLEncodedPath; + /*! * The path of the URL split into components. * * The first component must always be empty to designate the root. */ @@ -65,15 +110,33 @@ /*! * The query part of the URL. */ @property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *query; +/*! + * The query part of the URL in URL-encoded form. + * + * Setting this retains the original URL-encoding used - if more characters + * than necessary are URL-encoded, it is kept this way. + */ +@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) + OFString *URLEncodedQuery; + /*! * The fragment part of the URL. */ @property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *fragment; +/*! + * The fragment part of the URL in URL-encoded form. + * + * Setting this retains the original URL-encoding used - if more characters + * than necessary are URL-encoded, it is kept this way. + */ +@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) + OFString *URLEncodedFragment; + /*! * @brief Creates a new mutable URL. * * @return A new, autoreleased OFMutableURL */ Index: src/OFMutableURL.m ================================================================== --- src/OFMutableURL.m +++ src/OFMutableURL.m @@ -23,12 +23,13 @@ #import "OFURL+Private.h" #import "OFInvalidFormatException.h" @implementation OFMutableURL -@dynamic scheme, host, port, user, password, path, pathComponents, query; -@dynamic fragment; +@dynamic scheme, URLEncodedScheme, host, URLEncodedHost, port, user; +@dynamic URLEncodedUser, password, URLEncodedPassword, path, URLEncodedPath; +@dynamic pathComponents, query, URLEncodedQuery, fragment, URLEncodedFragment; + (instancetype)URL { return [[[self alloc] init] autorelease]; } @@ -38,19 +39,40 @@ return [super of_init]; } - (void)setScheme: (OFString *)scheme { - OFString *old = _scheme; - _scheme = [scheme copy]; + void *pool = objc_autoreleasePoolPush(); + + [self setURLEncodedScheme: + [scheme stringByURLEncodingWithAllowedCharacters: + [OFCharacterSet URLSchemeAllowedCharacterSet]]]; + + objc_autoreleasePoolPop(pool); +} + +- (void)setURLEncodedScheme: (OFString *)URLEncodedScheme +{ + OFString *old = _URLEncodedScheme; + _URLEncodedScheme = [URLEncodedScheme copy]; [old release]; } - (void)setHost: (OFString *)host { - OFString *old = _host; - _host = [host copy]; + void *pool = objc_autoreleasePoolPush(); + + [self setURLEncodedHost: [host stringByURLEncodingWithAllowedCharacters: + [OFCharacterSet URLHostAllowedCharacterSet]]]; + + objc_autoreleasePoolPop(pool); +} + +- (void)setURLEncodedHost: (OFString *)URLEncodedHost +{ + OFString *old = _URLEncodedHost; + _URLEncodedHost = [URLEncodedHost copy]; [old release]; } - (void)setPort: (OFNumber *)port { @@ -59,26 +81,57 @@ [old release]; } - (void)setUser: (OFString *)user { - OFString *old = _user; - _user = [user copy]; + void *pool = objc_autoreleasePoolPush(); + + [self setURLEncodedUser: [user stringByURLEncodingWithAllowedCharacters: + [OFCharacterSet URLUserAllowedCharacterSet]]]; + + objc_autoreleasePoolPop(pool); +} + +- (void)setURLEncodedUser: (OFString *)URLEncodedUser +{ + OFString *old = _URLEncodedUser; + _URLEncodedUser = [URLEncodedUser copy]; [old release]; } - (void)setPassword: (OFString *)password { - OFString *old = _password; - _password = [password copy]; + void *pool = objc_autoreleasePoolPush(); + + [self setURLEncodedPassword: + [password stringByURLEncodingWithAllowedCharacters: + [OFCharacterSet URLPasswordAllowedCharacterSet]]]; + + objc_autoreleasePoolPop(pool); +} + +- (void)setURLEncodedPassword: (OFString *)URLEncodedPassword +{ + OFString *old = _URLEncodedPassword; + _URLEncodedPassword = [URLEncodedPassword copy]; [old release]; } - (void)setPath: (OFString *)path { - OFString *old = _path; - _path = [path copy]; + void *pool = objc_autoreleasePoolPush(); + + [self setURLEncodedPath: [path stringByURLEncodingWithAllowedCharacters: + [OFCharacterSet URLPathAllowedCharacterSet]]]; + + objc_autoreleasePoolPop(pool); +} + +- (void)setURLEncodedPath: (OFString *)URLEncodedPath +{ + OFString *old = _URLEncodedPath; + _URLEncodedPath = [URLEncodedPath copy]; [old release]; } - (void)setPathComponents: (OFArray *)components { @@ -100,19 +153,41 @@ objc_autoreleasePoolPop(pool); } - (void)setQuery: (OFString *)query { - OFString *old = _query; - _query = [query copy]; + void *pool = objc_autoreleasePoolPush(); + + [self setURLEncodedQuery: + [query stringByURLEncodingWithAllowedCharacters: + [OFCharacterSet URLQueryAllowedCharacterSet]]]; + + objc_autoreleasePoolPop(pool); +} + +- (void)setURLEncodedQuery: (OFString *)URLEncodedQuery +{ + OFString *old = _URLEncodedQuery; + _URLEncodedQuery = [URLEncodedQuery copy]; [old release]; } - (void)setFragment: (OFString *)fragment { - OFString *old = _fragment; - _fragment = [fragment copy]; + void *pool = objc_autoreleasePoolPush(); + + [self setURLEncodedFragment: + [fragment stringByURLEncodingWithAllowedCharacters: + [OFCharacterSet URLFragmentAllowedCharacterSet]]]; + + objc_autoreleasePoolPop(pool); +} + +- (void)setURLEncodedFragment: (OFString *)URLEncodedFragment +{ + OFString *old = _URLEncodedFragment; + _URLEncodedFragment = [URLEncodedFragment copy]; [old release]; } - (id)copy { Index: src/OFURL.h ================================================================== --- src/OFURL.h +++ src/OFURL.h @@ -29,14 +29,15 @@ * * @brief A class for parsing URLs and accessing parts of it. */ @interface OFURL: OFObject { - OFString *_Nullable _scheme, *_Nullable _host; + OFString *_Nullable _URLEncodedScheme, *_Nullable _URLEncodedHost; OFNumber *_Nullable _port; - OFString *_Nullable _user, *_Nullable _password, *_path; - OFString *_Nullable _query, *_Nullable _fragment; + OFString *_Nullable _URLEncodedUser, *_Nullable _URLEncodedPassword; + OFString *_Nullable _URLEncodedPath; + OFString *_Nullable _URLEncodedQuery, *_Nullable _URLEncodedFragment; } /*! * The scheme part of the URL. */ Index: src/OFURL.m ================================================================== --- src/OFURL.m +++ src/OFURL.m @@ -346,13 +346,13 @@ @throw [OFInvalidFormatException exception]; for (tmp2 = UTF8String; tmp2 < tmp; tmp2++) *tmp2 = of_ascii_tolower(*tmp2); - _scheme = [[[OFString stringWithUTF8String: UTF8String - length: tmp - UTF8String] - stringByURLDecoding] copy]; + _URLEncodedScheme = [[OFString alloc] + initWithUTF8String: UTF8String + length: tmp - UTF8String]; UTF8String = tmp + 3; if ((tmp = strchr(UTF8String, '/')) != NULL) { *tmp = '\0'; @@ -367,65 +367,61 @@ if ((tmp3 = strchr(UTF8String, ':')) != NULL) { *tmp3 = '\0'; tmp3++; - _user = [[[OFString stringWithUTF8String: - UTF8String] stringByURLDecoding] copy]; - _password = [[[OFString stringWithUTF8String: - tmp3] stringByURLDecoding] copy]; + _URLEncodedUser = [[OFString alloc] + initWithUTF8String: UTF8String]; + _URLEncodedPassword = [[OFString alloc] + initWithUTF8String: tmp3]; } else - _user = [[[OFString stringWithUTF8String: - UTF8String] stringByURLDecoding] copy]; + _URLEncodedUser = [[OFString alloc] + initWithUTF8String: UTF8String]; UTF8String = tmp2; } if ((tmp2 = strchr(UTF8String, ':')) != NULL) { - void *pool2; OFString *portString; *tmp2 = '\0'; tmp2++; - _host = [[[OFString stringWithUTF8String: UTF8String] - stringByURLDecoding] copy]; + _URLEncodedHost = [[OFString alloc] + initWithUTF8String: UTF8String]; - pool2 = objc_autoreleasePoolPush(); portString = [OFString stringWithUTF8String: tmp2]; if ([portString decimalValue] > 65535) @throw [OFInvalidFormatException exception]; _port = [[OFNumber alloc] initWithUInt16: (uint16_t)[portString decimalValue]]; - - objc_autoreleasePoolPop(pool2); } else - _host = [[[OFString stringWithUTF8String: UTF8String] - stringByURLDecoding] copy]; + _URLEncodedHost = [[OFString alloc] + initWithUTF8String: UTF8String]; if ((UTF8String = tmp) != NULL) { if ((tmp = strchr(UTF8String, '#')) != NULL) { *tmp = '\0'; - _fragment = [[[OFString stringWithUTF8String: - tmp + 1] stringByURLDecoding] copy]; + _URLEncodedFragment = [[OFString alloc] + initWithUTF8String: tmp + 1]; } if ((tmp = strchr(UTF8String, '?')) != NULL) { *tmp = '\0'; - _query = [[[OFString stringWithUTF8String: - tmp + 1] stringByURLDecoding] copy]; + _URLEncodedQuery = [[OFString alloc] + initWithUTF8String: tmp + 1]; } UTF8String--; *UTF8String = '/'; - _path = [[[OFString stringWithUTF8String: UTF8String] - stringByURLDecoding] copy]; + _URLEncodedPath = [[OFString alloc] + initWithUTF8String: UTF8String]; } objc_autoreleasePoolPop(pool); } @catch (id e) { [self release]; @@ -449,15 +445,15 @@ @try { void *pool = objc_autoreleasePoolPush(); char *tmp; - _scheme = [URL->_scheme copy]; - _host = [URL->_host copy]; + _URLEncodedScheme = [URL->_URLEncodedScheme copy]; + _URLEncodedHost = [URL->_URLEncodedHost copy]; _port = [URL->_port copy]; - _user = [URL->_user copy]; - _password = [URL->_password copy]; + _URLEncodedUser = [URL->_URLEncodedUser copy]; + _URLEncodedPassword = [URL->_URLEncodedPassword copy]; if ((UTF8String2 = of_strdup([string UTF8String])) == NULL) @throw [OFOutOfMemoryException exceptionWithRequestedSize: [string UTF8StringLength]]; @@ -464,37 +460,37 @@ UTF8String = UTF8String2; if ((tmp = strchr(UTF8String, '#')) != NULL) { *tmp = '\0'; - _fragment = [[[OFString stringWithUTF8String: tmp + 1] - stringByURLDecoding] copy]; + _URLEncodedFragment = [[OFString alloc] + initWithUTF8String: tmp + 1]; } if ((tmp = strchr(UTF8String, '?')) != NULL) { *tmp = '\0'; - _query = [[[OFString stringWithUTF8String: tmp + 1] - stringByURLDecoding] copy]; + _URLEncodedQuery = [[OFString alloc] + initWithUTF8String: tmp + 1]; } if (*UTF8String == '/') - _path = [[[OFString stringWithUTF8String: UTF8String] - stringByURLDecoding] copy]; + _URLEncodedPath = [[OFString alloc] + initWithUTF8String: UTF8String]; else { OFString *path, *s; - path = [[OFString stringWithUTF8String: UTF8String] - stringByURLDecoding]; + path = [OFString stringWithUTF8String: UTF8String]; - if ([URL->_path hasSuffix: @"/"]) - s = [URL->_path stringByAppendingString: path]; + if ([URL->_URLEncodedPath hasSuffix: @"/"]) + s = [URL->_URLEncodedPath + stringByAppendingString: path]; else - s = [OFString stringWithFormat: @"%@/../%@", - URL->_path, - path]; + s = [OFString stringWithFormat: + @"%@/../%@", URL->_URLEncodedPath, path]; - _path = [[s stringByStandardizingURLPath] copy]; + _URLEncodedPath = + [[s stringByStandardizingURLPath] copy]; } objc_autoreleasePoolPop(pool); } @catch (id e) { [self release]; @@ -578,18 +574,18 @@ return self; } - (void)dealloc { - [_scheme release]; - [_host release]; + [_URLEncodedScheme release]; + [_URLEncodedHost release]; [_port release]; - [_user release]; - [_password release]; - [_path release]; - [_query release]; - [_fragment release]; + [_URLEncodedUser release]; + [_URLEncodedPassword release]; + [_URLEncodedPath release]; + [_URLEncodedQuery release]; + [_URLEncodedFragment release]; [super dealloc]; } - (bool)isEqual: (id)object @@ -599,25 +595,32 @@ if (![object isKindOfClass: [OFURL class]]) return false; URL = object; - if (URL->_scheme != _scheme && ![URL->_scheme isEqual: _scheme]) + if (URL->_URLEncodedScheme != _URLEncodedScheme && + ![URL->_URLEncodedScheme isEqual: _URLEncodedScheme]) return false; - if (URL->_host != _host && ![URL->_host isEqual: _host]) + if (URL->_URLEncodedHost != _URLEncodedHost && + ![URL->_URLEncodedHost isEqual: _URLEncodedHost]) return false; if (URL->_port != _port && ![URL->_port isEqual: _port]) return false; - if (URL->_user != _user && ![URL->_user isEqual: _user]) - return false; - if (URL->_password != _password && ![URL->_password isEqual: _password]) - return false; - if (URL->_path != _path && ![URL->_path isEqual: _path]) - return false; - if (URL->_query != _query && ![URL->_query isEqual: _query]) - return false; - if (URL->_fragment != _fragment && ![URL->_fragment isEqual: _fragment]) + if (URL->_URLEncodedUser != _URLEncodedUser && + ![URL->_URLEncodedUser isEqual: _URLEncodedUser]) + return false; + if (URL->_URLEncodedPassword != _URLEncodedPassword && + ![URL->_URLEncodedPassword isEqual: _URLEncodedPassword]) + return false; + if (URL->_URLEncodedPath != _URLEncodedPath && + ![URL->_URLEncodedPath isEqual: _URLEncodedPath]) + return false; + if (URL->_URLEncodedQuery != _URLEncodedQuery && + ![URL->_URLEncodedQuery isEqual: _URLEncodedQuery]) + return false; + if (URL->_URLEncodedFragment != _URLEncodedFragment && + ![URL->_URLEncodedFragment isEqual: _URLEncodedFragment]) return false; return true; } @@ -625,105 +628,103 @@ { uint32_t hash; OF_HASH_INIT(hash); - OF_HASH_ADD_HASH(hash, [_scheme hash]); - OF_HASH_ADD_HASH(hash, [_host hash]); + OF_HASH_ADD_HASH(hash, [_URLEncodedScheme hash]); + OF_HASH_ADD_HASH(hash, [_URLEncodedHost hash]); OF_HASH_ADD_HASH(hash, [_port hash]); - OF_HASH_ADD_HASH(hash, [_user hash]); - OF_HASH_ADD_HASH(hash, [_password hash]); - OF_HASH_ADD_HASH(hash, [_path hash]); - OF_HASH_ADD_HASH(hash, [_query hash]); - OF_HASH_ADD_HASH(hash, [_fragment hash]); + OF_HASH_ADD_HASH(hash, [_URLEncodedUser hash]); + OF_HASH_ADD_HASH(hash, [_URLEncodedPassword hash]); + OF_HASH_ADD_HASH(hash, [_URLEncodedPath hash]); + OF_HASH_ADD_HASH(hash, [_URLEncodedQuery hash]); + OF_HASH_ADD_HASH(hash, [_URLEncodedFragment hash]); OF_HASH_FINALIZE(hash); return hash; } - (OFString *)scheme { - return _scheme; + return [_URLEncodedScheme stringByURLDecoding]; } - (OFString *)URLEncodedScheme { - return [_scheme stringByURLEncodingWithAllowedCharacters: - [OFCharacterSet URLSchemeAllowedCharacterSet]]; + return _URLEncodedScheme; } - (OFString *)host { - return _host; + return [_URLEncodedHost stringByURLDecoding]; } - (OFString *)URLEncodedHost { - return [_host stringByURLEncodingWithAllowedCharacters: - [OFCharacterSet URLHostAllowedCharacterSet]]; + return _URLEncodedHost; } - (OFNumber *)port { return _port; } - (OFString *)user { - return _user; + return [_URLEncodedUser stringByURLDecoding]; } - (OFString *)URLEncodedUser { - return [_user stringByURLEncodingWithAllowedCharacters: - [OFCharacterSet URLUserAllowedCharacterSet]]; + return _URLEncodedUser; } - (OFString *)password { - return _password; + return [_URLEncodedPassword stringByURLDecoding]; } - (OFString *)URLEncodedPassword { - return [_password stringByURLEncodingWithAllowedCharacters: - [OFCharacterSet URLPasswordAllowedCharacterSet]]; + return _URLEncodedPassword; } - (OFString *)path { - return _path; + return [_URLEncodedPath stringByURLDecoding]; } - (OFString *)URLEncodedPath { - return [_path stringByURLEncodingWithAllowedCharacters: - [OFCharacterSet URLPathAllowedCharacterSet]]; + return _URLEncodedPath; } - (OFArray *)pathComponents { - return [_path componentsSeparatedByString: @"/"]; + return [[self path] componentsSeparatedByString: @"/"]; } - (OFString *)lastPathComponent { - void *pool; - OFString *path; + void *pool = objc_autoreleasePoolPush(); + OFString *path = [self path]; const char *UTF8String, *lastComponent; size_t length; OFString *ret; - if (_path == nil) + if (path == nil) { + objc_autoreleasePoolPop(pool); + return nil; + } - if ([_path isEqual: @"/"]) + if ([path isEqual: @"/"]) { + objc_autoreleasePoolPop(pool); + return @""; - - pool = objc_autoreleasePoolPush(); - path = _path; + } if ([path hasSuffix: @"/"]) path = [path substringWithRange: of_range(0, [path length] - 1)]; @@ -746,28 +747,26 @@ return [ret autorelease]; } - (OFString *)query { - return _query; + return [_URLEncodedQuery stringByURLDecoding]; } - (OFString *)URLEncodedQuery { - return [_query stringByURLEncodingWithAllowedCharacters: - [OFCharacterSet URLQueryAllowedCharacterSet]]; + return _URLEncodedQuery; } - (OFString *)fragment { - return _fragment; + return [_URLEncodedFragment stringByURLDecoding]; } - (OFString *)URLEncodedFragment { - return [_fragment stringByURLEncodingWithAllowedCharacters: - [OFCharacterSet URLFragmentAllowedCharacterSet]]; + return _URLEncodedFragment; } - (id)copy { return [self retain]; @@ -776,18 +775,18 @@ - (id)mutableCopy { OFMutableURL *copy = [[OFMutableURL alloc] init]; @try { - [copy setScheme: _scheme]; - [copy setHost: _host]; + [copy setURLEncodedScheme: _URLEncodedScheme]; + [copy setURLEncodedHost: _URLEncodedHost]; [copy setPort: _port]; - [copy setUser: _user]; - [copy setPassword: _password]; - [copy setPath: _path]; - [copy setQuery: _query]; - [copy setFragment: _fragment]; + [copy setURLEncodedUser: _URLEncodedUser]; + [copy setURLEncodedPassword: _URLEncodedPassword]; + [copy setURLEncodedPath: _URLEncodedPath]; + [copy setURLEncodedQuery: _URLEncodedQuery]; + [copy setURLEncodedFragment: _URLEncodedFragment]; } @catch (id e) { [copy release]; @throw e; } @@ -795,40 +794,36 @@ } - (OFString *)string { OFMutableString *ret = [OFMutableString string]; - void *pool = objc_autoreleasePoolPush(); + + [ret appendFormat: @"%@://", _URLEncodedScheme]; - [ret appendFormat: @"%@://", [self URLEncodedScheme]]; - - if (_user != nil && _password != nil) + if (_URLEncodedUser != nil && _URLEncodedPassword != nil) [ret appendFormat: @"%@:%@@", - [self URLEncodedUser], - [self URLEncodedPassword]]; - else if (_user != nil) - [ret appendFormat: @"%@@", [self URLEncodedUser]]; + _URLEncodedUser, _URLEncodedPassword]; + else if (_URLEncodedUser != nil) + [ret appendFormat: @"%@@", _URLEncodedUser]; - if (_host != nil) - [ret appendString: [self URLEncodedHost]]; + if (_URLEncodedHost != nil) + [ret appendString: _URLEncodedHost]; if (_port != nil) [ret appendFormat: @":%@", _port]; - if (_path != nil) { - if (![_path hasPrefix: @"/"]) + if (_URLEncodedPath != nil) { + if (![_URLEncodedPath hasPrefix: @"/"]) @throw [OFInvalidFormatException exception]; - [ret appendString: [self URLEncodedPath]]; + [ret appendString: _URLEncodedPath]; } - if (_query != nil) - [ret appendFormat: @"?%@", [self URLEncodedQuery]]; + if (_URLEncodedQuery != nil) + [ret appendFormat: @"?%@", _URLEncodedQuery]; - if (_fragment != nil) - [ret appendFormat: @"#%@", [self URLEncodedFragment]]; - - objc_autoreleasePoolPop(pool); + if (_URLEncodedFragment != nil) + [ret appendFormat: @"#%@", _URLEncodedFragment]; [ret makeImmutable]; return ret; } @@ -836,17 +831,17 @@ - (OFString *)fileSystemRepresentation { void *pool = objc_autoreleasePoolPush(); OFString *path; - if (![_scheme isEqual: @"file"]) + if (![_URLEncodedScheme isEqual: @"file"]) @throw [OFInvalidArgumentException exception]; - if (![_path hasPrefix: @"/"]) + if (![_URLEncodedPath hasPrefix: @"/"]) @throw [OFInvalidFormatException exception]; - path = _path; + path = [self path]; if ([path hasSuffix: @"/"]) path = [path substringWithRange: of_range(0, [path length] - 1)]; Index: tests/OFURLTests.m ================================================================== --- tests/OFURLTests.m +++ tests/OFURLTests.m @@ -28,18 +28,19 @@ #import "OFInvalidFormatException.h" #import "TestsAppDelegate.h" static OFString *module = @"OFURL"; -static OFString *url_str = @"ht%3Atp://us%3Aer:p%40w@ho%3Ast:1234/" +static OFString *url_str = @"ht%3atp://us%3Aer:p%40w@ho%3Ast:1234/" @"pa%3Fth?que%23ry#frag%23ment"; @implementation TestsAppDelegate (OFURLTests) - (void)URLTests { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; OFURL *u1, *u2, *u3, *u4; + OFMutableURL *mu; TEST(@"+[URLWithString:]", R(u1 = [OFURL URLWithString: url_str]) && R(u2 = [OFURL URLWithString: @"http://foo:80"]) && R(u3 = [OFURL URLWithString: @"http://bar/"]) && @@ -46,11 +47,11 @@ R(u4 = [OFURL URLWithString: @"file:///etc/passwd"])) TEST(@"+[URLWithString:relativeToURL:]", [[[OFURL URLWithString: @"/foo" relativeToURL: u1] string] isEqual: - @"ht%3Atp://us%3Aer:p%40w@ho%3Ast:1234/foo"] && + @"ht%3atp://us%3Aer:p%40w@ho%3Ast:1234/foo"] && [[[OFURL URLWithString: @"foo/bar?q" relativeToURL: [OFURL URLWithString: @"http://h/qux/quux"]] string] isEqual: @"http://h/qux/foo/bar?q"] && [[[OFURL URLWithString: @"foo/bar" relativeToURL: [OFURL URLWithString: @"http://h/qux/?x"]] @@ -109,8 +110,38 @@ TEST(@"-[hash:]", [u1 hash] == [u4 hash] && [u2 hash] != [u3 hash]) EXPECT_EXCEPTION(@"Detection of invalid format", OFInvalidFormatException, [OFURL URLWithString: @"http"]) + mu = [OFMutableURL URL]; + + TEST(@"-[setScheme:]", + R([mu setScheme: @"ht:tp"]) && + [[mu URLEncodedScheme] isEqual: @"ht%3Atp"]) + + TEST(@"-[setHost:]", + R([mu setHost: @"ho:st"]) && + [[mu URLEncodedHost] isEqual: @"ho%3Ast"]) + + TEST(@"-[setUser:]", + R([mu setUser: @"us:er"]) && + [[mu URLEncodedUser] isEqual: @"us%3Aer"]) + + TEST(@"-[setPassword:]", + R([mu setPassword: @"pass:word"]) && + [[mu URLEncodedPassword] isEqual: @"pass%3Aword"]) + + TEST(@"-[setPath:]", + R([mu setPath: @"pa/th@?"]) && + [[mu URLEncodedPath] isEqual: @"pa/th@%3F"]) + + TEST(@"-[setQuery:]", + R([mu setQuery: @"que/ry?#"]) && + [[mu URLEncodedQuery] isEqual: @"que/ry?%23"]) + + TEST(@"-[setFragment:]", + R([mu setFragment: @"frag/ment?#"]) && + [[mu URLEncodedFragment] isEqual: @"frag/ment?%23"]) + [pool drain]; } @end