BUrl: rework handling of URL encoding

The content of a BUrl should always be in encoded form, to simplify
handling and validation.

Deprecate the UrlEncode member function and make it private. Instead aadd a new
way to handle URL encoding:
- All ways to set an URL (constructors, SetUrlString, and all setters)
  now take an extra boolean parameter indicating if the string is already
  encoded. The default value is to encode strings automatically.
- The static version of UrlEncode and UrlDecode, which operate on a
  string, are preserved and used by other parts of the API.

All unit tests adjusted to handle this, and still passing.

Fixes #12983

Change-Id: I06f06978d0d35e56d7c92b67f001856bb7dcafc8
Reviewed-on: https://review.haiku-os.org/c/haiku/+/1193
Reviewed-by: nephele nephele <[email protected]>
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
athira-selvam
2025-05-27 10:43:12 +00:00
committed by Adrien Destugues
parent 60bb9a9f96
commit 1d242620b4
7 changed files with 98 additions and 56 deletions
+28 -10
View File
@@ -66,10 +66,14 @@
//! @{
/*!
\fn BUrl::BUrl(const char* url);
\fn BUrl::BUrl(const char* url, bool encode = true);
\brief Constructs a BUrl and fills it.
\param url A string to parse and populate the URL fields from.
\param encode Wether to urlencode the string.
The URL fields are extracted from the passed string and encoded. If you are constructing an
URL from a string that is already URL-encoded, set encode to false.
Call InitCheck() to verify that the string was succesfully parsed and
resulted in a valid URL.
@@ -143,10 +147,13 @@
//! @{
/*!
\fn BUrl& BUrl::SetUrlString(const BString& url);
\fn BUrl& BUrl::SetUrlString(const BString& url, bool encode = true);
\brief Parse a string and set the URL accordingly
\param url A string to parse as an absolute URL.
\param encode Wether to URL-encode the string.
Set encode to false if the URL string is already URL-encoded.
*/
/*!
@@ -225,8 +232,8 @@
\returns the string representation of the URL.
A complete URL string is of the form protocol://username:passord\@host:port/path?request#fragment . All the fields are optional, for example a file URL will
have only a protocol and a path.
A complete URL string is of the form protocol://username:passord\@host:port/path?request#fragment .
All the fields are optional, for example a file URL will have only a protocol and a path.
*/
/*!
@@ -404,20 +411,31 @@
/*!
\fn void BUrl::UrlEncode(bool strict=false)
\brief Undocumented public method
\fn static BString BUrl::UrlEncode(const BString& url, bool strict=false, bool directory=false)
\brief URL-encode a string containing an URL or URL component.
\param strict Undocumented
\param strict Use strict mode
\param directory Use directory mode
In strict mode, space are replaced by %20. In non-strict mode they are replaced by a +
character.
In directory mode, / and \\ characters are not encoded. In the other fields they are
percent-encoded.
\return The encoded URL string
\since Haiku R1
*/
/*!
\fn void BUrl::UrlDecode(bool strict=false)
\brief Undocumented public method
\fn static BString BUrl::UrlDecode(const BString& url, bool strict=false)
\brief URL-decode a string containing an URL or URL component.
\param strict Undocumented
\param strict Use strict mode.
\return The decoded URL string
\since Haiku R1
*/
+9 -6
View File
@@ -14,7 +14,7 @@
class BUrl : public BArchivable {
public:
BUrl(const char* url);
BUrl(const char* url, bool encode = true);
BUrl(BMessage* archive);
BUrl(const BUrl& other);
BUrl(const BUrl& base, const BString& relative);
@@ -23,7 +23,8 @@ public:
virtual ~BUrl();
// URL fields modifiers
BUrl& SetUrlString(const BString& url);
BUrl& SetUrlString(const BString& url,
bool encode = true);
BUrl& SetProtocol(const BString& scheme);
BUrl& SetUserName(const BString& user);
BUrl& SetPassword(const BString& password);
@@ -60,10 +61,6 @@ public:
bool HasRequest() const;
bool HasFragment() const;
// Url encoding/decoding of needed fields
void UrlEncode(bool strict = false);
void UrlDecode(bool strict = false);
status_t IDNAToAscii();
status_t IDNAToUnicode();
@@ -98,6 +95,12 @@ public:
operator const char*() const;
private:
// Deprecated methods, use the new constructor with bool parameter
explicit BUrl(const char* url);
void SetUrlString(const BString& url);
void UrlEncode(bool strict = false);
void UrlDecode(bool strict = false);
void _ResetFields();
bool _ContainsDelimiter(const BString& url);
status_t _ExplodeUrlString(const BString& urlString,
@@ -44,9 +44,6 @@ BDataRequest::_ProtocolLoop()
ssize_t length;
bool isBase64 = false;
// The RFC has examples where some characters are URL-Encoded.
fUrl.UrlDecode(true);
// The RFC says this uses a nonstandard scheme, so the path, query and
// fragment are a bit nonsensical. It would be nice to handle them, but
// some software (eg. WebKit) relies on data URIs with embedded "#" char
@@ -25,7 +25,6 @@ BFileRequest::BFileRequest(const BUrl& url, BDataIO* output,
BUrlRequest(url, output, listener, context, "BUrlProtocol.File", "file"),
fResult()
{
fUrl.UrlDecode(true);
}
@@ -192,7 +192,6 @@ BGopherRequest::BGopherRequest(const BUrl& url, BDataIO* output,
{
fSocket = new(std::nothrow) BSocket();
fUrl.UrlDecode();
// the first part of the path is actually the document type
fPath = Url().Path();
+60 -32
View File
@@ -36,7 +36,7 @@ const uint32 PARSE_NO_MASK_BIT = 0x00000000;
const uint32 PARSE_RAW_PATH_MASK_BIT = 0x00000001;
BUrl::BUrl(const char* url)
BUrl::BUrl(const char* url, bool encode)
:
fUrlString(),
fProtocol(),
@@ -49,7 +49,7 @@ BUrl::BUrl(const char* url)
fHasHost(false),
fHasFragment(false)
{
SetUrlString(url);
SetUrlString(url, encode);
}
@@ -69,7 +69,7 @@ BUrl::BUrl(BMessage* archive)
BString url;
if (archive->FindString(kArchivedUrl, &url) == B_OK)
SetUrlString(url);
SetUrlString(url, false);
else
_ResetFields();
}
@@ -206,7 +206,7 @@ BUrl::BUrl(const BPath& path)
fHasHost(false),
fHasFragment(false)
{
SetUrlString(UrlEncode(path.Path(), true, true));
SetUrlString(path.Path(), true);
SetProtocol("file");
}
@@ -220,8 +220,11 @@ BUrl::~BUrl()
BUrl&
BUrl::SetUrlString(const BString& url)
BUrl::SetUrlString(const BString& url, bool encode)
{
if (encode)
UrlEncode(url, true, true);
_ExplodeUrlString(url, PARSE_NO_MASK_BIT);
return *this;
}
@@ -611,31 +614,6 @@ BUrl::HasFragment() const
}
// #pragma mark URL encoding/decoding of needed fields
void
BUrl::UrlEncode(bool strict)
{
fUser = _DoUrlEncodeChunk(fUser, strict);
fPassword = _DoUrlEncodeChunk(fPassword, strict);
fHost = _DoUrlEncodeChunk(fHost, strict);
fFragment = _DoUrlEncodeChunk(fFragment, strict);
fPath = _DoUrlEncodeChunk(fPath, strict, true);
}
void
BUrl::UrlDecode(bool strict)
{
fUser = _DoUrlDecodeChunk(fUser, strict);
fPassword = _DoUrlDecodeChunk(fPassword, strict);
fHost = _DoUrlDecodeChunk(fHost, strict);
fFragment = _DoUrlDecodeChunk(fFragment, strict);
fPath = _DoUrlDecodeChunk(fPath, strict);
}
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
status_t
BUrl::IDNAToAscii()
@@ -864,7 +842,7 @@ BUrl::operator=(const BUrl& other)
const BUrl&
BUrl::operator=(const BString& string)
{
SetUrlString(string);
SetUrlString(string, true);
return *this;
}
@@ -872,7 +850,7 @@ BUrl::operator=(const BString& string)
const BUrl&
BUrl::operator=(const char* string)
{
SetUrlString(string);
SetUrlString(string, true);
return *this;
}
@@ -1485,3 +1463,53 @@ BUrl::_UrlMimeType() const
return BString(mime);
}
// #pragma mark Deprecated methods
BUrl::BUrl(const char* string)
:
fPort(0),
fHasHost(false),
fHasFragment(false)
{
SetUrlString(string, false);
}
void
BUrl::SetUrlString(const BString& string)
{
SetUrlString(string, false);
}
void
BUrl::UrlEncode(bool strict)
{
fUser = _DoUrlEncodeChunk(fUser, strict, false);
fPassword = _DoUrlEncodeChunk(fPassword, strict, false);
fHost = _DoUrlEncodeChunk(fHost, strict, false);
fFragment = _DoUrlEncodeChunk(fFragment, strict, false);
fPath = _DoUrlEncodeChunk(fPath, strict, true);
fUrlStringValid = false;
fAuthorityValid = false;
fUserInfoValid = false;
}
void
BUrl::UrlDecode(bool strict)
{
fUser = _DoUrlDecodeChunk(fUser, strict);
fPassword = _DoUrlDecodeChunk(fPassword, strict);
fHost = _DoUrlDecodeChunk(fHost, strict);
fFragment = _DoUrlDecodeChunk(fFragment, strict);
fPath = _DoUrlDecodeChunk(fPath, strict);
fUrlStringValid = false;
fAuthorityValid = false;
fUserInfoValid = false;
}
+1 -3
View File
@@ -537,7 +537,7 @@ UrlTest::RelativeUriTest()
CPPUNIT_ASSERT_EQUAL_MESSAGE(message.String(),
BString(tests[index].absolute),
BUrl(baseUrl, tests[index].relative).UrlString());
BUrl(baseUrl, BString(tests[index].relative)).UrlString());
}
}
@@ -597,8 +597,6 @@ UrlTest::IDNTest()
NextSubTest();
BUrl url(tests[i].escaped);
url.UrlDecode();
BUrl idn(tests[i].decoded);
status_t success = idn.IDNAToUnicode();