From 2bd3a3c9ef4d2fe34cd0891253e12e5e1de9930e Mon Sep 17 00:00:00 2001 From: roytam1 Date: Mon, 25 Jan 2021 17:28:58 +0800 Subject: [PATCH] partly import changes from tenfourfox: - #565: implement nsASCIIMask from M1358297 (41b1fc937) - #565: M1358297 parts 3 and 4 (3fd15a87a) - #632: M1424915 M1354233 M1324114 M1343008 M1236277(just backbugs) M1328955 (d87db7e16) - #632: M1362498 M1397686 M136178 M1320252 M1355875 (82cb3b59e) - #632: M241788 M1271955 M1249352(p1) + additional local optimizations (438bdb726) - #632: M1249352 part 2 (2c61821e4) - #632: M1249352(remaining) M1358297(backbugs) M1369317(pp1,3,4) M1426996 (1eab6170b) --- docshell/base/nsDefaultURIFixup.cpp | 2 +- docshell/base/nsDocShell.cpp | 2 +- dom/base/nsContentUtils.cpp | 4 +- dom/html/HTMLInputElement.cpp | 6 +- modules/libpref/init/all.js | 4 +- netwerk/base/nsISocketTransportService.idl | 4 +- netwerk/base/nsIStreamTransportService.idl | 2 +- netwerk/base/nsPISocketTransportService.idl | 2 +- netwerk/base/nsProtocolProxyService.cpp | 10 +++ netwerk/base/nsSimpleURI.cpp | 29 ++++---- netwerk/base/nsStandardURL.cpp | 14 ++-- netwerk/base/nsURLHelper.cpp | 40 +++++++++-- netwerk/base/nsURLHelper.h | 12 ++++ netwerk/mime/nsMIMEHeaderParamImpl.cpp | 4 +- netwerk/protocol/http/Http2Session.cpp | 34 ++++++--- netwerk/protocol/http/Http2Session.h | 5 +- netwerk/protocol/http/Http2Stream.cpp | 4 +- netwerk/protocol/http/nsHttpChannel.cpp | 26 +++---- netwerk/protocol/http/nsHttpConnectionMgr.cpp | 41 +++++++---- netwerk/protocol/http/nsHttpTransaction.cpp | 7 +- xpcom/build/ServiceList.h | 10 +++ xpcom/build/Services.cpp | 5 ++ xpcom/io/nsEscape.cpp | 44 ++++++++++-- xpcom/io/nsEscape.h | 13 ++++ xpcom/string/moz.build | 2 + xpcom/string/nsASCIIMask.cpp | 55 +++++++++++++++ xpcom/string/nsASCIIMask.h | 70 +++++++++++++++++++ xpcom/string/nsStringObsolete.cpp | 2 - xpcom/string/nsTStringObsolete.cpp | 60 +++++++++++++--- xpcom/string/nsTSubstring.cpp | 44 +++++++++++- xpcom/string/nsTSubstring.h | 26 +++++++ xpfe/appshell/nsXULWindow.cpp | 2 +- 32 files changed, 480 insertions(+), 105 deletions(-) create mode 100644 xpcom/string/nsASCIIMask.cpp create mode 100644 xpcom/string/nsASCIIMask.h diff --git a/docshell/base/nsDefaultURIFixup.cpp b/docshell/base/nsDefaultURIFixup.cpp index d2876181a..013ae2bf7 100644 --- a/docshell/base/nsDefaultURIFixup.cpp +++ b/docshell/base/nsDefaultURIFixup.cpp @@ -176,7 +176,7 @@ nsDefaultURIFixup::GetFixupURIInfo(const nsACString& aStringURI, nsAutoCString uriString(aStringURI); // Eliminate embedded newlines, which single-line text fields now allow: - uriString.StripChars("\r\n"); + uriString.StripCRLF(); // Cleanup the empty spaces and tabs that might be on each end: uriString.Trim(" \t"); diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 9114e47f3..58e3bf8ea 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -4740,7 +4740,7 @@ nsDocShell::LoadURIWithOptions(const char16_t* aURI, // Cleanup the empty spaces that might be on each end. uriString.Trim(" "); // Eliminate embedded newlines, which single-line text fields now allow: - uriString.StripChars("\r\n"); + uriString.StripCRLF(); NS_ENSURE_TRUE(!uriString.IsEmpty(), NS_ERROR_FAILURE); rv = NS_NewURI(getter_AddRefs(uri), uriString); diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index cfb8096a3..45ba8f88e 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -6504,9 +6504,7 @@ nsContentUtils::FlushLayoutForTree(nsPIDOMWindowOuter* aWindow) void nsContentUtils::RemoveNewlines(nsString &aString) { - // strip CR/LF and null - static const char badChars[] = {'\r', '\n', 0}; - aString.StripChars(badChars); + aString.StripCRLF(); } void diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index c8a09c4e8..2a45816ed 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -5211,15 +5211,13 @@ HTMLInputElement::SanitizeValue(nsAString& aValue) case NS_FORM_INPUT_TEL: case NS_FORM_INPUT_PASSWORD: { - char16_t crlf[] = { char16_t('\r'), char16_t('\n'), 0 }; - aValue.StripChars(crlf); + aValue.StripCRLF(); } break; case NS_FORM_INPUT_EMAIL: case NS_FORM_INPUT_URL: { - char16_t crlf[] = { char16_t('\r'), char16_t('\n'), 0 }; - aValue.StripChars(crlf); + aValue.StripCRLF(); aValue = nsContentUtils::TrimWhitespace(aValue); } diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 804c78dc6..3f7569647 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -1586,7 +1586,7 @@ pref("network.http.spdy.enabled.http2", true); pref("network.http.spdy.enabled.deps", true); pref("network.http.spdy.enforce-tls-profile", false); pref("network.http.spdy.chunk-size", 16000); -pref("network.http.spdy.timeout", 180); +pref("network.http.spdy.timeout", 170); pref("network.http.spdy.coalesce-hostnames", true); pref("network.http.spdy.persistent-settings", false); pref("network.http.spdy.ping-threshold", 58); @@ -3568,7 +3568,7 @@ pref("intl.imm.vertical_writing.always_assume_not_supported", false); // We cannot retrieve active IME name with IMM32 API if a TIP of TSF is active. // This pref can specify active IME name when Japanese TIP is active. // For example: -// Google Japanese Input: "Google ?¥æœ¬èªžå…¥??IMM32 ?¢ã‚¸?¥ãƒ¼?? +// Google Japanese Input: "Google 日本語入力 IMM32 モジュール" // ATOK 2011: "ATOK 2011" (similarly, e.g., ATOK 2013 is "ATOK 2013") pref("intl.imm.japanese.assume_active_tip_name_as", ""); diff --git a/netwerk/base/nsISocketTransportService.idl b/netwerk/base/nsISocketTransportService.idl index 06350b532..8e3bdd44d 100644 --- a/netwerk/base/nsISocketTransportService.idl +++ b/netwerk/base/nsISocketTransportService.idl @@ -18,7 +18,7 @@ struct PRFileDesc; [ptr] native PRFileDescPtr(PRFileDesc); [ptr] native nsASocketHandlerPtr(nsASocketHandler); -[scriptable, uuid(ad56b25f-e6bb-4db3-9f7b-5b7db33fd2b1)] +[builtinclass, scriptable, uuid(ad56b25f-e6bb-4db3-9f7b-5b7db33fd2b1)] interface nsISocketTransportService : nsISupports { /** @@ -119,7 +119,7 @@ interface nsISocketTransportService : nsISupports [noscript] void notifyWhenCanAttachSocket(in nsIRunnable aEvent); }; -[scriptable, uuid(c5204623-5b58-4a16-8b2e-67c34dd02e3f)] +[builtinclass, scriptable, uuid(c5204623-5b58-4a16-8b2e-67c34dd02e3f)] interface nsIRoutedSocketTransportService : nsISocketTransportService { // use this instead of createTransport when you have a transport diff --git a/netwerk/base/nsIStreamTransportService.idl b/netwerk/base/nsIStreamTransportService.idl index cd39f9cba..0babc2b7d 100644 --- a/netwerk/base/nsIStreamTransportService.idl +++ b/netwerk/base/nsIStreamTransportService.idl @@ -15,7 +15,7 @@ interface nsIOutputStream; * into a fully asynchronous stream that can be read/written without * blocking the main thread. */ -[scriptable, uuid(5e0adf7d-9785-45c3-a193-04f25a75da8f)] +[builtinclass, scriptable, uuid(5e0adf7d-9785-45c3-a193-04f25a75da8f)] interface nsIStreamTransportService : nsISupports { /** diff --git a/netwerk/base/nsPISocketTransportService.idl b/netwerk/base/nsPISocketTransportService.idl index d49745fac..da6376467 100644 --- a/netwerk/base/nsPISocketTransportService.idl +++ b/netwerk/base/nsPISocketTransportService.idl @@ -10,7 +10,7 @@ * This is a private interface used by the internals of the networking library. * It will never be frozen. Do not use it in external code. */ -[scriptable, uuid(18f73bf1-b35b-4b7b-aa9a-11bcbdbc389c)] +[builtinclass, scriptable, uuid(18f73bf1-b35b-4b7b-aa9a-11bcbdbc389c)] interface nsPISocketTransportService : nsIRoutedSocketTransportService { diff --git a/netwerk/base/nsProtocolProxyService.cpp b/netwerk/base/nsProtocolProxyService.cpp index 26eca0e88..5362b53d6 100644 --- a/netwerk/base/nsProtocolProxyService.cpp +++ b/netwerk/base/nsProtocolProxyService.cpp @@ -1273,6 +1273,16 @@ nsProtocolProxyService::AsyncResolveInternal(nsIChannel *channel, uint32_t flags nsCOMPtr pi; bool usePACThread; + // adapt to realtime changes in the system proxy service + if (mProxyConfig == PROXYCONFIG_SYSTEM) { + nsCOMPtr sp2 = + do_GetService(NS_SYSTEMPROXYSETTINGS_CONTRACTID); + if (sp2 != mSystemProxySettings) { + mSystemProxySettings = sp2; + ResetPACThread(); + } + } + // SystemProxySettings and PAC files can block the main thread // but if neither of them are in use, we can just do the work // right here and directly invoke the callback diff --git a/netwerk/base/nsSimpleURI.cpp b/netwerk/base/nsSimpleURI.cpp index dbc0dc817..c83f7ee6f 100644 --- a/netwerk/base/nsSimpleURI.cpp +++ b/netwerk/base/nsSimpleURI.cpp @@ -254,27 +254,22 @@ nsSimpleURI::SetSpec(const nsACString &aSpec) { NS_ENSURE_STATE(mMutable); - // filter out unexpected chars "\r\n\t" if necessary - nsAutoCString filteredSpec; - net_FilterURIString(aSpec, filteredSpec); + nsresult rv = net_ExtractURLScheme(aSpec, mScheme); + if (NS_FAILED(rv)) { + return rv; + } + ToLowerCase(mScheme); - // nsSimpleURI currently restricts the charset to US-ASCII nsAutoCString spec; - nsresult rv = NS_EscapeURL(filteredSpec, esc_OnlyNonASCII, spec, fallible); + rv = net_FilterAndEscapeURI(aSpec, esc_OnlyNonASCII, spec); if (NS_FAILED(rv)) { return rv; } int32_t colonPos = spec.FindChar(':'); - if (colonPos < 0 || !net_IsValidScheme(spec.get(), colonPos)) - return NS_ERROR_MALFORMED_URI; - - mScheme.Truncate(); - DebugOnly n = spec.Left(mScheme, colonPos); - NS_ASSERTION(n == colonPos, "Left failed"); - ToLowerCase(mScheme); - + MOZ_ASSERT(colonPos != kNotFound, "A colon should be in this string"); // This sets mPath, mQuery and mRef. + // If changed, see bug 1369317, especially part 2 -- Cameron return SetPath(Substring(spec, colonPos + 1)); } @@ -658,12 +653,12 @@ nsSimpleURI::Resolve(const nsACString &relativePath, nsACString &result) } NS_IMETHODIMP -nsSimpleURI::GetAsciiSpec(nsACString &result) +nsSimpleURI::GetAsciiSpec(nsACString &aResult) { - nsAutoCString buf; - nsresult rv = GetSpec(buf); + nsresult rv = GetSpec(aResult); if (NS_FAILED(rv)) return rv; - return NS_EscapeURL(buf, esc_OnlyNonASCII|esc_AlwaysCopy, result, fallible); + MOZ_ASSERT(IsASCII(aResult), "The spec should be ASCII"); + return NS_OK; } NS_IMETHODIMP diff --git a/netwerk/base/nsStandardURL.cpp b/netwerk/base/nsStandardURL.cpp index 04cd61f42..702ade5d2 100644 --- a/netwerk/base/nsStandardURL.cpp +++ b/netwerk/base/nsStandardURL.cpp @@ -1379,8 +1379,11 @@ nsStandardURL::SetSpec(const nsACString &input) { ENSURE_MUTABLE(); +#if DEBUG + // Don't pay the flat tax in optimized builds. const nsPromiseFlatCString &flat = PromiseFlatCString(input); LOG(("nsStandardURL::SetSpec [spec=%s]\n", flat.get())); +#endif if (input.Length() > (uint32_t) net_GetURLMaxLength()) { return NS_ERROR_MALFORMED_URI; @@ -1388,12 +1391,17 @@ nsStandardURL::SetSpec(const nsACString &input) // filter out unexpected chars "\r\n\t" if necessary nsAutoCString filteredURI; - net_FilterURIString(flat, filteredURI); + net_FilterURIString(input, filteredURI); if (filteredURI.Length() == 0) { return NS_ERROR_MALFORMED_URI; } + // NUL characters aren't allowed in the filtered URI. + if (filteredURI.Contains('\0')) { + return NS_ERROR_MALFORMED_URI; + } + // Make a backup of the curent URL nsStandardURL prevURL(false,false); prevURL.CopyMembers(this, eHonorRef, EmptyCString()); @@ -2241,11 +2249,9 @@ nsresult nsStandardURL::CopyMembers(nsStandardURL * source, NS_IMETHODIMP nsStandardURL::Resolve(const nsACString &in, nsACString &out) { - const nsPromiseFlatCString &flat = PromiseFlatCString(in); // filter out unexpected chars "\r\n\t" if necessary nsAutoCString buf; - net_FilterURIString(flat, buf); - + net_FilterURIString(in, buf); const char *relpath = buf.get(); int32_t relpathLen = buf.Length(); diff --git a/netwerk/base/nsURLHelper.cpp b/netwerk/base/nsURLHelper.cpp index 8def697da..98828b532 100644 --- a/netwerk/base/nsURLHelper.cpp +++ b/netwerk/base/nsURLHelper.cpp @@ -9,6 +9,7 @@ #include #include +#include "nsASCIIMask.h" #include "nsURLHelper.h" #include "nsIFile.h" #include "nsIURLParser.h" @@ -18,6 +19,7 @@ #include "mozilla/Preferences.h" #include "prnetdb.h" #include "mozilla/Tokenizer.h" +#include "nsEscape.h" using namespace mozilla; @@ -522,7 +524,7 @@ net_ExtractURLScheme(const nsACString &inURI, } p.Claim(scheme); - scheme.StripChars("\r\n\t"); + scheme.StripTaggedASCII(ASCIIMask::MaskCRLFTab()); return NS_OK; } @@ -591,8 +593,6 @@ net_IsAbsoluteURL(const nsACString& uri) void net_FilterURIString(const nsACString& input, nsACString& result) { - const char kCharsToStrip[] = "\r\n\t"; - result.Truncate(); auto start = input.BeginReading(); @@ -607,9 +607,14 @@ net_FilterURIString(const nsACString& input, nsACString& result) charFilter).base(); // Check if chars need to be stripped. - auto itr = std::find_first_of( - newStart, newEnd, std::begin(kCharsToStrip), std::end(kCharsToStrip)); - const bool needsStrip = itr != newEnd; + bool needsStrip = false; + const ASCIIMaskArray& mask = ASCIIMask::MaskCRLFTab(); + for (auto itr = start; itr != end; ++itr) { + if (ASCIIMask::IsMasked(mask, *itr)) { + needsStrip = true; + break; + } + } // Just use the passed in string rather than creating new copies if no // changes are necessary. @@ -620,10 +625,31 @@ net_FilterURIString(const nsACString& input, nsACString& result) result.Assign(Substring(newStart, newEnd)); if (needsStrip) { - result.StripChars(kCharsToStrip); + result.StripTaggedASCII(mask); } } +nsresult +net_FilterAndEscapeURI(const nsACString& aInput, uint32_t aFlags, nsACString& aResult) +{ + aResult.Truncate(); + + auto start = aInput.BeginReading(); + auto end = aInput.EndReading(); + + // Trim off leading and trailing invalid chars. + auto charFilter = [](char c) { return static_cast(c) > 0x20; }; + auto newStart = std::find_if(start, end, charFilter); + auto newEnd = std::find_if( + std::reverse_iterator(end), + std::reverse_iterator(newStart), + charFilter).base(); + + const ASCIIMaskArray& mask = ASCIIMask::MaskCRLFTab(); + return NS_EscapeAndFilterURL(Substring(newStart, newEnd), aFlags, + &mask, aResult, fallible); +} + #if defined(XP_WIN) bool diff --git a/netwerk/base/nsURLHelper.h b/netwerk/base/nsURLHelper.h index f30814c25..2bde59373 100644 --- a/netwerk/base/nsURLHelper.h +++ b/netwerk/base/nsURLHelper.h @@ -115,6 +115,18 @@ inline bool net_IsValidScheme(const nsAFlatCString &scheme) */ void net_FilterURIString(const nsACString& input, nsACString& result); +/** + * This function performs character stripping just like net_FilterURIString, + * with the added benefit of also performing percent escaping of dissallowed + * characters, all in one pass. Saving one pass is very important when operating + * on really large strings. + * + * @param aInput the URL spec we want to filter + * @param aFlags the flags which control which characters we escape + * @param aResult the out param to write to if filtering happens + */ +nsresult net_FilterAndEscapeURI(const nsACString& aInput, uint32_t aFlags, nsACString& aResult); + #if defined(XP_WIN) /** * On Win32 and OS/2 system's a back-slash in a file:// URL is equivalent to a diff --git a/netwerk/mime/nsMIMEHeaderParamImpl.cpp b/netwerk/mime/nsMIMEHeaderParamImpl.cpp index e202253ca..5c1f088ac 100644 --- a/netwerk/mime/nsMIMEHeaderParamImpl.cpp +++ b/netwerk/mime/nsMIMEHeaderParamImpl.cpp @@ -521,7 +521,7 @@ nsMIMEHeaderParamImpl::DoParameterInternal(const char *aHeaderValue, // if the parameter spans across multiple lines we have to strip out the // line continuation -- jht 4/29/98 nsAutoCString tempStr(valueStart, valueEnd - valueStart); - tempStr.StripChars("\r\n"); + tempStr.StripCRLF(); char *res = ToNewCString(tempStr); NS_ENSURE_TRUE(res, NS_ERROR_OUT_OF_MEMORY); @@ -764,7 +764,7 @@ internalDecodeRFC2047Header(const char* aHeaderVal, const char* aDefaultCharset, nsAutoCString temp(aResult); temp.ReplaceSubstring("\n\t", " "); temp.ReplaceSubstring("\r\t", " "); - temp.StripChars("\r\n"); + temp.StripCRLF(); aResult = temp; } diff --git a/netwerk/protocol/http/Http2Session.cpp b/netwerk/protocol/http/Http2Session.cpp index afbbdeb90..80e49b876 100644 --- a/netwerk/protocol/http/Http2Session.cpp +++ b/netwerk/protocol/http/Http2Session.cpp @@ -2415,15 +2415,14 @@ Http2Session::ReadSegmentsAgain(nsAHttpSegmentReader *reader, this, stream, stream->StreamID())); FlushOutputQueue(); SetWriteCallbacks(); + if (!mCannotDo0RTTStreams.Contains(stream)) { + mCannotDo0RTTStreams.AppendElement(stream); + } // We can still send our preamble *countRead = mOutputQueueUsed - mOutputQueueSent; return *countRead ? NS_OK : NS_BASE_STREAM_WOULD_BLOCK; } - if (!m0RTTStreams.Contains(stream->StreamID())) { - m0RTTStreams.AppendElement(stream->StreamID()); - } - // Need to adjust this to only take as much as we can fit in with the // preamble/settings/priority stuff count -= (mOutputQueueUsed - mOutputQueueSent); @@ -2446,6 +2445,12 @@ Http2Session::ReadSegmentsAgain(nsAHttpSegmentReader *reader, *countRead += earlyDataUsed; } + if (mAttemptingEarlyData && !m0RTTStreams.Contains(stream)) { + LOG3(("Http2Session::ReadSegmentsAgain adding stream %d to m0RTTStreams\n", + stream->StreamID())); + m0RTTStreams.AppendElement(stream); + } + // Not every permutation of stream->ReadSegents produces data (and therefore // tries to flush the output queue) - SENDING_FIN_STREAM can be an example // of that. But we might still have old data buffered that would be good @@ -2872,7 +2877,9 @@ Http2Session::WriteSegmentsAgain(nsAHttpSegmentWriter *writer, "stream->writeSegments returning code %x\n", this, streamID, mNeedsCleanup, rv)); MOZ_ASSERT(!mNeedsCleanup || mNeedsCleanup->StreamID() == streamID); - CleanupStream(streamID, NS_OK, CANCEL_ERROR); + CleanupStream(streamID, + (rv == NS_BINDING_RETARGETED) ? NS_BINDING_RETARGETED : NS_OK, + CANCEL_ERROR); mNeedsCleanup = nullptr; *again = false; ResumeRecv(); @@ -3015,9 +3022,8 @@ Http2Session::Finish0RTT(bool aRestart, bool aAlpnChanged) // the transaction rewind and read it all over again. We only need to rewind // the transaction if we're switching to a new protocol, because our buffer // won't get used in that case. - Http2Stream *stream = mStreamIDHash.Get(m0RTTStreams[i]); - if (stream) { - stream->Finish0RTT(aAlpnChanged, aAlpnChanged); + if (m0RTTStreams[i]) { + m0RTTStreams[i]->Finish0RTT(aRestart, aAlpnChanged); } } @@ -3039,15 +3045,27 @@ Http2Session::Finish0RTT(bool aRestart, bool aAlpnChanged) // This is the easy case - early data failed, but we're speaking h2, so // we just need to rewind to the beginning of the preamble and try again. mOutputQueueSent = 0; + + for (size_t i = 0; i < mCannotDo0RTTStreams.Length(); ++i) { + if (mCannotDo0RTTStreams[i] && VerifyStream(mCannotDo0RTTStreams[i])) { + TransactionHasDataToWrite(mCannotDo0RTTStreams[i]); + } + } } } else { // 0RTT succeeded + for (size_t i = 0; i < mCannotDo0RTTStreams.Length(); ++i) { + if (mCannotDo0RTTStreams[i] && VerifyStream(mCannotDo0RTTStreams[i])) { + TransactionHasDataToWrite(mCannotDo0RTTStreams[i]); + } + } // Make sure we look for any incoming data in repsonse to our early data. ResumeRecv(); } mAttemptingEarlyData = false; m0RTTStreams.Clear(); + mCannotDo0RTTStreams.Clear(); RealignOutputQueue(); return NS_OK; diff --git a/netwerk/protocol/http/Http2Session.h b/netwerk/protocol/http/Http2Session.h index d1195727d..49d02f93c 100644 --- a/netwerk/protocol/http/Http2Session.h +++ b/netwerk/protocol/http/Http2Session.h @@ -500,7 +500,10 @@ private: bool mAttemptingEarlyData; // The ID(s) of the stream(s) that we are getting 0RTT data from. - nsTArray m0RTTStreams; + nsTArray> m0RTTStreams; + // The ID(s) of the stream(s) that are not able to send 0RTT data. We need to + // remember them put them into mReadyForWrite queue when 0RTT finishes. + nsTArray> mCannotDo0RTTStreams; private: /// connect tunnels diff --git a/netwerk/protocol/http/Http2Stream.cpp b/netwerk/protocol/http/Http2Stream.cpp index 37ecc0600..6d97d8bd1 100644 --- a/netwerk/protocol/http/Http2Stream.cpp +++ b/netwerk/protocol/http/Http2Stream.cpp @@ -1495,8 +1495,8 @@ bool Http2Stream::Do0RTT() { MOZ_ASSERT(mTransaction); - mAttempting0RTT = true; - return mTransaction->Do0RTT(); + mAttempting0RTT = mTransaction->Do0RTT(); + return mAttempting0RTT; } nsresult diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index b517597b3..5bf1878a9 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -127,8 +127,6 @@ static uint64_t gNumIntercepted = 0; (result) == NS_ERROR_OUT_OF_MEMORY) static NS_DEFINE_CID(kStreamListenerTeeCID, NS_STREAMLISTENERTEE_CID); -static NS_DEFINE_CID(kStreamTransportServiceCID, - NS_STREAMTRANSPORTSERVICE_CID); enum CacheDisposition { kCacheHit = 1, @@ -3552,9 +3550,10 @@ nsHttpChannel::OpenCacheEntry(bool isHttps) } } - nsCOMPtr cacheStorageService = - do_GetService("@mozilla.org/netwerk/cache-storage-service;1", &rv); - NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr cacheStorageService(services::GetCacheStorageService()); + if (!cacheStorageService) { + return NS_ERROR_NOT_AVAILABLE; + } nsCOMPtr cacheStorage; nsCOMPtr openURI; @@ -4717,8 +4716,8 @@ nsHttpChannel::OpenCacheInputStream(nsICacheEntry* cacheEntry, bool startBufferi nsCOMPtr transport; nsCOMPtr wrapper; - nsCOMPtr sts = - do_GetService(kStreamTransportServiceCID, &rv); + nsCOMPtr sts(services::GetStreamTransportService()); + rv = sts ? NS_OK : NS_ERROR_NOT_AVAILABLE; if (NS_SUCCEEDED(rv)) { rv = sts->CreateInputTransport(stream, int64_t(-1), int64_t(-1), true, getter_AddRefs(transport)); @@ -5256,9 +5255,10 @@ nsHttpChannel::InstallCacheListener(int64_t offset) nsCOMPtr cacheIOTarget; if (!CacheObserver::UseNewCache()) { - nsCOMPtr serv = - do_GetService("@mozilla.org/netwerk/cache-storage-service;1", &rv); - NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr serv(services::GetCacheStorageService()); + if (!serv) { + return NS_ERROR_NOT_AVAILABLE; + } serv->GetIoTarget(getter_AddRefs(cacheIOTarget)); } @@ -6106,7 +6106,7 @@ nsHttpChannel::BeginConnectContinue() // Check to see if this principal exists on local blocklists. RefPtr channelClassifier = new nsChannelClassifier(this); if (mLoadFlags & LOAD_CLASSIFY_URI) { - nsCOMPtr classifier = do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID); + nsCOMPtr classifier(services::GetURIClassifier()); bool tpEnabled = false; channelClassifier->ShouldEnableTrackingProtection(&tpEnabled); if (classifier && tpEnabled) { @@ -8020,8 +8020,8 @@ nsHttpChannel::DoInvalidateCacheEntry(nsIURI* aURI) LOG(("DoInvalidateCacheEntry [channel=%p key=%s]", this, key.get())); - nsCOMPtr cacheStorageService = - do_GetService("@mozilla.org/netwerk/cache-storage-service;1", &rv); + nsCOMPtr cacheStorageService(services::GetCacheStorageService()); + rv = cacheStorageService ? NS_OK : NS_ERROR_FAILURE; nsCOMPtr cacheStorage; if (NS_SUCCEEDED(rv)) { diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp index 317bd835a..74d1259dc 100644 --- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp +++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp @@ -23,6 +23,7 @@ #include "mozilla/net/DNS.h" #include "nsISocketTransport.h" #include "nsISSLSocketControl.h" +#include "mozilla/Services.h" #include "mozilla/Telemetry.h" #include "mozilla/net/DashboardTypes.h" #include "NullHttpTransaction.h" @@ -102,11 +103,13 @@ nsHttpConnectionMgr::~nsHttpConnectionMgr() nsresult nsHttpConnectionMgr::EnsureSocketThreadTarget() { - nsresult rv; nsCOMPtr sts; - nsCOMPtr ioService = do_GetIOService(&rv); - if (NS_SUCCEEDED(rv)) - sts = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); + nsCOMPtr ioService = services::GetIOService(); + if (ioService) { + nsCOMPtr realSTS = + services::GetSocketTransportService(); + sts = do_QueryInterface(realSTS); + } ReentrantMonitorAutoEnter mon(mReentrantMonitor); @@ -116,7 +119,7 @@ nsHttpConnectionMgr::EnsureSocketThreadTarget() mSocketThreadTarget = sts; - return rv; + return sts ? NS_OK : NS_ERROR_NOT_AVAILABLE; } nsresult @@ -855,7 +858,7 @@ nsHttpConnectionMgr::GetSpdyPreferredEnt(nsConnectionEntry *aOriginalEntry) "with %s connections. rv=%x isJoined=%d", preferred->mConnInfo->Origin(), aOriginalEntry->mConnInfo->Origin(), rv, isJoined)); - Telemetry::Accumulate(Telemetry::SPDY_NPN_JOIN, false); + //Telemetry::Accumulate(Telemetry::SPDY_NPN_JOIN, false); return nullptr; } @@ -865,7 +868,7 @@ nsHttpConnectionMgr::GetSpdyPreferredEnt(nsConnectionEntry *aOriginalEntry) "so %s will be coalesced with %s", preferred->mConnInfo->Origin(), aOriginalEntry->mConnInfo->Origin(), aOriginalEntry->mConnInfo->Origin(), preferred->mConnInfo->Origin())); - Telemetry::Accumulate(Telemetry::SPDY_NPN_JOIN, true); + //Telemetry::Accumulate(Telemetry::SPDY_NPN_JOIN, true); return preferred; } @@ -1197,6 +1200,7 @@ nsHttpConnectionMgr::MakeNewConnection(nsConnectionEntry *ent, transport->SetConnectionFlags(flags); } +#if(0) Telemetry::AutoCounter usedSpeculativeConn; ++usedSpeculativeConn; @@ -1204,6 +1208,7 @@ nsHttpConnectionMgr::MakeNewConnection(nsConnectionEntry *ent, Telemetry::AutoCounter totalPreconnectsUsed; ++totalPreconnectsUsed; } +#endif // return OK because we have essentially opened a new connection // by converting a speculative half-open to general use @@ -1843,6 +1848,7 @@ nsHttpConnectionMgr::BuildPipeline(nsConnectionEntry *ent, void nsHttpConnectionMgr::ReportProxyTelemetry(nsConnectionEntry *ent) { +#if(0) enum { PROXY_NONE = 1, PROXY_HTTP = 2, PROXY_SOCKS = 3, PROXY_HTTPS = 4 }; if (!ent->mConnInfo->UsingProxy()) @@ -1853,6 +1859,7 @@ nsHttpConnectionMgr::ReportProxyTelemetry(nsConnectionEntry *ent) Telemetry::Accumulate(Telemetry::HTTP_PROXY_TYPE, PROXY_HTTP); else Telemetry::Accumulate(Telemetry::HTTP_PROXY_TYPE, PROXY_SOCKS); +#endif } nsresult @@ -1902,7 +1909,7 @@ nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans) ent = preferredEntry; } - ReportProxyTelemetry(ent); + //ReportProxyTelemetry(ent); // Check if the transaction already has a sticky reference to a connection. // If so, then we can just use it directly by transferring its reference @@ -2000,13 +2007,13 @@ nsHttpConnectionMgr::CreateTransport(nsConnectionEntry *ent, if (speculative) { sock->SetSpeculative(true); sock->SetAllow1918(allow1918); - Telemetry::AutoCounter totalSpeculativeConn; - ++totalSpeculativeConn; + //Telemetry::AutoCounter totalSpeculativeConn; + //++totalSpeculativeConn; if (isFromPredictor) { sock->SetIsFromPredictor(true); - Telemetry::AutoCounter totalPreconnectsCreated; - ++totalPreconnectsCreated; + //Telemetry::AutoCounter totalPreconnectsCreated; + //++totalPreconnectsCreated; } } @@ -3035,8 +3042,10 @@ nsHalfOpenSocket::SetupStreams(nsISocketTransport **transport, nsCOMPtr socketTransport; nsCOMPtr sts; - sts = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); + sts = services::GetSocketTransportService(); + if (!sts) { + return NS_ERROR_NOT_AVAILABLE; + } LOG(("nsHalfOpenSocket::SetupStreams [this=%p ent=%s] " "setup routed transport to origin %s:%d via %s:%d\n", @@ -3118,8 +3127,10 @@ nsHalfOpenSocket::SetupStreams(nsISocketTransport **transport, rv = socketTransport->SetSecurityCallbacks(this); NS_ENSURE_SUCCESS(rv, rv); + /* Telemetry::Accumulate(Telemetry::HTTP_CONNECTION_ENTRY_CACHE_HIT_1, mEnt->mUsedForConnection); + */ mEnt->mUsedForConnection = true; nsCOMPtr sout; @@ -3919,6 +3930,7 @@ nsConnectionEntry::RemoveHalfOpen(nsHalfOpenSocket *halfOpen) // will result in it not being present in the halfopen table. That's expected. if (mHalfOpens.RemoveElement(halfOpen)) { +#if(0) if (halfOpen->IsSpeculative()) { Telemetry::AutoCounter unusedSpeculativeConn; ++unusedSpeculativeConn; @@ -3928,6 +3940,7 @@ nsConnectionEntry::RemoveHalfOpen(nsHalfOpenSocket *halfOpen) ++totalPreconnectsUnused; } } +#endif MOZ_ASSERT(gHttpHandler->ConnMgr()->mNumHalfOpenConns); if (gHttpHandler->ConnMgr()->mNumHalfOpenConns) { // just in case diff --git a/netwerk/protocol/http/nsHttpTransaction.cpp b/netwerk/protocol/http/nsHttpTransaction.cpp index 01d0aa6db..32f8d7dc6 100644 --- a/netwerk/protocol/http/nsHttpTransaction.cpp +++ b/netwerk/protocol/http/nsHttpTransaction.cpp @@ -27,7 +27,6 @@ #include "nsStringStream.h" #include "nsComponentManagerUtils.h" // do_CreateInstance -#include "nsServiceManagerUtils.h" // do_GetService #include "nsIHttpActivityObserver.h" #include "nsSocketTransportService2.h" #include "nsICancelable.h" @@ -240,8 +239,10 @@ nsHttpTransaction::Init(uint32_t caps, MOZ_ASSERT(target); MOZ_ASSERT(NS_IsMainThread()); - mActivityDistributor = do_GetService(NS_HTTPACTIVITYDISTRIBUTOR_CONTRACTID, &rv); - if (NS_FAILED(rv)) return rv; + mActivityDistributor = services::GetActivityDistributor(); + if (!mActivityDistributor) { + return NS_ERROR_NOT_AVAILABLE; + } bool activityDistributorActive; rv = mActivityDistributor->GetIsActive(&activityDistributorActive); diff --git a/xpcom/build/ServiceList.h b/xpcom/build/ServiceList.h index 3bb8308dd..863febb20 100644 --- a/xpcom/build/ServiceList.h +++ b/xpcom/build/ServiceList.h @@ -33,6 +33,16 @@ MOZ_SERVICE(UUIDGenerator, nsIUUIDGenerator, "@mozilla.org/uuid-generator;1"); MOZ_SERVICE(GfxInfo, nsIGfxInfo, "@mozilla.org/gfx/info;1"); +MOZ_SERVICE(SocketTransportService, nsISocketTransportService, + "@mozilla.org/network/socket-transport-service;1"); +MOZ_SERVICE(StreamTransportService, nsIStreamTransportService, + "@mozilla.org/network/stream-transport-service;1"); +MOZ_SERVICE(CacheStorageService, nsICacheStorageService, + "@mozilla.org/netwerk/cache-storage-service;1"); +MOZ_SERVICE(URIClassifier, nsIURIClassifier, + "@mozilla.org/uriclassifierservice"); +MOZ_SERVICE(ActivityDistributor, nsIHttpActivityDistributor, + "@mozilla.org/network/http-activity-distributor;1"); #ifdef MOZ_USE_NAMESPACE namespace mozilla { diff --git a/xpcom/build/Services.cpp b/xpcom/build/Services.cpp index 8602d74f8..eab6f7656 100644 --- a/xpcom/build/Services.cpp +++ b/xpcom/build/Services.cpp @@ -22,6 +22,11 @@ #include "inIDOMUtils.h" #include "nsIPermissionManager.h" #include "nsIServiceWorkerManager.h" +#include "nsICacheStorageService.h" +#include "nsIStreamTransportService.h" +#include "nsISocketTransportService.h" +#include "nsIURIClassifier.h" +#include "nsIHttpActivityObserver.h" #include "nsIAsyncShutdown.h" #include "nsIUUIDGenerator.h" #include "nsIGfxInfo.h" diff --git a/xpcom/io/nsEscape.cpp b/xpcom/io/nsEscape.cpp index f16edc4ce..1f6abb5d8 100644 --- a/xpcom/io/nsEscape.cpp +++ b/xpcom/io/nsEscape.cpp @@ -11,6 +11,7 @@ #include "nsTArray.h" #include "nsCRT.h" #include "plstr.h" +#include "nsASCIIMask.h" static const char hexCharsUpper[] = "0123456789ABCDEF"; static const char hexCharsUpperLower[] = "0123456789ABCDEFabcdef"; @@ -382,7 +383,8 @@ static uint16_t dontNeedEscape(uint16_t aChar, uint32_t aFlags) template static nsresult T_EscapeURL(const typename T::char_type* aPart, size_t aPartLen, - uint32_t aFlags, T& aResult, bool& aDidAppend) + uint32_t aFlags, const ASCIIMaskArray* aFilterMask, + T& aResult, bool& aDidAppend) { typedef nsCharTraits traits; typedef typename traits::unsigned_char_type unsigned_char_type; @@ -409,6 +411,19 @@ T_EscapeURL(const typename T::char_type* aPart, size_t aPartLen, for (size_t i = 0; i < aPartLen; ++i) { unsigned_char_type c = *src++; + // If there is a filter, we wish to skip any characters which match it. + // This is needed so we don't perform an extra pass just to extract the + // filtered characters. + if (aFilterMask && ASCIIMask::IsMasked(*aFilterMask, c)) { + if (!writing) { + if (!aResult.Append(aPart, i, fallible)) { + return NS_ERROR_OUT_OF_MEMORY; + } + writing = true; + } + continue; + } + // if the char has not to be escaped or whatever follows % is // a valid escaped string, just copy the char. // @@ -474,7 +489,7 @@ NS_EscapeURL(const char* aPart, int32_t aPartLen, uint32_t aFlags, } bool result = false; - nsresult rv = T_EscapeURL(aPart, aPartLen, aFlags, aResult, result); + nsresult rv = T_EscapeURL(aPart, aPartLen, aFlags, nullptr, aResult, result); if (NS_FAILED(rv)) { ::NS_ABORT_OOM(aResult.Length() * sizeof(nsACString::char_type)); } @@ -487,7 +502,28 @@ NS_EscapeURL(const nsCSubstring& aStr, uint32_t aFlags, nsCSubstring& aResult, const mozilla::fallible_t&) { bool appended = false; - nsresult rv = T_EscapeURL(aStr.Data(), aStr.Length(), aFlags, aResult, appended); + nsresult rv = T_EscapeURL(aStr.Data(), aStr.Length(), aFlags, nullptr, aResult, appended); + if (NS_FAILED(rv)) { + aResult.Truncate(); + return rv; + } + + if (!appended) { + if (!aResult.Assign(aStr, fallible)) { + return NS_ERROR_OUT_OF_MEMORY; + } + } + + return rv; +} + +nsresult +NS_EscapeAndFilterURL(const nsACString& aStr, uint32_t aFlags, + const ASCIIMaskArray* aFilterMask, + nsACString& aResult, const mozilla::fallible_t&) +{ + bool appended = false; + nsresult rv = T_EscapeURL(aStr.Data(), aStr.Length(), aFlags, aFilterMask, aResult, appended); if (NS_FAILED(rv)) { aResult.Truncate(); return rv; @@ -504,7 +540,7 @@ const nsSubstring& NS_EscapeURL(const nsSubstring& aStr, uint32_t aFlags, nsSubstring& aResult) { bool result = false; - nsresult rv = T_EscapeURL(aStr.Data(), aStr.Length(), aFlags, aResult, result); + nsresult rv = T_EscapeURL(aStr.Data(), aStr.Length(), aFlags, nullptr, aResult, result); if (NS_FAILED(rv)) { ::NS_ABORT_OOM(aResult.Length() * sizeof(nsSubstring::char_type)); diff --git a/xpcom/io/nsEscape.h b/xpcom/io/nsEscape.h index bf89b737a..9d29ae65a 100644 --- a/xpcom/io/nsEscape.h +++ b/xpcom/io/nsEscape.h @@ -169,6 +169,19 @@ nsresult NS_EscapeURL(const nsCSubstring& aStr, uint32_t aFlags, nsCSubstring& aResult, const mozilla::fallible_t&); +// Forward declaration for nsASCIIMask.h +typedef std::array ASCIIMaskArray; + +/** + * The same as NS_EscapeURL, except it also filters out characters that match + * aFilterMask. + */ +nsresult +NS_EscapeAndFilterURL(const nsACString& aStr, uint32_t aFlags, + const ASCIIMaskArray* aFilterMask, + nsACString& aResult, const mozilla::fallible_t&); + + inline const nsCSubstring& NS_UnescapeURL(const nsCSubstring& aStr, uint32_t aFlags, nsCSubstring& aResult) { diff --git a/xpcom/string/moz.build b/xpcom/string/moz.build index 6ad7d7cc8..003f46a65 100644 --- a/xpcom/string/moz.build +++ b/xpcom/string/moz.build @@ -8,6 +8,7 @@ with Files('**'): BUG_COMPONENT = ('Core', 'String') EXPORTS += [ + 'nsASCIIMask.h', 'nsAString.h', 'nsCharTraits.h', 'nsDependentString.h', @@ -39,6 +40,7 @@ EXPORTS += [ ] UNIFIED_SOURCES += [ + 'nsASCIIMask.cpp', 'nsDependentString.cpp', 'nsDependentSubstring.cpp', 'nsPromiseFlatString.cpp', diff --git a/xpcom/string/nsASCIIMask.cpp b/xpcom/string/nsASCIIMask.cpp new file mode 100644 index 000000000..1c617a5b4 --- /dev/null +++ b/xpcom/string/nsASCIIMask.cpp @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsASCIIMask.h" + +namespace mozilla { + +constexpr bool TestWhitespace(char c) +{ + return c == '\f' || c == '\t' || c == '\r' || c == '\n' || c == ' '; +} +constexpr ASCIIMaskArray sWhitespaceMask = CreateASCIIMask(TestWhitespace); + +constexpr bool TestCRLF(char c) +{ + return c == '\r' || c == '\n'; +} +constexpr ASCIIMaskArray sCRLFMask = CreateASCIIMask(TestCRLF); + +constexpr bool TestCRLFTab(char c) +{ + return c == '\r' || c == '\n' || c == '\t'; +} +constexpr ASCIIMaskArray sCRLFTabMask = CreateASCIIMask(TestCRLFTab); + +constexpr bool TestZeroToNine(char c) +{ + return c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || + c == '5' || c == '6' || c == '7' || c == '8' || c == '9'; +} +constexpr ASCIIMaskArray sZeroToNineMask = CreateASCIIMask(TestZeroToNine); + +const ASCIIMaskArray& ASCIIMask::MaskWhitespace() +{ + return sWhitespaceMask; +} + +const ASCIIMaskArray& ASCIIMask::MaskCRLF() +{ + return sCRLFMask; +} + +const ASCIIMaskArray& ASCIIMask::MaskCRLFTab() +{ + return sCRLFTabMask; +} + +const ASCIIMaskArray& ASCIIMask::Mask0to9() +{ + return sZeroToNineMask; +} + +} // namespace mozilla diff --git a/xpcom/string/nsASCIIMask.h b/xpcom/string/nsASCIIMask.h new file mode 100644 index 000000000..7a3e76bef --- /dev/null +++ b/xpcom/string/nsASCIIMask.h @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsASCIIMask_h_ +#define nsASCIIMask_h_ + +#include +#include "mozilla/IndexSequence.h" + +typedef std::array ASCIIMaskArray; + +namespace mozilla { + +// Boolean arrays, fixed size and filled in at compile time, meant to +// record something about each of the (standard) ASCII characters. +// No extended ASCII for now, there has been no use case. +// If you have loops that go through a string character by character +// and test for equality to a certain set of characters before deciding +// on a course of action, chances are building up one of these arrays +// and using it is going to be faster, especially if the set of +// characters is more than one long, and known at compile time. +class ASCIIMask +{ +public: + // Preset masks for some common character groups + // When testing, you must check if the index is < 128 or use IsMasked() + // + // if (someChar < 128 && MaskCRLF()[someChar]) this is \r or \n + + static const ASCIIMaskArray& MaskCRLF(); + static const ASCIIMaskArray& Mask0to9(); + static const ASCIIMaskArray& MaskCRLFTab(); + static const ASCIIMaskArray& MaskWhitespace(); + + static MOZ_ALWAYS_INLINE bool IsMasked(const ASCIIMaskArray& aMask, uint32_t aChar) + { + return aChar < 128 && aMask[aChar]; + } +}; + +// Outside of the preset ones, use these templates to create more masks. +// +// The example creation will look like this: +// +// constexpr bool TestABC(char c) { return c == 'A' || c == 'B' || c == 'C'; } +// constexpr std::array sABCMask = CreateASCIIMask(TestABC); +// ... +// if (someChar < 128 && sABCMask[someChar]) this is A or B or C + + +namespace details +{ +template +constexpr std::array CreateASCIIMask(F fun, mozilla::IndexSequence) +{ + return {{ fun(Indices)... }}; +} +} // namespace details + +template +constexpr std::array CreateASCIIMask(F fun) +{ + return details::CreateASCIIMask(fun, mozilla::MakeIndexSequence<128>::Type{}); +} + +} // namespace mozilla + +#endif // nsASCIIMask_h_ diff --git a/xpcom/string/nsStringObsolete.cpp b/xpcom/string/nsStringObsolete.cpp index bd6daacab..2cfe06be3 100644 --- a/xpcom/string/nsStringObsolete.cpp +++ b/xpcom/string/nsStringObsolete.cpp @@ -540,8 +540,6 @@ StripChars2(char16_t* aString,uint32_t aLength,const char* aSet) { /* ***** END RICKG BLOCK ***** */ -static const char* kWhitespace="\f\t\r\n "; - // This function is used to implement FindCharInSet and friends template #ifndef __SUNPRO_CC diff --git a/xpcom/string/nsTStringObsolete.cpp b/xpcom/string/nsTStringObsolete.cpp index edab84b02..dd4911c42 100644 --- a/xpcom/string/nsTStringObsolete.cpp +++ b/xpcom/string/nsTStringObsolete.cpp @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsTArray.h" +#include "nsASCIIMask.h" #include "mozilla/CheckedInt.h" /** @@ -401,10 +402,9 @@ nsTString_CharT::SetCharAt( char16_t aChar, uint32_t aIndex ) void nsTString_CharT::StripChars( const char* aSet ) { - if (!EnsureMutable()) + if (!StripChars(aSet, mozilla::fallible)) { AllocFailed(mLength); - - mLength = nsBufferRoutines::strip_chars(mData, mLength, aSet); + } } bool @@ -421,13 +421,20 @@ nsTString_CharT::StripChars( const char* aSet, const fallible_t& ) void nsTString_CharT::StripWhitespace() { - StripChars(kWhitespace); + if (!StripWhitespace(mozilla::fallible)) { + AllocFailed(mLength); + } } bool -nsTString_CharT::StripWhitespace(const fallible_t& aFallible) +nsTString_CharT::StripWhitespace( const fallible_t& ) { - return StripChars(kWhitespace, aFallible); + if (!EnsureMutable()) { + return false; + } + + StripTaggedASCII(mozilla::ASCIIMask::MaskWhitespace()); + return true; } /** @@ -672,13 +679,44 @@ nsTString_CharT::Trim( const char* aSet, bool aTrimLeading, bool aTrimTrailing, void nsTString_CharT::CompressWhitespace( bool aTrimLeading, bool aTrimTrailing ) { - const char* set = kWhitespace; + // Quick exit + if (mLength == 0) { + return; + } - ReplaceChar(set, ' '); - Trim(set, aTrimLeading, aTrimTrailing); + if (!EnsureMutable()) + AllocFailed(mLength); - // this one does some questionable fu... just copying the old code! - mLength = nsBufferRoutines::compress_chars(mData, mLength, set); + const ASCIIMaskArray& mask = mozilla::ASCIIMask::MaskWhitespace(); + + char_type* to = mData; + char_type* from = mData; + char_type* end = mData + mLength; + + // Compresses runs of whitespace down to a normal space ' ' and convert + // any whitespace to a normal space. This assumes that whitespace is + // all standard 7-bit ASCII. + bool skipWS = aTrimLeading; + while (from < end) { + uint32_t theChar = *from++; + if (mozilla::ASCIIMask::IsMasked(mask, theChar)) { + if (!skipWS) { + *to++ = ' '; + skipWS = true; + } + } else { + *to++ = theChar; + skipWS = false; + } + } + + // If we need to trim the trailing whitespace, back up one character. + if (aTrimTrailing && skipWS && to > mData) { + to--; + } + + *to = char_type(0); // add the null + mLength = to - mData; } diff --git a/xpcom/string/nsTSubstring.cpp b/xpcom/string/nsTSubstring.cpp index ceaa008d2..6d2776ff0 100644 --- a/xpcom/string/nsTSubstring.cpp +++ b/xpcom/string/nsTSubstring.cpp @@ -4,6 +4,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "nsASCIIMask.h" #include "mozilla/CheckedInt.h" #include "mozilla/double-conversion.h" #include "mozilla/MemoryReporting.h" @@ -852,7 +853,8 @@ nsTSubstring_CharT::FindChar(char_type aChar, index_type aOffset) const void nsTSubstring_CharT::StripChar(char_type aChar, int32_t aOffset) { - if (mLength == 0 || aOffset >= int32_t(mLength)) { + // Note that this implicitly guarantees mLength > 0 + if (aOffset >= int32_t(mLength)) { return; } @@ -879,6 +881,7 @@ nsTSubstring_CharT::StripChar(char_type aChar, int32_t aOffset) void nsTSubstring_CharT::StripChars(const char_type* aChars, uint32_t aOffset) { + // Note that this implicitly guarantees mLength > 0 if (aOffset >= uint32_t(mLength)) { return; } @@ -908,6 +911,45 @@ nsTSubstring_CharT::StripChars(const char_type* aChars, uint32_t aOffset) mLength = to - mData; } +void +nsTSubstring_CharT::StripTaggedASCII(const ASCIIMaskArray& aToStrip, + uint32_t aOffset) +{ + // Note that this implicitly guarantees mLength > 0 + if (aOffset >= uint32_t(mLength)) { + return; + } + + if (!EnsureMutable()) { + AllocFailed(mLength); + } + + char_type* to = mData + aOffset; + char_type* from = mData + aOffset; + char_type* end = mData + mLength; + + while (from < end) { + uint32_t theChar = (uint32_t)*from++; + // Replacing this with a call to ASCIIMask::IsMasked + // regresses performance somewhat, so leaving it inlined. + if (!mozilla::ASCIIMask::IsMasked(aToStrip, theChar)) { + // Not stripped, copy this char. + *to++ = (char_type)theChar; + } + } + *to = char_type(0); // add the null + mLength = to - mData; +} + +void +nsTSubstring_CharT::StripCRLF(uint32_t aOffset) +{ + // Expanding this call to copy the code from StripTaggedASCII + // instead of just calling it does somewhat help with performance + // but it is not worth it given the duplicated code. + StripTaggedASCII(mozilla::ASCIIMask::MaskCRLF(), aOffset); +} + int nsTSubstring_CharT::AppendFunc(void* aArg, const char* aStr, uint32_t aLen) { diff --git a/xpcom/string/nsTSubstring.h b/xpcom/string/nsTSubstring.h index a08036b1f..53d76a8ee 100644 --- a/xpcom/string/nsTSubstring.h +++ b/xpcom/string/nsTSubstring.h @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // IWYU pragma: private, include "nsString.h" +#include #include "mozilla/Casting.h" #include "mozilla/MemoryReporting.h" @@ -826,6 +827,31 @@ public: void StripChars(const char_type* aChars, uint32_t aOffset = 0); + /** + * This method is used to remove all occurrences of some characters this + * from this string. The characters removed have the corresponding + * entries in the bool array set to true; we retain all characters + * with code beyond 127. + * THE CALLER IS RESPONSIBLE for making sure the complete boolean + * array, 128 entries, is properly initialized. + * + * See also: ASCIIMask class. + * + * @param aToStrip -- Array where each entry is true if the + * corresponding ASCII character is to be stripped. All + * characters beyond code 127 are retained. Note that this + * parameter is of ASCIIMaskArray type, but we expand the typedef + * to avoid having to include nsASCIIMask.h in this include file + * as it brings other includes. + * @param aOffset -- where in this string to start stripping chars + */ + void StripTaggedASCII(const std::array& aToStrip, uint32_t aOffset = 0); + + /** + * A shortcut to strip \r and \n. + */ + void StripCRLF(uint32_t aOffset = 0); + /** * If the string uses a shared buffer, this method * clears the pointer without releasing the buffer. diff --git a/xpfe/appshell/nsXULWindow.cpp b/xpfe/appshell/nsXULWindow.cpp index f52d85ad2..f82d525ac 100644 --- a/xpfe/appshell/nsXULWindow.cpp +++ b/xpfe/appshell/nsXULWindow.cpp @@ -913,7 +913,7 @@ NS_IMETHODIMP nsXULWindow::SetTitle(const char16_t* aTitle) { NS_ENSURE_STATE(mWindow); mTitle.Assign(aTitle); - mTitle.StripChars("\n\r"); + mTitle.StripCRLF(); NS_ENSURE_SUCCESS(mWindow->SetTitle(mTitle), NS_ERROR_FAILURE); // Tell the window mediator that a title has changed