summaryrefslogtreecommitdiffstats
path: root/toolkit/components/search/tests/xpcshell/data/searchSuggestions.sjs
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/search/tests/xpcshell/data/searchSuggestions.sjs')
-rw-r--r--toolkit/components/search/tests/xpcshell/data/searchSuggestions.sjs181
1 files changed, 181 insertions, 0 deletions
diff --git a/toolkit/components/search/tests/xpcshell/data/searchSuggestions.sjs b/toolkit/components/search/tests/xpcshell/data/searchSuggestions.sjs
new file mode 100644
index 0000000000..85f51795b6
--- /dev/null
+++ b/toolkit/components/search/tests/xpcshell/data/searchSuggestions.sjs
@@ -0,0 +1,181 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let { setTimeout } = ChromeUtils.importESModule(
+ "resource://gre/modules/Timer.sys.mjs"
+);
+let { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
+
+Cu.importGlobalProperties(["TextEncoder"]);
+
+/**
+ * Provide search suggestions in the OpenSearch JSON format.
+ */
+
+function handleRequest(request, response) {
+ // Get the query parameters from the query string.
+ let query = parseQueryString(request.queryString);
+
+ function convertToUtf8(str) {
+ return String.fromCharCode(...new TextEncoder().encode(str));
+ }
+
+ function writeSuggestions(q, completions = []) {
+ let jsonString = JSON.stringify([q, completions]);
+
+ // This script must be evaluated as UTF-8 for this to write out the bytes of
+ // the string in UTF-8. If it's evaluated as Latin-1, the written bytes
+ // will be the result of UTF-8-encoding the result-string *twice*, which
+ // will break the "I ❤️" case further down.
+ let stringOfUtf8Bytes = convertToUtf8(jsonString);
+
+ response.write(stringOfUtf8Bytes);
+ }
+
+ /**
+ * Sends `data` as suggestions directly. This is useful when testing rich
+ * suggestions, which do not conform to the object shape sent by
+ * writeSuggestions.
+ *
+ * @param {Array} data The data to send as suggestions.
+ */
+ function writeSuggestionsDirectly(data) {
+ let jsonString = JSON.stringify(data);
+ let stringOfUtf8Bytes = convertToUtf8(jsonString);
+ response.setHeader("Content-Type", "application/json", false);
+ response.write(stringOfUtf8Bytes);
+ }
+
+ response.setStatusLine(request.httpVersion, 200, "OK");
+
+ let q = request.method == "GET" ? query.q : undefined;
+ if (q == "cookie") {
+ response.setHeader("Set-Cookie", "cookie=1");
+ writeSuggestions(q);
+ } else if (q == "no remote" || q == "no results") {
+ writeSuggestions(q);
+ } else if (q == "Query Mismatch") {
+ writeSuggestions("This is an incorrect query string", ["some result"]);
+ } else if (q == "Query Case Mismatch") {
+ writeSuggestions(q.toUpperCase(), [q]);
+ } else if (q == "") {
+ writeSuggestions("", ["The server should never be sent an empty query"]);
+ } else if (q && q.startsWith("mo")) {
+ writeSuggestions(q, ["Mozilla", "modern", "mom"]);
+ } else if (q && q.startsWith("I ❤️")) {
+ writeSuggestions(q, ["I ❤️ Mozilla"]);
+ } else if (q && q.startsWith("stü")) {
+ writeSuggestions("st\\u00FC", ["stühle", "stüssy"]);
+ } else if (q && q.startsWith("tailjunk ")) {
+ writeSuggestionsDirectly([
+ q,
+ [q + " normal", q + " tail 1", q + " tail 2"],
+ [],
+ {
+ "google:irrelevantparameter": [],
+ "google:badformat": {
+ "google:suggestdetail": [
+ {},
+ { mp: "… ", t: "tail 1" },
+ { mp: "… ", t: "tail 2" },
+ ],
+ },
+ },
+ ]);
+ } else if (q && q.startsWith("tailjunk few ")) {
+ writeSuggestionsDirectly([
+ q,
+ [q + " normal", q + " tail 1", q + " tail 2"],
+ [],
+ {
+ "google:irrelevantparameter": [],
+ "google:badformat": {
+ "google:suggestdetail": [{ mp: "… ", t: "tail 1" }],
+ },
+ },
+ ]);
+ } else if (q && q.startsWith("tailalt ")) {
+ writeSuggestionsDirectly([
+ q,
+ [q + " normal", q + " tail 1", q + " tail 2"],
+ {
+ "google:suggestdetail": [
+ {},
+ { mp: "… ", t: "tail 1" },
+ { mp: "… ", t: "tail 2" },
+ ],
+ },
+ ]);
+ } else if (q && q.startsWith("tail ")) {
+ writeSuggestionsDirectly([
+ q,
+ [q + " normal", q + " tail 1", q + " tail 2"],
+ [],
+ {
+ "google:irrelevantparameter": [],
+ "google:suggestdetail": [
+ {},
+ { mp: "… ", t: "tail 1" },
+ { mp: "… ", t: "tail 2" },
+ ],
+ },
+ ]);
+ } else if (q && q.startsWith("richempty ")) {
+ writeSuggestionsDirectly([
+ q,
+ [q + " normal", q + " tail 1", q + " tail 2"],
+ [],
+ {
+ "google:irrelevantparameter": [],
+ "google:suggestdetail": [],
+ },
+ ]);
+ } else if (q && q.startsWith("letter ")) {
+ let letters = [];
+ for (
+ let charCode = "A".charCodeAt();
+ charCode <= "Z".charCodeAt();
+ charCode++
+ ) {
+ letters.push("letter " + String.fromCharCode(charCode));
+ }
+ writeSuggestions(q, letters);
+ } else if (q && q.startsWith("HTTP ")) {
+ response.setStatusLine(request.httpVersion, q.replace("HTTP ", ""), q);
+ writeSuggestions(q, [q]);
+ } else if (q && q.startsWith("delay")) {
+ // Delay the response by delayMs milliseconds. 200ms is the default, less
+ // than the timeout but hopefully enough to abort before completion.
+ let match = /^delay([0-9]+)/.exec(q);
+ let delayMs = match ? parseInt(match[1]) : 200;
+ response.processAsync();
+ writeSuggestions(q, [q]);
+ setTimeout(() => response.finish(), delayMs);
+ } else if (q && q.startsWith("slow ")) {
+ // Delay the response by 10 seconds so the client timeout is reached.
+ response.processAsync();
+ writeSuggestions(q, [q]);
+ setTimeout(() => response.finish(), 10000);
+ } else if (request.method == "POST") {
+ // This includes headers, not just the body
+ let requestText = NetUtil.readInputStreamToString(
+ request.bodyInputStream,
+ request.bodyInputStream.available()
+ );
+ // Only use the last line which contains the encoded params
+ let requestLines = requestText.split("\n");
+ let postParams = parseQueryString(requestLines[requestLines.length - 1]);
+ writeSuggestions(postParams.q, ["Mozilla", "modern", "mom"]);
+ } else {
+ response.setStatusLine(request.httpVersion, 404, "Not Found");
+ }
+}
+
+function parseQueryString(queryString) {
+ let query = {};
+ queryString.split("&").forEach(function (val) {
+ let [name, value] = val.split("=");
+ query[name] = decodeURIComponent(value).replace(/[+]/g, " ");
+ });
+ return query;
+}