From a9046dcd55c721bb3ddedadbbdb217848cb99d8e Mon Sep 17 00:00:00 2001 From: Moonchild Date: Wed, 8 Dec 2021 18:02:29 +0000 Subject: [Network] Escape external protocol handler URLs --- netwerk/base/nsINetUtil.idl | 3 ++ .../exthandler/nsExternalHelperAppService.cpp | 40 ++++++++++-------- uriloader/exthandler/nsExternalHelperAppService.h | 2 + xpcom/io/nsEscape.cpp | 47 +++++++++++----------- xpcom/io/nsEscape.h | 6 ++- 5 files changed, 58 insertions(+), 40 deletions(-) diff --git a/netwerk/base/nsINetUtil.idl b/netwerk/base/nsINetUtil.idl index 800a9ae905..1b5de18b61 100644 --- a/netwerk/base/nsINetUtil.idl +++ b/netwerk/base/nsINetUtil.idl @@ -167,6 +167,9 @@ interface nsINetUtil : nsISupports /** Skip C0 and DEL from unescaping */ const unsigned long ESCAPE_URL_SKIP_CONTROL = 1 << 15; + /** %XX-escape external protocol handler URL */ + const unsigned long ESCAPE_URL_EXT_HANDLER = 1 << 17; + /** * %XX-Escape invalid chars in a URL segment. * diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp index e3e135b053..02a555f04c 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -1,5 +1,4 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * vim:expandtab:shiftwidth=2:tabstop=2:cin: * 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/. */ @@ -851,6 +850,25 @@ NS_IMETHODIMP nsExternalHelperAppService::LoadUrl(nsIURI * aURL) static const char kExternalProtocolPrefPrefix[] = "network.protocol-handler.external."; static const char kExternalProtocolDefaultPref[] = "network.protocol-handler.external-default"; +// static +nsresult nsExternalHelperAppService::EscapeURI(nsIURI* aURI, nsIURI** aResult) { + MOZ_ASSERT(aURI); + MOZ_ASSERT(aResult); + + nsAutoCString spec; + aURI->GetSpec(spec); + + if (spec.Find("%00") != -1) return NS_ERROR_MALFORMED_URI; + + nsAutoCString escapedSpec; + nsresult rv = NS_EscapeURL(spec, esc_AlwaysCopy | esc_ExtHandler, escapedSpec, + fallible); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr ios(do_GetIOService()); + return ios->NewURI(escapedSpec, nullptr, nullptr, aResult); +} + NS_IMETHODIMP nsExternalHelperAppService::LoadURI(nsIURI *aURI, nsIInterfaceRequestor *aWindowContext) @@ -867,22 +885,12 @@ nsExternalHelperAppService::LoadURI(nsIURI *aURI, return NS_OK; } - nsAutoCString spec; - aURI->GetSpec(spec); - - if (spec.Find("%00") != -1) - return NS_ERROR_MALFORMED_URI; - - spec.ReplaceSubstring("\"", "%22"); - spec.ReplaceSubstring("`", "%60"); - - nsCOMPtr ios(do_GetIOService()); - nsCOMPtr uri; - nsresult rv = ios->NewURI(spec, nullptr, nullptr, getter_AddRefs(uri)); + nsCOMPtr escapedURI; + nsresult rv = EscapeURI(aURI, getter_AddRefs(escapedURI)); NS_ENSURE_SUCCESS(rv, rv); nsAutoCString scheme; - uri->GetScheme(scheme); + escapedURI->GetScheme(scheme); if (scheme.IsEmpty()) return NS_OK; // must have a scheme @@ -915,13 +923,13 @@ nsExternalHelperAppService::LoadURI(nsIURI *aURI, // a helper app or the system default, we just launch the URI. if (!alwaysAsk && (preferredAction == nsIHandlerInfo::useHelperApp || preferredAction == nsIHandlerInfo::useSystemDefault)) - return handler->LaunchWithURI(uri, aWindowContext); + return handler->LaunchWithURI(escapedURI, aWindowContext); nsCOMPtr chooser = do_CreateInstance("@mozilla.org/content-dispatch-chooser;1", &rv); NS_ENSURE_SUCCESS(rv, rv); - return chooser->Ask(handler, aWindowContext, uri, + return chooser->Ask(handler, aWindowContext, escapedURI, nsIContentDispatchChooser::REASON_CANNOT_HANDLE); } diff --git a/uriloader/exthandler/nsExternalHelperAppService.h b/uriloader/exthandler/nsExternalHelperAppService.h index ceec66661d..13dcbb7122 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.h +++ b/uriloader/exthandler/nsExternalHelperAppService.h @@ -198,6 +198,8 @@ private: bool aForceSave, nsIInterfaceRequestor *aWindowContext, nsIStreamListener ** aStreamListener); + + static nsresult EscapeURI(nsIURI* aURI, nsIURI** aResult); }; /** diff --git a/xpcom/io/nsEscape.cpp b/xpcom/io/nsEscape.cpp index 50de7db08c..7a5e3a3355 100644 --- a/xpcom/io/nsEscape.cpp +++ b/xpcom/io/nsEscape.cpp @@ -329,39 +329,40 @@ nsEscapeHTML2(const char16_t* aSourceBuffer, int32_t aSourceBufferLen) // parts of an URL. The bits are the "url components" in the enum EscapeMask, // see nsEscape.h. // -// esc_Scheme = 1 -// esc_Username = 2 -// esc_Password = 4 -// esc_Host = 8 -// esc_Directory = 16 -// esc_FileBaseName = 32 -// esc_FileExtension = 64 -// esc_Param = 128 -// esc_Query = 256 -// esc_Ref = 512 +// esc_Scheme = 1 +// esc_Username = 2 +// esc_Password = 4 +// esc_Host = 8 +// esc_Directory = 16 +// esc_FileBaseName = 32 +// esc_FileExtension = 64 +// esc_Param = 128 +// esc_Query = 256 +// esc_Ref = 512 +// esc_ExtHandler = 131072 static const uint32_t EscapeChars[256] = -// 0 1 2 3 4 5 6 7 8 9 A B C D E F +// 0 1 2 3 4 5 6 7 8 9 A B C D E F { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x - 0,1023, 0, 512,1023, 0,1023, 624,1023,1023,1023,1023,1023,1023, 953, 784, // 2x !"#$%&'()*+,-./ - 1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1008,1008, 0,1008, 0, 768, // 3x 0123456789:;<=>? - 1008,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023, // 4x @ABCDEFGHIJKLMNO - 1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1008, 896,1008, 896,1023, // 5x PQRSTUVWXYZ[\]^_ - 384,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023, // 6x `abcdefghijklmno - 1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023, 896,1012, 896,1023, 0, // 7x pqrstuvwxyz{|}~ DEL - 0 // 80 to FF are zero + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x + 0,132095, 0,131584,132095, 0,132095,131696,132095,132095,132095,132095,132095,132095,132025,131856, // 2x !"#$%&'()*+,-./ + 132095,132095,132095,132095,132095,132095,132095,132095,132095,132095,132080,132080, 0,132080, 0,131840, // 3x 0123456789:;<=>? + 132080,132095,132095,132095,132095,132095,132095,132095,132095,132095,132095,132095,132095,132095,132095,132095, // 4x @ABCDEFGHIJKLMNO + 132095,132095,132095,132095,132095,132095,132095,132095,132095,132095,132095,132080, 896,132080, 896,132095, // 5x PQRSTUVWXYZ[\]^_ + 384,132095,132095,132095,132095,132095,132095,132095,132095,132095,132095,132095,132095,132095,132095,132095, // 6x `abcdefghijklmno + 132095,132095,132095,132095,132095,132095,132095,132095,132095,132095,132095, 896, 1012, 896,132095, 0, // 7x pqrstuvwxyz{|}~ DEL + 0 // 80 to FF are zero }; -static uint16_t dontNeedEscape(unsigned char aChar, uint32_t aFlags) +static bool dontNeedEscape(unsigned char aChar, uint32_t aFlags) { return EscapeChars[(uint32_t)aChar] & aFlags; } -static uint16_t dontNeedEscape(uint16_t aChar, uint32_t aFlags) +static bool dontNeedEscape(uint16_t aChar, uint32_t aFlags) { return aChar < mozilla::ArrayLength(EscapeChars) ? - (EscapeChars[(uint32_t)aChar] & aFlags) : 0; + (EscapeChars[(uint32_t)aChar] & aFlags) : false; } //---------------------------------------------------------------------------------------- diff --git a/xpcom/io/nsEscape.h b/xpcom/io/nsEscape.h index b25e9ef8e7..f8ad8c7c8e 100644 --- a/xpcom/io/nsEscape.h +++ b/xpcom/io/nsEscape.h @@ -97,7 +97,11 @@ enum EscapeMask { * ascii octets (<= 0x7F) to be skipped when unescaping */ esc_AlwaysCopy = 1u << 13, /* copy input to result buf even if escaping is unnecessary */ esc_Colon = 1u << 14, /* forces escape of colon */ - esc_SkipControl = 1u << 15 /* skips C0 and DEL from unescaping */ + esc_SkipControl = 1u << 15, /* skips C0 and DEL from unescaping */ + esc_Spaces = 1u << 16, /* forces escape of spaces */ + esc_ExtHandler = 1u << 17 /* For escaping external protocol handler urls. + * Escapes everything except: + * a-z, 0-9 and !#$&'()*+,-./:;=?@[]_~ */ }; /** -- cgit v1.2.3