From 798cdc9e47f5b5231fb64d0ff552658026763b70 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Mon, 30 Dec 2019 08:46:47 -0500 Subject: Bug 1176399 - Multiple requests for master password when GMail OAuth2 is enabled. --- mailnews/base/public/nsIMsgAsyncPrompter.idl | 26 +++++++++++++---- mailnews/base/src/msgAsyncPrompter.js | 33 +++++++++++++++++----- mailnews/base/src/msgOAuth2Module.js | 42 ++++++++++++++++++++++------ mailnews/imap/src/nsImapProtocol.cpp | 7 +++++ mailnews/local/src/nsPop3Protocol.cpp | 7 +++++ mailnews/news/src/nsNNTPProtocol.cpp | 7 +++++ 6 files changed, 101 insertions(+), 21 deletions(-) diff --git a/mailnews/base/public/nsIMsgAsyncPrompter.idl b/mailnews/base/public/nsIMsgAsyncPrompter.idl index 5a59c4f39..4e1f81d12 100644 --- a/mailnews/base/public/nsIMsgAsyncPrompter.idl +++ b/mailnews/base/public/nsIMsgAsyncPrompter.idl @@ -35,20 +35,36 @@ interface nsIMsgAsyncPrompter : nsISupports { in nsIMsgAsyncPromptListener aCaller); }; +[scriptable, function, uuid(acca94c9-378e-46e3-9a91-6655bf9c91a3)] +interface nsIMsgAsyncPromptCallback : nsISupports { + /** + * Called when an auth result is available. Can be passed as a function. + * + * @param aResult True if there is auth information available following the + * prompt, false otherwise. + */ + void onAuthResult(in boolean aResult); +}; + /** * This is used in combination with nsIMsgAsyncPrompter. */ [scriptable, uuid(fb5307a3-39d0-462e-92c8-c5c288a2612f)] interface nsIMsgAsyncPromptListener : nsISupports { /** - * Called when the listener should do its prompt. The listener - * should not return until the prompt is complete. - * - * @return True if there is auth information available following the prompt, - * false otherwise. + * This method has been deprecated, please use onPromptStartAsync instead. */ boolean onPromptStart(); + /** + * Called when the listener should do its prompt. This can happen + * synchronously or asynchronously, but in any case when done the callback + * method should be called. + * + * @param aCallback The callback to execute when auth prompt has completed. + */ + void onPromptStartAsync(in nsIMsgAsyncPromptCallback aCallback); + /** * Called in the case that the queued prompt was combined with another and * there is now authentication information available. diff --git a/mailnews/base/src/msgAsyncPrompter.js b/mailnews/base/src/msgAsyncPrompter.js index 58b5288e9..ae114683a 100644 --- a/mailnews/base/src/msgAsyncPrompter.js +++ b/mailnews/base/src/msgAsyncPrompter.js @@ -2,6 +2,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/. */ +Components.utils.import("resource://gre/modules/Deprecated.jsm"); Components.utils.import("resource://gre/modules/Services.jsm"); Components.utils.import("resource://gre/modules/Task.jsm"); Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); @@ -19,28 +20,46 @@ runnablePrompter.prototype = { _asyncPrompter: null, _hashKey: null, + _promiseAuthPrompt: function(listener) { + return new Promise((resolve, reject) => { + try { + listener.onPromptStartAsync({ onAuthResult: resolve }); + } catch (e) { + if (e.result == Components.results.NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED) { + // Fall back to onPromptStart, for add-ons compat + Deprecated.warning("onPromptStart has been replaced by onPromptStartAsync", + "https://bugzilla.mozilla.org/show_bug.cgi?id=1176399"); + let ok = listener.onPromptStart(); + resolve(ok); + } else { + reject(e); + } + } + }); + }, + run: Task.async(function *() { yield Services.logins.initializationPromise; this._asyncPrompter._log.debug("Running prompt for " + this._hashKey); let prompter = this._asyncPrompter._pendingPrompts[this._hashKey]; let ok = false; try { - ok = prompter.first.onPromptStart(); - } - catch (ex) { + ok = yield this._promiseAuthPrompt(prompter.first); + } catch (ex) { Components.utils.reportError("runnablePrompter:run: " + ex + "\n"); + prompter.first.onPromptCanceled(); } delete this._asyncPrompter._pendingPrompts[this._hashKey]; for (var consumer of prompter.consumers) { try { - if (ok) + if (ok) { consumer.onPromptAuthAvailable(); - else + } else { consumer.onPromptCanceled(); - } - catch (ex) { + } + } catch (ex) { // Log the error for extension devs and others to pick up. Components.utils.reportError("runnablePrompter:run: consumer.onPrompt* reported an exception: " + ex + "\n"); } diff --git a/mailnews/base/src/msgOAuth2Module.js b/mailnews/base/src/msgOAuth2Module.js index 407ab0519..22d5dc572 100644 --- a/mailnews/base/src/msgOAuth2Module.js +++ b/mailnews/base/src/msgOAuth2Module.js @@ -126,19 +126,43 @@ OAuth2Module.prototype = { } } - // Otherwise, we need a new login, so create one and fill it in. - let login = Cc["@mozilla.org/login-manager/loginInfo;1"] - .createInstance(Ci.nsILoginInfo); - login.init(this._loginUrl, null, this._scope, this._username, token, - '', ''); - loginMgr.addLogin(login); + // Unless the token is null, we need to create and fill in a new login + if (token) { + let login = Cc["@mozilla.org/login-manager/loginInfo;1"] + .createInstance(Ci.nsILoginInfo); + login.init(this._loginUrl, null, this._scope, this._username, token, + '', ''); + loginMgr.addLogin(login); + } return token; }, connect(aWithUI, aListener) { - this._oauth.connect(() => aListener.onSuccess(this._oauth.accessToken), - x => aListener.onFailure(x), - aWithUI, false); + let oauth = this._oauth; + let promptlistener = { + onPromptStartAsync: function(callback) { + oauth.connect(() => { + this.onPromptAuthAvailable(); + callback.onAuthResult(true); + }, (err) => { + this.onPromptCanceled(); + callback.onAuthResult(false); + }, aWithUI, false); + }, + + onPromptAuthAvailable: function() { + aListener.onSuccess(oauth.accessToken); + }, + onPromptCanceled: function() { + aListener.onFailure(Components.results.NS_ERROR_ABORT); + }, + onPromptStart: function() {} + }; + + let asyncprompter = Components.classes["@mozilla.org/messenger/msgAsyncPrompter;1"] + .getService(Components.interfaces.nsIMsgAsyncPrompter); + let promptkey = this._loginUrl + "/" + this._username; + asyncprompter.queueAsyncAuthPrompt(promptkey, false, promptlistener); }, buildXOAuth2String() { diff --git a/mailnews/imap/src/nsImapProtocol.cpp b/mailnews/imap/src/nsImapProtocol.cpp index 4cfa9dab2..c8e3ceb67 100644 --- a/mailnews/imap/src/nsImapProtocol.cpp +++ b/mailnews/imap/src/nsImapProtocol.cpp @@ -8513,6 +8513,13 @@ nsresult nsImapProtocol::GetPassword(nsCString &password, return rv; } +NS_IMETHODIMP nsImapProtocol::OnPromptStartAsync(nsIMsgAsyncPromptCallback *aCallback) +{ + bool result = false; + OnPromptStart(&result); + return aCallback->OnAuthResult(result); +} + // This is called from the UI thread. NS_IMETHODIMP nsImapProtocol::OnPromptStart(bool *aResult) diff --git a/mailnews/local/src/nsPop3Protocol.cpp b/mailnews/local/src/nsPop3Protocol.cpp index 5d9d9145a..de129a494 100644 --- a/mailnews/local/src/nsPop3Protocol.cpp +++ b/mailnews/local/src/nsPop3Protocol.cpp @@ -740,6 +740,13 @@ nsresult nsPop3Protocol::StartGetAsyncPassword(Pop3StatesEnum aNextState) return rv; } +NS_IMETHODIMP nsPop3Protocol::OnPromptStartAsync(nsIMsgAsyncPromptCallback *aCallback) +{ + bool result = false; + OnPromptStart(&result); + return aCallback->OnAuthResult(result); +} + NS_IMETHODIMP nsPop3Protocol::OnPromptStart(bool *aResult) { MOZ_LOG(POP3LOGMODULE, LogLevel::Debug, (POP3LOG("OnPromptStart()"))); diff --git a/mailnews/news/src/nsNNTPProtocol.cpp b/mailnews/news/src/nsNNTPProtocol.cpp index 8ce367faa..035dff6e6 100644 --- a/mailnews/news/src/nsNNTPProtocol.cpp +++ b/mailnews/news/src/nsNNTPProtocol.cpp @@ -2472,6 +2472,13 @@ nsresult nsNNTPProtocol::PasswordResponse() return NS_ERROR_FAILURE; } +NS_IMETHODIMP nsNNTPProtocol::OnPromptStartAsync(nsIMsgAsyncPromptCallback *aCallback) +{ + bool result = false; + OnPromptStart(&result); + return aCallback->OnAuthResult(result); +} + NS_IMETHODIMP nsNNTPProtocol::OnPromptStart(bool *authAvailable) { NS_ENSURE_ARG_POINTER(authAvailable); -- cgit v1.2.3 From 1eb19e23097d94864d832993e9ed945affc0af66 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Mon, 30 Dec 2019 09:24:51 -0500 Subject: Bug 1453643 - Enable proper retry on oauth2 authenication failure. This prevents mail applications from attempting to use an unauthenticated connection to mailbox(s) and avoid unexpected deletion of local mbox files and subsequent re-download of mailbox content over imap. --- mailnews/imap/src/nsImapProtocol.cpp | 59 ++++++++++++++++++++---------------- mailnews/imap/src/nsImapProtocol.h | 1 + 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/mailnews/imap/src/nsImapProtocol.cpp b/mailnews/imap/src/nsImapProtocol.cpp index c8e3ceb67..940d87cbd 100644 --- a/mailnews/imap/src/nsImapProtocol.cpp +++ b/mailnews/imap/src/nsImapProtocol.cpp @@ -5714,6 +5714,36 @@ void nsImapProtocol::ResetAuthMethods() m_failedAuthMethods = 0; } +nsresult nsImapProtocol::SendDataParseIMAPandCheckForNewMail(const char *aData, const char *aCommand) +{ + nsresult rv; + bool isResend = false; + while (true) + { + // Send authentication string (true: suppress logging the string). + rv = SendData(aData, true); + if (NS_FAILED(rv)) + break; + ParseIMAPandCheckForNewMail(aCommand); + if (!GetServerStateParser().WaitingForMoreClientInput()) + break; + + // The server is asking for the authentication string again. So we send + // the same string again although we know that it might be rejected again. + // We do that to get a firm authentication failure instead of a resend + // request. That keeps things in order before failing authentication and + // trying another method if capable. + if (isResend) + { + rv = NS_ERROR_FAILURE; + break; + } + isResend = true; + } + + return rv; +} + nsresult nsImapProtocol::AuthLogin(const char *userName, const nsCString &password, eIMAPCapabilityFlag flag) { ProgressEventFunctionUsingName("imapStatusSendingAuthLogin"); @@ -5880,29 +5910,7 @@ nsresult nsImapProtocol::AuthLogin(const char *userName, const nsCString &passwo PR_snprintf(m_dataOutputBuf, OUTPUT_BUFFER_SIZE, "%s" CRLF, base64Str); PR_Free(base64Str); - bool isResend = false; - while (true) - { - // Send authentication string (true: suppress logging the string). - rv = SendData(m_dataOutputBuf, true); - if (NS_FAILED(rv)) - break; - ParseIMAPandCheckForNewMail(currentCommand); - if (!GetServerStateParser().WaitingForMoreClientInput()) - break; - - // Server is asking for authentication string again. So we send the - // same string again although we already know that it will be - // rejected again. We do that to get a firm authentication failure - // instead of a resend request. That keeps things in order before - // failing "authenticate PLAIN" and trying another method if capable. - if (isResend) - { - rv = NS_ERROR_FAILURE; - break; - } - isResend = true; - } + rv = SendDataParseIMAPandCheckForNewMail(m_dataOutputBuf, currentCommand); } // if the last command succeeded } // if auth plain capability else if (flag & kHasAuthLoginCapability) @@ -5953,9 +5961,8 @@ nsresult nsImapProtocol::AuthLogin(const char *userName, const nsCString &passwo EscapeUserNamePasswordString(password.get(), &correctedPassword); command.Append(correctedPassword); command.Append("\"" CRLF); - rv = SendData(command.get(), true /* suppress logging */); - NS_ENSURE_SUCCESS(rv, rv); - ParseIMAPandCheckForNewMail(); + + rv = SendDataParseIMAPandCheckForNewMail(command.get(), nullptr); } #ifdef MOZ_MAILNEWS_OAUTH2 else if (flag & kHasXOAuth2Capability) diff --git a/mailnews/imap/src/nsImapProtocol.h b/mailnews/imap/src/nsImapProtocol.h index ba2594c89..8cee4f4fb 100644 --- a/mailnews/imap/src/nsImapProtocol.h +++ b/mailnews/imap/src/nsImapProtocol.h @@ -485,6 +485,7 @@ private: void Namespace(); void InsecureLogin(const char *userName, const nsCString &password); nsresult AuthLogin(const char *userName, const nsCString &password, eIMAPCapabilityFlag flag); + nsresult SendDataParseIMAPandCheckForNewMail(const char *data, const char *command); void ProcessAuthenticatedStateURL(); void ProcessAfterAuthenticated(); void ProcessSelectedStateURL(); -- cgit v1.2.3 From 135098e06425cf20b60dcdd23c8af8d67aa69385 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Mon, 30 Dec 2019 09:33:56 -0500 Subject: Bug 1597933 - clean up OAuth2 code: remove responseType which is always code. Response type token is part of the OAuth 2.0 Implicit Flow which is not used in Mail Applications, but also discouraged by the OAuth Working Group: https://developer.okta.com/blog/2019/05/01/is-the-oauth-implicit-flow-dead --- mailnews/base/util/OAuth2.jsm | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/mailnews/base/util/OAuth2.jsm b/mailnews/base/util/OAuth2.jsm index 94f850e0b..dcbfb428f 100644 --- a/mailnews/base/util/OAuth2.jsm +++ b/mailnews/base/util/OAuth2.jsm @@ -3,7 +3,8 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ /** - * Provides OAuth 2.0 authentication + * Provides OAuth 2.0 authentication. + * @see RFC 6749 */ var EXPORTED_SYMBOLS = ["OAuth2"]; @@ -41,8 +42,6 @@ OAuth2.CODE_AUTHORIZATION = "authorization_code"; OAuth2.CODE_REFRESH = "refresh_token"; OAuth2.prototype = { - - responseType: "code", consumerKey: null, consumerSecret: null, completionURI: "http://localhost", @@ -79,7 +78,7 @@ OAuth2.prototype = { requestAuthorization: function requestAuthorization() { let params = [ - ["response_type", this.responseType], + ["response_type", "code"], ["client_id", this.consumerKey], ["redirect_uri", this.completionURI], ]; @@ -173,13 +172,11 @@ OAuth2.prototype = { onAuthorizationReceived: function(aData) { this.log.info("authorization received" + aData); let results = parseURLData(aData); - if (this.responseType == "code" && results.code) { + if (results.code) { this.requestAccessToken(results.code, OAuth2.CODE_AUTHORIZATION); - } else if (this.responseType == "token") { - this.onAccessTokenReceived(JSON.stringify(results)); - } - else + } else { this.onAuthorizationFailed(null, aData); + } }, onAuthorizationFailed: function(aError, aData) { -- cgit v1.2.3 From c33ae6a656453e960a10f815b6d5d9632a21a293 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Mon, 30 Dec 2019 09:49:29 -0500 Subject: Bug 1597933 - improve OAuth2 params parsing. --- mailnews/base/util/OAuth2.jsm | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/mailnews/base/util/OAuth2.jsm b/mailnews/base/util/OAuth2.jsm index dcbfb428f..8feee0e94 100644 --- a/mailnews/base/util/OAuth2.jsm +++ b/mailnews/base/util/OAuth2.jsm @@ -15,15 +15,6 @@ Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource:///modules/gloda/log4moz.js"); -function parseURLData(aData) { - let result = {}; - aData.split(/[?#]/, 2)[1].split("&").forEach(function (aParam) { - let [key, value] = aParam.split("="); - result[key] = decodeURIComponent(value); - }); - return result; -} - // Only allow one connecting window per endpoint. var gConnecting = {}; @@ -169,13 +160,14 @@ OAuth2.prototype = { delete this._browserRequest; }, - onAuthorizationReceived: function(aData) { - this.log.info("authorization received" + aData); - let results = parseURLData(aData); - if (results.code) { - this.requestAccessToken(results.code, OAuth2.CODE_AUTHORIZATION); + // @see RFC 6749 section 4.1.2: Authorization Response + onAuthorizationReceived(aURL) { + this.log.info("OAuth2 authorization received: url=" + aURL); + let params = new URLSearchParams(aURL.split("?", 2)[1]); + if (params.has("code")) { + this.requestAccessToken(params.get("code"), OAuth2.CODE_AUTHORIZATION); } else { - this.onAuthorizationFailed(null, aData); + this.onAuthorizationFailed(null, aURL); } }, -- cgit v1.2.3 From 925fd5411553ff74e53d42b8524c64131589a9a6 Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Mon, 30 Dec 2019 10:20:58 -0500 Subject: Bug 1597933 - don't pass string constants to determine OAuth refresh token or not. --- mailnews/base/util/OAuth2.jsm | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/mailnews/base/util/OAuth2.jsm b/mailnews/base/util/OAuth2.jsm index 8feee0e94..037333abc 100644 --- a/mailnews/base/util/OAuth2.jsm +++ b/mailnews/base/util/OAuth2.jsm @@ -29,9 +29,6 @@ function OAuth2(aBaseURI, aScope, aAppKey, aAppSecret) { this.log = Log4Moz.getConfiguredLogger("TBOAuth"); } -OAuth2.CODE_AUTHORIZATION = "authorization_code"; -OAuth2.CODE_REFRESH = "refresh_token"; - OAuth2.prototype = { consumerKey: null, consumerSecret: null, @@ -53,7 +50,7 @@ OAuth2.prototype = { if (!aRefresh && this.accessToken) { aSuccess(); } else if (this.refreshToken) { - this.requestAccessToken(this.refreshToken, OAuth2.CODE_REFRESH); + this.requestAccessToken(this.refreshToken, true); } else { if (!aWithUI) { aFailure('{ "error": "auth_noui" }'); @@ -165,7 +162,7 @@ OAuth2.prototype = { this.log.info("OAuth2 authorization received: url=" + aURL); let params = new URLSearchParams(aURL.split("?", 2)[1]); if (params.has("code")) { - this.requestAccessToken(params.get("code"), OAuth2.CODE_AUTHORIZATION); + this.requestAccessToken(params.get("code"), false); } else { this.onAuthorizationFailed(null, aURL); } @@ -175,18 +172,27 @@ OAuth2.prototype = { this.connectFailureCallback(aData); }, - requestAccessToken: function requestAccessToken(aCode, aType) { + /** + * Request a new access token, or refresh an existing one. + * @param {string} aCode - The token issued to the client. + * @param {boolean} aRefresh - Whether it's a refresh of a token or not. + */ + requestAccessToken(aCode, aRefresh) { + // @see RFC 6749 section 4.1.3. Access Token Request + // @see RFC 6749 section 6. Refreshing an Access Token + let params = [ ["client_id", this.consumerKey], ["client_secret", this.consumerSecret], - ["grant_type", aType], ]; - if (aType == OAuth2.CODE_AUTHORIZATION) { + if (aRefresh) { + params.push(["grant_type", "refresh_token"]); + params.push(["refresh_token", aCode]); + } else { + params.push(["grant_type", "authorization_code"]); params.push(["code", aCode]); params.push(["redirect_uri", this.completionURI]); - } else if (aType == OAuth2.CODE_REFRESH) { - params.push(["refresh_token", aCode]); } let options = { -- cgit v1.2.3 From 686415ad89af3b4d9cf2199230a9546d1bd9472e Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Mon, 30 Dec 2019 10:26:15 -0500 Subject: Bug 1597933 - use fetch + URLSearchParms instead of Http.jsm to request OAuth2 access token. --- mailnews/base/util/OAuth2.jsm | 64 +++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/mailnews/base/util/OAuth2.jsm b/mailnews/base/util/OAuth2.jsm index 037333abc..6b1eb84a1 100644 --- a/mailnews/base/util/OAuth2.jsm +++ b/mailnews/base/util/OAuth2.jsm @@ -10,11 +10,12 @@ var EXPORTED_SYMBOLS = ["OAuth2"]; var {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components; -Cu.import("resource://gre/modules/Http.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource:///modules/gloda/log4moz.js"); +Cu.importGlobalProperties(["fetch"]); + // Only allow one connecting window per endpoint. var gConnecting = {}; @@ -181,49 +182,48 @@ OAuth2.prototype = { // @see RFC 6749 section 4.1.3. Access Token Request // @see RFC 6749 section 6. Refreshing an Access Token - let params = [ - ["client_id", this.consumerKey], - ["client_secret", this.consumerSecret], - ]; + let data = new URLSearchParams(); + data.append("client_id", this.consumerKey); + data.append("client_secret", this.consumerSecret); if (aRefresh) { - params.push(["grant_type", "refresh_token"]); - params.push(["refresh_token", aCode]); + data.append("grant_type", "refresh_token"); + data.append("refresh_token", aCode); } else { - params.push(["grant_type", "authorization_code"]); - params.push(["code", aCode]); - params.push(["redirect_uri", this.completionURI]); + data.append("grant_type", "authorization_code"); + data.append("code", aCode); + data.append("redirect_uri", this.completionURI); } - let options = { - postData: params, - onLoad: this.onAccessTokenReceived.bind(this), - onError: this.onAccessTokenFailed.bind(this) - } - httpRequest(this.tokenURI, options); - }, - - onAccessTokenFailed: function onAccessTokenFailed(aError, aData) { - if (aError != "offline") { - this.refreshToken = null; - } - this.connectFailureCallback(aData); - }, - - onAccessTokenReceived: function onRequestTokenReceived(aData) { - let result = JSON.parse(aData); - + this.log.info( + `Making access token request to the token endpoint: ${this.tokenURI}` + ); + fetch(this.tokenURI, { + method: "POST", + cache: "no-cache", + body: data, + }) + .then(response => response.json()) + .then(result => { + this.log.info("The authorization server issued an access token."); this.accessToken = result.access_token; if ("refresh_token" in result) { - this.refreshToken = result.refresh_token; + this.refreshToken = result.refresh_token; } if ("expires_in" in result) { - this.tokenExpires = (new Date()).getTime() + (result.expires_in * 1000); + this.tokenExpires = new Date().getTime() + result.expires_in * 1000; } else { - this.tokenExpires = Number.MAX_VALUE; + this.tokenExpires = Number.MAX_VALUE; } this.tokenType = result.token_type; - this.connectSuccessCallback(); + }) + .catch(err => { + // Getting an access token failed. + this.log.info( + `The authorization server returned an error response: ${err}` + ); + this.connectFailureCallback(err); + }); } }; -- cgit v1.2.3 From c5b7a8f476239f63f23dc257969c77af07e38d6b Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Mon, 30 Dec 2019 10:31:00 -0500 Subject: Bug 1597933 - Use URLSearchParams for setting params for OAuth2 authorization request. --- mailnews/base/util/OAuth2.jsm | 57 ++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/mailnews/base/util/OAuth2.jsm b/mailnews/base/util/OAuth2.jsm index 6b1eb84a1..c838660f0 100644 --- a/mailnews/base/util/OAuth2.jsm +++ b/mailnews/base/util/OAuth2.jsm @@ -66,25 +66,31 @@ OAuth2.prototype = { }, requestAuthorization: function requestAuthorization() { - let params = [ - ["response_type", "code"], - ["client_id", this.consumerKey], - ["redirect_uri", this.completionURI], - ]; - // The scope can be optional. + let params = new URLSearchParams({ + response_type: "code", + client_id: this.consumerKey, + redirect_uri: this.completionURI, + }); + + // The scope is optional. if (this.scope) { - params.push(["scope", this.scope]); + params.append("scope", this.scope); } - // Add extra parameters - params.push(...this.extraAuthParams); + for (let [name, value] of this.extraAuthParams) { + params.append(name, value); + } - // Now map the parameters to a string - params = params.map(([k,v]) => k + "=" + encodeURIComponent(v)).join("&"); + let authEndpointURI = this.authURI + "?" + params.toString(); + this.log.info( + "Interacting with the resource owner to obtain an authorization grant " + + "from the authorization endpoint: " + + authEndpointURI + ); this._browserRequest = { account: this, - url: this.authURI + "?" + params, + url: authEndpointURI, _active: true, iconURI: "", cancelled: function() { @@ -187,17 +193,20 @@ OAuth2.prototype = { data.append("client_secret", this.consumerSecret); if (aRefresh) { + this.log.info( + `Making a refresh request to the token endpoint: ${this.tokenURI}` + ); data.append("grant_type", "refresh_token"); data.append("refresh_token", aCode); } else { + this.log.info( + `Making access token request to the token endpoint: ${this.tokenURI}` + ); data.append("grant_type", "authorization_code"); data.append("code", aCode); data.append("redirect_uri", this.completionURI); } - this.log.info( - `Making access token request to the token endpoint: ${this.tokenURI}` - ); fetch(this.tokenURI, { method: "POST", cache: "no-cache", @@ -205,6 +214,18 @@ OAuth2.prototype = { }) .then(response => response.json()) .then(result => { + if ("error" in result) { + // RFC 6749 section 5.2. Error Response + this.log.info( + `The authorization server returned an error response: ${JSON.stringify( + result + )}` + ); + this.connectFailureCallback(result); + return; + } + + // RFC 6749 section 5.1. Successful Response this.log.info("The authorization server issued an access token."); this.accessToken = result.access_token; if ("refresh_token" in result) { @@ -215,14 +236,10 @@ OAuth2.prototype = { } else { this.tokenExpires = Number.MAX_VALUE; } - this.tokenType = result.token_type; this.connectSuccessCallback(); }) .catch(err => { - // Getting an access token failed. - this.log.info( - `The authorization server returned an error response: ${err}` - ); + this.log.info(`Connection to authorization server failed: ${err}`); this.connectFailureCallback(err); }); } -- cgit v1.2.3 From c7fbaa67c6089fdb2682984d8d4a6f484c1eb49d Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Mon, 30 Dec 2019 10:33:31 -0500 Subject: Bug 1599054 - allow callers to ommit sending OAuth2 client_secret parameter. --- mailnews/base/util/OAuth2.jsm | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/mailnews/base/util/OAuth2.jsm b/mailnews/base/util/OAuth2.jsm index c838660f0..8c9282d02 100644 --- a/mailnews/base/util/OAuth2.jsm +++ b/mailnews/base/util/OAuth2.jsm @@ -19,7 +19,21 @@ Cu.importGlobalProperties(["fetch"]); // Only allow one connecting window per endpoint. var gConnecting = {}; -function OAuth2(aBaseURI, aScope, aAppKey, aAppSecret) { +/** + * Constructor for the OAuth2 object. + * + * @constructor + * @param {string} aBaseURI - The base URI for authentication and token + * requests, oauth2/auth or oauth2/token will be added for the actual + * requests. + * @param {?string} aScope - The scope as specified by RFC 6749 Section 3.3. + * Will not be included in the requests if falsy. + * @param {string} aAppKey - The client_id as specified by RFC 6749 Section + * 2.3.1. + * @param {string} [aAppSecret=null] - The client_secret as specified in + * RFC 6749 section 2.3.1. Will not be included in the requests if null. + */ +function OAuth2(aBaseURI, aScope, aAppKey, aAppSecret = null) { this.authURI = aBaseURI + "oauth2/auth"; this.tokenURI = aBaseURI + "oauth2/token"; this.consumerKey = aAppKey; @@ -190,7 +204,12 @@ OAuth2.prototype = { let data = new URLSearchParams(); data.append("client_id", this.consumerKey); - data.append("client_secret", this.consumerSecret); + if (this.consumerSecret !== null) { + // Section 2.3.1. of RFC 6749 states that empty secrets MAY be omitted + // by the client. This OAuth implementation delegates this decission to + // the caller: If the secret is null, it will be omitted. + data.append("client_secret", this.consumerSecret); + } if (aRefresh) { this.log.info( -- cgit v1.2.3 From f0e7aec5da5de7fa825397feb9b1cec402d77cee Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Tue, 7 Jan 2020 21:24:58 +0100 Subject: Reject sample rates that are out-of-range for libsoundtouch. We never reach this with our normal use of this lib but adding the sanity check just in case. (ported from upstream) --- media/libsoundtouch/src/SoundTouch.cpp | 2 +- media/libsoundtouch/src/TDStretch.cpp | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/media/libsoundtouch/src/SoundTouch.cpp b/media/libsoundtouch/src/SoundTouch.cpp index a9d23fc3c..955818810 100644 --- a/media/libsoundtouch/src/SoundTouch.cpp +++ b/media/libsoundtouch/src/SoundTouch.cpp @@ -283,9 +283,9 @@ void SoundTouch::calcEffectiveRateAndTempo() // Sets sample rate. void SoundTouch::setSampleRate(uint srate) { - bSrateSet = true; // set sample rate, leave other tempo changer parameters as they are. pTDStretch->setParameters((int)srate); + bSrateSet = true; } diff --git a/media/libsoundtouch/src/TDStretch.cpp b/media/libsoundtouch/src/TDStretch.cpp index 81bde22f0..b955bfc96 100644 --- a/media/libsoundtouch/src/TDStretch.cpp +++ b/media/libsoundtouch/src/TDStretch.cpp @@ -126,8 +126,13 @@ void TDStretch::setParameters(int aSampleRate, int aSequenceMS, int aSeekWindowMS, int aOverlapMS) { // accept only positive parameter values - if zero or negative, use old values instead - if (aSampleRate > 0) this->sampleRate = aSampleRate; - if (aOverlapMS > 0) this->overlapMs = aOverlapMS; + if (aSampleRate > 0) + { + if (aSampleRate > 192000) ST_THROW_RT_ERROR("Error: Excessive samplerate"); + this->sampleRate = aSampleRate; + } + + if (aOverlapMS > 0) this->overlapMs = aOverlapMS; if (aSequenceMS > 0) { -- cgit v1.2.3 From f61a99e5ed6de754e9e99d05634c508f0b4d951a Mon Sep 17 00:00:00 2001 From: Makoto Kato Date: Thu, 9 Jan 2020 09:53:16 +0100 Subject: Issue #1348 - Part 1: Clean up input scope support for IMM32. Use AutoTArray to set input scope. --- widget/windows/WinIMEHandler.cpp | 76 ++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 50 deletions(-) diff --git a/widget/windows/WinIMEHandler.cpp b/widget/windows/WinIMEHandler.cpp index d44f729c4..99f0fb136 100644 --- a/widget/windows/WinIMEHandler.cpp +++ b/widget/windows/WinIMEHandler.cpp @@ -588,77 +588,53 @@ IMEHandler::SetInputScopeForIMM32(nsWindow* aWindow, if (sIsInTSFMode || !sSetInputScopes || aWindow->Destroyed()) { return; } - UINT arraySize = 0; - const InputScope* scopes = nullptr; + AutoTArray scopes; // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html if (aHTMLInputType.IsEmpty() || aHTMLInputType.EqualsLiteral("text")) { if (aHTMLInputInputmode.EqualsLiteral("url")) { - static const InputScope inputScopes[] = { IS_URL }; - scopes = &inputScopes[0]; - arraySize = ArrayLength(inputScopes); + scopes.AppendElement(IS_URL); } else if (aHTMLInputInputmode.EqualsLiteral("email")) { - static const InputScope inputScopes[] = { IS_EMAIL_SMTPEMAILADDRESS }; - scopes = &inputScopes[0]; - arraySize = ArrayLength(inputScopes); + scopes.AppendElement(IS_EMAIL_SMTPEMAILADDRESS); } else if (aHTMLInputInputmode.EqualsLiteral("tel")) { - static const InputScope inputScopes[] = - {IS_TELEPHONE_LOCALNUMBER, IS_TELEPHONE_FULLTELEPHONENUMBER}; - scopes = &inputScopes[0]; - arraySize = ArrayLength(inputScopes); + scopes.AppendElement(IS_TELEPHONE_LOCALNUMBER); + scopes.AppendElement(IS_TELEPHONE_FULLTELEPHONENUMBER); } else if (aHTMLInputInputmode.EqualsLiteral("numeric")) { - static const InputScope inputScopes[] = { IS_NUMBER }; - scopes = &inputScopes[0]; - arraySize = ArrayLength(inputScopes); + scopes.AppendElement(IS_NUMBER); } else { - static const InputScope inputScopes[] = { IS_DEFAULT }; - scopes = &inputScopes[0]; - arraySize = ArrayLength(inputScopes); + scopes.AppendElement(IS_DEFAULT); } } else if (aHTMLInputType.EqualsLiteral("url")) { - static const InputScope inputScopes[] = { IS_URL }; - scopes = &inputScopes[0]; - arraySize = ArrayLength(inputScopes); + scopes.AppendElement(IS_URL); } else if (aHTMLInputType.EqualsLiteral("search")) { - static const InputScope inputScopes[] = { IS_SEARCH }; - scopes = &inputScopes[0]; - arraySize = ArrayLength(inputScopes); + scopes.AppendElement(IS_SEARCH); } else if (aHTMLInputType.EqualsLiteral("email")) { - static const InputScope inputScopes[] = { IS_EMAIL_SMTPEMAILADDRESS }; - scopes = &inputScopes[0]; - arraySize = ArrayLength(inputScopes); + scopes.AppendElement(IS_EMAIL_SMTPEMAILADDRESS); } else if (aHTMLInputType.EqualsLiteral("password")) { - static const InputScope inputScopes[] = { IS_PASSWORD }; - scopes = &inputScopes[0]; - arraySize = ArrayLength(inputScopes); + scopes.AppendElement(IS_PASSWORD); } else if (aHTMLInputType.EqualsLiteral("datetime") || aHTMLInputType.EqualsLiteral("datetime-local")) { - static const InputScope inputScopes[] = { - IS_DATE_FULLDATE, IS_TIME_FULLTIME }; - scopes = &inputScopes[0]; - arraySize = ArrayLength(inputScopes); + scopes.AppendElement(IS_DATE_FULLDATE); + scopes.AppendElement(IS_TIME_FULLTIME); } else if (aHTMLInputType.EqualsLiteral("date") || aHTMLInputType.EqualsLiteral("month") || aHTMLInputType.EqualsLiteral("week")) { - static const InputScope inputScopes[] = { IS_DATE_FULLDATE }; - scopes = &inputScopes[0]; - arraySize = ArrayLength(inputScopes); + scopes.AppendElement(IS_DATE_FULLDATE); } else if (aHTMLInputType.EqualsLiteral("time")) { - static const InputScope inputScopes[] = { IS_TIME_FULLTIME }; - scopes = &inputScopes[0]; - arraySize = ArrayLength(inputScopes); + scopes.AppendElement(IS_TIME_FULLTIME); } else if (aHTMLInputType.EqualsLiteral("tel")) { - static const InputScope inputScopes[] = { - IS_TELEPHONE_FULLTELEPHONENUMBER, IS_TELEPHONE_LOCALNUMBER }; - scopes = &inputScopes[0]; - arraySize = ArrayLength(inputScopes); + scopes.AppendElement(IS_TELEPHONE_FULLTELEPHONENUMBER); + scopes.AppendElement(IS_TELEPHONE_LOCALNUMBER); } else if (aHTMLInputType.EqualsLiteral("number")) { - static const InputScope inputScopes[] = { IS_NUMBER }; - scopes = &inputScopes[0]; - arraySize = ArrayLength(inputScopes); + scopes.AppendElement(IS_NUMBER); } - if (scopes && arraySize > 0) { - sSetInputScopes(aWindow->GetWindowHandle(), scopes, arraySize, nullptr, 0, - nullptr, nullptr); + if (!scopes.IsEmpty()) { + sSetInputScopes(aWindow->GetWindowHandle(), + scopes.Elements(), + scopes.Length(), + nullptr, + 0, + nullptr, + nullptr); } } -- cgit v1.2.3 From e338d996999867b5d4f66d47837c56dba73a7f6b Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 9 Jan 2020 13:19:56 +0100 Subject: Issue #1348 - Part 2: Teach IMEState about Private Browsing mode. --- dom/events/IMEStateManager.cpp | 24 ++++++++++++++++-------- dom/events/IMEStateManager.h | 1 + widget/IMEData.h | 4 ++++ 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/dom/events/IMEStateManager.cpp b/dom/events/IMEStateManager.cpp index 1c8ed63f0..80abad3cc 100644 --- a/dom/events/IMEStateManager.cpp +++ b/dom/events/IMEStateManager.cpp @@ -297,7 +297,7 @@ IMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext) IMEState newState = GetNewIMEState(sPresContext, nullptr); InputContextAction action(InputContextAction::CAUSE_UNKNOWN, InputContextAction::LOST_FOCUS); - SetIMEState(newState, nullptr, sWidget, action); + SetIMEState(newState, nullptr, nullptr, sWidget, action); } sWidget = nullptr; sContent = nullptr; @@ -352,7 +352,7 @@ IMEStateManager::OnRemoveContent(nsPresContext* aPresContext, IMEState newState = GetNewIMEState(sPresContext, nullptr); InputContextAction action(InputContextAction::CAUSE_UNKNOWN, InputContextAction::LOST_FOCUS); - SetIMEState(newState, nullptr, sWidget, action); + SetIMEState(newState, aPresContext, nullptr, sWidget, action); } sWidget = nullptr; @@ -542,7 +542,7 @@ IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext, } // Update IME state for new focus widget - SetIMEState(newState, aContent, newWidget, aAction); + SetIMEState(newState, aPresContext, aContent, newWidget, aAction); } sActiveTabParent = newTabParent; @@ -704,7 +704,7 @@ IMEStateManager::OnClickInEditor(nsPresContext* aPresContext, InputContextAction action(cause, InputContextAction::FOCUS_NOT_CHANGED); IMEState newState = GetNewIMEState(aPresContext, aContent); - SetIMEState(newState, aContent, widget, action); + SetIMEState(newState, aPresContext, aContent, widget, action); } // static @@ -912,7 +912,7 @@ IMEStateManager::UpdateIMEState(const IMEState& aNewIMEState, if (updateIMEState) { InputContextAction action(InputContextAction::CAUSE_UNKNOWN, InputContextAction::FOCUS_NOT_CHANGED); - SetIMEState(aNewIMEState, aContent, widget, action); + SetIMEState(aNewIMEState, sPresContext, aContent, widget, action); if (NS_WARN_IF(widget->Destroyed())) { MOZ_LOG(sISMLog, LogLevel::Error, (" UpdateIMEState(), widget has gone during setting input context")); @@ -1022,8 +1022,8 @@ IMEStateManager::SetInputContextForChildProcess( MOZ_LOG(sISMLog, LogLevel::Info, ("SetInputContextForChildProcess(aTabParent=0x%p, " "aInputContext={ mIMEState={ mEnabled=%s, mOpen=%s }, " - "mHTMLInputType=\"%s\", mHTMLInputInputmode=\"%s\", mActionHint=\"%s\" }, " - "aAction={ mCause=%s, mAction=%s }), " + "mHTMLInputType=\"%s\", mHTMLInputInputmode=\"%s\", mActionHint=\"%s\", " + "mInPrivateBrowsing=%s }, aAction={ mCause=%s, mAction=%s }), " "sPresContext=0x%p (available: %s), sWidget=0x%p (available: %s), " "sActiveTabParent=0x%p", aTabParent, GetIMEStateEnabledName(aInputContext.mIMEState.mEnabled), @@ -1031,6 +1031,7 @@ IMEStateManager::SetInputContextForChildProcess( NS_ConvertUTF16toUTF8(aInputContext.mHTMLInputType).get(), NS_ConvertUTF16toUTF8(aInputContext.mHTMLInputInputmode).get(), NS_ConvertUTF16toUTF8(aInputContext.mActionHint).get(), + GetBoolName(aInputContext.mInPrivateBrowsing), GetActionCauseName(aAction.mCause), GetActionFocusChangeName(aAction.mFocusChange), sPresContext.get(), GetBoolName(CanHandleWith(sPresContext)), @@ -1070,6 +1071,7 @@ IMEStateManager::SetInputContextForChildProcess( // static void IMEStateManager::SetIMEState(const IMEState& aState, + nsPresContext* aPresContext, nsIContent* aContent, nsIWidget* aWidget, InputContextAction aAction) @@ -1090,6 +1092,10 @@ IMEStateManager::SetIMEState(const IMEState& aState, context.mIMEState = aState; context.mMayBeIMEUnaware = context.mIMEState.IsEditable() && sCheckForIMEUnawareWebApps && MayBeIMEUnawareWebApp(aContent); + + context.mInPrivateBrowsing = + aPresContext && + nsContentUtils::IsInPrivateBrowsing(aPresContext->Document()); if (aContent && aContent->IsAnyOfHTMLElements(nsGkAtoms::input, nsGkAtoms::textarea)) { @@ -1175,7 +1181,8 @@ IMEStateManager::SetInputContext(nsIWidget* aWidget, MOZ_LOG(sISMLog, LogLevel::Info, ("SetInputContext(aWidget=0x%p, aInputContext={ " "mIMEState={ mEnabled=%s, mOpen=%s }, mHTMLInputType=\"%s\", " - "mHTMLInputInputmode=\"%s\", mActionHint=\"%s\" }, " + "mHTMLInputInputmode=\"%s\", mActionHint=\"%s\", " + "mInPrivateBrowsing=%s }, " "aAction={ mCause=%s, mAction=%s }), sActiveTabParent=0x%p", aWidget, GetIMEStateEnabledName(aInputContext.mIMEState.mEnabled), @@ -1183,6 +1190,7 @@ IMEStateManager::SetInputContext(nsIWidget* aWidget, NS_ConvertUTF16toUTF8(aInputContext.mHTMLInputType).get(), NS_ConvertUTF16toUTF8(aInputContext.mHTMLInputInputmode).get(), NS_ConvertUTF16toUTF8(aInputContext.mActionHint).get(), + GetBoolName(aInputContext.mInPrivateBrowsing), GetActionCauseName(aAction.mCause), GetActionFocusChangeName(aAction.mFocusChange), sActiveTabParent.get())); diff --git a/dom/events/IMEStateManager.h b/dom/events/IMEStateManager.h index 7dfc48aa5..34509847f 100644 --- a/dom/events/IMEStateManager.h +++ b/dom/events/IMEStateManager.h @@ -247,6 +247,7 @@ protected: nsIContent* aContent, InputContextAction aAction); static void SetIMEState(const IMEState &aState, + nsPresContext* aPresContext, nsIContent* aContent, nsIWidget* aWidget, InputContextAction aAction); diff --git a/widget/IMEData.h b/widget/IMEData.h index b12497be3..04245df26 100644 --- a/widget/IMEData.h +++ b/widget/IMEData.h @@ -300,6 +300,10 @@ struct InputContext final * compatibility with webapps relying on key listeners. */ bool mMayBeIMEUnaware; + /* Whether the owning document of the input element has been loaded + * in private browsing mode. */ + bool mInPrivateBrowsing; + bool IsOriginMainProcess() const { return mOrigin == ORIGIN_MAIN; -- cgit v1.2.3 From 00b8ab8be2ac97de7ccb22af499208a281afd161 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 9 Jan 2020 13:22:29 +0100 Subject: Issue #1348 - Part 3: Set IS_PRIVATE input scope in private browsing. Microsoft IME on Windows 10 20H1 (build 19025+) supports IME private mode by input scope. Although previous Windows versions use an undocumented API for Edge and IE only, the next Windows 10 release will use a public API for it. We pre-empt this potential privacy concern by setting the IS_PRIVATE flag when in PB mode. --- widget/windows/TSFTextStore.cpp | 15 ++++++++++++--- widget/windows/TSFTextStore.h | 3 ++- widget/windows/WinIMEHandler.cpp | 16 ++++++++++++---- widget/windows/WinIMEHandler.h | 3 ++- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/widget/windows/TSFTextStore.cpp b/widget/windows/TSFTextStore.cpp index c80de831c..12b8cd0c1 100644 --- a/widget/windows/TSFTextStore.cpp +++ b/widget/windows/TSFTextStore.cpp @@ -1355,7 +1355,9 @@ TSFTextStore::Init(nsWindowBase* aWidget, return false; } - SetInputScope(aContext.mHTMLInputType, aContext.mHTMLInputInputmode); + SetInputScope(aContext.mHTMLInputType, + aContext.mHTMLInputInputmode, + aContext.mInPrivateBrowsing); // Create document manager RefPtr threadMgr = sThreadMgr; @@ -3205,9 +3207,15 @@ TSFTextStore::InsertEmbedded(DWORD dwFlags, void TSFTextStore::SetInputScope(const nsString& aHTMLInputType, - const nsString& aHTMLInputInputMode) + const nsString& aHTMLInputInputMode, + bool aInPrivateBrowsing) { mInputScopes.Clear(); + + if (aInPrivateBrowsing) { + mInputScopes.AppendElement(IS_PRIVATE); + } + if (aHTMLInputType.IsEmpty() || aHTMLInputType.EqualsLiteral("text")) { if (aHTMLInputInputMode.EqualsLiteral("url")) { mInputScopes.AppendElement(IS_URL); @@ -5688,7 +5696,8 @@ TSFTextStore::SetInputContext(nsWindowBase* aWidget, if (sEnabledTextStore) { RefPtr textStore(sEnabledTextStore); textStore->SetInputScope(aContext.mHTMLInputType, - aContext.mHTMLInputInputmode); + aContext.mHTMLInputInputmode, + aContext.mInPrivateBrowsing); } return; } diff --git a/widget/windows/TSFTextStore.h b/widget/windows/TSFTextStore.h index 9596510d5..d1431e95d 100644 --- a/widget/windows/TSFTextStore.h +++ b/widget/windows/TSFTextStore.h @@ -355,7 +355,8 @@ protected: ULONG aFilterCount, const TS_ATTRID* aFilterAttrs); void SetInputScope(const nsString& aHTMLInputType, - const nsString& aHTMLInputInputmode); + const nsString& aHTMLInputInputmode, + bool aInPrivateBrowsing); // Creates native caret over our caret. This method only works on desktop // application. Otherwise, this does nothing. diff --git a/widget/windows/WinIMEHandler.cpp b/widget/windows/WinIMEHandler.cpp index 99f0fb136..9debaa2dd 100644 --- a/widget/windows/WinIMEHandler.cpp +++ b/widget/windows/WinIMEHandler.cpp @@ -409,7 +409,7 @@ IMEHandler::OnDestroyWindow(nsWindow* aWindow) if (!sIsInTSFMode) { // MSDN says we need to set IS_DEFAULT to avoid memory leak when we use // SetInputScopes API. Use an empty string to do this. - SetInputScopeForIMM32(aWindow, EmptyString(), EmptyString()); + SetInputScopeForIMM32(aWindow, EmptyString(), EmptyString(), false); } #endif // #ifdef NS_ENABLE_TSF AssociateIMEContext(aWindow, true); @@ -481,8 +481,10 @@ IMEHandler::SetInputContext(nsWindow* aWindow, } } else { // Set at least InputScope even when TextStore is not available. - SetInputScopeForIMM32(aWindow, aInputContext.mHTMLInputType, - aInputContext.mHTMLInputInputmode); + SetInputScopeForIMM32(aWindow, + aInputContext.mHTMLInputType, + aInputContext.mHTMLInputInputmode, + aInputContext.mInPrivateBrowsing); } #endif // #ifdef NS_ENABLE_TSF @@ -583,12 +585,18 @@ IMEHandler::OnKeyboardLayoutChanged() void IMEHandler::SetInputScopeForIMM32(nsWindow* aWindow, const nsAString& aHTMLInputType, - const nsAString& aHTMLInputInputmode) + const nsAString& aHTMLInputInputmode, + bool aInPrivateBrowsing) { if (sIsInTSFMode || !sSetInputScopes || aWindow->Destroyed()) { return; } AutoTArray scopes; + + if (aInPrivateBrowsing) { + scopes.AppendElement(IS_PRIVATE); + } + // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html if (aHTMLInputType.IsEmpty() || aHTMLInputType.EqualsLiteral("text")) { if (aHTMLInputInputmode.EqualsLiteral("url")) { diff --git a/widget/windows/WinIMEHandler.h b/widget/windows/WinIMEHandler.h index c18a4437e..c836e8626 100644 --- a/widget/windows/WinIMEHandler.h +++ b/widget/windows/WinIMEHandler.h @@ -144,7 +144,8 @@ private: static decltype(SetInputScopes)* sSetInputScopes; static void SetInputScopeForIMM32(nsWindow* aWindow, const nsAString& aHTMLInputType, - const nsAString& aHTMLInputInputmode); + const nsAString& aHTMLInputInputmode, + bool aInPrivateBrowsing); static bool sIsInTSFMode; // If sIMMEnabled is false, any IME messages are not handled in TSF mode. // Additionally, IME context is always disassociated from focused window. -- cgit v1.2.3 From 19939f17f015f2155894f8e4c5e4ec9b8acc3ddc Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 9 Jan 2020 18:26:06 +0100 Subject: Simplify value setting. This gets rid of unused boolean return values on setters and a level of indirection for calls to set values. --- js/public/RootingAPI.h | 14 ++++---- js/public/Value.h | 91 ++++++++++++++++++-------------------------------- 2 files changed, 39 insertions(+), 66 deletions(-) diff --git a/js/public/RootingAPI.h b/js/public/RootingAPI.h index 9f6ed8943..ca35ea4a5 100644 --- a/js/public/RootingAPI.h +++ b/js/public/RootingAPI.h @@ -274,6 +274,12 @@ class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase T* unsafeGet() { return &ptr; } + void set(const T& newPtr) { + T tmp = ptr; + ptr = newPtr; + post(tmp, ptr); + } + explicit operator bool() const { return bool(js::BarrierMethods::asGCThingOrNull(ptr)); } @@ -287,12 +293,6 @@ class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase post(GCPolicy::initial(), ptr); } - void set(const T& newPtr) { - T tmp = ptr; - ptr = newPtr; - post(tmp, ptr); - } - void post(const T& prev, const T& next) { js::BarrierMethods::postBarrier(&ptr, prev, next); } @@ -1172,13 +1172,13 @@ class PersistentRooted : public js::PersistentRootedBase, return ptr; } - private: template void set(U&& value) { MOZ_ASSERT(initialized()); ptr = mozilla::Forward(value); } + private: // See the comment above Rooted::ptr. using MaybeWrapped = typename mozilla::Conditional< MapTypeToRootKind::kind == JS::RootKind::Traceable, diff --git a/js/public/Value.h b/js/public/Value.h index 7c4f833e3..272d9b478 100644 --- a/js/public/Value.h +++ b/js/public/Value.h @@ -399,25 +399,21 @@ class MOZ_NON_PARAM alignas(8) Value data.asBits = bitsFromTagAndPayload(JSVAL_TAG_MAGIC, payload); } - bool setNumber(uint32_t ui) { + void setNumber(uint32_t ui) { if (ui > JSVAL_INT_MAX) { setDouble((double)ui); - return false; } else { setInt32((int32_t)ui); - return true; } } - bool setNumber(double d) { + void setNumber(double d) { int32_t i; if (mozilla::NumberIsInt32(d, &i)) { setInt32(i); - return true; + } else { + setDouble(d); } - - setDouble(d); - return false; } void setObjectOrNull(JSObject* arg) { @@ -1406,25 +1402,29 @@ class ValueOperations template class MutableValueOperations : public ValueOperations { - JS::Value& value() { return static_cast(this)->get(); } + protected: + void set(const JS::Value& v) { + // Call Outer::set to trigger any barriers. + static_cast(this)->set(v); + } public: - void setNull() { value().setNull(); } - void setUndefined() { value().setUndefined(); } - void setInt32(int32_t i) { value().setInt32(i); } - void setDouble(double d) { value().setDouble(d); } + void setNull() { set(JS::NullValue()); } + void setUndefined() { set(JS::UndefinedValue()); } + void setInt32(int32_t i) { set(JS::Int32Value(i)); } + void setDouble(double d) { set(JS::DoubleValue(d)); } void setNaN() { setDouble(JS::GenericNaN()); } - void setBoolean(bool b) { value().setBoolean(b); } - void setMagic(JSWhyMagic why) { value().setMagic(why); } - bool setNumber(uint32_t ui) { return value().setNumber(ui); } - bool setNumber(double d) { return value().setNumber(d); } - void setString(JSString* str) { this->value().setString(str); } - void setSymbol(JS::Symbol* sym) { this->value().setSymbol(sym); } - void setObject(JSObject& obj) { this->value().setObject(obj); } - void setObjectOrNull(JSObject* arg) { this->value().setObjectOrNull(arg); } - void setPrivate(void* ptr) { this->value().setPrivate(ptr); } - void setPrivateUint32(uint32_t ui) { this->value().setPrivateUint32(ui); } - void setPrivateGCThing(js::gc::Cell* cell) { this->value().setPrivateGCThing(cell); } + void setBoolean(bool b) { set(JS::BooleanValue(b)); } + void setMagic(JSWhyMagic why) { set(JS::MagicValue(why)); } + void setNumber(uint32_t ui) { set(JS::NumberValue(ui)); } + void setNumber(double d) { set(JS::NumberValue(d)); } + void setString(JSString* str) { set(JS::StringValue(str)); } + void setSymbol(JS::Symbol* sym) { set(JS::SymbolValue(sym)); } + void setObject(JSObject& obj) { set(JS::ObjectValue(obj)); } + void setObjectOrNull(JSObject* arg) { set(JS::ObjectOrNullValue(arg)); } + void setPrivate(void* ptr) { set(JS::PrivateValue(ptr)); } + void setPrivateUint32(uint32_t ui) { set(JS::PrivateUint32Value(ui)); } + void setPrivateGCThing(js::gc::Cell* cell) { set(JS::PrivateGCThingValue(cell)); } }; /* @@ -1432,55 +1432,28 @@ class MutableValueOperations : public ValueOperations * type-querying, value-extracting, and mutating operations. */ template <> -class HeapBase : public ValueOperations > +class HeapBase : public MutableValueOperations > { typedef JS::Heap Outer; friend class ValueOperations; - void setBarriered(const JS::Value& v) { - *static_cast*>(this) = v; - } - public: - void setNull() { setBarriered(JS::NullValue()); } - void setUndefined() { setBarriered(JS::UndefinedValue()); } - void setInt32(int32_t i) { setBarriered(JS::Int32Value(i)); } - void setDouble(double d) { setBarriered(JS::DoubleValue(d)); } - void setNaN() { setDouble(JS::GenericNaN()); } - void setBoolean(bool b) { setBarriered(JS::BooleanValue(b)); } - void setMagic(JSWhyMagic why) { setBarriered(JS::MagicValue(why)); } - void setString(JSString* str) { setBarriered(JS::StringValue(str)); } - void setSymbol(JS::Symbol* sym) { setBarriered(JS::SymbolValue(sym)); } - void setObject(JSObject& obj) { setBarriered(JS::ObjectValue(obj)); } - void setPrivateGCThing(js::gc::Cell* cell) { setBarriered(JS::PrivateGCThingValue(cell)); } - - bool setNumber(uint32_t ui) { + void setNumber(uint32_t ui) { if (ui > JSVAL_INT_MAX) { - setDouble((double)ui); - return false; + this->setDouble((double)ui); } else { - setInt32((int32_t)ui); - return true; + this->setInt32((int32_t)ui); } } - bool setNumber(double d) { + void setNumber(double d) { int32_t i; if (mozilla::NumberIsInt32(d, &i)) { - setInt32(i); - return true; + this->setInt32(i); + } else { + this->setDouble(d); } - - setDouble(d); - return false; - } - - void setObjectOrNull(JSObject* arg) { - if (arg) - setObject(*arg); - else - setNull(); } }; -- cgit v1.2.3 From d0256e1afc1ba721e98f377d8925e7b7282f5a99 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 9 Jan 2020 21:39:28 +0100 Subject: Be more consistent about decoding IP addresses in PSM. --- security/manager/ssl/TransportSecurityInfo.cpp | 5 ++++- security/manager/ssl/nsNSSCertHelper.cpp | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/security/manager/ssl/TransportSecurityInfo.cpp b/security/manager/ssl/TransportSecurityInfo.cpp index 3c7023302..3f4bf4a90 100644 --- a/security/manager/ssl/TransportSecurityInfo.cpp +++ b/security/manager/ssl/TransportSecurityInfo.cpp @@ -8,6 +8,7 @@ #include "PSMRunnable.h" #include "mozilla/Casting.h" +#include "mozilla/net/DNS.h" #include "nsComponentManagerUtils.h" #include "nsIArray.h" #include "nsICertOverrideService.h" @@ -681,8 +682,10 @@ GetSubjectAltNames(CERTCertificate* nssCert, nsString& allNames) case certIPAddress: { - char buf[INET6_ADDRSTRLEN]; + // According to DNS.h, this includes space for the null-terminator + char buf[net::kNetAddrMaxCStrBufSize] = {0}; PRNetAddr addr; + memset(&addr, 0, sizeof(addr)); if (current->name.other.len == 4) { addr.inet.family = PR_AF_INET; memcpy(&addr.inet.ip, current->name.other.data, current->name.other.len); diff --git a/security/manager/ssl/nsNSSCertHelper.cpp b/security/manager/ssl/nsNSSCertHelper.cpp index 64c87ad2f..efcb8747a 100644 --- a/security/manager/ssl/nsNSSCertHelper.cpp +++ b/security/manager/ssl/nsNSSCertHelper.cpp @@ -11,6 +11,7 @@ #include "mozilla/NotNull.h" #include "mozilla/Sprintf.h" #include "mozilla/UniquePtr.h" +#include "mozilla/net/DNS.h" #include "nsCOMPtr.h" #include "nsComponentManagerUtils.h" #include "nsDateTimeFormatCID.h" @@ -1006,8 +1007,9 @@ ProcessGeneralName(const UniquePLArenaPool& arena, CERTGeneralName* current, break; case certIPAddress: { - char buf[INET6_ADDRSTRLEN]; PRStatus status = PR_FAILURE; + // According to DNS.h, this includes space for the null-terminator + char buf[net::kNetAddrMaxCStrBufSize] = {0}; PRNetAddr addr; memset(&addr, 0, sizeof(addr)); nssComponent->GetPIPNSSBundleString("CertDumpIPAddress", key); -- cgit v1.2.3 From d62795c868dff9a12a8868d09b3331cb8c4ad39b Mon Sep 17 00:00:00 2001 From: Yaron Tausky Date: Thu, 9 Jan 2020 22:23:13 +0100 Subject: Make copy of list before iterating over it. --- dom/cache/StreamControl.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dom/cache/StreamControl.cpp b/dom/cache/StreamControl.cpp index aab176666..69a72d0b6 100644 --- a/dom/cache/StreamControl.cpp +++ b/dom/cache/StreamControl.cpp @@ -68,7 +68,8 @@ StreamControl::CloseAllReadStreams() { AssertOwningThread(); - ReadStreamList::ForwardIterator iter(mReadStreamList); + auto readStreamList = mReadStreamList; + ReadStreamList::ForwardIterator iter(readStreamList); while (iter.HasMore()) { iter.GetNext()->CloseStream(); } -- cgit v1.2.3 From 38b00414148f4b013499b759ba3cd6cb72a15179 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Thu, 9 Jan 2020 22:35:03 +0100 Subject: Handle missing base64 challenge in NegotiateAuth and NTLMAuth. --- extensions/auth/nsHttpNegotiateAuth.cpp | 5 ++++- netwerk/protocol/http/nsHttpNTLMAuth.cpp | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/extensions/auth/nsHttpNegotiateAuth.cpp b/extensions/auth/nsHttpNegotiateAuth.cpp index adea54b85..8b6be915e 100644 --- a/extensions/auth/nsHttpNegotiateAuth.cpp +++ b/extensions/auth/nsHttpNegotiateAuth.cpp @@ -530,8 +530,11 @@ nsHttpNegotiateAuth::GenerateCredentials(nsIHttpAuthenticableChannel *authChanne challenge++; len = strlen(challenge); + if (!len) + return NS_ERROR_UNEXPECTED; + // strip off any padding (see bug 230351) - while (challenge[len - 1] == '=') + while (len && challenge[len - 1] == '=') len--; // diff --git a/netwerk/protocol/http/nsHttpNTLMAuth.cpp b/netwerk/protocol/http/nsHttpNTLMAuth.cpp index aa5b1f8f7..86bfcf4d1 100644 --- a/netwerk/protocol/http/nsHttpNTLMAuth.cpp +++ b/netwerk/protocol/http/nsHttpNTLMAuth.cpp @@ -486,8 +486,8 @@ nsHttpNTLMAuth::GenerateCredentials(nsIHttpAuthenticableChannel *authChannel, len -= 5; // strip off any padding (see bug 230351) - while (challenge[len - 1] == '=') - len--; + while (len && challenge[len - 1] == '=') + len--; // decode into the input secbuffer rv = Base64Decode(challenge, len, (char**)&inBuf, &inBufLen); -- cgit v1.2.3 From e01d499617b7e090785006c13e92f02e22993ca5 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 10 Jan 2020 19:40:14 +0100 Subject: Update GTK clipboard handling - Store the clipboard even if it was set in a GTK dialog. - Fix a GtkTargetList leak. - Notify GTK that the data is no longer available for clipboard_get_cb(), so that GTK will no longer advertise nor attempt to store the data. --- widget/gtk/nsClipboard.cpp | 51 ++++++++++++++++++++++++++-------------------- widget/gtk/nsClipboard.h | 5 ++--- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/widget/gtk/nsClipboard.cpp b/widget/gtk/nsClipboard.cpp index 950be1dc4..1ae3673b0 100644 --- a/widget/gtk/nsClipboard.cpp +++ b/widget/gtk/nsClipboard.cpp @@ -120,24 +120,13 @@ NS_IMETHODIMP nsClipboard::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *aData) { if (strcmp(aTopic, "quit-application") == 0) { - // application is going to quit, save clipboard content - Store(); + // Application is going to quit, save clipboard content + gtk_clipboard_store(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD)); gdk_window_remove_filter(nullptr, selection_request_filter, nullptr); } return NS_OK; } -nsresult -nsClipboard::Store(void) -{ - // Ask the clipboard manager to store the current clipboard content - if (mGlobalTransferable) { - GtkClipboard *clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); - gtk_clipboard_store(clipboard); - } - return NS_OK; -} - NS_IMETHODIMP nsClipboard::SetData(nsITransferable *aTransferable, nsIClipboardOwner *aOwner, int32_t aWhichClipboard) @@ -152,9 +141,6 @@ nsClipboard::SetData(nsITransferable *aTransferable, return NS_OK; } - // Clear out the clipboard in order to set the new data - EmptyClipboard(aWhichClipboard); - // List of suported targets GtkTargetList *list = gtk_target_list_new(nullptr, 0); @@ -163,8 +149,12 @@ nsClipboard::SetData(nsITransferable *aTransferable, nsresult rv = aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavors)); - if (!flavors || NS_FAILED(rv)) + if (!flavors || NS_FAILED(rv)) { + // Clear references to the any old data and let GTK know that it is no + // longer available. + EmptyClipboard(aWhichClipboard); return NS_ERROR_FAILURE; + } // Add all the flavors to this widget's supported type. bool imagesAdded = false; @@ -232,8 +222,10 @@ nsClipboard::SetData(nsITransferable *aTransferable, } rv = NS_OK; - } - else { + } else { + // Clear references to the any old data and let GTK know that it is no + // longer available. + EmptyClipboard(aWhichClipboard); rv = NS_ERROR_FAILURE; } @@ -373,6 +365,23 @@ nsClipboard::GetData(nsITransferable *aTransferable, int32_t aWhichClipboard) NS_IMETHODIMP nsClipboard::EmptyClipboard(int32_t aWhichClipboard) { + if (aWhichClipboard == kSelectionClipboard) { + if (mSelectionTransferable) { + gtk_clipboard_clear(gtk_clipboard_get(GDK_SELECTION_PRIMARY)); + MOZ_ASSERT(!mSelectionTransferable); + } + } else { + if (mGlobalTransferable) { + gtk_clipboard_clear(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD)); + MOZ_ASSERT(!mGlobalTransferable); + } + } + + return NS_OK; +} + +void +nsClipboard::ClearTransferable(int32_t aWhichClipboard) { if (aWhichClipboard == kSelectionClipboard) { if (mSelectionOwner) { mSelectionOwner->LosingOwnership(mSelectionTransferable); @@ -387,8 +396,6 @@ nsClipboard::EmptyClipboard(int32_t aWhichClipboard) } mGlobalTransferable = nullptr; } - - return NS_OK; } NS_IMETHODIMP @@ -652,7 +659,7 @@ nsClipboard::SelectionClearEvent(GtkClipboard *aGtkClipboard) else return; // THAT AIN'T NO CLIPBOARD I EVER HEARD OF - EmptyClipboard(whichClipboard); + ClearTransferable(whichClipboard); } void diff --git a/widget/gtk/nsClipboard.h b/widget/gtk/nsClipboard.h index 70c866a01..c3129bf20 100644 --- a/widget/gtk/nsClipboard.h +++ b/widget/gtk/nsClipboard.h @@ -39,13 +39,12 @@ private: static GdkAtom GetSelectionAtom (int32_t aWhichClipboard); static GtkSelectionData *GetTargets (GdkAtom aWhichClipboard); - // Save global clipboard content to gtk - nsresult Store (void); - // Get our hands on the correct transferable, given a specific // clipboard nsITransferable *GetTransferable (int32_t aWhichClipboard); + void ClearTransferable(int32_t aWhichClipboard); + // Hang on to our owners and transferables so we can transfer data // when asked. nsCOMPtr mSelectionOwner; -- cgit v1.2.3 From 81f3185e0e2d72e147af0d39cded0c5b2a32bb8f Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Fri, 10 Jan 2020 23:56:29 +0100 Subject: Prefer file extension as-provided over default extension for mimetype to look up default applications on Windows --- uriloader/exthandler/win/nsOSHelperAppService.cpp | 136 +++++++++++++--------- 1 file changed, 84 insertions(+), 52 deletions(-) diff --git a/uriloader/exthandler/win/nsOSHelperAppService.cpp b/uriloader/exthandler/win/nsOSHelperAppService.cpp index 48b6f1795..1d1ef2dcb 100644 --- a/uriloader/exthandler/win/nsOSHelperAppService.cpp +++ b/uriloader/exthandler/win/nsOSHelperAppService.cpp @@ -406,75 +406,107 @@ already_AddRefed nsOSHelperAppService::GetByExtension(const nsAFl return mimeInfo.forget(); } -already_AddRefed nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType, const nsACString& aFileExt, bool *aFound) +already_AddRefed nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType, + const nsACString& aFileExt, + bool *aFound) { - *aFound = true; + *aFound = false; const nsCString& flatType = PromiseFlatCString(aMIMEType); - const nsCString& flatExt = PromiseFlatCString(aFileExt); - nsAutoString fileExtension; - /* XXX The Equals is a gross hack to wallpaper over the most common Win32 - * extension issues caused by the fix for bug 116938. See bug - * 120327, comment 271 for why this is needed. Not even sure we + CopyUTF8toUTF16(aFileExt, fileExtension); + + /* XXX The octet-stream check is a gross hack to wallpaper over the most + * common Win32 extension issues caused by the fix for bug 116938. See bug + * 120327, comment 271 for why this is needed. Not even sure we * want to remove this once we have fixed all this stuff to work * right; any info we get from the OS on this type is pretty much - * useless.... - * We'll do extension-based lookup for this type later in this function. + * useless... */ - if (!aMIMEType.LowerCaseEqualsLiteral(APPLICATION_OCTET_STREAM)) { - // try to use the windows mime database to see if there is a mapping to a file extension - GetExtensionFromWindowsMimeDatabase(aMIMEType, fileExtension); - LOG(("Windows mime database: extension '%s'\n", fileExtension.get())); - } - // If we found an extension for the type, do the lookup + bool haveMeaningfulMimeType = + !aMIMEType.IsEmpty() && + !aMIMEType.LowerCaseEqualsLiteral(APPLICATION_OCTET_STREAM); + LOG(("Extension lookup on '%s' with mimetype '%s'%s\n", fileExtension.get(), + flatType.get(), + haveMeaningfulMimeType ? " (treated as meaningful)" : "")); + RefPtr mi; - if (!fileExtension.IsEmpty()) - mi = GetByExtension(fileExtension, flatType.get()); - LOG(("Extension lookup on '%s' found: 0x%p\n", fileExtension.get(), mi.get())); - bool hasDefault = false; - if (mi) { - mi->GetHasDefaultHandler(&hasDefault); - // OK. We might have the case that |aFileExt| is a valid extension for the - // mimetype we were given. In that case, we do want to append aFileExt - // to the mimeinfo that we have. (E.g.: We are asked for video/mpeg and - // .mpg, but the primary extension for video/mpeg is .mpeg. But because - // .mpg is an extension for video/mpeg content, we want to append it) - if (!aFileExt.IsEmpty() && typeFromExtEquals(NS_ConvertUTF8toUTF16(flatExt).get(), flatType.get())) { - LOG(("Appending extension '%s' to mimeinfo, because its mimetype is '%s'\n", - flatExt.get(), flatType.get())); - bool extExist = false; - mi->ExtensionExists(aFileExt, &extExist); - if (!extExist) - mi->AppendExtension(aFileExt); - } + // We should have *something* to go on here. + if (fileExtension.IsEmpty() && !haveMeaningfulMimeType) { + mi = new nsMIMEInfoWin(flatType.get()); + return mi.forget(); } - if (!mi || !hasDefault) { - RefPtr miByExt = - GetByExtension(NS_ConvertUTF8toUTF16(aFileExt), flatType.get()); - LOG(("Ext. lookup for '%s' found 0x%p\n", flatExt.get(), miByExt.get())); - if (!miByExt && mi) - return mi.forget(); - if (miByExt && !mi) { - return miByExt.forget(); - } - if (!miByExt && !mi) { - *aFound = false; - mi = new nsMIMEInfoWin(flatType); + + nsAutoString extensionFromMimeType; + if (haveMeaningfulMimeType) { + GetExtensionFromWindowsMimeDatabase(aMIMEType, extensionFromMimeType); + if (extensionFromMimeType.IsEmpty()) { + // We can't verify the mime type and file extension make sense. + mi = new nsMIMEInfoWin(flatType.get()); if (!aFileExt.IsEmpty()) { mi->AppendExtension(aFileExt); } - return mi.forget(); } + } + // Either fileExtension or extensionFromMimeType must now be non-empty. + + *aFound = true; - // if we get here, mi has no default app. copy from extension lookup. - nsCOMPtr defaultApp; - nsAutoString desc; - miByExt->GetDefaultDescription(desc); + // On Windows, we prefer the file extension for lookups over the mimetype, + // because that's how windows does things. + // If we have no file extension or it doesn't match the mimetype, use the + // mime type's default file extension instead. + bool usedMimeTypeExtensionForLookup = false; + if (fileExtension.IsEmpty() || + (haveMeaningfulMimeType && + !typeFromExtEquals(fileExtension.get(), flatType.get()))) { + usedMimeTypeExtensionForLookup = true; + fileExtension = extensionFromMimeType; + LOG(("Now using '%s' mimetype's default file extension '%s' for lookup\n", + flatType.get(), fileExtension.get())); + } - mi->SetDefaultDescription(desc); + // If we have an extension, use it for lookup: + mi = GetByExtension(fileExtension, flatType.get()); + LOG(("Extension lookup on '%s' found: 0x%p\n", fileExtension.get(), mi.get())); + + if (mi) { + bool hasDefault = false; + mi->GetHasDefaultHandler(&hasDefault); + // If we don't find a default handler description, see if we can find one + // using the mimetype. + if (!hasDefault && !usedMimeTypeExtensionForLookup) { + RefPtr miFromMimeType = + GetByExtension(extensionFromMimeType, flatType.get()); + LOG(("Mime-based ext. lookup for '%s' found 0x%p\n", + extensionFromMimeType.get(), miFromMimeType.get())); + if (miFromMimeType) { + nsAutoString desc; + miFromMimeType->GetDefaultDescription(desc); + mi->SetDefaultDescription(desc); + } + } + return mi.forget(); + } + // The extension didn't work. Try the extension from the mimetype if + // different: + if (!extensionFromMimeType.IsEmpty() && !usedMimeTypeExtensionForLookup) { + mi = GetByExtension(extensionFromMimeType, flatType.get()); + LOG(("Mime-based ext. lookup for '%s' found 0x%p\n", + extensionFromMimeType.get(), mi.get())); + } + if (mi) { + return mi.forget(); + } + // This didn't work either, so just return an empty dummy mimeinfo. + *aFound = false; + mi = new nsMIMEInfoWin(flatType.get()); + // If we didn't resort to the mime type's extension, we must have had a + // valid extension, so stick it on the mime info. + if (!usedMimeTypeExtensionForLookup) { + mi->AppendExtension(aFileExt); } return mi.forget(); } -- cgit v1.2.3 From cffb44547ae7997e5eaf71c644bd626eeb3bba00 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 11 Jan 2020 13:09:17 +0100 Subject: Simplify some alias sets in IonMonkey. --- js/src/jit/AliasAnalysisShared.cpp | 4 ++-- js/src/jit/MIR.h | 9 --------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/js/src/jit/AliasAnalysisShared.cpp b/js/src/jit/AliasAnalysisShared.cpp index 0f0d4a66a..400626b33 100644 --- a/js/src/jit/AliasAnalysisShared.cpp +++ b/js/src/jit/AliasAnalysisShared.cpp @@ -86,8 +86,6 @@ GetObject(const MDefinition* ins) case MDefinition::Op_SetInitializedLength: case MDefinition::Op_ArrayLength: case MDefinition::Op_SetArrayLength: - case MDefinition::Op_StoreElementHole: - case MDefinition::Op_FallibleStoreElement: case MDefinition::Op_TypedObjectDescr: case MDefinition::Op_Slots: case MDefinition::Op_Elements: @@ -143,6 +141,8 @@ GetObject(const MDefinition* ins) case MDefinition::Op_WasmStoreGlobalVar: case MDefinition::Op_ArrayJoin: case MDefinition::Op_ArraySlice: + case MDefinition::Op_StoreElementHole: + case MDefinition::Op_FallibleStoreElement: return nullptr; default: #ifdef DEBUG diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 6c376d528..7b0ed65f2 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -9460,12 +9460,6 @@ class MStoreElementHole TRIVIAL_NEW_WRAPPERS NAMED_OPERANDS((0, object), (1, elements), (2, index), (3, value)) - AliasSet getAliasSet() const override { - // StoreElementHole can update the initialized length, the array length - // or reallocate obj->elements. - return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element); - } - ALLOW_CLONE(MStoreElementHole) }; @@ -9496,9 +9490,6 @@ class MFallibleStoreElement TRIVIAL_NEW_WRAPPERS NAMED_OPERANDS((0, object), (1, elements), (2, index), (3, value)) - AliasSet getAliasSet() const override { - return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element); - } bool strict() const { return strict_; } -- cgit v1.2.3