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
33*a609673cSAndrew Lindesay /*! These flags can be combined to control the parse process. */
34*a609673cSAndrew Lindesay
35*a609673cSAndrew Lindesay const uint32 PARSE_NO_MASK_BIT = 0x00000000;
36*a609673cSAndrew Lindesay const uint32 PARSE_RAW_PATH_MASK_BIT = 0x00000001;
37*a609673cSAndrew Lindesay
382c26ad4bSAdrien Destugues
BUrl(const char * url)392c26ad4bSAdrien Destugues BUrl::BUrl(const char* url)
402c26ad4bSAdrien Destugues :
412c26ad4bSAdrien Destugues fUrlString(),
422c26ad4bSAdrien Destugues fProtocol(),
432c26ad4bSAdrien Destugues fUser(),
442c26ad4bSAdrien Destugues fPassword(),
452c26ad4bSAdrien Destugues fHost(),
462c26ad4bSAdrien Destugues fPort(0),
472c26ad4bSAdrien Destugues fPath(),
482c26ad4bSAdrien Destugues fRequest(),
492c26ad4bSAdrien Destugues fHasHost(false),
502c26ad4bSAdrien Destugues fHasFragment(false)
512c26ad4bSAdrien Destugues {
522c26ad4bSAdrien Destugues SetUrlString(url);
532c26ad4bSAdrien Destugues }
542c26ad4bSAdrien Destugues
552c26ad4bSAdrien Destugues
BUrl(BMessage * archive)562c26ad4bSAdrien Destugues BUrl::BUrl(BMessage* archive)
572c26ad4bSAdrien Destugues :
582c26ad4bSAdrien Destugues fUrlString(),
592c26ad4bSAdrien Destugues fProtocol(),
602c26ad4bSAdrien Destugues fUser(),
612c26ad4bSAdrien Destugues fPassword(),
622c26ad4bSAdrien Destugues fHost(),
632c26ad4bSAdrien Destugues fPort(0),
642c26ad4bSAdrien Destugues fPath(),
652c26ad4bSAdrien Destugues fRequest(),
662c26ad4bSAdrien Destugues fHasHost(false),
672c26ad4bSAdrien Destugues fHasFragment(false)
682c26ad4bSAdrien Destugues {
692c26ad4bSAdrien Destugues BString url;
702c26ad4bSAdrien Destugues
712c26ad4bSAdrien Destugues if (archive->FindString(kArchivedUrl, &url) == B_OK)
722c26ad4bSAdrien Destugues SetUrlString(url);
732c26ad4bSAdrien Destugues else
742c26ad4bSAdrien Destugues _ResetFields();
752c26ad4bSAdrien Destugues }
762c26ad4bSAdrien Destugues
772c26ad4bSAdrien Destugues
BUrl(const BUrl & other)782c26ad4bSAdrien Destugues BUrl::BUrl(const BUrl& other)
792c26ad4bSAdrien Destugues :
802c26ad4bSAdrien Destugues BArchivable(),
812c26ad4bSAdrien Destugues fUrlString(),
822c26ad4bSAdrien Destugues fProtocol(other.fProtocol),
832c26ad4bSAdrien Destugues fUser(other.fUser),
842c26ad4bSAdrien Destugues fPassword(other.fPassword),
852c26ad4bSAdrien Destugues fHost(other.fHost),
862c26ad4bSAdrien Destugues fPort(other.fPort),
872c26ad4bSAdrien Destugues fPath(other.fPath),
882c26ad4bSAdrien Destugues fRequest(other.fRequest),
892c26ad4bSAdrien Destugues fFragment(other.fFragment),
902c26ad4bSAdrien Destugues fUrlStringValid(other.fUrlStringValid),
912c26ad4bSAdrien Destugues fAuthorityValid(other.fAuthorityValid),
922c26ad4bSAdrien Destugues fUserInfoValid(other.fUserInfoValid),
932c26ad4bSAdrien Destugues fHasProtocol(other.fHasProtocol),
942c26ad4bSAdrien Destugues fHasUserName(other.fHasUserName),
952c26ad4bSAdrien Destugues fHasPassword(other.fHasPassword),
962c26ad4bSAdrien Destugues fHasHost(other.fHasHost),
972c26ad4bSAdrien Destugues fHasPort(other.fHasPort),
982c26ad4bSAdrien Destugues fHasPath(other.fHasPath),
992c26ad4bSAdrien Destugues fHasRequest(other.fHasRequest),
1002c26ad4bSAdrien Destugues fHasFragment(other.fHasFragment)
1012c26ad4bSAdrien Destugues {
1022c26ad4bSAdrien Destugues if (fUrlStringValid)
1032c26ad4bSAdrien Destugues fUrlString = other.fUrlString;
1042c26ad4bSAdrien Destugues
1052c26ad4bSAdrien Destugues if (fAuthorityValid)
1062c26ad4bSAdrien Destugues fAuthority = other.fAuthority;
1072c26ad4bSAdrien Destugues
1082c26ad4bSAdrien Destugues if (fUserInfoValid)
1092c26ad4bSAdrien Destugues fUserInfo = other.fUserInfo;
1102c26ad4bSAdrien Destugues
1112c26ad4bSAdrien Destugues }
1122c26ad4bSAdrien Destugues
1132c26ad4bSAdrien Destugues
BUrl(const BUrl & base,const BString & location)1142c26ad4bSAdrien Destugues BUrl::BUrl(const BUrl& base, const BString& location)
1152c26ad4bSAdrien Destugues :
1162c26ad4bSAdrien Destugues fUrlString(),
1172c26ad4bSAdrien Destugues fProtocol(),
1182c26ad4bSAdrien Destugues fUser(),
1192c26ad4bSAdrien Destugues fPassword(),
1202c26ad4bSAdrien Destugues fHost(),
1212c26ad4bSAdrien Destugues fPort(0),
1222c26ad4bSAdrien Destugues fPath(),
1232c26ad4bSAdrien Destugues fRequest(),
1242c26ad4bSAdrien Destugues fAuthorityValid(false),
1252c26ad4bSAdrien Destugues fUserInfoValid(false),
1262c26ad4bSAdrien Destugues fHasUserName(false),
1272c26ad4bSAdrien Destugues fHasPassword(false),
1282c26ad4bSAdrien Destugues fHasHost(false),
1292c26ad4bSAdrien Destugues fHasPort(false),
1302c26ad4bSAdrien Destugues fHasFragment(false)
1312c26ad4bSAdrien Destugues {
1322c26ad4bSAdrien Destugues // This implements the algorithm in RFC3986, Section 5.2.
1332c26ad4bSAdrien Destugues
134*a609673cSAndrew Lindesay BUrl relative;
135*a609673cSAndrew Lindesay relative._ExplodeUrlString(location, PARSE_RAW_PATH_MASK_BIT);
136*a609673cSAndrew Lindesay // This parse will leave the path 'raw' so that it still carries any
137*a609673cSAndrew Lindesay // special sequences such as '..' and '.' in it. This way it can be
138*a609673cSAndrew Lindesay // later combined with the base.
139*a609673cSAndrew Lindesay
1402c26ad4bSAdrien Destugues if (relative.HasProtocol()) {
1412c26ad4bSAdrien Destugues SetProtocol(relative.Protocol());
1422c26ad4bSAdrien Destugues if (relative.HasAuthority())
1432c26ad4bSAdrien Destugues SetAuthority(relative.Authority());
1442c26ad4bSAdrien Destugues SetPath(relative.Path());
1452c26ad4bSAdrien Destugues SetRequest(relative.Request());
1462c26ad4bSAdrien Destugues } else {
1472c26ad4bSAdrien Destugues if (relative.HasAuthority()) {
1482c26ad4bSAdrien Destugues SetAuthority(relative.Authority());
1492c26ad4bSAdrien Destugues SetPath(relative.Path());
1502c26ad4bSAdrien Destugues SetRequest(relative.Request());
1512c26ad4bSAdrien Destugues } else {
1522c26ad4bSAdrien Destugues if (relative.Path().IsEmpty()) {
1532c26ad4bSAdrien Destugues _SetPathUnsafe(base.Path());
1542c26ad4bSAdrien Destugues if (relative.HasRequest())
1552c26ad4bSAdrien Destugues SetRequest(relative.Request());
1562c26ad4bSAdrien Destugues else
1572c26ad4bSAdrien Destugues SetRequest(base.Request());
1582c26ad4bSAdrien Destugues } else {
1592c26ad4bSAdrien Destugues if (relative.Path()[0] == '/')
1602c26ad4bSAdrien Destugues SetPath(relative.Path());
1612c26ad4bSAdrien Destugues else {
1622c26ad4bSAdrien Destugues BString path = base._MergePath(relative.Path());
1632c26ad4bSAdrien Destugues SetPath(path);
1642c26ad4bSAdrien Destugues }
1652c26ad4bSAdrien Destugues SetRequest(relative.Request());
1662c26ad4bSAdrien Destugues }
1672c26ad4bSAdrien Destugues
1682c26ad4bSAdrien Destugues if (base.HasAuthority())
1692c26ad4bSAdrien Destugues SetAuthority(base.Authority());
1702c26ad4bSAdrien Destugues }
1712c26ad4bSAdrien Destugues SetProtocol(base.Protocol());
1722c26ad4bSAdrien Destugues }
1732c26ad4bSAdrien Destugues
1742c26ad4bSAdrien Destugues if (relative.HasFragment())
1752c26ad4bSAdrien Destugues SetFragment(relative.Fragment());
1762c26ad4bSAdrien Destugues }
1772c26ad4bSAdrien Destugues
1782c26ad4bSAdrien Destugues
BUrl()1792c26ad4bSAdrien Destugues BUrl::BUrl()
1802c26ad4bSAdrien Destugues :
1812c26ad4bSAdrien Destugues fUrlString(),
1822c26ad4bSAdrien Destugues fProtocol(),
1832c26ad4bSAdrien Destugues fUser(),
1842c26ad4bSAdrien Destugues fPassword(),
1852c26ad4bSAdrien Destugues fHost(),
1862c26ad4bSAdrien Destugues fPort(0),
1872c26ad4bSAdrien Destugues fPath(),
1882c26ad4bSAdrien Destugues fRequest(),
1892c26ad4bSAdrien Destugues fHasHost(false),
1902c26ad4bSAdrien Destugues fHasFragment(false)
1912c26ad4bSAdrien Destugues {
1922c26ad4bSAdrien Destugues _ResetFields();
1932c26ad4bSAdrien Destugues }
1942c26ad4bSAdrien Destugues
1952c26ad4bSAdrien Destugues
BUrl(const BPath & path)1962c26ad4bSAdrien Destugues BUrl::BUrl(const BPath& path)
1972c26ad4bSAdrien Destugues :
1982c26ad4bSAdrien Destugues fUrlString(),
1992c26ad4bSAdrien Destugues fProtocol(),
2002c26ad4bSAdrien Destugues fUser(),
2012c26ad4bSAdrien Destugues fPassword(),
2022c26ad4bSAdrien Destugues fHost(),
2032c26ad4bSAdrien Destugues fPort(0),
2042c26ad4bSAdrien Destugues fPath(),
2052c26ad4bSAdrien Destugues fRequest(),
2062c26ad4bSAdrien Destugues fHasHost(false),
2072c26ad4bSAdrien Destugues fHasFragment(false)
2082c26ad4bSAdrien Destugues {
2092c26ad4bSAdrien Destugues SetUrlString(UrlEncode(path.Path(), true, true));
2102c26ad4bSAdrien Destugues SetProtocol("file");
2112c26ad4bSAdrien Destugues }
2122c26ad4bSAdrien Destugues
2132c26ad4bSAdrien Destugues
~BUrl()2142c26ad4bSAdrien Destugues BUrl::~BUrl()
2152c26ad4bSAdrien Destugues {
2162c26ad4bSAdrien Destugues }
2172c26ad4bSAdrien Destugues
2182c26ad4bSAdrien Destugues
2192c26ad4bSAdrien Destugues // #pragma mark URL fields modifiers
2202c26ad4bSAdrien Destugues
2212c26ad4bSAdrien Destugues
2222c26ad4bSAdrien Destugues BUrl&
SetUrlString(const BString & url)2232c26ad4bSAdrien Destugues BUrl::SetUrlString(const BString& url)
2242c26ad4bSAdrien Destugues {
225*a609673cSAndrew Lindesay _ExplodeUrlString(url, PARSE_NO_MASK_BIT);
2262c26ad4bSAdrien Destugues return *this;
2272c26ad4bSAdrien Destugues }
2282c26ad4bSAdrien Destugues
2292c26ad4bSAdrien Destugues
2302c26ad4bSAdrien Destugues BUrl&
SetProtocol(const BString & protocol)2312c26ad4bSAdrien Destugues BUrl::SetProtocol(const BString& protocol)
2322c26ad4bSAdrien Destugues {
2332c26ad4bSAdrien Destugues fProtocol = protocol;
2342c26ad4bSAdrien Destugues fHasProtocol = !fProtocol.IsEmpty();
2352c26ad4bSAdrien Destugues fUrlStringValid = false;
2362c26ad4bSAdrien Destugues return *this;
2372c26ad4bSAdrien Destugues }
2382c26ad4bSAdrien Destugues
2392c26ad4bSAdrien Destugues
2402c26ad4bSAdrien Destugues BUrl&
SetUserName(const BString & user)2412c26ad4bSAdrien Destugues BUrl::SetUserName(const BString& user)
2422c26ad4bSAdrien Destugues {
2432c26ad4bSAdrien Destugues fUser = user;
2442c26ad4bSAdrien Destugues fHasUserName = !fUser.IsEmpty();
2452c26ad4bSAdrien Destugues fUrlStringValid = false;
2462c26ad4bSAdrien Destugues fAuthorityValid = false;
2472c26ad4bSAdrien Destugues fUserInfoValid = false;
2482c26ad4bSAdrien Destugues return *this;
2492c26ad4bSAdrien Destugues }
2502c26ad4bSAdrien Destugues
2512c26ad4bSAdrien Destugues
2522c26ad4bSAdrien Destugues BUrl&
SetPassword(const BString & password)2532c26ad4bSAdrien Destugues BUrl::SetPassword(const BString& password)
2542c26ad4bSAdrien Destugues {
2552c26ad4bSAdrien Destugues fPassword = password;
2562c26ad4bSAdrien Destugues fHasPassword = !fPassword.IsEmpty();
2572c26ad4bSAdrien Destugues fUrlStringValid = false;
2582c26ad4bSAdrien Destugues fAuthorityValid = false;
2592c26ad4bSAdrien Destugues fUserInfoValid = false;
2602c26ad4bSAdrien Destugues return *this;
2612c26ad4bSAdrien Destugues }
2622c26ad4bSAdrien Destugues
2632c26ad4bSAdrien Destugues
2642c26ad4bSAdrien Destugues BUrl&
SetHost(const BString & host)2652c26ad4bSAdrien Destugues BUrl::SetHost(const BString& host)
2662c26ad4bSAdrien Destugues {
2672c26ad4bSAdrien Destugues fHost = host;
2682c26ad4bSAdrien Destugues fHasHost = !fHost.IsEmpty();
2692c26ad4bSAdrien Destugues fUrlStringValid = false;
2702c26ad4bSAdrien Destugues fAuthorityValid = false;
2712c26ad4bSAdrien Destugues return *this;
2722c26ad4bSAdrien Destugues }
2732c26ad4bSAdrien Destugues
2742c26ad4bSAdrien Destugues
2752c26ad4bSAdrien Destugues BUrl&
SetPort(int port)2762c26ad4bSAdrien Destugues BUrl::SetPort(int port)
2772c26ad4bSAdrien Destugues {
2782c26ad4bSAdrien Destugues fPort = port;
2792c26ad4bSAdrien Destugues fHasPort = (port != 0);
2802c26ad4bSAdrien Destugues fUrlStringValid = false;
2812c26ad4bSAdrien Destugues fAuthorityValid = false;
2822c26ad4bSAdrien Destugues return *this;
2832c26ad4bSAdrien Destugues }
2842c26ad4bSAdrien Destugues
2852c26ad4bSAdrien Destugues
286*a609673cSAndrew Lindesay void
_RemoveLastPathComponent(BString & path)287*a609673cSAndrew Lindesay BUrl::_RemoveLastPathComponent(BString& path)
288*a609673cSAndrew Lindesay {
289*a609673cSAndrew Lindesay int32 outputLastSlashIdx = path.FindLast('/');
290*a609673cSAndrew Lindesay
291*a609673cSAndrew Lindesay if (outputLastSlashIdx == B_ERROR)
292*a609673cSAndrew Lindesay path.Truncate(0);
293*a609673cSAndrew Lindesay else
294*a609673cSAndrew Lindesay path.Truncate(outputLastSlashIdx);
295*a609673cSAndrew Lindesay }
296*a609673cSAndrew Lindesay
297*a609673cSAndrew Lindesay
2982c26ad4bSAdrien Destugues BUrl&
SetPath(const BString & path)2992c26ad4bSAdrien Destugues BUrl::SetPath(const BString& path)
3002c26ad4bSAdrien Destugues {
3012c26ad4bSAdrien Destugues // Implements RFC3986 section 5.2.4, "Remove dot segments"
3022c26ad4bSAdrien Destugues
3032c26ad4bSAdrien Destugues // 1.
3042c26ad4bSAdrien Destugues BString output;
3052c26ad4bSAdrien Destugues BString input(path);
3062c26ad4bSAdrien Destugues
3072c26ad4bSAdrien Destugues // 2.
308cd6365c7SJérôme Duval while (!input.IsEmpty()) {
3092c26ad4bSAdrien Destugues // 2.A.
310cd6365c7SJérôme Duval if (input.StartsWith("./")) {
3112c26ad4bSAdrien Destugues input.Remove(0, 2);
3122c26ad4bSAdrien Destugues continue;
3132c26ad4bSAdrien Destugues }
3142c26ad4bSAdrien Destugues
315cd6365c7SJérôme Duval if (input.StartsWith("../")) {
3162c26ad4bSAdrien Destugues input.Remove(0, 3);
3172c26ad4bSAdrien Destugues continue;
3182c26ad4bSAdrien Destugues }
3192c26ad4bSAdrien Destugues
3202c26ad4bSAdrien Destugues // 2.B.
321cd6365c7SJérôme Duval if (input.StartsWith("/./")) {
3222c26ad4bSAdrien Destugues input.Remove(0, 2);
3232c26ad4bSAdrien Destugues continue;
3242c26ad4bSAdrien Destugues }
3252c26ad4bSAdrien Destugues
326cd6365c7SJérôme Duval if (input == "/.") {
3272c26ad4bSAdrien Destugues input.Remove(1, 1);
3282c26ad4bSAdrien Destugues continue;
3292c26ad4bSAdrien Destugues }
3302c26ad4bSAdrien Destugues
3312c26ad4bSAdrien Destugues // 2.C.
332cd6365c7SJérôme Duval if (input.StartsWith("/../")) {
3332c26ad4bSAdrien Destugues input.Remove(0, 3);
334*a609673cSAndrew Lindesay _RemoveLastPathComponent(output);
3352c26ad4bSAdrien Destugues continue;
3362c26ad4bSAdrien Destugues }
3372c26ad4bSAdrien Destugues
338cd6365c7SJérôme Duval if (input == "/..") {
3392c26ad4bSAdrien Destugues input.Remove(1, 2);
340*a609673cSAndrew Lindesay _RemoveLastPathComponent(output);
3412c26ad4bSAdrien Destugues continue;
3422c26ad4bSAdrien Destugues }
3432c26ad4bSAdrien Destugues
3442c26ad4bSAdrien Destugues // 2.D.
345cd6365c7SJérôme Duval if (input == "." || input == "..") {
3462c26ad4bSAdrien Destugues break;
3472c26ad4bSAdrien Destugues }
3482c26ad4bSAdrien Destugues
349cd6365c7SJérôme Duval if (input == "/.") {
3502c26ad4bSAdrien Destugues input.Remove(1, 1);
3512c26ad4bSAdrien Destugues continue;
3522c26ad4bSAdrien Destugues }
3532c26ad4bSAdrien Destugues
3542c26ad4bSAdrien Destugues // 2.E.
3552c26ad4bSAdrien Destugues int slashpos = input.FindFirst('/', 1);
3562c26ad4bSAdrien Destugues if (slashpos > 0) {
3572c26ad4bSAdrien Destugues output.Append(input, slashpos);
3582c26ad4bSAdrien Destugues input.Remove(0, slashpos);
3592c26ad4bSAdrien Destugues } else {
3602c26ad4bSAdrien Destugues output.Append(input);
3612c26ad4bSAdrien Destugues break;
3622c26ad4bSAdrien Destugues }
3632c26ad4bSAdrien Destugues }
3642c26ad4bSAdrien Destugues
3652c26ad4bSAdrien Destugues _SetPathUnsafe(output);
3662c26ad4bSAdrien Destugues return *this;
3672c26ad4bSAdrien Destugues }
3682c26ad4bSAdrien Destugues
3692c26ad4bSAdrien Destugues
3702c26ad4bSAdrien Destugues BUrl&
SetRequest(const BString & request)3712c26ad4bSAdrien Destugues BUrl::SetRequest(const BString& request)
3722c26ad4bSAdrien Destugues {
3732c26ad4bSAdrien Destugues fRequest = request;
3742c26ad4bSAdrien Destugues fHasRequest = !fRequest.IsEmpty();
3752c26ad4bSAdrien Destugues fUrlStringValid = false;
3762c26ad4bSAdrien Destugues return *this;
3772c26ad4bSAdrien Destugues }
3782c26ad4bSAdrien Destugues
3792c26ad4bSAdrien Destugues
3802c26ad4bSAdrien Destugues BUrl&
SetFragment(const BString & fragment)3812c26ad4bSAdrien Destugues BUrl::SetFragment(const BString& fragment)
3822c26ad4bSAdrien Destugues {
3832c26ad4bSAdrien Destugues fFragment = fragment;
3842c26ad4bSAdrien Destugues fHasFragment = true;
3852c26ad4bSAdrien Destugues fUrlStringValid = false;
3862c26ad4bSAdrien Destugues return *this;
3872c26ad4bSAdrien Destugues }
3882c26ad4bSAdrien Destugues
3892c26ad4bSAdrien Destugues
3902c26ad4bSAdrien Destugues // #pragma mark URL fields access
3912c26ad4bSAdrien Destugues
3922c26ad4bSAdrien Destugues
3932c26ad4bSAdrien Destugues const BString&
UrlString() const3942c26ad4bSAdrien Destugues BUrl::UrlString() const
3952c26ad4bSAdrien Destugues {
3962c26ad4bSAdrien Destugues if (!fUrlStringValid) {
3972c26ad4bSAdrien Destugues fUrlString.Truncate(0);
3982c26ad4bSAdrien Destugues
3992c26ad4bSAdrien Destugues if (HasProtocol()) {
4002c26ad4bSAdrien Destugues fUrlString << fProtocol << ':';
4012c26ad4bSAdrien Destugues }
4022c26ad4bSAdrien Destugues
4032c26ad4bSAdrien Destugues if (HasAuthority()) {
4042c26ad4bSAdrien Destugues fUrlString << "//";
4052c26ad4bSAdrien Destugues fUrlString << Authority();
4062c26ad4bSAdrien Destugues }
4072c26ad4bSAdrien Destugues fUrlString << Path();
4082c26ad4bSAdrien Destugues
4092c26ad4bSAdrien Destugues if (HasRequest())
4102c26ad4bSAdrien Destugues fUrlString << '?' << fRequest;
4112c26ad4bSAdrien Destugues
4122c26ad4bSAdrien Destugues if (HasFragment())
4132c26ad4bSAdrien Destugues fUrlString << '#' << fFragment;
4142c26ad4bSAdrien Destugues
4152c26ad4bSAdrien Destugues fUrlStringValid = true;
4162c26ad4bSAdrien Destugues }
4172c26ad4bSAdrien Destugues
4182c26ad4bSAdrien Destugues return fUrlString;
4192c26ad4bSAdrien Destugues }
4202c26ad4bSAdrien Destugues
4212c26ad4bSAdrien Destugues
4222c26ad4bSAdrien Destugues const BString&
Protocol() const4232c26ad4bSAdrien Destugues BUrl::Protocol() const
4242c26ad4bSAdrien Destugues {
4252c26ad4bSAdrien Destugues return fProtocol;
4262c26ad4bSAdrien Destugues }
4272c26ad4bSAdrien Destugues
4282c26ad4bSAdrien Destugues
4292c26ad4bSAdrien Destugues const BString&
UserName() const4302c26ad4bSAdrien Destugues BUrl::UserName() const
4312c26ad4bSAdrien Destugues {
4322c26ad4bSAdrien Destugues return fUser;
4332c26ad4bSAdrien Destugues }
4342c26ad4bSAdrien Destugues
4352c26ad4bSAdrien Destugues
4362c26ad4bSAdrien Destugues const BString&
Password() const4372c26ad4bSAdrien Destugues BUrl::Password() const
4382c26ad4bSAdrien Destugues {
4392c26ad4bSAdrien Destugues return fPassword;
4402c26ad4bSAdrien Destugues }
4412c26ad4bSAdrien Destugues
4422c26ad4bSAdrien Destugues
4432c26ad4bSAdrien Destugues const BString&
UserInfo() const4442c26ad4bSAdrien Destugues BUrl::UserInfo() const
4452c26ad4bSAdrien Destugues {
4462c26ad4bSAdrien Destugues if (!fUserInfoValid) {
4472c26ad4bSAdrien Destugues fUserInfo = fUser;
4482c26ad4bSAdrien Destugues
4492c26ad4bSAdrien Destugues if (HasPassword())
4502c26ad4bSAdrien Destugues fUserInfo << ':' << fPassword;
4512c26ad4bSAdrien Destugues
4522c26ad4bSAdrien Destugues fUserInfoValid = true;
4532c26ad4bSAdrien Destugues }
4542c26ad4bSAdrien Destugues
4552c26ad4bSAdrien Destugues return fUserInfo;
4562c26ad4bSAdrien Destugues }
4572c26ad4bSAdrien Destugues
4582c26ad4bSAdrien Destugues
4592c26ad4bSAdrien Destugues const BString&
Host() const4602c26ad4bSAdrien Destugues BUrl::Host() const
4612c26ad4bSAdrien Destugues {
4622c26ad4bSAdrien Destugues return fHost;
4632c26ad4bSAdrien Destugues }
4642c26ad4bSAdrien Destugues
4652c26ad4bSAdrien Destugues
4662c26ad4bSAdrien Destugues int
Port() const4672c26ad4bSAdrien Destugues BUrl::Port() const
4682c26ad4bSAdrien Destugues {
4692c26ad4bSAdrien Destugues return fPort;
4702c26ad4bSAdrien Destugues }
4712c26ad4bSAdrien Destugues
4722c26ad4bSAdrien Destugues
4732c26ad4bSAdrien Destugues const BString&
Authority() const4742c26ad4bSAdrien Destugues BUrl::Authority() const
4752c26ad4bSAdrien Destugues {
4762c26ad4bSAdrien Destugues if (!fAuthorityValid) {
4772c26ad4bSAdrien Destugues fAuthority.Truncate(0);
4782c26ad4bSAdrien Destugues
4792c26ad4bSAdrien Destugues if (HasUserInfo())
4802c26ad4bSAdrien Destugues fAuthority << UserInfo() << '@';
4812c26ad4bSAdrien Destugues fAuthority << Host();
4822c26ad4bSAdrien Destugues
4832c26ad4bSAdrien Destugues if (HasPort())
4842c26ad4bSAdrien Destugues fAuthority << ':' << fPort;
4852c26ad4bSAdrien Destugues
4862c26ad4bSAdrien Destugues fAuthorityValid = true;
4872c26ad4bSAdrien Destugues }
4882c26ad4bSAdrien Destugues return fAuthority;
4892c26ad4bSAdrien Destugues }
4902c26ad4bSAdrien Destugues
4912c26ad4bSAdrien Destugues
4922c26ad4bSAdrien Destugues const BString&
Path() const4932c26ad4bSAdrien Destugues BUrl::Path() const
4942c26ad4bSAdrien Destugues {
4952c26ad4bSAdrien Destugues return fPath;
4962c26ad4bSAdrien Destugues }
4972c26ad4bSAdrien Destugues
4982c26ad4bSAdrien Destugues
4992c26ad4bSAdrien Destugues const BString&
Request() const5002c26ad4bSAdrien Destugues BUrl::Request() const
5012c26ad4bSAdrien Destugues {
5022c26ad4bSAdrien Destugues return fRequest;
5032c26ad4bSAdrien Destugues }
5042c26ad4bSAdrien Destugues
5052c26ad4bSAdrien Destugues
5062c26ad4bSAdrien Destugues const BString&
Fragment() const5072c26ad4bSAdrien Destugues BUrl::Fragment() const
5082c26ad4bSAdrien Destugues {
5092c26ad4bSAdrien Destugues return fFragment;
5102c26ad4bSAdrien Destugues }
5112c26ad4bSAdrien Destugues
5122c26ad4bSAdrien Destugues
5132c26ad4bSAdrien Destugues // #pragma mark URL fields tests
5142c26ad4bSAdrien Destugues
5152c26ad4bSAdrien Destugues
5162c26ad4bSAdrien Destugues bool
IsValid() const5172c26ad4bSAdrien Destugues BUrl::IsValid() const
5182c26ad4bSAdrien Destugues {
5192c26ad4bSAdrien Destugues if (!fHasProtocol)
5202c26ad4bSAdrien Destugues return false;
5212c26ad4bSAdrien Destugues
5228f30879bSAndrew Lindesay if (!_IsProtocolValid())
5238f30879bSAndrew Lindesay return false;
5248f30879bSAndrew Lindesay
5258f30879bSAndrew Lindesay // it is possible that there can be an authority but no host.
5268f30879bSAndrew Lindesay // wierd://tea:tree@/x
5278f30879bSAndrew Lindesay if (HasHost() && !(fHost.IsEmpty() && HasAuthority()) && !_IsHostValid())
5288f30879bSAndrew Lindesay return false;
5298f30879bSAndrew Lindesay
5302c26ad4bSAdrien Destugues if (fProtocol == "http" || fProtocol == "https" || fProtocol == "ftp"
5312c26ad4bSAdrien Destugues || fProtocol == "ipp" || fProtocol == "afp" || fProtocol == "telnet"
5322c26ad4bSAdrien Destugues || fProtocol == "gopher" || fProtocol == "nntp" || fProtocol == "sftp"
5332c26ad4bSAdrien Destugues || fProtocol == "finger" || fProtocol == "pop" || fProtocol == "imap") {
5348f30879bSAndrew Lindesay return HasHost() && !fHost.IsEmpty();
5352c26ad4bSAdrien Destugues }
5362c26ad4bSAdrien Destugues
5372c26ad4bSAdrien Destugues if (fProtocol == "file")
5382c26ad4bSAdrien Destugues return fHasPath;
5392c26ad4bSAdrien Destugues
5402c26ad4bSAdrien Destugues return true;
5412c26ad4bSAdrien Destugues }
5422c26ad4bSAdrien Destugues
5432c26ad4bSAdrien Destugues
5442c26ad4bSAdrien Destugues bool
HasProtocol() const5452c26ad4bSAdrien Destugues BUrl::HasProtocol() const
5462c26ad4bSAdrien Destugues {
5472c26ad4bSAdrien Destugues return fHasProtocol;
5482c26ad4bSAdrien Destugues }
5492c26ad4bSAdrien Destugues
5502c26ad4bSAdrien Destugues
5512c26ad4bSAdrien Destugues bool
HasAuthority() const5522c26ad4bSAdrien Destugues BUrl::HasAuthority() const
5532c26ad4bSAdrien Destugues {
5542c26ad4bSAdrien Destugues return fHasHost || fHasUserName;
5552c26ad4bSAdrien Destugues }
5562c26ad4bSAdrien Destugues
5572c26ad4bSAdrien Destugues
5582c26ad4bSAdrien Destugues bool
HasUserName() const5592c26ad4bSAdrien Destugues BUrl::HasUserName() const
5602c26ad4bSAdrien Destugues {
5612c26ad4bSAdrien Destugues return fHasUserName;
5622c26ad4bSAdrien Destugues }
5632c26ad4bSAdrien Destugues
5642c26ad4bSAdrien Destugues
5652c26ad4bSAdrien Destugues bool
HasPassword() const5662c26ad4bSAdrien Destugues BUrl::HasPassword() const
5672c26ad4bSAdrien Destugues {
5682c26ad4bSAdrien Destugues return fHasPassword;
5692c26ad4bSAdrien Destugues }
5702c26ad4bSAdrien Destugues
5712c26ad4bSAdrien Destugues
5722c26ad4bSAdrien Destugues bool
HasUserInfo() const5732c26ad4bSAdrien Destugues BUrl::HasUserInfo() const
5742c26ad4bSAdrien Destugues {
5752c26ad4bSAdrien Destugues return fHasUserName || fHasPassword;
5762c26ad4bSAdrien Destugues }
5772c26ad4bSAdrien Destugues
5782c26ad4bSAdrien Destugues
5792c26ad4bSAdrien Destugues bool
HasHost() const5802c26ad4bSAdrien Destugues BUrl::HasHost() const
5812c26ad4bSAdrien Destugues {
5822c26ad4bSAdrien Destugues return fHasHost;
5832c26ad4bSAdrien Destugues }
5842c26ad4bSAdrien Destugues
5852c26ad4bSAdrien Destugues
5862c26ad4bSAdrien Destugues bool
HasPort() const5872c26ad4bSAdrien Destugues BUrl::HasPort() const
5882c26ad4bSAdrien Destugues {
5892c26ad4bSAdrien Destugues return fHasPort;
5902c26ad4bSAdrien Destugues }
5912c26ad4bSAdrien Destugues
5922c26ad4bSAdrien Destugues
5932c26ad4bSAdrien Destugues bool
HasPath() const5942c26ad4bSAdrien Destugues BUrl::HasPath() const
5952c26ad4bSAdrien Destugues {
5962c26ad4bSAdrien Destugues return fHasPath;
5972c26ad4bSAdrien Destugues }
5982c26ad4bSAdrien Destugues
5992c26ad4bSAdrien Destugues
6002c26ad4bSAdrien Destugues bool
HasRequest() const6012c26ad4bSAdrien Destugues BUrl::HasRequest() const
6022c26ad4bSAdrien Destugues {
6032c26ad4bSAdrien Destugues return fHasRequest;
6042c26ad4bSAdrien Destugues }
6052c26ad4bSAdrien Destugues
6062c26ad4bSAdrien Destugues
6072c26ad4bSAdrien Destugues bool
HasFragment() const6082c26ad4bSAdrien Destugues BUrl::HasFragment() const
6092c26ad4bSAdrien Destugues {
6102c26ad4bSAdrien Destugues return fHasFragment;
6112c26ad4bSAdrien Destugues }
6122c26ad4bSAdrien Destugues
6132c26ad4bSAdrien Destugues
6142c26ad4bSAdrien Destugues // #pragma mark URL encoding/decoding of needed fields
6152c26ad4bSAdrien Destugues
6162c26ad4bSAdrien Destugues
6172c26ad4bSAdrien Destugues void
UrlEncode(bool strict)6182c26ad4bSAdrien Destugues BUrl::UrlEncode(bool strict)
6192c26ad4bSAdrien Destugues {
6202c26ad4bSAdrien Destugues fUser = _DoUrlEncodeChunk(fUser, strict);
6212c26ad4bSAdrien Destugues fPassword = _DoUrlEncodeChunk(fPassword, strict);
6222c26ad4bSAdrien Destugues fHost = _DoUrlEncodeChunk(fHost, strict);
6232c26ad4bSAdrien Destugues fFragment = _DoUrlEncodeChunk(fFragment, strict);
6242c26ad4bSAdrien Destugues fPath = _DoUrlEncodeChunk(fPath, strict, true);
6252c26ad4bSAdrien Destugues }
6262c26ad4bSAdrien Destugues
6272c26ad4bSAdrien Destugues
6282c26ad4bSAdrien Destugues void
UrlDecode(bool strict)6292c26ad4bSAdrien Destugues BUrl::UrlDecode(bool strict)
6302c26ad4bSAdrien Destugues {
6312c26ad4bSAdrien Destugues fUser = _DoUrlDecodeChunk(fUser, strict);
6322c26ad4bSAdrien Destugues fPassword = _DoUrlDecodeChunk(fPassword, strict);
6332c26ad4bSAdrien Destugues fHost = _DoUrlDecodeChunk(fHost, strict);
6342c26ad4bSAdrien Destugues fFragment = _DoUrlDecodeChunk(fFragment, strict);
6352c26ad4bSAdrien Destugues fPath = _DoUrlDecodeChunk(fPath, strict);
6362c26ad4bSAdrien Destugues }
6372c26ad4bSAdrien Destugues
6382c26ad4bSAdrien Destugues
6392c26ad4bSAdrien Destugues #ifdef HAIKU_TARGET_PLATFORM_HAIKU
6402c26ad4bSAdrien Destugues status_t
IDNAToAscii()6412c26ad4bSAdrien Destugues BUrl::IDNAToAscii()
6422c26ad4bSAdrien Destugues {
6432c26ad4bSAdrien Destugues UErrorCode err = U_ZERO_ERROR;
6442c26ad4bSAdrien Destugues icu::IDNA* converter = icu::IDNA::createUTS46Instance(0, err);
6452c26ad4bSAdrien Destugues icu::IDNAInfo info;
6462c26ad4bSAdrien Destugues
6472c26ad4bSAdrien Destugues BString result;
6482c26ad4bSAdrien Destugues BStringByteSink sink(&result);
6492c26ad4bSAdrien Destugues converter->nameToASCII_UTF8(icu::StringPiece(fHost.String()), sink, info,
6502c26ad4bSAdrien Destugues err);
6512c26ad4bSAdrien Destugues
6522c26ad4bSAdrien Destugues delete converter;
6532c26ad4bSAdrien Destugues
6542c26ad4bSAdrien Destugues if (U_FAILURE(err))
6552c26ad4bSAdrien Destugues return B_ERROR;
6562c26ad4bSAdrien Destugues
6572c26ad4bSAdrien Destugues fHost = result;
6582c26ad4bSAdrien Destugues return B_OK;
6592c26ad4bSAdrien Destugues }
6602c26ad4bSAdrien Destugues #endif
6612c26ad4bSAdrien Destugues
6622c26ad4bSAdrien Destugues
6632c26ad4bSAdrien Destugues #ifdef HAIKU_TARGET_PLATFORM_HAIKU
6642c26ad4bSAdrien Destugues status_t
IDNAToUnicode()6652c26ad4bSAdrien Destugues BUrl::IDNAToUnicode()
6662c26ad4bSAdrien Destugues {
6672c26ad4bSAdrien Destugues UErrorCode err = U_ZERO_ERROR;
6682c26ad4bSAdrien Destugues icu::IDNA* converter = icu::IDNA::createUTS46Instance(0, err);
6692c26ad4bSAdrien Destugues icu::IDNAInfo info;
6702c26ad4bSAdrien Destugues
6712c26ad4bSAdrien Destugues BString result;
6722c26ad4bSAdrien Destugues BStringByteSink sink(&result);
6732c26ad4bSAdrien Destugues converter->nameToUnicodeUTF8(icu::StringPiece(fHost.String()), sink, info,
6742c26ad4bSAdrien Destugues err);
6752c26ad4bSAdrien Destugues
6762c26ad4bSAdrien Destugues delete converter;
6772c26ad4bSAdrien Destugues
6782c26ad4bSAdrien Destugues if (U_FAILURE(err))
6792c26ad4bSAdrien Destugues return B_ERROR;
6802c26ad4bSAdrien Destugues
6812c26ad4bSAdrien Destugues fHost = result;
6822c26ad4bSAdrien Destugues return B_OK;
6832c26ad4bSAdrien Destugues }
6842c26ad4bSAdrien Destugues #endif
6852c26ad4bSAdrien Destugues
6862c26ad4bSAdrien Destugues
6872c26ad4bSAdrien Destugues // #pragma mark - utility functionality
6882c26ad4bSAdrien Destugues
6892c26ad4bSAdrien Destugues
6902c26ad4bSAdrien Destugues #ifdef HAIKU_TARGET_PLATFORM_HAIKU
6912c26ad4bSAdrien Destugues bool
HasPreferredApplication() const6922c26ad4bSAdrien Destugues BUrl::HasPreferredApplication() const
6932c26ad4bSAdrien Destugues {
6942c26ad4bSAdrien Destugues BString appSignature = PreferredApplication();
6952c26ad4bSAdrien Destugues BMimeType mime(appSignature.String());
6962c26ad4bSAdrien Destugues
6972c26ad4bSAdrien Destugues if (appSignature.IFindFirst("application/") == 0
6982c26ad4bSAdrien Destugues && mime.IsValid())
6992c26ad4bSAdrien Destugues return true;
7002c26ad4bSAdrien Destugues
7012c26ad4bSAdrien Destugues return false;
7022c26ad4bSAdrien Destugues }
7032c26ad4bSAdrien Destugues #endif
7042c26ad4bSAdrien Destugues
7052c26ad4bSAdrien Destugues
7062c26ad4bSAdrien Destugues #ifdef HAIKU_TARGET_PLATFORM_HAIKU
7072c26ad4bSAdrien Destugues BString
PreferredApplication() const7082c26ad4bSAdrien Destugues BUrl::PreferredApplication() const
7092c26ad4bSAdrien Destugues {
7102c26ad4bSAdrien Destugues BString appSignature;
7112c26ad4bSAdrien Destugues BMimeType mime(_UrlMimeType().String());
7122c26ad4bSAdrien Destugues mime.GetPreferredApp(appSignature.LockBuffer(B_MIME_TYPE_LENGTH));
7132c26ad4bSAdrien Destugues appSignature.UnlockBuffer();
7142c26ad4bSAdrien Destugues
7152c26ad4bSAdrien Destugues return BString(appSignature);
7162c26ad4bSAdrien Destugues }
7172c26ad4bSAdrien Destugues #endif
7182c26ad4bSAdrien Destugues
7192c26ad4bSAdrien Destugues
7202c26ad4bSAdrien Destugues #ifdef HAIKU_TARGET_PLATFORM_HAIKU
7212c26ad4bSAdrien Destugues status_t
OpenWithPreferredApplication(bool onProblemAskUser) const7222c26ad4bSAdrien Destugues BUrl::OpenWithPreferredApplication(bool onProblemAskUser) const
7232c26ad4bSAdrien Destugues {
7242c26ad4bSAdrien Destugues if (!IsValid())
7252c26ad4bSAdrien Destugues return B_BAD_VALUE;
7262c26ad4bSAdrien Destugues
7272c26ad4bSAdrien Destugues BString urlString = UrlString();
7282c26ad4bSAdrien Destugues if (urlString.Length() > B_PATH_NAME_LENGTH) {
7292c26ad4bSAdrien Destugues // TODO: BAlert
7302c26ad4bSAdrien Destugues // if (onProblemAskUser)
7312c26ad4bSAdrien Destugues // BAlert ... Too long URL!
7322c26ad4bSAdrien Destugues #if DEBUG
7332c26ad4bSAdrien Destugues fprintf(stderr, "URL too long");
7342c26ad4bSAdrien Destugues #endif
7352c26ad4bSAdrien Destugues return B_NAME_TOO_LONG;
7362c26ad4bSAdrien Destugues }
7372c26ad4bSAdrien Destugues
7382c26ad4bSAdrien Destugues char* argv[] = {
7392c26ad4bSAdrien Destugues const_cast<char*>("BUrlInvokedApplication"),
7402c26ad4bSAdrien Destugues const_cast<char*>(urlString.String()),
7412c26ad4bSAdrien Destugues NULL
7422c26ad4bSAdrien Destugues };
7432c26ad4bSAdrien Destugues
7442c26ad4bSAdrien Destugues #if DEBUG
7452c26ad4bSAdrien Destugues if (HasPreferredApplication())
7462c26ad4bSAdrien Destugues printf("HasPreferredApplication() == true\n");
7472c26ad4bSAdrien Destugues else
7482c26ad4bSAdrien Destugues printf("HasPreferredApplication() == false\n");
7492c26ad4bSAdrien Destugues #endif
7502c26ad4bSAdrien Destugues
7512c26ad4bSAdrien Destugues status_t status = be_roster->Launch(_UrlMimeType().String(), 1, argv+1);
7522c26ad4bSAdrien Destugues if (status != B_OK) {
7532c26ad4bSAdrien Destugues #if DEBUG
7542c26ad4bSAdrien Destugues fprintf(stderr, "Opening URL failed: %s\n", strerror(status));
7552c26ad4bSAdrien Destugues #endif
7562c26ad4bSAdrien Destugues }
7572c26ad4bSAdrien Destugues
7582c26ad4bSAdrien Destugues return status;
7592c26ad4bSAdrien Destugues }
7602c26ad4bSAdrien Destugues #endif
7612c26ad4bSAdrien Destugues
7622c26ad4bSAdrien Destugues
7632c26ad4bSAdrien Destugues // #pragma mark Url encoding/decoding of string
7642c26ad4bSAdrien Destugues
7652c26ad4bSAdrien Destugues
7662c26ad4bSAdrien Destugues /*static*/ BString
UrlEncode(const BString & url,bool strict,bool directory)7672c26ad4bSAdrien Destugues BUrl::UrlEncode(const BString& url, bool strict, bool directory)
7682c26ad4bSAdrien Destugues {
7692c26ad4bSAdrien Destugues return _DoUrlEncodeChunk(url, strict, directory);
7702c26ad4bSAdrien Destugues }
7712c26ad4bSAdrien Destugues
7722c26ad4bSAdrien Destugues
7732c26ad4bSAdrien Destugues /*static*/ BString
UrlDecode(const BString & url,bool strict)7742c26ad4bSAdrien Destugues BUrl::UrlDecode(const BString& url, bool strict)
7752c26ad4bSAdrien Destugues {
7762c26ad4bSAdrien Destugues return _DoUrlDecodeChunk(url, strict);
7772c26ad4bSAdrien Destugues }
7782c26ad4bSAdrien Destugues
7792c26ad4bSAdrien Destugues
7802c26ad4bSAdrien Destugues // #pragma mark BArchivable members
7812c26ad4bSAdrien Destugues
7822c26ad4bSAdrien Destugues
7832c26ad4bSAdrien Destugues status_t
Archive(BMessage * into,bool deep) const7842c26ad4bSAdrien Destugues BUrl::Archive(BMessage* into, bool deep) const
7852c26ad4bSAdrien Destugues {
7862c26ad4bSAdrien Destugues status_t ret = BArchivable::Archive(into, deep);
7872c26ad4bSAdrien Destugues
7882c26ad4bSAdrien Destugues if (ret == B_OK)
7892c26ad4bSAdrien Destugues ret = into->AddString(kArchivedUrl, UrlString());
7902c26ad4bSAdrien Destugues
7912c26ad4bSAdrien Destugues return ret;
7922c26ad4bSAdrien Destugues }
7932c26ad4bSAdrien Destugues
7942c26ad4bSAdrien Destugues
7952c26ad4bSAdrien Destugues /*static*/ BArchivable*
Instantiate(BMessage * archive)7962c26ad4bSAdrien Destugues BUrl::Instantiate(BMessage* archive)
7972c26ad4bSAdrien Destugues {
7982c26ad4bSAdrien Destugues if (validate_instantiation(archive, "BUrl"))
7992c26ad4bSAdrien Destugues return new(std::nothrow) BUrl(archive);
8002c26ad4bSAdrien Destugues return NULL;
8012c26ad4bSAdrien Destugues }
8022c26ad4bSAdrien Destugues
8032c26ad4bSAdrien Destugues
8042c26ad4bSAdrien Destugues // #pragma mark URL comparison
8052c26ad4bSAdrien Destugues
8062c26ad4bSAdrien Destugues
8072c26ad4bSAdrien Destugues bool
operator ==(BUrl & other) const8082c26ad4bSAdrien Destugues BUrl::operator==(BUrl& other) const
8092c26ad4bSAdrien Destugues {
8102c26ad4bSAdrien Destugues UrlString();
8112c26ad4bSAdrien Destugues other.UrlString();
8122c26ad4bSAdrien Destugues
8132c26ad4bSAdrien Destugues return fUrlString == other.fUrlString;
8142c26ad4bSAdrien Destugues }
8152c26ad4bSAdrien Destugues
8162c26ad4bSAdrien Destugues
8172c26ad4bSAdrien Destugues bool
operator !=(BUrl & other) const8182c26ad4bSAdrien Destugues BUrl::operator!=(BUrl& other) const
8192c26ad4bSAdrien Destugues {
8202c26ad4bSAdrien Destugues return !(*this == other);
8212c26ad4bSAdrien Destugues }
8222c26ad4bSAdrien Destugues
8232c26ad4bSAdrien Destugues
8242c26ad4bSAdrien Destugues // #pragma mark URL assignment
8252c26ad4bSAdrien Destugues
8262c26ad4bSAdrien Destugues
8272c26ad4bSAdrien Destugues const BUrl&
operator =(const BUrl & other)8282c26ad4bSAdrien Destugues BUrl::operator=(const BUrl& other)
8292c26ad4bSAdrien Destugues {
8302c26ad4bSAdrien Destugues fUrlStringValid = other.fUrlStringValid;
8312c26ad4bSAdrien Destugues if (fUrlStringValid)
8322c26ad4bSAdrien Destugues fUrlString = other.fUrlString;
8332c26ad4bSAdrien Destugues
8342c26ad4bSAdrien Destugues fAuthorityValid = other.fAuthorityValid;
8352c26ad4bSAdrien Destugues if (fAuthorityValid)
8362c26ad4bSAdrien Destugues fAuthority = other.fAuthority;
8372c26ad4bSAdrien Destugues
8382c26ad4bSAdrien Destugues fUserInfoValid = other.fUserInfoValid;
8392c26ad4bSAdrien Destugues if (fUserInfoValid)
8402c26ad4bSAdrien Destugues fUserInfo = other.fUserInfo;
8412c26ad4bSAdrien Destugues
8422c26ad4bSAdrien Destugues fProtocol = other.fProtocol;
8432c26ad4bSAdrien Destugues fUser = other.fUser;
8442c26ad4bSAdrien Destugues fPassword = other.fPassword;
8452c26ad4bSAdrien Destugues fHost = other.fHost;
8462c26ad4bSAdrien Destugues fPort = other.fPort;
8472c26ad4bSAdrien Destugues fPath = other.fPath;
8482c26ad4bSAdrien Destugues fRequest = other.fRequest;
8492c26ad4bSAdrien Destugues fFragment = other.fFragment;
8502c26ad4bSAdrien Destugues
8512c26ad4bSAdrien Destugues fHasProtocol = other.fHasProtocol;
8522c26ad4bSAdrien Destugues fHasUserName = other.fHasUserName;
8532c26ad4bSAdrien Destugues fHasPassword = other.fHasPassword;
8542c26ad4bSAdrien Destugues fHasHost = other.fHasHost;
8552c26ad4bSAdrien Destugues fHasPort = other.fHasPort;
8562c26ad4bSAdrien Destugues fHasPath = other.fHasPath;
8572c26ad4bSAdrien Destugues fHasRequest = other.fHasRequest;
8582c26ad4bSAdrien Destugues fHasFragment = other.fHasFragment;
8592c26ad4bSAdrien Destugues
8602c26ad4bSAdrien Destugues return *this;
8612c26ad4bSAdrien Destugues }
8622c26ad4bSAdrien Destugues
8632c26ad4bSAdrien Destugues
8642c26ad4bSAdrien Destugues const BUrl&
operator =(const BString & string)8652c26ad4bSAdrien Destugues BUrl::operator=(const BString& string)
8662c26ad4bSAdrien Destugues {
8672c26ad4bSAdrien Destugues SetUrlString(string);
8682c26ad4bSAdrien Destugues return *this;
8692c26ad4bSAdrien Destugues }
8702c26ad4bSAdrien Destugues
8712c26ad4bSAdrien Destugues
8722c26ad4bSAdrien Destugues const BUrl&
operator =(const char * string)8732c26ad4bSAdrien Destugues BUrl::operator=(const char* string)
8742c26ad4bSAdrien Destugues {
8752c26ad4bSAdrien Destugues SetUrlString(string);
8762c26ad4bSAdrien Destugues return *this;
8772c26ad4bSAdrien Destugues }
8782c26ad4bSAdrien Destugues
8792c26ad4bSAdrien Destugues
8802c26ad4bSAdrien Destugues // #pragma mark URL to string conversion
8812c26ad4bSAdrien Destugues
8822c26ad4bSAdrien Destugues
operator const char*() const8832c26ad4bSAdrien Destugues BUrl::operator const char*() const
8842c26ad4bSAdrien Destugues {
8852c26ad4bSAdrien Destugues return UrlString();
8862c26ad4bSAdrien Destugues }
8872c26ad4bSAdrien Destugues
8882c26ad4bSAdrien Destugues
8892c26ad4bSAdrien Destugues void
_ResetFields()8902c26ad4bSAdrien Destugues BUrl::_ResetFields()
8912c26ad4bSAdrien Destugues {
8922c26ad4bSAdrien Destugues fHasProtocol = false;
8932c26ad4bSAdrien Destugues fHasUserName = false;
8942c26ad4bSAdrien Destugues fHasPassword = false;
8952c26ad4bSAdrien Destugues fHasHost = false;
8962c26ad4bSAdrien Destugues fHasPort = false;
8972c26ad4bSAdrien Destugues fHasPath = false;
8982c26ad4bSAdrien Destugues fHasRequest = false;
8992c26ad4bSAdrien Destugues fHasFragment = false;
9002c26ad4bSAdrien Destugues
9012c26ad4bSAdrien Destugues fProtocol.Truncate(0);
9022c26ad4bSAdrien Destugues fUser.Truncate(0);
9032c26ad4bSAdrien Destugues fPassword.Truncate(0);
9042c26ad4bSAdrien Destugues fHost.Truncate(0);
9052c26ad4bSAdrien Destugues fPort = 0;
9062c26ad4bSAdrien Destugues fPath.Truncate(0);
9072c26ad4bSAdrien Destugues fRequest.Truncate(0);
9082c26ad4bSAdrien Destugues fFragment.Truncate(0);
9092c26ad4bSAdrien Destugues
9102c26ad4bSAdrien Destugues // Force re-generation of these fields
9112c26ad4bSAdrien Destugues fUrlStringValid = false;
9122c26ad4bSAdrien Destugues fUserInfoValid = false;
9132c26ad4bSAdrien Destugues fAuthorityValid = false;
9142c26ad4bSAdrien Destugues }
9152c26ad4bSAdrien Destugues
9162c26ad4bSAdrien Destugues
9172c26ad4bSAdrien Destugues bool
_ContainsDelimiter(const BString & url)9182c26ad4bSAdrien Destugues BUrl::_ContainsDelimiter(const BString& url)
9192c26ad4bSAdrien Destugues {
9202c26ad4bSAdrien Destugues int32 len = url.Length();
9212c26ad4bSAdrien Destugues
9222c26ad4bSAdrien Destugues for (int32 i = 0; i < len; i++) {
9232c26ad4bSAdrien Destugues switch (url[i]) {
9242c26ad4bSAdrien Destugues case ' ':
9252c26ad4bSAdrien Destugues case '\n':
9262c26ad4bSAdrien Destugues case '\t':
9272c26ad4bSAdrien Destugues case '\r':
9282c26ad4bSAdrien Destugues case '<':
9292c26ad4bSAdrien Destugues case '>':
9302c26ad4bSAdrien Destugues case '"':
9312c26ad4bSAdrien Destugues return true;
9322c26ad4bSAdrien Destugues }
9332c26ad4bSAdrien Destugues }
9342c26ad4bSAdrien Destugues
9352c26ad4bSAdrien Destugues return false;
9362c26ad4bSAdrien Destugues }
9372c26ad4bSAdrien Destugues
9382c26ad4bSAdrien Destugues
9392c26ad4bSAdrien Destugues enum explode_url_parse_state {
9402c26ad4bSAdrien Destugues EXPLODE_PROTOCOL,
9412c26ad4bSAdrien Destugues EXPLODE_PROTOCOLTERMINATOR,
9422c26ad4bSAdrien Destugues EXPLODE_AUTHORITYORPATH,
9432c26ad4bSAdrien Destugues EXPLODE_AUTHORITY,
9442c26ad4bSAdrien Destugues EXPLODE_PATH,
9452c26ad4bSAdrien Destugues EXPLODE_REQUEST, // query
9462c26ad4bSAdrien Destugues EXPLODE_FRAGMENT,
9472c26ad4bSAdrien Destugues EXPLODE_COMPLETE
9482c26ad4bSAdrien Destugues };
9492c26ad4bSAdrien Destugues
9502c26ad4bSAdrien Destugues
9512c26ad4bSAdrien Destugues typedef bool (*explode_char_match_fn)(char c);
9522c26ad4bSAdrien Destugues
9532c26ad4bSAdrien Destugues
9542c26ad4bSAdrien Destugues static bool
explode_is_protocol_char(char c)9552c26ad4bSAdrien Destugues explode_is_protocol_char(char c)
9562c26ad4bSAdrien Destugues {
9572c26ad4bSAdrien Destugues return isalnum(c) || c == '+' || c == '.' || c == '-';
9582c26ad4bSAdrien Destugues }
9592c26ad4bSAdrien Destugues
9602c26ad4bSAdrien Destugues
9612c26ad4bSAdrien Destugues static bool
explode_is_authority_char(char c)9622c26ad4bSAdrien Destugues explode_is_authority_char(char c)
9632c26ad4bSAdrien Destugues {
9642c26ad4bSAdrien Destugues return !(c == '/' || c == '?' || c == '#');
9652c26ad4bSAdrien Destugues }
9662c26ad4bSAdrien Destugues
9672c26ad4bSAdrien Destugues
9682c26ad4bSAdrien Destugues static bool
explode_is_path_char(char c)9692c26ad4bSAdrien Destugues explode_is_path_char(char c)
9702c26ad4bSAdrien Destugues {
9712c26ad4bSAdrien Destugues return !(c == '#' || c == '?');
9722c26ad4bSAdrien Destugues }
9732c26ad4bSAdrien Destugues
9742c26ad4bSAdrien Destugues
9752c26ad4bSAdrien Destugues static bool
explode_is_request_char(char c)9762c26ad4bSAdrien Destugues explode_is_request_char(char c)
9772c26ad4bSAdrien Destugues {
9782c26ad4bSAdrien Destugues return c != '#';
9792c26ad4bSAdrien Destugues }
9802c26ad4bSAdrien Destugues
9812c26ad4bSAdrien Destugues
9822c26ad4bSAdrien Destugues static int32
char_offset_until_fn_false(const char * url,int32 len,int32 offset,explode_char_match_fn fn)9832c26ad4bSAdrien Destugues char_offset_until_fn_false(const char* url, int32 len, int32 offset,
9842c26ad4bSAdrien Destugues explode_char_match_fn fn)
9852c26ad4bSAdrien Destugues {
9862c26ad4bSAdrien Destugues while (offset < len && fn(url[offset]))
9872c26ad4bSAdrien Destugues offset++;
9882c26ad4bSAdrien Destugues
9892c26ad4bSAdrien Destugues return offset;
9902c26ad4bSAdrien Destugues }
9912c26ad4bSAdrien Destugues
9922c26ad4bSAdrien Destugues /*
9932c26ad4bSAdrien Destugues * This function takes a URL in string-form and parses the components of the URL out.
9942c26ad4bSAdrien Destugues */
9952c26ad4bSAdrien Destugues status_t
_ExplodeUrlString(const BString & url,uint32 flags)996*a609673cSAndrew Lindesay BUrl::_ExplodeUrlString(const BString& url, uint32 flags)
9972c26ad4bSAdrien Destugues {
9982c26ad4bSAdrien Destugues _ResetFields();
9992c26ad4bSAdrien Destugues
10002c26ad4bSAdrien Destugues // RFC3986, Appendix C; the URL should not contain whitespace or delimiters
10012c26ad4bSAdrien Destugues // by this point.
10022c26ad4bSAdrien Destugues
10032c26ad4bSAdrien Destugues if (_ContainsDelimiter(url))
10042c26ad4bSAdrien Destugues return B_BAD_VALUE;
10052c26ad4bSAdrien Destugues
10062c26ad4bSAdrien Destugues explode_url_parse_state state = EXPLODE_PROTOCOL;
10072c26ad4bSAdrien Destugues int32 offset = 0;
10082c26ad4bSAdrien Destugues int32 length = url.Length();
10093cc5e76fSAndrew Lindesay bool forceHasHost = false;
10102c26ad4bSAdrien Destugues const char *url_c = url.String();
10112c26ad4bSAdrien Destugues
10122c26ad4bSAdrien Destugues // The regexp is provided in RFC3986 (URI generic syntax), Appendix B
10132c26ad4bSAdrien Destugues // ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?
10142c26ad4bSAdrien Destugues // The ensuing logic attempts to simulate the behaviour of extracting the groups
10152c26ad4bSAdrien Destugues // from the string without requiring a group-capable regex engine.
10162c26ad4bSAdrien Destugues
10172c26ad4bSAdrien Destugues while (offset < length) {
10182c26ad4bSAdrien Destugues switch (state) {
10192c26ad4bSAdrien Destugues
10202c26ad4bSAdrien Destugues case EXPLODE_PROTOCOL:
10212c26ad4bSAdrien Destugues {
10222c26ad4bSAdrien Destugues int32 end_protocol = char_offset_until_fn_false(url_c, length,
10232c26ad4bSAdrien Destugues offset, explode_is_protocol_char);
10242c26ad4bSAdrien Destugues
10252c26ad4bSAdrien Destugues if (end_protocol < length) {
10262c26ad4bSAdrien Destugues SetProtocol(BString(&url_c[offset], end_protocol - offset));
10272c26ad4bSAdrien Destugues state = EXPLODE_PROTOCOLTERMINATOR;
10282c26ad4bSAdrien Destugues offset = end_protocol;
10292c26ad4bSAdrien Destugues } else {
10302c26ad4bSAdrien Destugues // No protocol was found, try parsing from the string
10312c26ad4bSAdrien Destugues // start, beginning with authority or path
10322c26ad4bSAdrien Destugues SetProtocol("");
10332c26ad4bSAdrien Destugues offset = 0;
10342c26ad4bSAdrien Destugues state = EXPLODE_AUTHORITYORPATH;
10352c26ad4bSAdrien Destugues }
10362c26ad4bSAdrien Destugues break;
10372c26ad4bSAdrien Destugues }
10382c26ad4bSAdrien Destugues
10392c26ad4bSAdrien Destugues case EXPLODE_PROTOCOLTERMINATOR:
10402c26ad4bSAdrien Destugues {
10412c26ad4bSAdrien Destugues if (url[offset] == ':') {
10422c26ad4bSAdrien Destugues offset++;
10432c26ad4bSAdrien Destugues } else {
10442c26ad4bSAdrien Destugues // No protocol was found, try parsing from the string
10452c26ad4bSAdrien Destugues // start, beginning with authority or path
10462c26ad4bSAdrien Destugues SetProtocol("");
10472c26ad4bSAdrien Destugues offset = 0;
10482c26ad4bSAdrien Destugues }
10492c26ad4bSAdrien Destugues state = EXPLODE_AUTHORITYORPATH;
10502c26ad4bSAdrien Destugues break;
10512c26ad4bSAdrien Destugues }
10522c26ad4bSAdrien Destugues
10532c26ad4bSAdrien Destugues case EXPLODE_AUTHORITYORPATH:
10542c26ad4bSAdrien Destugues {
10552c26ad4bSAdrien Destugues // The authority must start with //. If it isn't there, skip
10562c26ad4bSAdrien Destugues // to parsing the path.
10572c26ad4bSAdrien Destugues if (strncmp(&url_c[offset], "//", 2) == 0) {
10582c26ad4bSAdrien Destugues state = EXPLODE_AUTHORITY;
10593cc5e76fSAndrew Lindesay // if we see the // then this would imply that a host is
10603cc5e76fSAndrew Lindesay // to be rendered even if no host has been parsed.
10613cc5e76fSAndrew Lindesay forceHasHost = true;
10622c26ad4bSAdrien Destugues offset += 2;
10632c26ad4bSAdrien Destugues } else {
10642c26ad4bSAdrien Destugues state = EXPLODE_PATH;
10652c26ad4bSAdrien Destugues }
10662c26ad4bSAdrien Destugues break;
10672c26ad4bSAdrien Destugues }
10682c26ad4bSAdrien Destugues
10692c26ad4bSAdrien Destugues case EXPLODE_AUTHORITY:
10702c26ad4bSAdrien Destugues {
10712c26ad4bSAdrien Destugues int end_authority = char_offset_until_fn_false(url_c, length,
10722c26ad4bSAdrien Destugues offset, explode_is_authority_char);
10732c26ad4bSAdrien Destugues SetAuthority(BString(&url_c[offset], end_authority - offset));
10742c26ad4bSAdrien Destugues state = EXPLODE_PATH;
10752c26ad4bSAdrien Destugues offset = end_authority;
10762c26ad4bSAdrien Destugues break;
10772c26ad4bSAdrien Destugues }
10782c26ad4bSAdrien Destugues
10792c26ad4bSAdrien Destugues case EXPLODE_PATH:
10802c26ad4bSAdrien Destugues {
10812c26ad4bSAdrien Destugues int end_path = char_offset_until_fn_false(url_c, length, offset,
10822c26ad4bSAdrien Destugues explode_is_path_char);
1083*a609673cSAndrew Lindesay BString path(&url_c[offset], end_path - offset);
1084*a609673cSAndrew Lindesay
1085*a609673cSAndrew Lindesay if ((flags & PARSE_RAW_PATH_MASK_BIT) == 0)
1086*a609673cSAndrew Lindesay SetPath(path);
1087*a609673cSAndrew Lindesay else
1088*a609673cSAndrew Lindesay _SetPathUnsafe(path);
10892c26ad4bSAdrien Destugues state = EXPLODE_REQUEST;
10902c26ad4bSAdrien Destugues offset = end_path;
10912c26ad4bSAdrien Destugues break;
10922c26ad4bSAdrien Destugues }
10932c26ad4bSAdrien Destugues
10942c26ad4bSAdrien Destugues case EXPLODE_REQUEST: // query
10952c26ad4bSAdrien Destugues {
10962c26ad4bSAdrien Destugues if (url_c[offset] == '?') {
10972c26ad4bSAdrien Destugues offset++;
10982c26ad4bSAdrien Destugues int end_request = char_offset_until_fn_false(url_c, length,
10992c26ad4bSAdrien Destugues offset, explode_is_request_char);
11002c26ad4bSAdrien Destugues SetRequest(BString(&url_c[offset], end_request - offset));
11012c26ad4bSAdrien Destugues offset = end_request;
11023cc5e76fSAndrew Lindesay // if there is a "?" in the parse then it is clear that
11033cc5e76fSAndrew Lindesay // there is a 'request' / query present regardless if there
11043cc5e76fSAndrew Lindesay // are any valid key-value pairs.
11053cc5e76fSAndrew Lindesay fHasRequest = true;
11062c26ad4bSAdrien Destugues }
11072c26ad4bSAdrien Destugues state = EXPLODE_FRAGMENT;
11082c26ad4bSAdrien Destugues break;
11092c26ad4bSAdrien Destugues }
11102c26ad4bSAdrien Destugues
11112c26ad4bSAdrien Destugues case EXPLODE_FRAGMENT:
11122c26ad4bSAdrien Destugues {
11132c26ad4bSAdrien Destugues if (url_c[offset] == '#') {
11142c26ad4bSAdrien Destugues offset++;
11152c26ad4bSAdrien Destugues SetFragment(BString(&url_c[offset], length - offset));
11162c26ad4bSAdrien Destugues offset = length;
11172c26ad4bSAdrien Destugues }
11182c26ad4bSAdrien Destugues state = EXPLODE_COMPLETE;
11192c26ad4bSAdrien Destugues break;
11202c26ad4bSAdrien Destugues }
11212c26ad4bSAdrien Destugues
11222c26ad4bSAdrien Destugues case EXPLODE_COMPLETE:
11232c26ad4bSAdrien Destugues // should never be reached - keeps the compiler happy
11242c26ad4bSAdrien Destugues break;
11252c26ad4bSAdrien Destugues
11262c26ad4bSAdrien Destugues }
11272c26ad4bSAdrien Destugues }
11282c26ad4bSAdrien Destugues
11293cc5e76fSAndrew Lindesay if (forceHasHost)
11303cc5e76fSAndrew Lindesay fHasHost = true;
11313cc5e76fSAndrew Lindesay
11322c26ad4bSAdrien Destugues return B_OK;
11332c26ad4bSAdrien Destugues }
11342c26ad4bSAdrien Destugues
11352c26ad4bSAdrien Destugues
11362c26ad4bSAdrien Destugues BString
_MergePath(const BString & relative) const11372c26ad4bSAdrien Destugues BUrl::_MergePath(const BString& relative) const
11382c26ad4bSAdrien Destugues {
11392c26ad4bSAdrien Destugues // This implements RFC3986, Section 5.2.3.
1140cd6365c7SJérôme Duval if (HasAuthority() && fPath == "") {
11412c26ad4bSAdrien Destugues BString result("/");
11422c26ad4bSAdrien Destugues result << relative;
11432c26ad4bSAdrien Destugues return result;
11442c26ad4bSAdrien Destugues }
11452c26ad4bSAdrien Destugues
1146*a609673cSAndrew Lindesay int32 lastSlashIndex = fPath.FindLast("/");
1147*a609673cSAndrew Lindesay
1148*a609673cSAndrew Lindesay if (lastSlashIndex == B_ERROR)
1149*a609673cSAndrew Lindesay return relative;
1150*a609673cSAndrew Lindesay
1151*a609673cSAndrew Lindesay BString result;
1152*a609673cSAndrew Lindesay result.SetTo(fPath, lastSlashIndex + 1);
11532c26ad4bSAdrien Destugues result << relative;
11542c26ad4bSAdrien Destugues
11552c26ad4bSAdrien Destugues return result;
11562c26ad4bSAdrien Destugues }
11572c26ad4bSAdrien Destugues
11582c26ad4bSAdrien Destugues
11592c26ad4bSAdrien Destugues // This sets the path without normalizing it. If fed with a path that has . or
11602c26ad4bSAdrien Destugues // .. segments, this would make the URL invalid.
11612c26ad4bSAdrien Destugues void
_SetPathUnsafe(const BString & path)11622c26ad4bSAdrien Destugues BUrl::_SetPathUnsafe(const BString& path)
11632c26ad4bSAdrien Destugues {
11642c26ad4bSAdrien Destugues fPath = path;
11652c26ad4bSAdrien Destugues fHasPath = true; // RFC says an empty path is still a path
11662c26ad4bSAdrien Destugues fUrlStringValid = false;
11672c26ad4bSAdrien Destugues }
11682c26ad4bSAdrien Destugues
11692c26ad4bSAdrien Destugues
11702c26ad4bSAdrien Destugues enum authority_parse_state {
11712c26ad4bSAdrien Destugues AUTHORITY_USERNAME,
11722c26ad4bSAdrien Destugues AUTHORITY_PASSWORD,
11732c26ad4bSAdrien Destugues AUTHORITY_HOST,
11742c26ad4bSAdrien Destugues AUTHORITY_PORT,
11752c26ad4bSAdrien Destugues AUTHORITY_COMPLETE
11762c26ad4bSAdrien Destugues };
11772c26ad4bSAdrien Destugues
11782c26ad4bSAdrien Destugues void
SetAuthority(const BString & authority)11792c26ad4bSAdrien Destugues BUrl::SetAuthority(const BString& authority)
11802c26ad4bSAdrien Destugues {
11812c26ad4bSAdrien Destugues fAuthority = authority;
11822c26ad4bSAdrien Destugues
11832c26ad4bSAdrien Destugues fUser.Truncate(0);
11842c26ad4bSAdrien Destugues fPassword.Truncate(0);
11852c26ad4bSAdrien Destugues fHost.Truncate(0);
11862c26ad4bSAdrien Destugues fPort = 0;
11872c26ad4bSAdrien Destugues fHasPort = false;
11882c26ad4bSAdrien Destugues fHasUserName = false;
11892c26ad4bSAdrien Destugues fHasPassword = false;
11902c26ad4bSAdrien Destugues
11912c26ad4bSAdrien Destugues bool hasUsernamePassword = B_ERROR != fAuthority.FindFirst('@');
11922c26ad4bSAdrien Destugues authority_parse_state state = AUTHORITY_USERNAME;
11932c26ad4bSAdrien Destugues int32 offset = 0;
11942c26ad4bSAdrien Destugues int32 length = authority.Length();
11952c26ad4bSAdrien Destugues const char *authority_c = authority.String();
11962c26ad4bSAdrien Destugues
11972c26ad4bSAdrien Destugues while (AUTHORITY_COMPLETE != state && offset < length) {
11982c26ad4bSAdrien Destugues
11992c26ad4bSAdrien Destugues switch (state) {
12002c26ad4bSAdrien Destugues
12012c26ad4bSAdrien Destugues case AUTHORITY_USERNAME:
12022c26ad4bSAdrien Destugues {
12032c26ad4bSAdrien Destugues if (hasUsernamePassword) {
12042c26ad4bSAdrien Destugues int32 end_username = char_offset_until_fn_false(
12058f30879bSAndrew Lindesay authority_c, length, offset, _IsUsernameChar);
12062c26ad4bSAdrien Destugues
12072c26ad4bSAdrien Destugues SetUserName(BString(&authority_c[offset],
12082c26ad4bSAdrien Destugues end_username - offset));
12092c26ad4bSAdrien Destugues
12102c26ad4bSAdrien Destugues state = AUTHORITY_PASSWORD;
12112c26ad4bSAdrien Destugues offset = end_username;
12122c26ad4bSAdrien Destugues } else {
12132c26ad4bSAdrien Destugues state = AUTHORITY_HOST;
12142c26ad4bSAdrien Destugues }
12152c26ad4bSAdrien Destugues break;
12162c26ad4bSAdrien Destugues }
12172c26ad4bSAdrien Destugues
12182c26ad4bSAdrien Destugues case AUTHORITY_PASSWORD:
12192c26ad4bSAdrien Destugues {
12202c26ad4bSAdrien Destugues if (hasUsernamePassword && ':' == authority[offset]) {
12212c26ad4bSAdrien Destugues offset++; // move past the delimiter
12222c26ad4bSAdrien Destugues int32 end_password = char_offset_until_fn_false(
12238f30879bSAndrew Lindesay authority_c, length, offset, _IsPasswordChar);
12242c26ad4bSAdrien Destugues
12252c26ad4bSAdrien Destugues SetPassword(BString(&authority_c[offset],
12262c26ad4bSAdrien Destugues end_password - offset));
12272c26ad4bSAdrien Destugues
12282c26ad4bSAdrien Destugues offset = end_password;
12292c26ad4bSAdrien Destugues }
12302c26ad4bSAdrien Destugues
12312c26ad4bSAdrien Destugues // if the host was preceded by a username + password couple
12322c26ad4bSAdrien Destugues // then there will be an '@' delimiter to avoid.
12332c26ad4bSAdrien Destugues
12342c26ad4bSAdrien Destugues if (authority_c[offset] == '@') {
12352c26ad4bSAdrien Destugues offset++;
12362c26ad4bSAdrien Destugues }
12372c26ad4bSAdrien Destugues
12382c26ad4bSAdrien Destugues state = AUTHORITY_HOST;
12392c26ad4bSAdrien Destugues break;
12402c26ad4bSAdrien Destugues }
12412c26ad4bSAdrien Destugues
12422c26ad4bSAdrien Destugues case AUTHORITY_HOST:
12432c26ad4bSAdrien Destugues {
12442c26ad4bSAdrien Destugues
12452c26ad4bSAdrien Destugues // the host may be enclosed within brackets in order to express
12462c26ad4bSAdrien Destugues // an IPV6 address.
12472c26ad4bSAdrien Destugues
12482c26ad4bSAdrien Destugues if (authority_c[offset] == '[') {
12492c26ad4bSAdrien Destugues int32 end_ipv6_host = char_offset_until_fn_false(
12508f30879bSAndrew Lindesay authority_c, length, offset + 1, _IsIPV6Char);
12512c26ad4bSAdrien Destugues
12522c26ad4bSAdrien Destugues if (authority_c[end_ipv6_host] == ']') {
12532c26ad4bSAdrien Destugues SetHost(BString(&authority_c[offset],
12542c26ad4bSAdrien Destugues (end_ipv6_host - offset) + 1));
12552c26ad4bSAdrien Destugues state = AUTHORITY_PORT;
12562c26ad4bSAdrien Destugues offset = end_ipv6_host + 1;
12572c26ad4bSAdrien Destugues }
12582c26ad4bSAdrien Destugues }
12592c26ad4bSAdrien Destugues
12602c26ad4bSAdrien Destugues // if an IPV6 host was not found.
12612c26ad4bSAdrien Destugues
12622c26ad4bSAdrien Destugues if (AUTHORITY_HOST == state) {
12632c26ad4bSAdrien Destugues int32 end_host = char_offset_until_fn_false(
12648f30879bSAndrew Lindesay authority_c, length, offset, _IsHostChar);
12652c26ad4bSAdrien Destugues
12662c26ad4bSAdrien Destugues SetHost(BString(&authority_c[offset], end_host - offset));
12672c26ad4bSAdrien Destugues state = AUTHORITY_PORT;
12682c26ad4bSAdrien Destugues offset = end_host;
12692c26ad4bSAdrien Destugues }
12702c26ad4bSAdrien Destugues
12712c26ad4bSAdrien Destugues break;
12722c26ad4bSAdrien Destugues }
12732c26ad4bSAdrien Destugues
12742c26ad4bSAdrien Destugues case AUTHORITY_PORT:
12752c26ad4bSAdrien Destugues {
12762c26ad4bSAdrien Destugues if (authority_c[offset] == ':') {
12772c26ad4bSAdrien Destugues offset++;
12782c26ad4bSAdrien Destugues int32 end_port = char_offset_until_fn_false(
12798f30879bSAndrew Lindesay authority_c, length, offset, _IsPortChar);
12802c26ad4bSAdrien Destugues SetPort(atoi(&authority_c[offset]));
12812c26ad4bSAdrien Destugues offset = end_port;
12822c26ad4bSAdrien Destugues }
12832c26ad4bSAdrien Destugues
12842c26ad4bSAdrien Destugues state = AUTHORITY_COMPLETE;
12852c26ad4bSAdrien Destugues
12862c26ad4bSAdrien Destugues break;
12872c26ad4bSAdrien Destugues }
12882c26ad4bSAdrien Destugues
12892c26ad4bSAdrien Destugues case AUTHORITY_COMPLETE:
12902c26ad4bSAdrien Destugues // should never be reached - keeps the compiler happy
12912c26ad4bSAdrien Destugues break;
12922c26ad4bSAdrien Destugues }
12932c26ad4bSAdrien Destugues }
12942c26ad4bSAdrien Destugues
12952c26ad4bSAdrien Destugues // An empty authority is still an authority, making it possible to have
12962c26ad4bSAdrien Destugues // URLs such as file:///path/to/file.
12972c26ad4bSAdrien Destugues // TODO however, there is no way to unset the authority once it is set...
12982c26ad4bSAdrien Destugues // We may want to take a const char* parameter and allow NULL.
12992c26ad4bSAdrien Destugues fHasHost = true;
13002c26ad4bSAdrien Destugues }
13012c26ad4bSAdrien Destugues
13022c26ad4bSAdrien Destugues
13032c26ad4bSAdrien Destugues /*static*/ BString
_DoUrlEncodeChunk(const BString & chunk,bool strict,bool directory)13042c26ad4bSAdrien Destugues BUrl::_DoUrlEncodeChunk(const BString& chunk, bool strict, bool directory)
13052c26ad4bSAdrien Destugues {
13062c26ad4bSAdrien Destugues BString result;
13072c26ad4bSAdrien Destugues
13082c26ad4bSAdrien Destugues for (int32 i = 0; i < chunk.Length(); i++) {
13092c26ad4bSAdrien Destugues if (_IsUnreserved(chunk[i])
13102c26ad4bSAdrien Destugues || (directory && (chunk[i] == '/' || chunk[i] == '\\'))) {
13112c26ad4bSAdrien Destugues result << chunk[i];
13122c26ad4bSAdrien Destugues } else {
13132c26ad4bSAdrien Destugues if (chunk[i] == ' ' && !strict) {
13142c26ad4bSAdrien Destugues result << '+';
13152c26ad4bSAdrien Destugues // In non-strict mode, spaces are encoded by a plus sign
13162c26ad4bSAdrien Destugues } else {
13172c26ad4bSAdrien Destugues char hexString[5];
13182c26ad4bSAdrien Destugues snprintf(hexString, 5, "%X", chunk[i]);
13192c26ad4bSAdrien Destugues
13202c26ad4bSAdrien Destugues result << '%' << hexString;
13212c26ad4bSAdrien Destugues }
13222c26ad4bSAdrien Destugues }
13232c26ad4bSAdrien Destugues }
13242c26ad4bSAdrien Destugues
13252c26ad4bSAdrien Destugues return result;
13262c26ad4bSAdrien Destugues }
13272c26ad4bSAdrien Destugues
13282c26ad4bSAdrien Destugues
13292c26ad4bSAdrien Destugues /*static*/ BString
_DoUrlDecodeChunk(const BString & chunk,bool strict)13302c26ad4bSAdrien Destugues BUrl::_DoUrlDecodeChunk(const BString& chunk, bool strict)
13312c26ad4bSAdrien Destugues {
13322c26ad4bSAdrien Destugues BString result;
13332c26ad4bSAdrien Destugues
13342c26ad4bSAdrien Destugues for (int32 i = 0; i < chunk.Length(); i++) {
13352c26ad4bSAdrien Destugues if (chunk[i] == '+' && !strict)
13362c26ad4bSAdrien Destugues result << ' ';
13372c26ad4bSAdrien Destugues else {
13382c26ad4bSAdrien Destugues char decoded = 0;
13392c26ad4bSAdrien Destugues char* out = NULL;
13402c26ad4bSAdrien Destugues char hexString[3];
13412c26ad4bSAdrien Destugues
13422c26ad4bSAdrien Destugues if (chunk[i] == '%' && i < chunk.Length() - 2
13432c26ad4bSAdrien Destugues && isxdigit(chunk[i + 1]) && isxdigit(chunk[i+2])) {
13442c26ad4bSAdrien Destugues hexString[0] = chunk[i + 1];
13452c26ad4bSAdrien Destugues hexString[1] = chunk[i + 2];
13462c26ad4bSAdrien Destugues hexString[2] = 0;
13472c26ad4bSAdrien Destugues decoded = (char)strtol(hexString, &out, 16);
13482c26ad4bSAdrien Destugues }
13492c26ad4bSAdrien Destugues
13502c26ad4bSAdrien Destugues if (out == hexString + 2) {
13512c26ad4bSAdrien Destugues i += 2;
13522c26ad4bSAdrien Destugues result << decoded;
13532c26ad4bSAdrien Destugues } else
13542c26ad4bSAdrien Destugues result << chunk[i];
13552c26ad4bSAdrien Destugues }
13562c26ad4bSAdrien Destugues }
13572c26ad4bSAdrien Destugues return result;
13582c26ad4bSAdrien Destugues }
13592c26ad4bSAdrien Destugues
13602c26ad4bSAdrien Destugues
13612c26ad4bSAdrien Destugues bool
_IsHostIPV6Valid(size_t offset,int32 length) const13628f30879bSAndrew Lindesay BUrl::_IsHostIPV6Valid(size_t offset, int32 length) const
13638f30879bSAndrew Lindesay {
13648f30879bSAndrew Lindesay for (int32 i = 0; i < length; i++) {
13658f30879bSAndrew Lindesay char c = fHost[offset + i];
13668f30879bSAndrew Lindesay if (!_IsIPV6Char(c))
13678f30879bSAndrew Lindesay return false;
13688f30879bSAndrew Lindesay }
13698f30879bSAndrew Lindesay
13708f30879bSAndrew Lindesay return length > 0;
13718f30879bSAndrew Lindesay }
13728f30879bSAndrew Lindesay
13738f30879bSAndrew Lindesay
13748f30879bSAndrew Lindesay bool
_IsHostValid() const13758f30879bSAndrew Lindesay BUrl::_IsHostValid() const
13768f30879bSAndrew Lindesay {
13778f30879bSAndrew Lindesay if (fHost.StartsWith("[") && fHost.EndsWith("]"))
13788f30879bSAndrew Lindesay return _IsHostIPV6Valid(1, fHost.Length() - 2);
13798f30879bSAndrew Lindesay
13808f30879bSAndrew Lindesay bool lastWasDot = false;
13818f30879bSAndrew Lindesay
13828f30879bSAndrew Lindesay for (int32 i = 0; i < fHost.Length(); i++) {
13838f30879bSAndrew Lindesay char c = fHost[i];
13848f30879bSAndrew Lindesay
13858f30879bSAndrew Lindesay if (c == '.') {
13868f30879bSAndrew Lindesay if (lastWasDot || i == 0)
13878f30879bSAndrew Lindesay return false;
13888f30879bSAndrew Lindesay lastWasDot = true;
13898f30879bSAndrew Lindesay } else {
13908f30879bSAndrew Lindesay lastWasDot = false;
13918f30879bSAndrew Lindesay }
13928f30879bSAndrew Lindesay
13938f30879bSAndrew Lindesay if (!_IsHostChar(c) && c != '.') {
13948f30879bSAndrew Lindesay // the underscore is technically not allowed, but occurs sometimes
13958f30879bSAndrew Lindesay // in the wild.
13968f30879bSAndrew Lindesay return false;
13978f30879bSAndrew Lindesay }
13988f30879bSAndrew Lindesay }
13998f30879bSAndrew Lindesay
14008f30879bSAndrew Lindesay return true;
14018f30879bSAndrew Lindesay }
14028f30879bSAndrew Lindesay
14038f30879bSAndrew Lindesay
14048f30879bSAndrew Lindesay bool
_IsProtocolValid() const14058f30879bSAndrew Lindesay BUrl::_IsProtocolValid() const
14062c26ad4bSAdrien Destugues {
14072c26ad4bSAdrien Destugues for (int8 index = 0; index < fProtocol.Length(); index++) {
14082c26ad4bSAdrien Destugues char c = fProtocol[index];
14092c26ad4bSAdrien Destugues
14102c26ad4bSAdrien Destugues if (index == 0 && !isalpha(c))
14112c26ad4bSAdrien Destugues return false;
14122c26ad4bSAdrien Destugues else if (!isalnum(c) && c != '+' && c != '-' && c != '.')
14132c26ad4bSAdrien Destugues return false;
14142c26ad4bSAdrien Destugues }
14152c26ad4bSAdrien Destugues
14168f30879bSAndrew Lindesay return !fProtocol.IsEmpty();
14172c26ad4bSAdrien Destugues }
14182c26ad4bSAdrien Destugues
14192c26ad4bSAdrien Destugues
14202c26ad4bSAdrien Destugues bool
_IsUnreserved(char c)14212c26ad4bSAdrien Destugues BUrl::_IsUnreserved(char c)
14222c26ad4bSAdrien Destugues {
14232c26ad4bSAdrien Destugues return isalnum(c) || c == '-' || c == '.' || c == '_' || c == '~';
14242c26ad4bSAdrien Destugues }
14252c26ad4bSAdrien Destugues
14262c26ad4bSAdrien Destugues
14272c26ad4bSAdrien Destugues bool
_IsGenDelim(char c)14282c26ad4bSAdrien Destugues BUrl::_IsGenDelim(char c)
14292c26ad4bSAdrien Destugues {
14302c26ad4bSAdrien Destugues return c == ':' || c == '/' || c == '?' || c == '#' || c == '['
14312c26ad4bSAdrien Destugues || c == ']' || c == '@';
14322c26ad4bSAdrien Destugues }
14332c26ad4bSAdrien Destugues
14342c26ad4bSAdrien Destugues
14352c26ad4bSAdrien Destugues bool
_IsSubDelim(char c)14362c26ad4bSAdrien Destugues BUrl::_IsSubDelim(char c)
14372c26ad4bSAdrien Destugues {
14382c26ad4bSAdrien Destugues return c == '!' || c == '$' || c == '&' || c == '\'' || c == '('
14392c26ad4bSAdrien Destugues || c == ')' || c == '*' || c == '+' || c == ',' || c == ';'
14402c26ad4bSAdrien Destugues || c == '=';
14412c26ad4bSAdrien Destugues }
14422c26ad4bSAdrien Destugues
14432c26ad4bSAdrien Destugues
14448f30879bSAndrew Lindesay bool
_IsUsernameChar(char c)14458f30879bSAndrew Lindesay BUrl::_IsUsernameChar(char c)
14468f30879bSAndrew Lindesay {
14478f30879bSAndrew Lindesay return !(c == ':' || c == '@');
14488f30879bSAndrew Lindesay }
14498f30879bSAndrew Lindesay
14508f30879bSAndrew Lindesay
14518f30879bSAndrew Lindesay bool
_IsPasswordChar(char c)14528f30879bSAndrew Lindesay BUrl::_IsPasswordChar(char c)
14538f30879bSAndrew Lindesay {
14548f30879bSAndrew Lindesay return !(c == '@');
14558f30879bSAndrew Lindesay }
14568f30879bSAndrew Lindesay
14578f30879bSAndrew Lindesay
14588f30879bSAndrew Lindesay bool
_IsHostChar(char c)14598f30879bSAndrew Lindesay BUrl::_IsHostChar(char c)
14608f30879bSAndrew Lindesay {
14618f30879bSAndrew Lindesay return ((uint8) c) > 127 || isalnum(c) || c == '-' || c == '_' || c == '.'
14628f30879bSAndrew Lindesay || c == '%';
14638f30879bSAndrew Lindesay }
14648f30879bSAndrew Lindesay
14658f30879bSAndrew Lindesay
14668f30879bSAndrew Lindesay bool
_IsPortChar(char c)14678f30879bSAndrew Lindesay BUrl::_IsPortChar(char c)
14688f30879bSAndrew Lindesay {
14698f30879bSAndrew Lindesay return isdigit(c);
14708f30879bSAndrew Lindesay }
14718f30879bSAndrew Lindesay
14728f30879bSAndrew Lindesay
14738f30879bSAndrew Lindesay bool
_IsIPV6Char(char c)14748f30879bSAndrew Lindesay BUrl::_IsIPV6Char(char c)
14758f30879bSAndrew Lindesay {
14768f30879bSAndrew Lindesay return c == ':' || isxdigit(c);
14778f30879bSAndrew Lindesay }
14788f30879bSAndrew Lindesay
14798f30879bSAndrew Lindesay
14802c26ad4bSAdrien Destugues BString
_UrlMimeType() const14812c26ad4bSAdrien Destugues BUrl::_UrlMimeType() const
14822c26ad4bSAdrien Destugues {
14832c26ad4bSAdrien Destugues BString mime;
14842c26ad4bSAdrien Destugues mime << "application/x-vnd.Be.URL." << fProtocol;
14852c26ad4bSAdrien Destugues
14862c26ad4bSAdrien Destugues return BString(mime);
14872c26ad4bSAdrien Destugues }
1488