12c26ad4bSAdrien Destugues /* 28f30879bSAndrew Lindesay * Copyright 2010-2018 Haiku Inc. All rights reserved. 32c26ad4bSAdrien Destugues * Distributed under the terms of the MIT License. 42c26ad4bSAdrien Destugues * 52c26ad4bSAdrien Destugues * Authors: 62c26ad4bSAdrien Destugues * Christophe Huriaux, c.huriaux@gmail.com 72c26ad4bSAdrien Destugues * Andrew Lindesay, apl@lindesay.co.nz 82c26ad4bSAdrien Destugues */ 92c26ad4bSAdrien Destugues 102c26ad4bSAdrien Destugues 112c26ad4bSAdrien Destugues #include <Url.h> 122c26ad4bSAdrien Destugues 132c26ad4bSAdrien Destugues #include <ctype.h> 142c26ad4bSAdrien Destugues #include <cstdio> 152c26ad4bSAdrien Destugues #include <cstdlib> 162c26ad4bSAdrien Destugues #include <new> 172c26ad4bSAdrien Destugues 182c26ad4bSAdrien Destugues #include <MimeType.h> 192c26ad4bSAdrien Destugues #include <Roster.h> 202c26ad4bSAdrien Destugues 212c26ad4bSAdrien Destugues #ifdef HAIKU_TARGET_PLATFORM_HAIKU 222c26ad4bSAdrien Destugues #include <ICUWrapper.h> 232c26ad4bSAdrien Destugues #endif 242c26ad4bSAdrien Destugues 252c26ad4bSAdrien Destugues #ifdef HAIKU_TARGET_PLATFORM_HAIKU 262c26ad4bSAdrien Destugues #include <unicode/idna.h> 272c26ad4bSAdrien Destugues #include <unicode/stringpiece.h> 282c26ad4bSAdrien Destugues #endif 292c26ad4bSAdrien Destugues 302c26ad4bSAdrien Destugues 312c26ad4bSAdrien Destugues static const char* kArchivedUrl = "be:url string"; 322c26ad4bSAdrien Destugues 332c26ad4bSAdrien Destugues 342c26ad4bSAdrien Destugues BUrl::BUrl(const char* url) 352c26ad4bSAdrien Destugues : 362c26ad4bSAdrien Destugues fUrlString(), 372c26ad4bSAdrien Destugues fProtocol(), 382c26ad4bSAdrien Destugues fUser(), 392c26ad4bSAdrien Destugues fPassword(), 402c26ad4bSAdrien Destugues fHost(), 412c26ad4bSAdrien Destugues fPort(0), 422c26ad4bSAdrien Destugues fPath(), 432c26ad4bSAdrien Destugues fRequest(), 442c26ad4bSAdrien Destugues fHasHost(false), 452c26ad4bSAdrien Destugues fHasFragment(false) 462c26ad4bSAdrien Destugues { 472c26ad4bSAdrien Destugues SetUrlString(url); 482c26ad4bSAdrien Destugues } 492c26ad4bSAdrien Destugues 502c26ad4bSAdrien Destugues 512c26ad4bSAdrien Destugues BUrl::BUrl(BMessage* archive) 522c26ad4bSAdrien Destugues : 532c26ad4bSAdrien Destugues fUrlString(), 542c26ad4bSAdrien Destugues fProtocol(), 552c26ad4bSAdrien Destugues fUser(), 562c26ad4bSAdrien Destugues fPassword(), 572c26ad4bSAdrien Destugues fHost(), 582c26ad4bSAdrien Destugues fPort(0), 592c26ad4bSAdrien Destugues fPath(), 602c26ad4bSAdrien Destugues fRequest(), 612c26ad4bSAdrien Destugues fHasHost(false), 622c26ad4bSAdrien Destugues fHasFragment(false) 632c26ad4bSAdrien Destugues { 642c26ad4bSAdrien Destugues BString url; 652c26ad4bSAdrien Destugues 662c26ad4bSAdrien Destugues if (archive->FindString(kArchivedUrl, &url) == B_OK) 672c26ad4bSAdrien Destugues SetUrlString(url); 682c26ad4bSAdrien Destugues else 692c26ad4bSAdrien Destugues _ResetFields(); 702c26ad4bSAdrien Destugues } 712c26ad4bSAdrien Destugues 722c26ad4bSAdrien Destugues 732c26ad4bSAdrien Destugues BUrl::BUrl(const BUrl& other) 742c26ad4bSAdrien Destugues : 752c26ad4bSAdrien Destugues BArchivable(), 762c26ad4bSAdrien Destugues fUrlString(), 772c26ad4bSAdrien Destugues fProtocol(other.fProtocol), 782c26ad4bSAdrien Destugues fUser(other.fUser), 792c26ad4bSAdrien Destugues fPassword(other.fPassword), 802c26ad4bSAdrien Destugues fHost(other.fHost), 812c26ad4bSAdrien Destugues fPort(other.fPort), 822c26ad4bSAdrien Destugues fPath(other.fPath), 832c26ad4bSAdrien Destugues fRequest(other.fRequest), 842c26ad4bSAdrien Destugues fFragment(other.fFragment), 852c26ad4bSAdrien Destugues fUrlStringValid(other.fUrlStringValid), 862c26ad4bSAdrien Destugues fAuthorityValid(other.fAuthorityValid), 872c26ad4bSAdrien Destugues fUserInfoValid(other.fUserInfoValid), 882c26ad4bSAdrien Destugues fHasProtocol(other.fHasProtocol), 892c26ad4bSAdrien Destugues fHasUserName(other.fHasUserName), 902c26ad4bSAdrien Destugues fHasPassword(other.fHasPassword), 912c26ad4bSAdrien Destugues fHasHost(other.fHasHost), 922c26ad4bSAdrien Destugues fHasPort(other.fHasPort), 932c26ad4bSAdrien Destugues fHasPath(other.fHasPath), 942c26ad4bSAdrien Destugues fHasRequest(other.fHasRequest), 952c26ad4bSAdrien Destugues fHasFragment(other.fHasFragment) 962c26ad4bSAdrien Destugues { 972c26ad4bSAdrien Destugues if (fUrlStringValid) 982c26ad4bSAdrien Destugues fUrlString = other.fUrlString; 992c26ad4bSAdrien Destugues 1002c26ad4bSAdrien Destugues if (fAuthorityValid) 1012c26ad4bSAdrien Destugues fAuthority = other.fAuthority; 1022c26ad4bSAdrien Destugues 1032c26ad4bSAdrien Destugues if (fUserInfoValid) 1042c26ad4bSAdrien Destugues fUserInfo = other.fUserInfo; 1052c26ad4bSAdrien Destugues 1062c26ad4bSAdrien Destugues } 1072c26ad4bSAdrien Destugues 1082c26ad4bSAdrien Destugues 1092c26ad4bSAdrien Destugues BUrl::BUrl(const BUrl& base, const BString& location) 1102c26ad4bSAdrien Destugues : 1112c26ad4bSAdrien Destugues fUrlString(), 1122c26ad4bSAdrien Destugues fProtocol(), 1132c26ad4bSAdrien Destugues fUser(), 1142c26ad4bSAdrien Destugues fPassword(), 1152c26ad4bSAdrien Destugues fHost(), 1162c26ad4bSAdrien Destugues fPort(0), 1172c26ad4bSAdrien Destugues fPath(), 1182c26ad4bSAdrien Destugues fRequest(), 1192c26ad4bSAdrien Destugues fAuthorityValid(false), 1202c26ad4bSAdrien Destugues fUserInfoValid(false), 1212c26ad4bSAdrien Destugues fHasUserName(false), 1222c26ad4bSAdrien Destugues fHasPassword(false), 1232c26ad4bSAdrien Destugues fHasHost(false), 1242c26ad4bSAdrien Destugues fHasPort(false), 1252c26ad4bSAdrien Destugues fHasFragment(false) 1262c26ad4bSAdrien Destugues { 1272c26ad4bSAdrien Destugues // This implements the algorithm in RFC3986, Section 5.2. 1282c26ad4bSAdrien Destugues 1292c26ad4bSAdrien Destugues BUrl relative(location); 1302c26ad4bSAdrien Destugues if (relative.HasProtocol()) { 1312c26ad4bSAdrien Destugues SetProtocol(relative.Protocol()); 1322c26ad4bSAdrien Destugues if (relative.HasAuthority()) 1332c26ad4bSAdrien Destugues SetAuthority(relative.Authority()); 1342c26ad4bSAdrien Destugues SetPath(relative.Path()); 1352c26ad4bSAdrien Destugues SetRequest(relative.Request()); 1362c26ad4bSAdrien Destugues } else { 1372c26ad4bSAdrien Destugues if (relative.HasAuthority()) { 1382c26ad4bSAdrien Destugues SetAuthority(relative.Authority()); 1392c26ad4bSAdrien Destugues SetPath(relative.Path()); 1402c26ad4bSAdrien Destugues SetRequest(relative.Request()); 1412c26ad4bSAdrien Destugues } else { 1422c26ad4bSAdrien Destugues if (relative.Path().IsEmpty()) { 1432c26ad4bSAdrien Destugues _SetPathUnsafe(base.Path()); 1442c26ad4bSAdrien Destugues if (relative.HasRequest()) 1452c26ad4bSAdrien Destugues SetRequest(relative.Request()); 1462c26ad4bSAdrien Destugues else 1472c26ad4bSAdrien Destugues SetRequest(base.Request()); 1482c26ad4bSAdrien Destugues } else { 1492c26ad4bSAdrien Destugues if (relative.Path()[0] == '/') 1502c26ad4bSAdrien Destugues SetPath(relative.Path()); 1512c26ad4bSAdrien Destugues else { 1522c26ad4bSAdrien Destugues BString path = base._MergePath(relative.Path()); 1532c26ad4bSAdrien Destugues SetPath(path); 1542c26ad4bSAdrien Destugues } 1552c26ad4bSAdrien Destugues SetRequest(relative.Request()); 1562c26ad4bSAdrien Destugues } 1572c26ad4bSAdrien Destugues 1582c26ad4bSAdrien Destugues if (base.HasAuthority()) 1592c26ad4bSAdrien Destugues SetAuthority(base.Authority()); 1602c26ad4bSAdrien Destugues } 1612c26ad4bSAdrien Destugues SetProtocol(base.Protocol()); 1622c26ad4bSAdrien Destugues } 1632c26ad4bSAdrien Destugues 1642c26ad4bSAdrien Destugues if (relative.HasFragment()) 1652c26ad4bSAdrien Destugues SetFragment(relative.Fragment()); 1662c26ad4bSAdrien Destugues } 1672c26ad4bSAdrien Destugues 1682c26ad4bSAdrien Destugues 1692c26ad4bSAdrien Destugues BUrl::BUrl() 1702c26ad4bSAdrien Destugues : 1712c26ad4bSAdrien Destugues fUrlString(), 1722c26ad4bSAdrien Destugues fProtocol(), 1732c26ad4bSAdrien Destugues fUser(), 1742c26ad4bSAdrien Destugues fPassword(), 1752c26ad4bSAdrien Destugues fHost(), 1762c26ad4bSAdrien Destugues fPort(0), 1772c26ad4bSAdrien Destugues fPath(), 1782c26ad4bSAdrien Destugues fRequest(), 1792c26ad4bSAdrien Destugues fHasHost(false), 1802c26ad4bSAdrien Destugues fHasFragment(false) 1812c26ad4bSAdrien Destugues { 1822c26ad4bSAdrien Destugues _ResetFields(); 1832c26ad4bSAdrien Destugues } 1842c26ad4bSAdrien Destugues 1852c26ad4bSAdrien Destugues 1862c26ad4bSAdrien Destugues BUrl::BUrl(const BPath& path) 1872c26ad4bSAdrien Destugues : 1882c26ad4bSAdrien Destugues fUrlString(), 1892c26ad4bSAdrien Destugues fProtocol(), 1902c26ad4bSAdrien Destugues fUser(), 1912c26ad4bSAdrien Destugues fPassword(), 1922c26ad4bSAdrien Destugues fHost(), 1932c26ad4bSAdrien Destugues fPort(0), 1942c26ad4bSAdrien Destugues fPath(), 1952c26ad4bSAdrien Destugues fRequest(), 1962c26ad4bSAdrien Destugues fHasHost(false), 1972c26ad4bSAdrien Destugues fHasFragment(false) 1982c26ad4bSAdrien Destugues { 1992c26ad4bSAdrien Destugues SetUrlString(UrlEncode(path.Path(), true, true)); 2002c26ad4bSAdrien Destugues SetProtocol("file"); 2012c26ad4bSAdrien Destugues } 2022c26ad4bSAdrien Destugues 2032c26ad4bSAdrien Destugues 2042c26ad4bSAdrien Destugues BUrl::~BUrl() 2052c26ad4bSAdrien Destugues { 2062c26ad4bSAdrien Destugues } 2072c26ad4bSAdrien Destugues 2082c26ad4bSAdrien Destugues 2092c26ad4bSAdrien Destugues // #pragma mark URL fields modifiers 2102c26ad4bSAdrien Destugues 2112c26ad4bSAdrien Destugues 2122c26ad4bSAdrien Destugues BUrl& 2132c26ad4bSAdrien Destugues BUrl::SetUrlString(const BString& url) 2142c26ad4bSAdrien Destugues { 2152c26ad4bSAdrien Destugues _ExplodeUrlString(url); 2162c26ad4bSAdrien Destugues return *this; 2172c26ad4bSAdrien Destugues } 2182c26ad4bSAdrien Destugues 2192c26ad4bSAdrien Destugues 2202c26ad4bSAdrien Destugues BUrl& 2212c26ad4bSAdrien Destugues BUrl::SetProtocol(const BString& protocol) 2222c26ad4bSAdrien Destugues { 2232c26ad4bSAdrien Destugues fProtocol = protocol; 2242c26ad4bSAdrien Destugues fHasProtocol = !fProtocol.IsEmpty(); 2252c26ad4bSAdrien Destugues fUrlStringValid = false; 2262c26ad4bSAdrien Destugues return *this; 2272c26ad4bSAdrien Destugues } 2282c26ad4bSAdrien Destugues 2292c26ad4bSAdrien Destugues 2302c26ad4bSAdrien Destugues BUrl& 2312c26ad4bSAdrien Destugues BUrl::SetUserName(const BString& user) 2322c26ad4bSAdrien Destugues { 2332c26ad4bSAdrien Destugues fUser = user; 2342c26ad4bSAdrien Destugues fHasUserName = !fUser.IsEmpty(); 2352c26ad4bSAdrien Destugues fUrlStringValid = false; 2362c26ad4bSAdrien Destugues fAuthorityValid = false; 2372c26ad4bSAdrien Destugues fUserInfoValid = false; 2382c26ad4bSAdrien Destugues return *this; 2392c26ad4bSAdrien Destugues } 2402c26ad4bSAdrien Destugues 2412c26ad4bSAdrien Destugues 2422c26ad4bSAdrien Destugues BUrl& 2432c26ad4bSAdrien Destugues BUrl::SetPassword(const BString& password) 2442c26ad4bSAdrien Destugues { 2452c26ad4bSAdrien Destugues fPassword = password; 2462c26ad4bSAdrien Destugues fHasPassword = !fPassword.IsEmpty(); 2472c26ad4bSAdrien Destugues fUrlStringValid = false; 2482c26ad4bSAdrien Destugues fAuthorityValid = false; 2492c26ad4bSAdrien Destugues fUserInfoValid = false; 2502c26ad4bSAdrien Destugues return *this; 2512c26ad4bSAdrien Destugues } 2522c26ad4bSAdrien Destugues 2532c26ad4bSAdrien Destugues 2542c26ad4bSAdrien Destugues BUrl& 2552c26ad4bSAdrien Destugues BUrl::SetHost(const BString& host) 2562c26ad4bSAdrien Destugues { 2572c26ad4bSAdrien Destugues fHost = host; 2582c26ad4bSAdrien Destugues fHasHost = !fHost.IsEmpty(); 2592c26ad4bSAdrien Destugues fUrlStringValid = false; 2602c26ad4bSAdrien Destugues fAuthorityValid = false; 2612c26ad4bSAdrien Destugues return *this; 2622c26ad4bSAdrien Destugues } 2632c26ad4bSAdrien Destugues 2642c26ad4bSAdrien Destugues 2652c26ad4bSAdrien Destugues BUrl& 2662c26ad4bSAdrien Destugues BUrl::SetPort(int port) 2672c26ad4bSAdrien Destugues { 2682c26ad4bSAdrien Destugues fPort = port; 2692c26ad4bSAdrien Destugues fHasPort = (port != 0); 2702c26ad4bSAdrien Destugues fUrlStringValid = false; 2712c26ad4bSAdrien Destugues fAuthorityValid = false; 2722c26ad4bSAdrien Destugues return *this; 2732c26ad4bSAdrien Destugues } 2742c26ad4bSAdrien Destugues 2752c26ad4bSAdrien Destugues 2762c26ad4bSAdrien Destugues BUrl& 2772c26ad4bSAdrien Destugues BUrl::SetPath(const BString& path) 2782c26ad4bSAdrien Destugues { 2792c26ad4bSAdrien Destugues // Implements RFC3986 section 5.2.4, "Remove dot segments" 2802c26ad4bSAdrien Destugues 2812c26ad4bSAdrien Destugues // 1. 2822c26ad4bSAdrien Destugues BString output; 2832c26ad4bSAdrien Destugues BString input(path); 2842c26ad4bSAdrien Destugues 2852c26ad4bSAdrien Destugues // 2. 286cd6365c7SJérôme Duval while (!input.IsEmpty()) { 2872c26ad4bSAdrien Destugues // 2.A. 288cd6365c7SJérôme Duval if (input.StartsWith("./")) { 2892c26ad4bSAdrien Destugues input.Remove(0, 2); 2902c26ad4bSAdrien Destugues continue; 2912c26ad4bSAdrien Destugues } 2922c26ad4bSAdrien Destugues 293cd6365c7SJérôme Duval if (input.StartsWith("../")) { 2942c26ad4bSAdrien Destugues input.Remove(0, 3); 2952c26ad4bSAdrien Destugues continue; 2962c26ad4bSAdrien Destugues } 2972c26ad4bSAdrien Destugues 2982c26ad4bSAdrien Destugues // 2.B. 299cd6365c7SJérôme Duval if (input.StartsWith("/./")) { 3002c26ad4bSAdrien Destugues input.Remove(0, 2); 3012c26ad4bSAdrien Destugues continue; 3022c26ad4bSAdrien Destugues } 3032c26ad4bSAdrien Destugues 304cd6365c7SJérôme Duval if (input == "/.") { 3052c26ad4bSAdrien Destugues input.Remove(1, 1); 3062c26ad4bSAdrien Destugues continue; 3072c26ad4bSAdrien Destugues } 3082c26ad4bSAdrien Destugues 3092c26ad4bSAdrien Destugues // 2.C. 310cd6365c7SJérôme Duval if (input.StartsWith("/../")) { 3112c26ad4bSAdrien Destugues input.Remove(0, 3); 3122c26ad4bSAdrien Destugues output.Truncate(output.FindLast('/')); 3132c26ad4bSAdrien Destugues continue; 3142c26ad4bSAdrien Destugues } 3152c26ad4bSAdrien Destugues 316cd6365c7SJérôme Duval if (input == "/..") { 3172c26ad4bSAdrien Destugues input.Remove(1, 2); 3182c26ad4bSAdrien Destugues output.Truncate(output.FindLast('/')); 3192c26ad4bSAdrien Destugues continue; 3202c26ad4bSAdrien Destugues } 3212c26ad4bSAdrien Destugues 3222c26ad4bSAdrien Destugues // 2.D. 323cd6365c7SJérôme Duval if (input == "." || input == "..") { 3242c26ad4bSAdrien Destugues break; 3252c26ad4bSAdrien Destugues } 3262c26ad4bSAdrien Destugues 327cd6365c7SJérôme Duval if (input == "/.") { 3282c26ad4bSAdrien Destugues input.Remove(1, 1); 3292c26ad4bSAdrien Destugues continue; 3302c26ad4bSAdrien Destugues } 3312c26ad4bSAdrien Destugues 3322c26ad4bSAdrien Destugues // 2.E. 3332c26ad4bSAdrien Destugues int slashpos = input.FindFirst('/', 1); 3342c26ad4bSAdrien Destugues if (slashpos > 0) { 3352c26ad4bSAdrien Destugues output.Append(input, slashpos); 3362c26ad4bSAdrien Destugues input.Remove(0, slashpos); 3372c26ad4bSAdrien Destugues } else { 3382c26ad4bSAdrien Destugues output.Append(input); 3392c26ad4bSAdrien Destugues break; 3402c26ad4bSAdrien Destugues } 3412c26ad4bSAdrien Destugues } 3422c26ad4bSAdrien Destugues 3432c26ad4bSAdrien Destugues _SetPathUnsafe(output); 3442c26ad4bSAdrien Destugues return *this; 3452c26ad4bSAdrien Destugues } 3462c26ad4bSAdrien Destugues 3472c26ad4bSAdrien Destugues 3482c26ad4bSAdrien Destugues BUrl& 3492c26ad4bSAdrien Destugues BUrl::SetRequest(const BString& request) 3502c26ad4bSAdrien Destugues { 3512c26ad4bSAdrien Destugues fRequest = request; 3522c26ad4bSAdrien Destugues fHasRequest = !fRequest.IsEmpty(); 3532c26ad4bSAdrien Destugues fUrlStringValid = false; 3542c26ad4bSAdrien Destugues return *this; 3552c26ad4bSAdrien Destugues } 3562c26ad4bSAdrien Destugues 3572c26ad4bSAdrien Destugues 3582c26ad4bSAdrien Destugues BUrl& 3592c26ad4bSAdrien Destugues BUrl::SetFragment(const BString& fragment) 3602c26ad4bSAdrien Destugues { 3612c26ad4bSAdrien Destugues fFragment = fragment; 3622c26ad4bSAdrien Destugues fHasFragment = true; 3632c26ad4bSAdrien Destugues fUrlStringValid = false; 3642c26ad4bSAdrien Destugues return *this; 3652c26ad4bSAdrien Destugues } 3662c26ad4bSAdrien Destugues 3672c26ad4bSAdrien Destugues 3682c26ad4bSAdrien Destugues // #pragma mark URL fields access 3692c26ad4bSAdrien Destugues 3702c26ad4bSAdrien Destugues 3712c26ad4bSAdrien Destugues const BString& 3722c26ad4bSAdrien Destugues BUrl::UrlString() const 3732c26ad4bSAdrien Destugues { 3742c26ad4bSAdrien Destugues if (!fUrlStringValid) { 3752c26ad4bSAdrien Destugues fUrlString.Truncate(0); 3762c26ad4bSAdrien Destugues 3772c26ad4bSAdrien Destugues if (HasProtocol()) { 3782c26ad4bSAdrien Destugues fUrlString << fProtocol << ':'; 3792c26ad4bSAdrien Destugues } 3802c26ad4bSAdrien Destugues 3812c26ad4bSAdrien Destugues if (HasAuthority()) { 3822c26ad4bSAdrien Destugues fUrlString << "//"; 3832c26ad4bSAdrien Destugues fUrlString << Authority(); 3842c26ad4bSAdrien Destugues } 3852c26ad4bSAdrien Destugues fUrlString << Path(); 3862c26ad4bSAdrien Destugues 3872c26ad4bSAdrien Destugues if (HasRequest()) 3882c26ad4bSAdrien Destugues fUrlString << '?' << fRequest; 3892c26ad4bSAdrien Destugues 3902c26ad4bSAdrien Destugues if (HasFragment()) 3912c26ad4bSAdrien Destugues fUrlString << '#' << fFragment; 3922c26ad4bSAdrien Destugues 3932c26ad4bSAdrien Destugues fUrlStringValid = true; 3942c26ad4bSAdrien Destugues } 3952c26ad4bSAdrien Destugues 3962c26ad4bSAdrien Destugues return fUrlString; 3972c26ad4bSAdrien Destugues } 3982c26ad4bSAdrien Destugues 3992c26ad4bSAdrien Destugues 4002c26ad4bSAdrien Destugues const BString& 4012c26ad4bSAdrien Destugues BUrl::Protocol() const 4022c26ad4bSAdrien Destugues { 4032c26ad4bSAdrien Destugues return fProtocol; 4042c26ad4bSAdrien Destugues } 4052c26ad4bSAdrien Destugues 4062c26ad4bSAdrien Destugues 4072c26ad4bSAdrien Destugues const BString& 4082c26ad4bSAdrien Destugues BUrl::UserName() const 4092c26ad4bSAdrien Destugues { 4102c26ad4bSAdrien Destugues return fUser; 4112c26ad4bSAdrien Destugues } 4122c26ad4bSAdrien Destugues 4132c26ad4bSAdrien Destugues 4142c26ad4bSAdrien Destugues const BString& 4152c26ad4bSAdrien Destugues BUrl::Password() const 4162c26ad4bSAdrien Destugues { 4172c26ad4bSAdrien Destugues return fPassword; 4182c26ad4bSAdrien Destugues } 4192c26ad4bSAdrien Destugues 4202c26ad4bSAdrien Destugues 4212c26ad4bSAdrien Destugues const BString& 4222c26ad4bSAdrien Destugues BUrl::UserInfo() const 4232c26ad4bSAdrien Destugues { 4242c26ad4bSAdrien Destugues if (!fUserInfoValid) { 4252c26ad4bSAdrien Destugues fUserInfo = fUser; 4262c26ad4bSAdrien Destugues 4272c26ad4bSAdrien Destugues if (HasPassword()) 4282c26ad4bSAdrien Destugues fUserInfo << ':' << fPassword; 4292c26ad4bSAdrien Destugues 4302c26ad4bSAdrien Destugues fUserInfoValid = true; 4312c26ad4bSAdrien Destugues } 4322c26ad4bSAdrien Destugues 4332c26ad4bSAdrien Destugues return fUserInfo; 4342c26ad4bSAdrien Destugues } 4352c26ad4bSAdrien Destugues 4362c26ad4bSAdrien Destugues 4372c26ad4bSAdrien Destugues const BString& 4382c26ad4bSAdrien Destugues BUrl::Host() const 4392c26ad4bSAdrien Destugues { 4402c26ad4bSAdrien Destugues return fHost; 4412c26ad4bSAdrien Destugues } 4422c26ad4bSAdrien Destugues 4432c26ad4bSAdrien Destugues 4442c26ad4bSAdrien Destugues int 4452c26ad4bSAdrien Destugues BUrl::Port() const 4462c26ad4bSAdrien Destugues { 4472c26ad4bSAdrien Destugues return fPort; 4482c26ad4bSAdrien Destugues } 4492c26ad4bSAdrien Destugues 4502c26ad4bSAdrien Destugues 4512c26ad4bSAdrien Destugues const BString& 4522c26ad4bSAdrien Destugues BUrl::Authority() const 4532c26ad4bSAdrien Destugues { 4542c26ad4bSAdrien Destugues if (!fAuthorityValid) { 4552c26ad4bSAdrien Destugues fAuthority.Truncate(0); 4562c26ad4bSAdrien Destugues 4572c26ad4bSAdrien Destugues if (HasUserInfo()) 4582c26ad4bSAdrien Destugues fAuthority << UserInfo() << '@'; 4592c26ad4bSAdrien Destugues fAuthority << Host(); 4602c26ad4bSAdrien Destugues 4612c26ad4bSAdrien Destugues if (HasPort()) 4622c26ad4bSAdrien Destugues fAuthority << ':' << fPort; 4632c26ad4bSAdrien Destugues 4642c26ad4bSAdrien Destugues fAuthorityValid = true; 4652c26ad4bSAdrien Destugues } 4662c26ad4bSAdrien Destugues return fAuthority; 4672c26ad4bSAdrien Destugues } 4682c26ad4bSAdrien Destugues 4692c26ad4bSAdrien Destugues 4702c26ad4bSAdrien Destugues const BString& 4712c26ad4bSAdrien Destugues BUrl::Path() const 4722c26ad4bSAdrien Destugues { 4732c26ad4bSAdrien Destugues return fPath; 4742c26ad4bSAdrien Destugues } 4752c26ad4bSAdrien Destugues 4762c26ad4bSAdrien Destugues 4772c26ad4bSAdrien Destugues const BString& 4782c26ad4bSAdrien Destugues BUrl::Request() const 4792c26ad4bSAdrien Destugues { 4802c26ad4bSAdrien Destugues return fRequest; 4812c26ad4bSAdrien Destugues } 4822c26ad4bSAdrien Destugues 4832c26ad4bSAdrien Destugues 4842c26ad4bSAdrien Destugues const BString& 4852c26ad4bSAdrien Destugues BUrl::Fragment() const 4862c26ad4bSAdrien Destugues { 4872c26ad4bSAdrien Destugues return fFragment; 4882c26ad4bSAdrien Destugues } 4892c26ad4bSAdrien Destugues 4902c26ad4bSAdrien Destugues 4912c26ad4bSAdrien Destugues // #pragma mark URL fields tests 4922c26ad4bSAdrien Destugues 4932c26ad4bSAdrien Destugues 4942c26ad4bSAdrien Destugues bool 4952c26ad4bSAdrien Destugues BUrl::IsValid() const 4962c26ad4bSAdrien Destugues { 4972c26ad4bSAdrien Destugues if (!fHasProtocol) 4982c26ad4bSAdrien Destugues return false; 4992c26ad4bSAdrien Destugues 5008f30879bSAndrew Lindesay if (!_IsProtocolValid()) 5018f30879bSAndrew Lindesay return false; 5028f30879bSAndrew Lindesay 5038f30879bSAndrew Lindesay // it is possible that there can be an authority but no host. 5048f30879bSAndrew Lindesay // wierd://tea:tree@/x 5058f30879bSAndrew Lindesay if (HasHost() && !(fHost.IsEmpty() && HasAuthority()) && !_IsHostValid()) 5068f30879bSAndrew Lindesay return false; 5078f30879bSAndrew Lindesay 5082c26ad4bSAdrien Destugues if (fProtocol == "http" || fProtocol == "https" || fProtocol == "ftp" 5092c26ad4bSAdrien Destugues || fProtocol == "ipp" || fProtocol == "afp" || fProtocol == "telnet" 5102c26ad4bSAdrien Destugues || fProtocol == "gopher" || fProtocol == "nntp" || fProtocol == "sftp" 5112c26ad4bSAdrien Destugues || fProtocol == "finger" || fProtocol == "pop" || fProtocol == "imap") { 5128f30879bSAndrew Lindesay return HasHost() && !fHost.IsEmpty(); 5132c26ad4bSAdrien Destugues } 5142c26ad4bSAdrien Destugues 5152c26ad4bSAdrien Destugues if (fProtocol == "file") 5162c26ad4bSAdrien Destugues return fHasPath; 5172c26ad4bSAdrien Destugues 5182c26ad4bSAdrien Destugues return true; 5192c26ad4bSAdrien Destugues } 5202c26ad4bSAdrien Destugues 5212c26ad4bSAdrien Destugues 5222c26ad4bSAdrien Destugues bool 5232c26ad4bSAdrien Destugues BUrl::HasProtocol() const 5242c26ad4bSAdrien Destugues { 5252c26ad4bSAdrien Destugues return fHasProtocol; 5262c26ad4bSAdrien Destugues } 5272c26ad4bSAdrien Destugues 5282c26ad4bSAdrien Destugues 5292c26ad4bSAdrien Destugues bool 5302c26ad4bSAdrien Destugues BUrl::HasAuthority() const 5312c26ad4bSAdrien Destugues { 5322c26ad4bSAdrien Destugues return fHasHost || fHasUserName; 5332c26ad4bSAdrien Destugues } 5342c26ad4bSAdrien Destugues 5352c26ad4bSAdrien Destugues 5362c26ad4bSAdrien Destugues bool 5372c26ad4bSAdrien Destugues BUrl::HasUserName() const 5382c26ad4bSAdrien Destugues { 5392c26ad4bSAdrien Destugues return fHasUserName; 5402c26ad4bSAdrien Destugues } 5412c26ad4bSAdrien Destugues 5422c26ad4bSAdrien Destugues 5432c26ad4bSAdrien Destugues bool 5442c26ad4bSAdrien Destugues BUrl::HasPassword() const 5452c26ad4bSAdrien Destugues { 5462c26ad4bSAdrien Destugues return fHasPassword; 5472c26ad4bSAdrien Destugues } 5482c26ad4bSAdrien Destugues 5492c26ad4bSAdrien Destugues 5502c26ad4bSAdrien Destugues bool 5512c26ad4bSAdrien Destugues BUrl::HasUserInfo() const 5522c26ad4bSAdrien Destugues { 5532c26ad4bSAdrien Destugues return fHasUserName || fHasPassword; 5542c26ad4bSAdrien Destugues } 5552c26ad4bSAdrien Destugues 5562c26ad4bSAdrien Destugues 5572c26ad4bSAdrien Destugues bool 5582c26ad4bSAdrien Destugues BUrl::HasHost() const 5592c26ad4bSAdrien Destugues { 5602c26ad4bSAdrien Destugues return fHasHost; 5612c26ad4bSAdrien Destugues } 5622c26ad4bSAdrien Destugues 5632c26ad4bSAdrien Destugues 5642c26ad4bSAdrien Destugues bool 5652c26ad4bSAdrien Destugues BUrl::HasPort() const 5662c26ad4bSAdrien Destugues { 5672c26ad4bSAdrien Destugues return fHasPort; 5682c26ad4bSAdrien Destugues } 5692c26ad4bSAdrien Destugues 5702c26ad4bSAdrien Destugues 5712c26ad4bSAdrien Destugues bool 5722c26ad4bSAdrien Destugues BUrl::HasPath() const 5732c26ad4bSAdrien Destugues { 5742c26ad4bSAdrien Destugues return fHasPath; 5752c26ad4bSAdrien Destugues } 5762c26ad4bSAdrien Destugues 5772c26ad4bSAdrien Destugues 5782c26ad4bSAdrien Destugues bool 5792c26ad4bSAdrien Destugues BUrl::HasRequest() const 5802c26ad4bSAdrien Destugues { 5812c26ad4bSAdrien Destugues return fHasRequest; 5822c26ad4bSAdrien Destugues } 5832c26ad4bSAdrien Destugues 5842c26ad4bSAdrien Destugues 5852c26ad4bSAdrien Destugues bool 5862c26ad4bSAdrien Destugues BUrl::HasFragment() const 5872c26ad4bSAdrien Destugues { 5882c26ad4bSAdrien Destugues return fHasFragment; 5892c26ad4bSAdrien Destugues } 5902c26ad4bSAdrien Destugues 5912c26ad4bSAdrien Destugues 5922c26ad4bSAdrien Destugues // #pragma mark URL encoding/decoding of needed fields 5932c26ad4bSAdrien Destugues 5942c26ad4bSAdrien Destugues 5952c26ad4bSAdrien Destugues void 5962c26ad4bSAdrien Destugues BUrl::UrlEncode(bool strict) 5972c26ad4bSAdrien Destugues { 5982c26ad4bSAdrien Destugues fUser = _DoUrlEncodeChunk(fUser, strict); 5992c26ad4bSAdrien Destugues fPassword = _DoUrlEncodeChunk(fPassword, strict); 6002c26ad4bSAdrien Destugues fHost = _DoUrlEncodeChunk(fHost, strict); 6012c26ad4bSAdrien Destugues fFragment = _DoUrlEncodeChunk(fFragment, strict); 6022c26ad4bSAdrien Destugues fPath = _DoUrlEncodeChunk(fPath, strict, true); 6032c26ad4bSAdrien Destugues } 6042c26ad4bSAdrien Destugues 6052c26ad4bSAdrien Destugues 6062c26ad4bSAdrien Destugues void 6072c26ad4bSAdrien Destugues BUrl::UrlDecode(bool strict) 6082c26ad4bSAdrien Destugues { 6092c26ad4bSAdrien Destugues fUser = _DoUrlDecodeChunk(fUser, strict); 6102c26ad4bSAdrien Destugues fPassword = _DoUrlDecodeChunk(fPassword, strict); 6112c26ad4bSAdrien Destugues fHost = _DoUrlDecodeChunk(fHost, strict); 6122c26ad4bSAdrien Destugues fFragment = _DoUrlDecodeChunk(fFragment, strict); 6132c26ad4bSAdrien Destugues fPath = _DoUrlDecodeChunk(fPath, strict); 6142c26ad4bSAdrien Destugues } 6152c26ad4bSAdrien Destugues 6162c26ad4bSAdrien Destugues 6172c26ad4bSAdrien Destugues #ifdef HAIKU_TARGET_PLATFORM_HAIKU 6182c26ad4bSAdrien Destugues status_t 6192c26ad4bSAdrien Destugues BUrl::IDNAToAscii() 6202c26ad4bSAdrien Destugues { 6212c26ad4bSAdrien Destugues UErrorCode err = U_ZERO_ERROR; 6222c26ad4bSAdrien Destugues icu::IDNA* converter = icu::IDNA::createUTS46Instance(0, err); 6232c26ad4bSAdrien Destugues icu::IDNAInfo info; 6242c26ad4bSAdrien Destugues 6252c26ad4bSAdrien Destugues BString result; 6262c26ad4bSAdrien Destugues BStringByteSink sink(&result); 6272c26ad4bSAdrien Destugues converter->nameToASCII_UTF8(icu::StringPiece(fHost.String()), sink, info, 6282c26ad4bSAdrien Destugues err); 6292c26ad4bSAdrien Destugues 6302c26ad4bSAdrien Destugues delete converter; 6312c26ad4bSAdrien Destugues 6322c26ad4bSAdrien Destugues if (U_FAILURE(err)) 6332c26ad4bSAdrien Destugues return B_ERROR; 6342c26ad4bSAdrien Destugues 6352c26ad4bSAdrien Destugues fHost = result; 6362c26ad4bSAdrien Destugues return B_OK; 6372c26ad4bSAdrien Destugues } 6382c26ad4bSAdrien Destugues #endif 6392c26ad4bSAdrien Destugues 6402c26ad4bSAdrien Destugues 6412c26ad4bSAdrien Destugues #ifdef HAIKU_TARGET_PLATFORM_HAIKU 6422c26ad4bSAdrien Destugues status_t 6432c26ad4bSAdrien Destugues BUrl::IDNAToUnicode() 6442c26ad4bSAdrien Destugues { 6452c26ad4bSAdrien Destugues UErrorCode err = U_ZERO_ERROR; 6462c26ad4bSAdrien Destugues icu::IDNA* converter = icu::IDNA::createUTS46Instance(0, err); 6472c26ad4bSAdrien Destugues icu::IDNAInfo info; 6482c26ad4bSAdrien Destugues 6492c26ad4bSAdrien Destugues BString result; 6502c26ad4bSAdrien Destugues BStringByteSink sink(&result); 6512c26ad4bSAdrien Destugues converter->nameToUnicodeUTF8(icu::StringPiece(fHost.String()), sink, info, 6522c26ad4bSAdrien Destugues err); 6532c26ad4bSAdrien Destugues 6542c26ad4bSAdrien Destugues delete converter; 6552c26ad4bSAdrien Destugues 6562c26ad4bSAdrien Destugues if (U_FAILURE(err)) 6572c26ad4bSAdrien Destugues return B_ERROR; 6582c26ad4bSAdrien Destugues 6592c26ad4bSAdrien Destugues fHost = result; 6602c26ad4bSAdrien Destugues return B_OK; 6612c26ad4bSAdrien Destugues } 6622c26ad4bSAdrien Destugues #endif 6632c26ad4bSAdrien Destugues 6642c26ad4bSAdrien Destugues 6652c26ad4bSAdrien Destugues // #pragma mark - utility functionality 6662c26ad4bSAdrien Destugues 6672c26ad4bSAdrien Destugues 6682c26ad4bSAdrien Destugues #ifdef HAIKU_TARGET_PLATFORM_HAIKU 6692c26ad4bSAdrien Destugues bool 6702c26ad4bSAdrien Destugues BUrl::HasPreferredApplication() const 6712c26ad4bSAdrien Destugues { 6722c26ad4bSAdrien Destugues BString appSignature = PreferredApplication(); 6732c26ad4bSAdrien Destugues BMimeType mime(appSignature.String()); 6742c26ad4bSAdrien Destugues 6752c26ad4bSAdrien Destugues if (appSignature.IFindFirst("application/") == 0 6762c26ad4bSAdrien Destugues && mime.IsValid()) 6772c26ad4bSAdrien Destugues return true; 6782c26ad4bSAdrien Destugues 6792c26ad4bSAdrien Destugues return false; 6802c26ad4bSAdrien Destugues } 6812c26ad4bSAdrien Destugues #endif 6822c26ad4bSAdrien Destugues 6832c26ad4bSAdrien Destugues 6842c26ad4bSAdrien Destugues #ifdef HAIKU_TARGET_PLATFORM_HAIKU 6852c26ad4bSAdrien Destugues BString 6862c26ad4bSAdrien Destugues BUrl::PreferredApplication() const 6872c26ad4bSAdrien Destugues { 6882c26ad4bSAdrien Destugues BString appSignature; 6892c26ad4bSAdrien Destugues BMimeType mime(_UrlMimeType().String()); 6902c26ad4bSAdrien Destugues mime.GetPreferredApp(appSignature.LockBuffer(B_MIME_TYPE_LENGTH)); 6912c26ad4bSAdrien Destugues appSignature.UnlockBuffer(); 6922c26ad4bSAdrien Destugues 6932c26ad4bSAdrien Destugues return BString(appSignature); 6942c26ad4bSAdrien Destugues } 6952c26ad4bSAdrien Destugues #endif 6962c26ad4bSAdrien Destugues 6972c26ad4bSAdrien Destugues 6982c26ad4bSAdrien Destugues #ifdef HAIKU_TARGET_PLATFORM_HAIKU 6992c26ad4bSAdrien Destugues status_t 7002c26ad4bSAdrien Destugues BUrl::OpenWithPreferredApplication(bool onProblemAskUser) const 7012c26ad4bSAdrien Destugues { 7022c26ad4bSAdrien Destugues if (!IsValid()) 7032c26ad4bSAdrien Destugues return B_BAD_VALUE; 7042c26ad4bSAdrien Destugues 7052c26ad4bSAdrien Destugues BString urlString = UrlString(); 7062c26ad4bSAdrien Destugues if (urlString.Length() > B_PATH_NAME_LENGTH) { 7072c26ad4bSAdrien Destugues // TODO: BAlert 7082c26ad4bSAdrien Destugues // if (onProblemAskUser) 7092c26ad4bSAdrien Destugues // BAlert ... Too long URL! 7102c26ad4bSAdrien Destugues #if DEBUG 7112c26ad4bSAdrien Destugues fprintf(stderr, "URL too long"); 7122c26ad4bSAdrien Destugues #endif 7132c26ad4bSAdrien Destugues return B_NAME_TOO_LONG; 7142c26ad4bSAdrien Destugues } 7152c26ad4bSAdrien Destugues 7162c26ad4bSAdrien Destugues char* argv[] = { 7172c26ad4bSAdrien Destugues const_cast<char*>("BUrlInvokedApplication"), 7182c26ad4bSAdrien Destugues const_cast<char*>(urlString.String()), 7192c26ad4bSAdrien Destugues NULL 7202c26ad4bSAdrien Destugues }; 7212c26ad4bSAdrien Destugues 7222c26ad4bSAdrien Destugues #if DEBUG 7232c26ad4bSAdrien Destugues if (HasPreferredApplication()) 7242c26ad4bSAdrien Destugues printf("HasPreferredApplication() == true\n"); 7252c26ad4bSAdrien Destugues else 7262c26ad4bSAdrien Destugues printf("HasPreferredApplication() == false\n"); 7272c26ad4bSAdrien Destugues #endif 7282c26ad4bSAdrien Destugues 7292c26ad4bSAdrien Destugues status_t status = be_roster->Launch(_UrlMimeType().String(), 1, argv+1); 7302c26ad4bSAdrien Destugues if (status != B_OK) { 7312c26ad4bSAdrien Destugues #if DEBUG 7322c26ad4bSAdrien Destugues fprintf(stderr, "Opening URL failed: %s\n", strerror(status)); 7332c26ad4bSAdrien Destugues #endif 7342c26ad4bSAdrien Destugues } 7352c26ad4bSAdrien Destugues 7362c26ad4bSAdrien Destugues return status; 7372c26ad4bSAdrien Destugues } 7382c26ad4bSAdrien Destugues #endif 7392c26ad4bSAdrien Destugues 7402c26ad4bSAdrien Destugues 7412c26ad4bSAdrien Destugues // #pragma mark Url encoding/decoding of string 7422c26ad4bSAdrien Destugues 7432c26ad4bSAdrien Destugues 7442c26ad4bSAdrien Destugues /*static*/ BString 7452c26ad4bSAdrien Destugues BUrl::UrlEncode(const BString& url, bool strict, bool directory) 7462c26ad4bSAdrien Destugues { 7472c26ad4bSAdrien Destugues return _DoUrlEncodeChunk(url, strict, directory); 7482c26ad4bSAdrien Destugues } 7492c26ad4bSAdrien Destugues 7502c26ad4bSAdrien Destugues 7512c26ad4bSAdrien Destugues /*static*/ BString 7522c26ad4bSAdrien Destugues BUrl::UrlDecode(const BString& url, bool strict) 7532c26ad4bSAdrien Destugues { 7542c26ad4bSAdrien Destugues return _DoUrlDecodeChunk(url, strict); 7552c26ad4bSAdrien Destugues } 7562c26ad4bSAdrien Destugues 7572c26ad4bSAdrien Destugues 7582c26ad4bSAdrien Destugues // #pragma mark BArchivable members 7592c26ad4bSAdrien Destugues 7602c26ad4bSAdrien Destugues 7612c26ad4bSAdrien Destugues status_t 7622c26ad4bSAdrien Destugues BUrl::Archive(BMessage* into, bool deep) const 7632c26ad4bSAdrien Destugues { 7642c26ad4bSAdrien Destugues status_t ret = BArchivable::Archive(into, deep); 7652c26ad4bSAdrien Destugues 7662c26ad4bSAdrien Destugues if (ret == B_OK) 7672c26ad4bSAdrien Destugues ret = into->AddString(kArchivedUrl, UrlString()); 7682c26ad4bSAdrien Destugues 7692c26ad4bSAdrien Destugues return ret; 7702c26ad4bSAdrien Destugues } 7712c26ad4bSAdrien Destugues 7722c26ad4bSAdrien Destugues 7732c26ad4bSAdrien Destugues /*static*/ BArchivable* 7742c26ad4bSAdrien Destugues BUrl::Instantiate(BMessage* archive) 7752c26ad4bSAdrien Destugues { 7762c26ad4bSAdrien Destugues if (validate_instantiation(archive, "BUrl")) 7772c26ad4bSAdrien Destugues return new(std::nothrow) BUrl(archive); 7782c26ad4bSAdrien Destugues return NULL; 7792c26ad4bSAdrien Destugues } 7802c26ad4bSAdrien Destugues 7812c26ad4bSAdrien Destugues 7822c26ad4bSAdrien Destugues // #pragma mark URL comparison 7832c26ad4bSAdrien Destugues 7842c26ad4bSAdrien Destugues 7852c26ad4bSAdrien Destugues bool 7862c26ad4bSAdrien Destugues BUrl::operator==(BUrl& other) const 7872c26ad4bSAdrien Destugues { 7882c26ad4bSAdrien Destugues UrlString(); 7892c26ad4bSAdrien Destugues other.UrlString(); 7902c26ad4bSAdrien Destugues 7912c26ad4bSAdrien Destugues return fUrlString == other.fUrlString; 7922c26ad4bSAdrien Destugues } 7932c26ad4bSAdrien Destugues 7942c26ad4bSAdrien Destugues 7952c26ad4bSAdrien Destugues bool 7962c26ad4bSAdrien Destugues BUrl::operator!=(BUrl& other) const 7972c26ad4bSAdrien Destugues { 7982c26ad4bSAdrien Destugues return !(*this == other); 7992c26ad4bSAdrien Destugues } 8002c26ad4bSAdrien Destugues 8012c26ad4bSAdrien Destugues 8022c26ad4bSAdrien Destugues // #pragma mark URL assignment 8032c26ad4bSAdrien Destugues 8042c26ad4bSAdrien Destugues 8052c26ad4bSAdrien Destugues const BUrl& 8062c26ad4bSAdrien Destugues BUrl::operator=(const BUrl& other) 8072c26ad4bSAdrien Destugues { 8082c26ad4bSAdrien Destugues fUrlStringValid = other.fUrlStringValid; 8092c26ad4bSAdrien Destugues if (fUrlStringValid) 8102c26ad4bSAdrien Destugues fUrlString = other.fUrlString; 8112c26ad4bSAdrien Destugues 8122c26ad4bSAdrien Destugues fAuthorityValid = other.fAuthorityValid; 8132c26ad4bSAdrien Destugues if (fAuthorityValid) 8142c26ad4bSAdrien Destugues fAuthority = other.fAuthority; 8152c26ad4bSAdrien Destugues 8162c26ad4bSAdrien Destugues fUserInfoValid = other.fUserInfoValid; 8172c26ad4bSAdrien Destugues if (fUserInfoValid) 8182c26ad4bSAdrien Destugues fUserInfo = other.fUserInfo; 8192c26ad4bSAdrien Destugues 8202c26ad4bSAdrien Destugues fProtocol = other.fProtocol; 8212c26ad4bSAdrien Destugues fUser = other.fUser; 8222c26ad4bSAdrien Destugues fPassword = other.fPassword; 8232c26ad4bSAdrien Destugues fHost = other.fHost; 8242c26ad4bSAdrien Destugues fPort = other.fPort; 8252c26ad4bSAdrien Destugues fPath = other.fPath; 8262c26ad4bSAdrien Destugues fRequest = other.fRequest; 8272c26ad4bSAdrien Destugues fFragment = other.fFragment; 8282c26ad4bSAdrien Destugues 8292c26ad4bSAdrien Destugues fHasProtocol = other.fHasProtocol; 8302c26ad4bSAdrien Destugues fHasUserName = other.fHasUserName; 8312c26ad4bSAdrien Destugues fHasPassword = other.fHasPassword; 8322c26ad4bSAdrien Destugues fHasHost = other.fHasHost; 8332c26ad4bSAdrien Destugues fHasPort = other.fHasPort; 8342c26ad4bSAdrien Destugues fHasPath = other.fHasPath; 8352c26ad4bSAdrien Destugues fHasRequest = other.fHasRequest; 8362c26ad4bSAdrien Destugues fHasFragment = other.fHasFragment; 8372c26ad4bSAdrien Destugues 8382c26ad4bSAdrien Destugues return *this; 8392c26ad4bSAdrien Destugues } 8402c26ad4bSAdrien Destugues 8412c26ad4bSAdrien Destugues 8422c26ad4bSAdrien Destugues const BUrl& 8432c26ad4bSAdrien Destugues BUrl::operator=(const BString& string) 8442c26ad4bSAdrien Destugues { 8452c26ad4bSAdrien Destugues SetUrlString(string); 8462c26ad4bSAdrien Destugues return *this; 8472c26ad4bSAdrien Destugues } 8482c26ad4bSAdrien Destugues 8492c26ad4bSAdrien Destugues 8502c26ad4bSAdrien Destugues const BUrl& 8512c26ad4bSAdrien Destugues BUrl::operator=(const char* string) 8522c26ad4bSAdrien Destugues { 8532c26ad4bSAdrien Destugues SetUrlString(string); 8542c26ad4bSAdrien Destugues return *this; 8552c26ad4bSAdrien Destugues } 8562c26ad4bSAdrien Destugues 8572c26ad4bSAdrien Destugues 8582c26ad4bSAdrien Destugues // #pragma mark URL to string conversion 8592c26ad4bSAdrien Destugues 8602c26ad4bSAdrien Destugues 8612c26ad4bSAdrien Destugues BUrl::operator const char*() const 8622c26ad4bSAdrien Destugues { 8632c26ad4bSAdrien Destugues return UrlString(); 8642c26ad4bSAdrien Destugues } 8652c26ad4bSAdrien Destugues 8662c26ad4bSAdrien Destugues 8672c26ad4bSAdrien Destugues void 8682c26ad4bSAdrien Destugues BUrl::_ResetFields() 8692c26ad4bSAdrien Destugues { 8702c26ad4bSAdrien Destugues fHasProtocol = false; 8712c26ad4bSAdrien Destugues fHasUserName = false; 8722c26ad4bSAdrien Destugues fHasPassword = false; 8732c26ad4bSAdrien Destugues fHasHost = false; 8742c26ad4bSAdrien Destugues fHasPort = false; 8752c26ad4bSAdrien Destugues fHasPath = false; 8762c26ad4bSAdrien Destugues fHasRequest = false; 8772c26ad4bSAdrien Destugues fHasFragment = false; 8782c26ad4bSAdrien Destugues 8792c26ad4bSAdrien Destugues fProtocol.Truncate(0); 8802c26ad4bSAdrien Destugues fUser.Truncate(0); 8812c26ad4bSAdrien Destugues fPassword.Truncate(0); 8822c26ad4bSAdrien Destugues fHost.Truncate(0); 8832c26ad4bSAdrien Destugues fPort = 0; 8842c26ad4bSAdrien Destugues fPath.Truncate(0); 8852c26ad4bSAdrien Destugues fRequest.Truncate(0); 8862c26ad4bSAdrien Destugues fFragment.Truncate(0); 8872c26ad4bSAdrien Destugues 8882c26ad4bSAdrien Destugues // Force re-generation of these fields 8892c26ad4bSAdrien Destugues fUrlStringValid = false; 8902c26ad4bSAdrien Destugues fUserInfoValid = false; 8912c26ad4bSAdrien Destugues fAuthorityValid = false; 8922c26ad4bSAdrien Destugues } 8932c26ad4bSAdrien Destugues 8942c26ad4bSAdrien Destugues 8952c26ad4bSAdrien Destugues bool 8962c26ad4bSAdrien Destugues BUrl::_ContainsDelimiter(const BString& url) 8972c26ad4bSAdrien Destugues { 8982c26ad4bSAdrien Destugues int32 len = url.Length(); 8992c26ad4bSAdrien Destugues 9002c26ad4bSAdrien Destugues for (int32 i = 0; i < len; i++) { 9012c26ad4bSAdrien Destugues switch (url[i]) { 9022c26ad4bSAdrien Destugues case ' ': 9032c26ad4bSAdrien Destugues case '\n': 9042c26ad4bSAdrien Destugues case '\t': 9052c26ad4bSAdrien Destugues case '\r': 9062c26ad4bSAdrien Destugues case '<': 9072c26ad4bSAdrien Destugues case '>': 9082c26ad4bSAdrien Destugues case '"': 9092c26ad4bSAdrien Destugues return true; 9102c26ad4bSAdrien Destugues } 9112c26ad4bSAdrien Destugues } 9122c26ad4bSAdrien Destugues 9132c26ad4bSAdrien Destugues return false; 9142c26ad4bSAdrien Destugues } 9152c26ad4bSAdrien Destugues 9162c26ad4bSAdrien Destugues 9172c26ad4bSAdrien Destugues enum explode_url_parse_state { 9182c26ad4bSAdrien Destugues EXPLODE_PROTOCOL, 9192c26ad4bSAdrien Destugues EXPLODE_PROTOCOLTERMINATOR, 9202c26ad4bSAdrien Destugues EXPLODE_AUTHORITYORPATH, 9212c26ad4bSAdrien Destugues EXPLODE_AUTHORITY, 9222c26ad4bSAdrien Destugues EXPLODE_PATH, 9232c26ad4bSAdrien Destugues EXPLODE_REQUEST, // query 9242c26ad4bSAdrien Destugues EXPLODE_FRAGMENT, 9252c26ad4bSAdrien Destugues EXPLODE_COMPLETE 9262c26ad4bSAdrien Destugues }; 9272c26ad4bSAdrien Destugues 9282c26ad4bSAdrien Destugues 9292c26ad4bSAdrien Destugues typedef bool (*explode_char_match_fn)(char c); 9302c26ad4bSAdrien Destugues 9312c26ad4bSAdrien Destugues 9322c26ad4bSAdrien Destugues static bool 9332c26ad4bSAdrien Destugues explode_is_protocol_char(char c) 9342c26ad4bSAdrien Destugues { 9352c26ad4bSAdrien Destugues return isalnum(c) || c == '+' || c == '.' || c == '-'; 9362c26ad4bSAdrien Destugues } 9372c26ad4bSAdrien Destugues 9382c26ad4bSAdrien Destugues 9392c26ad4bSAdrien Destugues static bool 9402c26ad4bSAdrien Destugues explode_is_authority_char(char c) 9412c26ad4bSAdrien Destugues { 9422c26ad4bSAdrien Destugues return !(c == '/' || c == '?' || c == '#'); 9432c26ad4bSAdrien Destugues } 9442c26ad4bSAdrien Destugues 9452c26ad4bSAdrien Destugues 9462c26ad4bSAdrien Destugues static bool 9472c26ad4bSAdrien Destugues explode_is_path_char(char c) 9482c26ad4bSAdrien Destugues { 9492c26ad4bSAdrien Destugues return !(c == '#' || c == '?'); 9502c26ad4bSAdrien Destugues } 9512c26ad4bSAdrien Destugues 9522c26ad4bSAdrien Destugues 9532c26ad4bSAdrien Destugues static bool 9542c26ad4bSAdrien Destugues explode_is_request_char(char c) 9552c26ad4bSAdrien Destugues { 9562c26ad4bSAdrien Destugues return c != '#'; 9572c26ad4bSAdrien Destugues } 9582c26ad4bSAdrien Destugues 9592c26ad4bSAdrien Destugues 9602c26ad4bSAdrien Destugues static int32 9612c26ad4bSAdrien Destugues char_offset_until_fn_false(const char* url, int32 len, int32 offset, 9622c26ad4bSAdrien Destugues explode_char_match_fn fn) 9632c26ad4bSAdrien Destugues { 9642c26ad4bSAdrien Destugues while (offset < len && fn(url[offset])) 9652c26ad4bSAdrien Destugues offset++; 9662c26ad4bSAdrien Destugues 9672c26ad4bSAdrien Destugues return offset; 9682c26ad4bSAdrien Destugues } 9692c26ad4bSAdrien Destugues 9702c26ad4bSAdrien Destugues /* 9712c26ad4bSAdrien Destugues * This function takes a URL in string-form and parses the components of the URL out. 9722c26ad4bSAdrien Destugues */ 9732c26ad4bSAdrien Destugues status_t 9742c26ad4bSAdrien Destugues BUrl::_ExplodeUrlString(const BString& url) 9752c26ad4bSAdrien Destugues { 9762c26ad4bSAdrien Destugues _ResetFields(); 9772c26ad4bSAdrien Destugues 9782c26ad4bSAdrien Destugues // RFC3986, Appendix C; the URL should not contain whitespace or delimiters 9792c26ad4bSAdrien Destugues // by this point. 9802c26ad4bSAdrien Destugues 9812c26ad4bSAdrien Destugues if (_ContainsDelimiter(url)) 9822c26ad4bSAdrien Destugues return B_BAD_VALUE; 9832c26ad4bSAdrien Destugues 9842c26ad4bSAdrien Destugues explode_url_parse_state state = EXPLODE_PROTOCOL; 9852c26ad4bSAdrien Destugues int32 offset = 0; 9862c26ad4bSAdrien Destugues int32 length = url.Length(); 987*3cc5e76fSAndrew Lindesay bool forceHasHost = false; 9882c26ad4bSAdrien Destugues const char *url_c = url.String(); 9892c26ad4bSAdrien Destugues 9902c26ad4bSAdrien Destugues // The regexp is provided in RFC3986 (URI generic syntax), Appendix B 9912c26ad4bSAdrien Destugues // ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))? 9922c26ad4bSAdrien Destugues // The ensuing logic attempts to simulate the behaviour of extracting the groups 9932c26ad4bSAdrien Destugues // from the string without requiring a group-capable regex engine. 9942c26ad4bSAdrien Destugues 9952c26ad4bSAdrien Destugues while (offset < length) { 9962c26ad4bSAdrien Destugues switch (state) { 9972c26ad4bSAdrien Destugues 9982c26ad4bSAdrien Destugues case EXPLODE_PROTOCOL: 9992c26ad4bSAdrien Destugues { 10002c26ad4bSAdrien Destugues int32 end_protocol = char_offset_until_fn_false(url_c, length, 10012c26ad4bSAdrien Destugues offset, explode_is_protocol_char); 10022c26ad4bSAdrien Destugues 10032c26ad4bSAdrien Destugues if (end_protocol < length) { 10042c26ad4bSAdrien Destugues SetProtocol(BString(&url_c[offset], end_protocol - offset)); 10052c26ad4bSAdrien Destugues state = EXPLODE_PROTOCOLTERMINATOR; 10062c26ad4bSAdrien Destugues offset = end_protocol; 10072c26ad4bSAdrien Destugues } else { 10082c26ad4bSAdrien Destugues // No protocol was found, try parsing from the string 10092c26ad4bSAdrien Destugues // start, beginning with authority or path 10102c26ad4bSAdrien Destugues SetProtocol(""); 10112c26ad4bSAdrien Destugues offset = 0; 10122c26ad4bSAdrien Destugues state = EXPLODE_AUTHORITYORPATH; 10132c26ad4bSAdrien Destugues } 10142c26ad4bSAdrien Destugues break; 10152c26ad4bSAdrien Destugues } 10162c26ad4bSAdrien Destugues 10172c26ad4bSAdrien Destugues case EXPLODE_PROTOCOLTERMINATOR: 10182c26ad4bSAdrien Destugues { 10192c26ad4bSAdrien Destugues if (url[offset] == ':') { 10202c26ad4bSAdrien Destugues offset++; 10212c26ad4bSAdrien Destugues } else { 10222c26ad4bSAdrien Destugues // No protocol was found, try parsing from the string 10232c26ad4bSAdrien Destugues // start, beginning with authority or path 10242c26ad4bSAdrien Destugues SetProtocol(""); 10252c26ad4bSAdrien Destugues offset = 0; 10262c26ad4bSAdrien Destugues } 10272c26ad4bSAdrien Destugues state = EXPLODE_AUTHORITYORPATH; 10282c26ad4bSAdrien Destugues break; 10292c26ad4bSAdrien Destugues } 10302c26ad4bSAdrien Destugues 10312c26ad4bSAdrien Destugues case EXPLODE_AUTHORITYORPATH: 10322c26ad4bSAdrien Destugues { 10332c26ad4bSAdrien Destugues // The authority must start with //. If it isn't there, skip 10342c26ad4bSAdrien Destugues // to parsing the path. 10352c26ad4bSAdrien Destugues if (strncmp(&url_c[offset], "//", 2) == 0) { 10362c26ad4bSAdrien Destugues state = EXPLODE_AUTHORITY; 1037*3cc5e76fSAndrew Lindesay // if we see the // then this would imply that a host is 1038*3cc5e76fSAndrew Lindesay // to be rendered even if no host has been parsed. 1039*3cc5e76fSAndrew Lindesay forceHasHost = true; 10402c26ad4bSAdrien Destugues offset += 2; 10412c26ad4bSAdrien Destugues } else { 10422c26ad4bSAdrien Destugues state = EXPLODE_PATH; 10432c26ad4bSAdrien Destugues } 10442c26ad4bSAdrien Destugues break; 10452c26ad4bSAdrien Destugues } 10462c26ad4bSAdrien Destugues 10472c26ad4bSAdrien Destugues case EXPLODE_AUTHORITY: 10482c26ad4bSAdrien Destugues { 10492c26ad4bSAdrien Destugues int end_authority = char_offset_until_fn_false(url_c, length, 10502c26ad4bSAdrien Destugues offset, explode_is_authority_char); 10512c26ad4bSAdrien Destugues SetAuthority(BString(&url_c[offset], end_authority - offset)); 10522c26ad4bSAdrien Destugues state = EXPLODE_PATH; 10532c26ad4bSAdrien Destugues offset = end_authority; 10542c26ad4bSAdrien Destugues break; 10552c26ad4bSAdrien Destugues } 10562c26ad4bSAdrien Destugues 10572c26ad4bSAdrien Destugues case EXPLODE_PATH: 10582c26ad4bSAdrien Destugues { 10592c26ad4bSAdrien Destugues int end_path = char_offset_until_fn_false(url_c, length, offset, 10602c26ad4bSAdrien Destugues explode_is_path_char); 10612c26ad4bSAdrien Destugues SetPath(BString(&url_c[offset], end_path - offset)); 10622c26ad4bSAdrien Destugues state = EXPLODE_REQUEST; 10632c26ad4bSAdrien Destugues offset = end_path; 10642c26ad4bSAdrien Destugues break; 10652c26ad4bSAdrien Destugues } 10662c26ad4bSAdrien Destugues 10672c26ad4bSAdrien Destugues case EXPLODE_REQUEST: // query 10682c26ad4bSAdrien Destugues { 10692c26ad4bSAdrien Destugues if (url_c[offset] == '?') { 10702c26ad4bSAdrien Destugues offset++; 10712c26ad4bSAdrien Destugues int end_request = char_offset_until_fn_false(url_c, length, 10722c26ad4bSAdrien Destugues offset, explode_is_request_char); 10732c26ad4bSAdrien Destugues SetRequest(BString(&url_c[offset], end_request - offset)); 10742c26ad4bSAdrien Destugues offset = end_request; 1075*3cc5e76fSAndrew Lindesay // if there is a "?" in the parse then it is clear that 1076*3cc5e76fSAndrew Lindesay // there is a 'request' / query present regardless if there 1077*3cc5e76fSAndrew Lindesay // are any valid key-value pairs. 1078*3cc5e76fSAndrew Lindesay fHasRequest = true; 10792c26ad4bSAdrien Destugues } 10802c26ad4bSAdrien Destugues state = EXPLODE_FRAGMENT; 10812c26ad4bSAdrien Destugues break; 10822c26ad4bSAdrien Destugues } 10832c26ad4bSAdrien Destugues 10842c26ad4bSAdrien Destugues case EXPLODE_FRAGMENT: 10852c26ad4bSAdrien Destugues { 10862c26ad4bSAdrien Destugues if (url_c[offset] == '#') { 10872c26ad4bSAdrien Destugues offset++; 10882c26ad4bSAdrien Destugues SetFragment(BString(&url_c[offset], length - offset)); 10892c26ad4bSAdrien Destugues offset = length; 10902c26ad4bSAdrien Destugues } 10912c26ad4bSAdrien Destugues state = EXPLODE_COMPLETE; 10922c26ad4bSAdrien Destugues break; 10932c26ad4bSAdrien Destugues } 10942c26ad4bSAdrien Destugues 10952c26ad4bSAdrien Destugues case EXPLODE_COMPLETE: 10962c26ad4bSAdrien Destugues // should never be reached - keeps the compiler happy 10972c26ad4bSAdrien Destugues break; 10982c26ad4bSAdrien Destugues 10992c26ad4bSAdrien Destugues } 11002c26ad4bSAdrien Destugues } 11012c26ad4bSAdrien Destugues 1102*3cc5e76fSAndrew Lindesay if (forceHasHost) 1103*3cc5e76fSAndrew Lindesay fHasHost = true; 1104*3cc5e76fSAndrew Lindesay 11052c26ad4bSAdrien Destugues return B_OK; 11062c26ad4bSAdrien Destugues } 11072c26ad4bSAdrien Destugues 11082c26ad4bSAdrien Destugues 11092c26ad4bSAdrien Destugues BString 11102c26ad4bSAdrien Destugues BUrl::_MergePath(const BString& relative) const 11112c26ad4bSAdrien Destugues { 11122c26ad4bSAdrien Destugues // This implements RFC3986, Section 5.2.3. 1113cd6365c7SJérôme Duval if (HasAuthority() && fPath == "") { 11142c26ad4bSAdrien Destugues BString result("/"); 11152c26ad4bSAdrien Destugues result << relative; 11162c26ad4bSAdrien Destugues return result; 11172c26ad4bSAdrien Destugues } 11182c26ad4bSAdrien Destugues 11192c26ad4bSAdrien Destugues BString result(fPath); 11202c26ad4bSAdrien Destugues result.Truncate(result.FindLast("/") + 1); 11212c26ad4bSAdrien Destugues result << relative; 11222c26ad4bSAdrien Destugues 11232c26ad4bSAdrien Destugues return result; 11242c26ad4bSAdrien Destugues } 11252c26ad4bSAdrien Destugues 11262c26ad4bSAdrien Destugues 11272c26ad4bSAdrien Destugues // This sets the path without normalizing it. If fed with a path that has . or 11282c26ad4bSAdrien Destugues // .. segments, this would make the URL invalid. 11292c26ad4bSAdrien Destugues void 11302c26ad4bSAdrien Destugues BUrl::_SetPathUnsafe(const BString& path) 11312c26ad4bSAdrien Destugues { 11322c26ad4bSAdrien Destugues fPath = path; 11332c26ad4bSAdrien Destugues fHasPath = true; // RFC says an empty path is still a path 11342c26ad4bSAdrien Destugues fUrlStringValid = false; 11352c26ad4bSAdrien Destugues } 11362c26ad4bSAdrien Destugues 11372c26ad4bSAdrien Destugues 11382c26ad4bSAdrien Destugues enum authority_parse_state { 11392c26ad4bSAdrien Destugues AUTHORITY_USERNAME, 11402c26ad4bSAdrien Destugues AUTHORITY_PASSWORD, 11412c26ad4bSAdrien Destugues AUTHORITY_HOST, 11422c26ad4bSAdrien Destugues AUTHORITY_PORT, 11432c26ad4bSAdrien Destugues AUTHORITY_COMPLETE 11442c26ad4bSAdrien Destugues }; 11452c26ad4bSAdrien Destugues 11462c26ad4bSAdrien Destugues void 11472c26ad4bSAdrien Destugues BUrl::SetAuthority(const BString& authority) 11482c26ad4bSAdrien Destugues { 11492c26ad4bSAdrien Destugues fAuthority = authority; 11502c26ad4bSAdrien Destugues 11512c26ad4bSAdrien Destugues fUser.Truncate(0); 11522c26ad4bSAdrien Destugues fPassword.Truncate(0); 11532c26ad4bSAdrien Destugues fHost.Truncate(0); 11542c26ad4bSAdrien Destugues fPort = 0; 11552c26ad4bSAdrien Destugues fHasPort = false; 11562c26ad4bSAdrien Destugues fHasUserName = false; 11572c26ad4bSAdrien Destugues fHasPassword = false; 11582c26ad4bSAdrien Destugues 11592c26ad4bSAdrien Destugues bool hasUsernamePassword = B_ERROR != fAuthority.FindFirst('@'); 11602c26ad4bSAdrien Destugues authority_parse_state state = AUTHORITY_USERNAME; 11612c26ad4bSAdrien Destugues int32 offset = 0; 11622c26ad4bSAdrien Destugues int32 length = authority.Length(); 11632c26ad4bSAdrien Destugues const char *authority_c = authority.String(); 11642c26ad4bSAdrien Destugues 11652c26ad4bSAdrien Destugues while (AUTHORITY_COMPLETE != state && offset < length) { 11662c26ad4bSAdrien Destugues 11672c26ad4bSAdrien Destugues switch (state) { 11682c26ad4bSAdrien Destugues 11692c26ad4bSAdrien Destugues case AUTHORITY_USERNAME: 11702c26ad4bSAdrien Destugues { 11712c26ad4bSAdrien Destugues if (hasUsernamePassword) { 11722c26ad4bSAdrien Destugues int32 end_username = char_offset_until_fn_false( 11738f30879bSAndrew Lindesay authority_c, length, offset, _IsUsernameChar); 11742c26ad4bSAdrien Destugues 11752c26ad4bSAdrien Destugues SetUserName(BString(&authority_c[offset], 11762c26ad4bSAdrien Destugues end_username - offset)); 11772c26ad4bSAdrien Destugues 11782c26ad4bSAdrien Destugues state = AUTHORITY_PASSWORD; 11792c26ad4bSAdrien Destugues offset = end_username; 11802c26ad4bSAdrien Destugues } else { 11812c26ad4bSAdrien Destugues state = AUTHORITY_HOST; 11822c26ad4bSAdrien Destugues } 11832c26ad4bSAdrien Destugues break; 11842c26ad4bSAdrien Destugues } 11852c26ad4bSAdrien Destugues 11862c26ad4bSAdrien Destugues case AUTHORITY_PASSWORD: 11872c26ad4bSAdrien Destugues { 11882c26ad4bSAdrien Destugues if (hasUsernamePassword && ':' == authority[offset]) { 11892c26ad4bSAdrien Destugues offset++; // move past the delimiter 11902c26ad4bSAdrien Destugues int32 end_password = char_offset_until_fn_false( 11918f30879bSAndrew Lindesay authority_c, length, offset, _IsPasswordChar); 11922c26ad4bSAdrien Destugues 11932c26ad4bSAdrien Destugues SetPassword(BString(&authority_c[offset], 11942c26ad4bSAdrien Destugues end_password - offset)); 11952c26ad4bSAdrien Destugues 11962c26ad4bSAdrien Destugues offset = end_password; 11972c26ad4bSAdrien Destugues } 11982c26ad4bSAdrien Destugues 11992c26ad4bSAdrien Destugues // if the host was preceded by a username + password couple 12002c26ad4bSAdrien Destugues // then there will be an '@' delimiter to avoid. 12012c26ad4bSAdrien Destugues 12022c26ad4bSAdrien Destugues if (authority_c[offset] == '@') { 12032c26ad4bSAdrien Destugues offset++; 12042c26ad4bSAdrien Destugues } 12052c26ad4bSAdrien Destugues 12062c26ad4bSAdrien Destugues state = AUTHORITY_HOST; 12072c26ad4bSAdrien Destugues break; 12082c26ad4bSAdrien Destugues } 12092c26ad4bSAdrien Destugues 12102c26ad4bSAdrien Destugues case AUTHORITY_HOST: 12112c26ad4bSAdrien Destugues { 12122c26ad4bSAdrien Destugues 12132c26ad4bSAdrien Destugues // the host may be enclosed within brackets in order to express 12142c26ad4bSAdrien Destugues // an IPV6 address. 12152c26ad4bSAdrien Destugues 12162c26ad4bSAdrien Destugues if (authority_c[offset] == '[') { 12172c26ad4bSAdrien Destugues int32 end_ipv6_host = char_offset_until_fn_false( 12188f30879bSAndrew Lindesay authority_c, length, offset + 1, _IsIPV6Char); 12192c26ad4bSAdrien Destugues 12202c26ad4bSAdrien Destugues if (authority_c[end_ipv6_host] == ']') { 12212c26ad4bSAdrien Destugues SetHost(BString(&authority_c[offset], 12222c26ad4bSAdrien Destugues (end_ipv6_host - offset) + 1)); 12232c26ad4bSAdrien Destugues state = AUTHORITY_PORT; 12242c26ad4bSAdrien Destugues offset = end_ipv6_host + 1; 12252c26ad4bSAdrien Destugues } 12262c26ad4bSAdrien Destugues } 12272c26ad4bSAdrien Destugues 12282c26ad4bSAdrien Destugues // if an IPV6 host was not found. 12292c26ad4bSAdrien Destugues 12302c26ad4bSAdrien Destugues if (AUTHORITY_HOST == state) { 12312c26ad4bSAdrien Destugues int32 end_host = char_offset_until_fn_false( 12328f30879bSAndrew Lindesay authority_c, length, offset, _IsHostChar); 12332c26ad4bSAdrien Destugues 12342c26ad4bSAdrien Destugues SetHost(BString(&authority_c[offset], end_host - offset)); 12352c26ad4bSAdrien Destugues state = AUTHORITY_PORT; 12362c26ad4bSAdrien Destugues offset = end_host; 12372c26ad4bSAdrien Destugues } 12382c26ad4bSAdrien Destugues 12392c26ad4bSAdrien Destugues break; 12402c26ad4bSAdrien Destugues } 12412c26ad4bSAdrien Destugues 12422c26ad4bSAdrien Destugues case AUTHORITY_PORT: 12432c26ad4bSAdrien Destugues { 12442c26ad4bSAdrien Destugues if (authority_c[offset] == ':') { 12452c26ad4bSAdrien Destugues offset++; 12462c26ad4bSAdrien Destugues int32 end_port = char_offset_until_fn_false( 12478f30879bSAndrew Lindesay authority_c, length, offset, _IsPortChar); 12482c26ad4bSAdrien Destugues SetPort(atoi(&authority_c[offset])); 12492c26ad4bSAdrien Destugues offset = end_port; 12502c26ad4bSAdrien Destugues } 12512c26ad4bSAdrien Destugues 12522c26ad4bSAdrien Destugues state = AUTHORITY_COMPLETE; 12532c26ad4bSAdrien Destugues 12542c26ad4bSAdrien Destugues break; 12552c26ad4bSAdrien Destugues } 12562c26ad4bSAdrien Destugues 12572c26ad4bSAdrien Destugues case AUTHORITY_COMPLETE: 12582c26ad4bSAdrien Destugues // should never be reached - keeps the compiler happy 12592c26ad4bSAdrien Destugues break; 12602c26ad4bSAdrien Destugues } 12612c26ad4bSAdrien Destugues } 12622c26ad4bSAdrien Destugues 12632c26ad4bSAdrien Destugues // An empty authority is still an authority, making it possible to have 12642c26ad4bSAdrien Destugues // URLs such as file:///path/to/file. 12652c26ad4bSAdrien Destugues // TODO however, there is no way to unset the authority once it is set... 12662c26ad4bSAdrien Destugues // We may want to take a const char* parameter and allow NULL. 12672c26ad4bSAdrien Destugues fHasHost = true; 12682c26ad4bSAdrien Destugues } 12692c26ad4bSAdrien Destugues 12702c26ad4bSAdrien Destugues 12712c26ad4bSAdrien Destugues /*static*/ BString 12722c26ad4bSAdrien Destugues BUrl::_DoUrlEncodeChunk(const BString& chunk, bool strict, bool directory) 12732c26ad4bSAdrien Destugues { 12742c26ad4bSAdrien Destugues BString result; 12752c26ad4bSAdrien Destugues 12762c26ad4bSAdrien Destugues for (int32 i = 0; i < chunk.Length(); i++) { 12772c26ad4bSAdrien Destugues if (_IsUnreserved(chunk[i]) 12782c26ad4bSAdrien Destugues || (directory && (chunk[i] == '/' || chunk[i] == '\\'))) { 12792c26ad4bSAdrien Destugues result << chunk[i]; 12802c26ad4bSAdrien Destugues } else { 12812c26ad4bSAdrien Destugues if (chunk[i] == ' ' && !strict) { 12822c26ad4bSAdrien Destugues result << '+'; 12832c26ad4bSAdrien Destugues // In non-strict mode, spaces are encoded by a plus sign 12842c26ad4bSAdrien Destugues } else { 12852c26ad4bSAdrien Destugues char hexString[5]; 12862c26ad4bSAdrien Destugues snprintf(hexString, 5, "%X", chunk[i]); 12872c26ad4bSAdrien Destugues 12882c26ad4bSAdrien Destugues result << '%' << hexString; 12892c26ad4bSAdrien Destugues } 12902c26ad4bSAdrien Destugues } 12912c26ad4bSAdrien Destugues } 12922c26ad4bSAdrien Destugues 12932c26ad4bSAdrien Destugues return result; 12942c26ad4bSAdrien Destugues } 12952c26ad4bSAdrien Destugues 12962c26ad4bSAdrien Destugues 12972c26ad4bSAdrien Destugues /*static*/ BString 12982c26ad4bSAdrien Destugues BUrl::_DoUrlDecodeChunk(const BString& chunk, bool strict) 12992c26ad4bSAdrien Destugues { 13002c26ad4bSAdrien Destugues BString result; 13012c26ad4bSAdrien Destugues 13022c26ad4bSAdrien Destugues for (int32 i = 0; i < chunk.Length(); i++) { 13032c26ad4bSAdrien Destugues if (chunk[i] == '+' && !strict) 13042c26ad4bSAdrien Destugues result << ' '; 13052c26ad4bSAdrien Destugues else { 13062c26ad4bSAdrien Destugues char decoded = 0; 13072c26ad4bSAdrien Destugues char* out = NULL; 13082c26ad4bSAdrien Destugues char hexString[3]; 13092c26ad4bSAdrien Destugues 13102c26ad4bSAdrien Destugues if (chunk[i] == '%' && i < chunk.Length() - 2 13112c26ad4bSAdrien Destugues && isxdigit(chunk[i + 1]) && isxdigit(chunk[i+2])) { 13122c26ad4bSAdrien Destugues hexString[0] = chunk[i + 1]; 13132c26ad4bSAdrien Destugues hexString[1] = chunk[i + 2]; 13142c26ad4bSAdrien Destugues hexString[2] = 0; 13152c26ad4bSAdrien Destugues decoded = (char)strtol(hexString, &out, 16); 13162c26ad4bSAdrien Destugues } 13172c26ad4bSAdrien Destugues 13182c26ad4bSAdrien Destugues if (out == hexString + 2) { 13192c26ad4bSAdrien Destugues i += 2; 13202c26ad4bSAdrien Destugues result << decoded; 13212c26ad4bSAdrien Destugues } else 13222c26ad4bSAdrien Destugues result << chunk[i]; 13232c26ad4bSAdrien Destugues } 13242c26ad4bSAdrien Destugues } 13252c26ad4bSAdrien Destugues return result; 13262c26ad4bSAdrien Destugues } 13272c26ad4bSAdrien Destugues 13282c26ad4bSAdrien Destugues 13292c26ad4bSAdrien Destugues bool 13308f30879bSAndrew Lindesay BUrl::_IsHostIPV6Valid(size_t offset, int32 length) const 13318f30879bSAndrew Lindesay { 13328f30879bSAndrew Lindesay for (int32 i = 0; i < length; i++) { 13338f30879bSAndrew Lindesay char c = fHost[offset + i]; 13348f30879bSAndrew Lindesay if (!_IsIPV6Char(c)) 13358f30879bSAndrew Lindesay return false; 13368f30879bSAndrew Lindesay } 13378f30879bSAndrew Lindesay 13388f30879bSAndrew Lindesay return length > 0; 13398f30879bSAndrew Lindesay } 13408f30879bSAndrew Lindesay 13418f30879bSAndrew Lindesay 13428f30879bSAndrew Lindesay bool 13438f30879bSAndrew Lindesay BUrl::_IsHostValid() const 13448f30879bSAndrew Lindesay { 13458f30879bSAndrew Lindesay if (fHost.StartsWith("[") && fHost.EndsWith("]")) 13468f30879bSAndrew Lindesay return _IsHostIPV6Valid(1, fHost.Length() - 2); 13478f30879bSAndrew Lindesay 13488f30879bSAndrew Lindesay bool lastWasDot = false; 13498f30879bSAndrew Lindesay 13508f30879bSAndrew Lindesay for (int32 i = 0; i < fHost.Length(); i++) { 13518f30879bSAndrew Lindesay char c = fHost[i]; 13528f30879bSAndrew Lindesay 13538f30879bSAndrew Lindesay if (c == '.') { 13548f30879bSAndrew Lindesay if (lastWasDot || i == 0) 13558f30879bSAndrew Lindesay return false; 13568f30879bSAndrew Lindesay lastWasDot = true; 13578f30879bSAndrew Lindesay } else { 13588f30879bSAndrew Lindesay lastWasDot = false; 13598f30879bSAndrew Lindesay } 13608f30879bSAndrew Lindesay 13618f30879bSAndrew Lindesay if (!_IsHostChar(c) && c != '.') { 13628f30879bSAndrew Lindesay // the underscore is technically not allowed, but occurs sometimes 13638f30879bSAndrew Lindesay // in the wild. 13648f30879bSAndrew Lindesay return false; 13658f30879bSAndrew Lindesay } 13668f30879bSAndrew Lindesay } 13678f30879bSAndrew Lindesay 13688f30879bSAndrew Lindesay return true; 13698f30879bSAndrew Lindesay } 13708f30879bSAndrew Lindesay 13718f30879bSAndrew Lindesay 13728f30879bSAndrew Lindesay bool 13738f30879bSAndrew Lindesay BUrl::_IsProtocolValid() const 13742c26ad4bSAdrien Destugues { 13752c26ad4bSAdrien Destugues for (int8 index = 0; index < fProtocol.Length(); index++) { 13762c26ad4bSAdrien Destugues char c = fProtocol[index]; 13772c26ad4bSAdrien Destugues 13782c26ad4bSAdrien Destugues if (index == 0 && !isalpha(c)) 13792c26ad4bSAdrien Destugues return false; 13802c26ad4bSAdrien Destugues else if (!isalnum(c) && c != '+' && c != '-' && c != '.') 13812c26ad4bSAdrien Destugues return false; 13822c26ad4bSAdrien Destugues } 13832c26ad4bSAdrien Destugues 13848f30879bSAndrew Lindesay return !fProtocol.IsEmpty(); 13852c26ad4bSAdrien Destugues } 13862c26ad4bSAdrien Destugues 13872c26ad4bSAdrien Destugues 13882c26ad4bSAdrien Destugues bool 13892c26ad4bSAdrien Destugues BUrl::_IsUnreserved(char c) 13902c26ad4bSAdrien Destugues { 13912c26ad4bSAdrien Destugues return isalnum(c) || c == '-' || c == '.' || c == '_' || c == '~'; 13922c26ad4bSAdrien Destugues } 13932c26ad4bSAdrien Destugues 13942c26ad4bSAdrien Destugues 13952c26ad4bSAdrien Destugues bool 13962c26ad4bSAdrien Destugues BUrl::_IsGenDelim(char c) 13972c26ad4bSAdrien Destugues { 13982c26ad4bSAdrien Destugues return c == ':' || c == '/' || c == '?' || c == '#' || c == '[' 13992c26ad4bSAdrien Destugues || c == ']' || c == '@'; 14002c26ad4bSAdrien Destugues } 14012c26ad4bSAdrien Destugues 14022c26ad4bSAdrien Destugues 14032c26ad4bSAdrien Destugues bool 14042c26ad4bSAdrien Destugues BUrl::_IsSubDelim(char c) 14052c26ad4bSAdrien Destugues { 14062c26ad4bSAdrien Destugues return c == '!' || c == '$' || c == '&' || c == '\'' || c == '(' 14072c26ad4bSAdrien Destugues || c == ')' || c == '*' || c == '+' || c == ',' || c == ';' 14082c26ad4bSAdrien Destugues || c == '='; 14092c26ad4bSAdrien Destugues } 14102c26ad4bSAdrien Destugues 14112c26ad4bSAdrien Destugues 14128f30879bSAndrew Lindesay bool 14138f30879bSAndrew Lindesay BUrl::_IsUsernameChar(char c) 14148f30879bSAndrew Lindesay { 14158f30879bSAndrew Lindesay return !(c == ':' || c == '@'); 14168f30879bSAndrew Lindesay } 14178f30879bSAndrew Lindesay 14188f30879bSAndrew Lindesay 14198f30879bSAndrew Lindesay bool 14208f30879bSAndrew Lindesay BUrl::_IsPasswordChar(char c) 14218f30879bSAndrew Lindesay { 14228f30879bSAndrew Lindesay return !(c == '@'); 14238f30879bSAndrew Lindesay } 14248f30879bSAndrew Lindesay 14258f30879bSAndrew Lindesay 14268f30879bSAndrew Lindesay bool 14278f30879bSAndrew Lindesay BUrl::_IsHostChar(char c) 14288f30879bSAndrew Lindesay { 14298f30879bSAndrew Lindesay return ((uint8) c) > 127 || isalnum(c) || c == '-' || c == '_' || c == '.' 14308f30879bSAndrew Lindesay || c == '%'; 14318f30879bSAndrew Lindesay } 14328f30879bSAndrew Lindesay 14338f30879bSAndrew Lindesay 14348f30879bSAndrew Lindesay bool 14358f30879bSAndrew Lindesay BUrl::_IsPortChar(char c) 14368f30879bSAndrew Lindesay { 14378f30879bSAndrew Lindesay return isdigit(c); 14388f30879bSAndrew Lindesay } 14398f30879bSAndrew Lindesay 14408f30879bSAndrew Lindesay 14418f30879bSAndrew Lindesay bool 14428f30879bSAndrew Lindesay BUrl::_IsIPV6Char(char c) 14438f30879bSAndrew Lindesay { 14448f30879bSAndrew Lindesay return c == ':' || isxdigit(c); 14458f30879bSAndrew Lindesay } 14468f30879bSAndrew Lindesay 14478f30879bSAndrew Lindesay 14482c26ad4bSAdrien Destugues BString 14492c26ad4bSAdrien Destugues BUrl::_UrlMimeType() const 14502c26ad4bSAdrien Destugues { 14512c26ad4bSAdrien Destugues BString mime; 14522c26ad4bSAdrien Destugues mime << "application/x-vnd.Be.URL." << fProtocol; 14532c26ad4bSAdrien Destugues 14542c26ad4bSAdrien Destugues return BString(mime); 14552c26ad4bSAdrien Destugues } 1456