Bug 652186 - Implement URL Standard's backslash replacement r?mcmanus
* * *
[mq]: test
MozReview-Commit-ID: JAZ36DstjFs
--- a/netwerk/base/nsStandardURL.cpp
+++ b/netwerk/base/nsStandardURL.cpp
@@ -1182,16 +1182,39 @@ nsStandardURL::GetOriginCharset(nsACStri
{
if (mOriginCharset.IsEmpty())
result.AssignLiteral("UTF-8");
else
result = mOriginCharset;
return NS_OK;
}
+static bool
+IsSpecialProtocol(const nsACString &input)
+{
+ nsACString::const_iterator start, end;
+ input.BeginReading(start);
+ nsACString::const_iterator iterator(start);
+ input.EndReading(end);
+
+ while (iterator != end && *iterator != ':') {
+ iterator++;
+ }
+
+ nsAutoCString protocol(nsDependentCSubstring(start.get(), iterator.get()));
+
+ return protocol.LowerCaseEqualsLiteral("http") ||
+ protocol.LowerCaseEqualsLiteral("https") ||
+ protocol.LowerCaseEqualsLiteral("ftp") ||
+ protocol.LowerCaseEqualsLiteral("ws") ||
+ protocol.LowerCaseEqualsLiteral("wss") ||
+ protocol.LowerCaseEqualsLiteral("file") ||
+ protocol.LowerCaseEqualsLiteral("gopher");
+}
+
NS_IMETHODIMP
nsStandardURL::SetSpec(const nsACString &input)
{
ENSURE_MUTABLE();
const nsPromiseFlatCString &flat = PromiseFlatCString(input);
const char *spec = flat.get();
int32_t specLength = flat.Length();
@@ -1212,22 +1235,45 @@ nsStandardURL::SetSpec(const nsACString
}
// Make a backup of the curent URL
nsStandardURL prevURL(false,false);
prevURL.CopyMembers(this, eHonorRef);
Clear();
// filter out unexpected chars "\r\n\t" if necessary
- nsAutoCString buf1;
- if (net_FilterURIString(spec, buf1)) {
- spec = buf1.get();
- specLength = buf1.Length();
+ nsAutoCString filteredURI;
+ if (!net_FilterURIString(spec, filteredURI)) {
+ // Copy the content into filteredURI even if no whitespace was stripped.
+ // We need a non-const buffer to perform backslash replacement.
+ filteredURI = input;
}
+ if (IsSpecialProtocol(filteredURI)) {
+ // Bug 652186: Replace all backslashes with slashes when parsing paths
+ // Stop when we reach the query or the hash.
+ nsAutoCString::iterator start;
+ nsAutoCString::iterator end;
+ filteredURI.BeginWriting(start);
+ filteredURI.EndWriting(end);
+ while (start != end) {
+ if (*start == '?' || *start == '#') {
+ break;
+ }
+ if (*start == '\\') {
+ *start = '/';
+ }
+ start++;
+ }
+ }
+
+ spec = filteredURI.get();
+ specLength = filteredURI.Length();
+
+
// parse the given URL...
nsresult rv = ParseURL(spec, specLength);
if (NS_SUCCEEDED(rv)) {
// finally, use the URLSegment member variables to build a normalized
// copy of |spec|
rv = BuildNormalizedSpec(spec);
}
@@ -1999,22 +2045,25 @@ NS_IMETHODIMP
nsStandardURL::Resolve(const nsACString &in, nsACString &out)
{
const nsPromiseFlatCString &flat = PromiseFlatCString(in);
const char *relpath = flat.get();
// filter out unexpected chars "\r\n\t" if necessary
nsAutoCString buf;
int32_t relpathLen;
- if (net_FilterURIString(relpath, buf)) {
- relpath = buf.get();
- relpathLen = buf.Length();
- } else
- relpathLen = flat.Length();
-
+ if (!net_FilterURIString(relpath, buf)) {
+ // Copy the content into filteredURI even if no whitespace was stripped.
+ // We need a non-const buffer to perform backslash replacement.
+ buf = in;
+ }
+
+ relpath = buf.get();
+ relpathLen = buf.Length();
+
char *result = nullptr;
LOG(("nsStandardURL::Resolve [this=%p spec=%s relpath=%s]\n",
this, mSpec.get(), relpath));
NS_ASSERTION(mParser, "no parser: unitialized");
// NOTE: there is no need for this function to produce normalized
@@ -2041,16 +2090,40 @@ nsStandardURL::Resolve(const nsACString
&scheme.mPos, &scheme.mLen,
nullptr, nullptr,
nullptr, nullptr);
// if the parser fails (for example because there is no valid scheme)
// reset the scheme and assume a relative url
if (NS_FAILED(rv)) scheme.Reset();
+ nsAutoCString protocol(Segment(scheme));
+ nsAutoCString baseProtocol(Scheme());
+
+ // We need to do backslash replacement for the following cases:
+ // 1. The input is an absolute path with a http/https/ftp scheme
+ // 2. The input is a relative path, and the base URL has a http/https/ftp scheme
+ if ((protocol.IsEmpty() && IsSpecialProtocol(baseProtocol)) ||
+ IsSpecialProtocol(protocol)) {
+
+ nsAutoCString::iterator start;
+ nsAutoCString::iterator end;
+ buf.BeginWriting(start);
+ buf.EndWriting(end);
+ while (start != end) {
+ if (*start == '?' || *start == '#') {
+ break;
+ }
+ if (*start == '\\') {
+ *start = '/';
+ }
+ start++;
+ }
+ }
+
if (scheme.mLen >= 0) {
// add some flags to coalesceFlag if it is an ftp-url
// need this later on when coalescing the resulting URL
if (SegmentIs(relpath, scheme, "ftp", true)) {
coalesceFlag = (netCoalesceFlags) (coalesceFlag
| NET_COALESCE_ALLOW_RELATIVE_ROOT
| NET_COALESCE_DOUBLE_SLASH_IS_ROOT);
--- a/netwerk/test/unit/test_standardurl.js
+++ b/netwerk/test/unit/test_standardurl.js
@@ -328,8 +328,21 @@ add_test(function test_pathPercentEncode
});
add_test(function test_filterWhitespace()
{
var url = stringToURL(" \r\n\th\nt\rt\tp://ex\r\n\tample.com/path\r\n\t/\r\n\tto the/fil\r\n\te.e\r\n\txt?que\r\n\try#ha\r\n\tsh \r\n\t ");
do_check_eq(url.spec, "http://example.com/path/to%20the/file.ext?query#hash");
run_next_test();
});
+
+add_test(function test_backslashReplacement()
+{
+ var url = stringToURL("http:\\\\test.com\\path/to\\file?query\\backslash#hash\\");
+ do_check_eq(url.spec, "http://test.com/path/to/file?query\\backslash#hash\\");
+
+ url = stringToURL("http:\\\\test.com\\example.org/path\\to/file");
+ do_check_eq(url.spec, "http://test.com/example.org/path/to/file");
+ do_check_eq(url.host, "test.com");
+ do_check_eq(url.path, "/example.org/path/to/file");
+
+ run_next_test();
+});