Bug 1244340 - Part 3: pass userContextId to search suggestions r=mak

This commit is contained in:
Yoshi Huang 2016-05-31 18:59:41 +08:00
Родитель 69ed1a79e4
Коммит 8c13a9fd49
11 изменённых файлов: 111 добавлений и 15 удалений

Просмотреть файл

@ -13,6 +13,7 @@
#include "nsIServiceManager.h"
#include "nsReadableUtils.h"
#include "nsUnicharUtils.h"
#include "nsIScriptSecurityManager.h"
#include "nsITreeBoxObject.h"
#include "nsITreeColumns.h"
#include "nsIObserverService.h"
@ -1201,6 +1202,14 @@ nsAutoCompleteController::StartSearch(uint16_t aSearchType)
searchParam.AppendLiteral(" prohibit-autofill");
}
uint32_t userContextId;
rv = input->GetUserContextId(&userContextId);
if (NS_SUCCEEDED(rv) &&
userContextId != nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID) {
searchParam.AppendLiteral(" user-context-id:");
searchParam.AppendInt(userContextId, 10);
}
rv = search->StartSearch(mSearchString, searchParam, result, static_cast<nsIAutoCompleteObserver *>(this));
if (NS_FAILED(rv)) {
++mSearchesFailed;

Просмотреть файл

@ -154,4 +154,9 @@ interface nsIAutoCompleteInput : nsISupports
* Don't rollup the popup when the caret is moved.
*/
readonly attribute boolean noRollupOnCaretMove;
/**
* The userContextId of the current browser.
*/
readonly attribute unsigned long userContextId;
};

Просмотреть файл

@ -5,6 +5,7 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
/**
* Dummy nsIAutoCompleteInput source that returns

Просмотреть файл

@ -0,0 +1,45 @@
"use strict";
Cu.import("resource://gre/modules/Promise.jsm");
function AutoCompleteInput(aSearches, aUserContextId) {
this.searches = aSearches;
this.userContextId = aUserContextId;
this.popup.selectedIndex = -1;
}
AutoCompleteInput.prototype = Object.create(AutoCompleteInputBase.prototype);
function AutoCompleteSearch(aName) {
this.name = aName;
}
AutoCompleteSearch.prototype = Object.create(AutoCompleteSearchBase.prototype);
add_task(function *test_userContextId() {
let searchParam = yield doSearch("test", 1);
Assert.equal(searchParam, " user-context-id:1");
});
function doSearch(aString, aUserContextId) {
let deferred = Promise.defer();
let search = new AutoCompleteSearch("test");
search.startSearch = function (aSearchString,
aSearchParam,
aPreviousResult,
aListener) {
unregisterAutoCompleteSearch(search);
deferred.resolve(aSearchParam);
};
registerAutoCompleteSearch(search);
let controller = Cc["@mozilla.org/autocomplete/controller;1"].
getService(Ci.nsIAutoCompleteController);
let input = new AutoCompleteInput([ search.name ], aUserContextId);
controller.input = input;
controller.startSearch(aString);
return deferred.promise;
}

Просмотреть файл

@ -10,6 +10,7 @@ skip-if = toolkit == 'gonk'
[test_463023.js]
[test_660156.js]
[test_autocomplete_multiple.js]
[test_autocomplete_userContextId.js]
[test_autofillSelectedPopupIndex.js]
[test_badDefaultIndex.js]
[test_completeDefaultIndex_casing.js]

Просмотреть файл

@ -113,13 +113,14 @@ const SearchAutocompleteProviderInternal = {
}
},
getSuggestionController(searchToken, inPrivateContext, maxResults) {
getSuggestionController(searchToken, inPrivateContext, maxResults, userContextId) {
let engine = Services.search.currentEngine;
if (!engine) {
return null;
}
return new SearchSuggestionControllerWrapper(engine, searchToken,
inPrivateContext, maxResults);
inPrivateContext, maxResults,
userContextId);
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
@ -127,11 +128,12 @@ const SearchAutocompleteProviderInternal = {
}
function SearchSuggestionControllerWrapper(engine, searchToken,
inPrivateContext, maxResults) {
inPrivateContext, maxResults,
userContextId) {
this._controller = new SearchSuggestionController();
this._controller.maxLocalResults = 0;
this._controller.maxRemoteResults = maxResults;
let promise = this._controller.fetch(searchToken, inPrivateContext, engine);
let promise = this._controller.fetch(searchToken, inPrivateContext, engine, userContextId);
this._suggestions = [];
this._success = false;
this._promise = promise.then(results => {
@ -283,11 +285,11 @@ this.PlacesSearchAutocompleteProvider = Object.freeze({
};
},
getSuggestionController(searchToken, inPrivateContext, maxResults) {
getSuggestionController(searchToken, inPrivateContext, maxResults, userContextId) {
if (!SearchAutocompleteProviderInternal.initialized) {
throw new Error("The component has not been initialized.");
}
return SearchAutocompleteProviderInternal.getSuggestionController(
searchToken, inPrivateContext, maxResults);
searchToken, inPrivateContext, maxResults, userContextId);
},
});

Просмотреть файл

@ -75,6 +75,9 @@ const MINIMUM_LOCAL_MATCHES = 6;
// don't need to be exhaustive here, so allow dashes anywhere.
const REGEXP_SINGLEWORD_HOST = new RegExp("^[a-z0-9-]+$", "i");
// Regex used to match userContextId.
const REGEXP_USER_CONTEXT_ID = /(?:^| )user-context-id:(\d+)/;
// Regex used to match one or more whitespace.
const REGEXP_SPACES = /\s+/;
@ -641,6 +644,7 @@ function looksLikeUrl(str) {
* * private-window: The search is taking place in a private window,
* possibly in permanent private-browsing mode. The search
* should exclude privacy-sensitive results as appropriate.
* * user-context-id: The userContextId of the selected tab.
* @param autocompleteListener
* An nsIAutoCompleteObserver.
* @param resultListener
@ -668,6 +672,11 @@ function Search(searchString, searchParam, autocompleteListener,
this._inPrivateWindow = params.has("private-window");
this._prohibitAutoFill = params.has("prohibit-autofill");
let userContextId = searchParam.match(REGEXP_USER_CONTEXT_ID);
this._userContextId = userContextId ?
parseInt(userContextId[1], 10) :
Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID;
this._searchTokens =
this.filterTokens(getUnfilteredSearchTokens(this._searchString));
// The protocol and the host are lowercased by nsIURI, so it's fine to
@ -1010,7 +1019,8 @@ Search.prototype = {
PlacesSearchAutocompleteProvider.getSuggestionController(
searchString,
this._inPrivateWindow,
Prefs.maxRichResults
Prefs.maxRichResults,
this._userContextId
);
let promise = this._searchSuggestionController.fetchCompletePromise
.then(() => {

Просмотреть файл

@ -38,6 +38,7 @@
#include "nsContentUtils.h"
#include "nsILoadContext.h"
#include "nsIFrame.h"
#include "nsIScriptSecurityManager.h"
using namespace mozilla::dom;
@ -625,6 +626,13 @@ nsFormFillController::GetNoRollupOnCaretMove(bool *aNoRollupOnCaretMove)
return NS_OK;
}
NS_IMETHODIMP
nsFormFillController::GetUserContextId(uint32_t* aUserContextId)
{
*aUserContextId = nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
//// nsIAutoCompleteSearch

Просмотреть файл

@ -106,10 +106,11 @@ this.SearchSuggestionController.prototype = {
* @param {string} searchTerm - the term to provide suggestions for
* @param {bool} privateMode - whether the request is being made in the context of private browsing
* @param {nsISearchEngine} engine - search engine for the suggestions.
* @param {int} userContextId - the userContextId of the selected tab.
*
* @return {Promise} resolving to an object containing results or null.
*/
fetch: function(searchTerm, privateMode, engine) {
fetch: function(searchTerm, privateMode, engine, userContextId) {
// There is no smart filtering from previous results here (as there is when looking through
// history/form data) because the result set returned by the server is different for every typed
// value - e.g. "ocean breathes" does not return a subset of the results returned for "ocean".
@ -139,7 +140,7 @@ this.SearchSuggestionController.prototype = {
// Remote results
if (searchTerm && gRemoteSuggestionsEnabled && this.maxRemoteResults &&
engine.supportsResponseType(SEARCH_RESPONSE_SUGGESTION_JSON)) {
this._deferredRemoteResult = this._fetchRemote(searchTerm, engine, privateMode);
this._deferredRemoteResult = this._fetchRemote(searchTerm, engine, privateMode, userContextId);
promises.push(this._deferredRemoteResult.promise);
}
@ -230,7 +231,7 @@ this.SearchSuggestionController.prototype = {
/**
* Fetch suggestions from the search engine over the network.
*/
_fetchRemote: function(searchTerm, engine, privateMode) {
_fetchRemote: function(searchTerm, engine, privateMode, userContextId) {
let deferredResponse = Promise.defer();
this._request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
createInstance(Ci.nsIXMLHttpRequest);
@ -238,9 +239,10 @@ this.SearchSuggestionController.prototype = {
SEARCH_RESPONSE_SUGGESTION_JSON);
let method = (submission.postData ? "POST" : "GET");
this._request.open(method, submission.uri.spec, true);
if (this._request.channel instanceof Ci.nsIPrivateBrowsingChannel) {
this._request.channel.setPrivate(privateMode);
}
this._request.setOriginAttributes({userContextId,
privateBrowsingId: privateMode ? 1 : 0});
this._request.mozBackgroundRequest = true; // suppress dialogs and fail silently
this._request.addEventListener("load", this._onRemoteLoaded.bind(this, deferredResponse));

Просмотреть файл

@ -539,6 +539,15 @@ add_task(function* minus_one_results_requested() {
}, /result/i);
});
add_task(function* test_userContextId() {
let controller = new SearchSuggestionController();
controller._fetchRemote = function(searchTerm, engine, privateMode, userContextId) {
Assert.equal(userContextId, 1);
return Promise.defer();
};
controller.fetch("test", false, getEngine, 1);
});
// Helpers

Просмотреть файл

@ -621,8 +621,12 @@
<handler event="compositionend" phase="capturing"
action="if (this.mController.input == this) this.mController.handleEndComposition();"/>
<handler event="focus" phase="capturing"
action="this.attachController();"/>
<handler event="focus" phase="capturing"><![CDATA[
this.attachController();
if (window.gBrowser) {
this.userContextId = window.gBrowser.selectedBrowser.contentPrincipal.originAttributes.userContextId;
}
]]></handler>
<handler event="blur" phase="capturing"><![CDATA[
if (!this._dontBlur) {