Overview
Comment: | OFURL: URL-encode according to RFC 3986
This also means the parameters go away and get folded into the path. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
5f7305c65925d7c61225422fe0a8db59 |
User & Date: | js on 2017-10-31 21:39:36 |
Other Links: | manifest | tags |
Context
2017-10-31
| ||
21:55 | OFString+URLEncoding: Change default allowed chars check-in: 4db6713bda user: js tags: trunk | |
21:39 | OFURL: URL-encode according to RFC 3986 check-in: 5f7305c659 user: js tags: trunk | |
2017-10-30
| ||
00:29 | Fix nullable properties in Doxygen check-in: 06a922c912 user: js tags: trunk | |
Changes
Modified src/OFMutableURL.h from [db8fdd5d15] to [716b3b017c].
︙ | ︙ | |||
58 59 60 61 62 63 64 | * The path of the URL split into components. * * The first component must always be empty to designate the root. */ @property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFArray OF_GENERIC(OFString *) *pathComponents; | < < < < < < | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | * The path of the URL split into components. * * The first component must always be empty to designate the root. */ @property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFArray OF_GENERIC(OFString *) *pathComponents; /*! * The query part of the URL. */ @property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *query; /*! * The fragment part of the URL. |
︙ | ︙ |
Modified src/OFMutableURL.m from [6d9eb70d6a] to [f6b587c9bc].
︙ | ︙ | |||
21 22 23 24 25 26 27 | #import "OFNumber.h" #import "OFString.h" #import "OFURL+Private.h" #import "OFInvalidFormatException.h" @implementation OFMutableURL | | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #import "OFNumber.h" #import "OFString.h" #import "OFURL+Private.h" #import "OFInvalidFormatException.h" @implementation OFMutableURL @dynamic scheme, host, port, user, password, path, pathComponents, query; @dynamic fragment; + (instancetype)URL { return [[[self alloc] init] autorelease]; } - (instancetype)init |
︙ | ︙ | |||
96 97 98 99 100 101 102 | @throw [OFInvalidFormatException exception]; [self setPath: [components componentsJoinedByString: @"/"]]; objc_autoreleasePoolPop(pool); } | < < < < < < < | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | @throw [OFInvalidFormatException exception]; [self setPath: [components componentsJoinedByString: @"/"]]; objc_autoreleasePoolPop(pool); } - (void)setQuery: (OFString *)query { OFString *old = _query; _query = [query copy]; [old release]; } |
︙ | ︙ |
Modified src/OFURL.h from [cb95b72aba] to [a6d37c0b2c].
︙ | ︙ | |||
29 30 31 32 33 34 35 | * @brief A class for parsing URLs and accessing parts of it. */ @interface OFURL: OFObject <OFCopying, OFMutableCopying, OFSerialization> { OFString *_Nullable _scheme, *_Nullable _host; OFNumber *_Nullable _port; OFString *_Nullable _user, *_Nullable _password, *_path; | < | | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | * @brief A class for parsing URLs and accessing parts of it. */ @interface OFURL: OFObject <OFCopying, OFMutableCopying, OFSerialization> { OFString *_Nullable _scheme, *_Nullable _host; OFNumber *_Nullable _port; OFString *_Nullable _user, *_Nullable _password, *_path; OFString *_Nullable _query, *_Nullable _fragment; } /*! * The scheme part of the URL. */ @property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFString *scheme; |
︙ | ︙ | |||
79 80 81 82 83 84 85 | * The last path component of the URL. * * Returns the empty string if the path is the root. */ @property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFString *lastPathComponent; | < < < < < | 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | * The last path component of the URL. * * Returns the empty string if the path is the root. */ @property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFString *lastPathComponent; /*! * The query part of the URL. */ @property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFString *query; /*! * The fragment part of the URL. |
︙ | ︙ |
Modified src/OFURL.m from [48d985e9ad] to [45850285e0].
︙ | ︙ | |||
168 169 170 171 172 173 174 | if ((tmp = strchr(UTF8String, '?')) != NULL) { *tmp = '\0'; _query = [[[OFString stringWithUTF8String: tmp + 1] stringByURLDecoding] copy]; } | < < < < < < < | 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | if ((tmp = strchr(UTF8String, '?')) != NULL) { *tmp = '\0'; _query = [[[OFString stringWithUTF8String: tmp + 1] stringByURLDecoding] copy]; } UTF8String--; *UTF8String = '/'; _path = [[[OFString stringWithUTF8String: UTF8String] stringByURLDecoding] copy]; } |
︙ | ︙ | |||
232 233 234 235 236 237 238 | if ((tmp = strchr(UTF8String, '?')) != NULL) { *tmp = '\0'; _query = [[[OFString stringWithUTF8String: tmp + 1] stringByURLDecoding] copy]; } | < < < < < < | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | if ((tmp = strchr(UTF8String, '?')) != NULL) { *tmp = '\0'; _query = [[[OFString stringWithUTF8String: tmp + 1] stringByURLDecoding] copy]; } if (*UTF8String == '/') _path = [[[OFString stringWithUTF8String: UTF8String] stringByURLDecoding] copy]; else { OFString *path, *s; path = [[OFString stringWithUTF8String: UTF8String] |
︙ | ︙ | |||
348 349 350 351 352 353 354 | { [_scheme release]; [_host release]; [_port release]; [_user release]; [_password release]; [_path release]; | < | 335 336 337 338 339 340 341 342 343 344 345 346 347 348 | { [_scheme release]; [_host release]; [_port release]; [_user release]; [_password release]; [_path release]; [_query release]; [_fragment release]; [super dealloc]; } - (bool)isEqual: (id)object |
︙ | ︙ | |||
376 377 378 379 380 381 382 | 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; | < < < < | 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 | 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]) return false; return true; } - (uint32_t)hash { 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, [_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_FINALIZE(hash); return hash; } |
︙ | ︙ | |||
483 484 485 486 487 488 489 | length: length - (lastComponent - UTF8String)]; objc_autoreleasePoolPop(pool); return [ret autorelease]; } | < < < < < | 465 466 467 468 469 470 471 472 473 474 475 476 477 478 | length: length - (lastComponent - UTF8String)]; objc_autoreleasePoolPop(pool); return [ret autorelease]; } - (OFString *)query { return _query; } - (OFString *)fragment { |
︙ | ︙ | |||
514 515 516 517 518 519 520 | @try { [copy setScheme: _scheme]; [copy setHost: _host]; [copy setPort: _port]; [copy setUser: _user]; [copy setPassword: _password]; [copy setPath: _path]; | < | 491 492 493 494 495 496 497 498 499 500 501 502 503 504 | @try { [copy setScheme: _scheme]; [copy setHost: _host]; [copy setPort: _port]; [copy setUser: _user]; [copy setPassword: _password]; [copy setPath: _path]; [copy setQuery: _query]; [copy setFragment: _fragment]; } @catch (id e) { [copy release]; @throw e; } |
︙ | ︙ | |||
549 550 551 552 553 554 555 | [ret appendFormat: @":%@", _port]; if (_path != nil) { if (![_path hasPrefix: @"/"]) @throw [OFInvalidFormatException exception]; [ret appendString: [_path | | > < < < | > > | > > | 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 | [ret appendFormat: @":%@", _port]; if (_path != nil) { if (![_path hasPrefix: @"/"]) @throw [OFInvalidFormatException exception]; [ret appendString: [_path stringByURLEncodingWithAllowedCharacters: "-._~!$&'()*+,;=:@/"]]; } if (_query != nil) [ret appendFormat: @"?%@", [_query stringByURLEncodingWithAllowedCharacters: "-._~!$&'()*+,;=:@/?"]]; if (_fragment != nil) [ret appendFormat: @"#%@", [_fragment stringByURLEncodingWithAllowedCharacters: "-._~!$&'()*+,;=:@/?"]]; objc_autoreleasePoolPop(pool); [ret makeImmutable]; return ret; } |
︙ | ︙ |
Modified tests/OFURLTests.m from [9dd7664004] to [96f3992920].
︙ | ︙ | |||
27 28 29 30 31 32 33 | #import "OFInvalidFormatException.h" #import "TestsAppDelegate.h" static OFString *module = @"OFURL"; static OFString *url_str = @"ht%3Atp://us%3Aer:p%40w@ho%3Ast:1234/" | | | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | #import "OFInvalidFormatException.h" #import "TestsAppDelegate.h" static OFString *module = @"OFURL"; 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; |
︙ | ︙ | |||
76 77 78 79 80 81 82 | TEST(@"-[user]", [[u1 user] isEqual: @"us:er"] && [u4 user] == nil) TEST(@"-[password]", [[u1 password] isEqual: @"p@w"] && [u4 password] == nil) TEST(@"-[host]", [[u1 host] isEqual: @"ho:st"] && [u4 port] == 0) TEST(@"-[port]", [[u1 port] isEqual: [OFNumber numberWithUInt16: 1234]]) TEST(@"-[path]", | | | < < | 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | TEST(@"-[user]", [[u1 user] isEqual: @"us:er"] && [u4 user] == nil) TEST(@"-[password]", [[u1 password] isEqual: @"p@w"] && [u4 password] == nil) TEST(@"-[host]", [[u1 host] isEqual: @"ho:st"] && [u4 port] == 0) TEST(@"-[port]", [[u1 port] isEqual: [OFNumber numberWithUInt16: 1234]]) TEST(@"-[path]", [[u1 path] isEqual: @"/pa?th"] && [[u4 path] isEqual: @"/etc/passwd"]) TEST(@"-[pathComponents]", [[u1 pathComponents] isEqual: [OFArray arrayWithObjects: @"", @"pa?th", nil]] && [[u4 pathComponents] isEqual: [OFArray arrayWithObjects: @"", @"etc", @"passwd", nil]]) TEST(@"-[lastPathComponent", [[[OFURL URLWithString: @"http://host/foo//bar/baz"] lastPathComponent] isEqual: @"baz"] && [[[OFURL URLWithString: @"http://host/foo//bar/baz/"] lastPathComponent] isEqual: @"baz"] && [[[OFURL URLWithString: @"http://host/foo/"] lastPathComponent] isEqual: @"foo"] && [[[OFURL URLWithString: @"http://host/"] lastPathComponent] isEqual: @""]) TEST(@"-[query]", [[u1 query] isEqual: @"que#ry"] && [u4 query] == nil) TEST(@"-[fragment]", [[u1 fragment] isEqual: @"frag#ment"] && [u4 fragment] == nil) TEST(@"-[copy]", R(u4 = [[u1 copy] autorelease])) |
︙ | ︙ |
Modified tests/serialization.xml from [9ca884a2b7] to [4a5293ca90].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?xml version='1.0' encoding='UTF-8'?> <serialization xmlns='https://webkeks.org/objfw/serialization' version='1'> <OFMutableDictionary> <key> <OFString>Blub</OFString> </key> <object> <OFString>B"la</OFString> </object> <key> <OFList> <OFString>Hello</OFString> <OFString>Wo
ld! How are you?</OFString> <OFURL>https://webkeks.org/</OFURL> <OFXMLElement name='x'> | > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | <?xml version='1.0' encoding='UTF-8'?> <serialization xmlns='https://webkeks.org/objfw/serialization' version='1'> <OFMutableDictionary> <key> <OFString>Blub</OFString> </key> <object> <OFString>B"la</OFString> </object> <key> <OFData>MDEyMzQ1Njc4OTo7PEFCQ0RFRkdISklLTE1OT1BRUlNUVVZXWFla</OFData> </key> <object> <OFString>data</OFString> </object> <key> <OFArray> <OFString>Qu"xbar test</OFString> <OFNumber type='signed'>1234</OFNumber> <OFNumber type='double'>40934a456d5cfaad</OFNumber> <OFMutableString>asd</OFMutableString> <OFDate>40934a456d5cfaad</OFDate> </OFArray> </key> <object> <OFString>Hello</OFString> </object> <key> <OFList> <OFString>Hello</OFString> <OFString>Wo
ld! How are you?</OFString> <OFURL>https://webkeks.org/</OFURL> <OFXMLElement name='x'> |
︙ | ︙ | |||
34 35 36 37 38 39 40 | </object> </OFCountedSet> </OFList> </key> <object> <OFString>list</OFString> </object> | < < < < < < < < < < < < < < < < < < < | 53 54 55 56 57 58 59 60 61 | </object> </OFCountedSet> </OFList> </key> <object> <OFString>list</OFString> </object> </OFMutableDictionary> </serialization> |