Bug 1054739 - Normalize language tags when setting the Accept-Language header. r=gerv,mcmanus
authorawake <bugzillafx@gmail.com>
Thu, 27 Nov 2014 15:23:00 +0100
changeset 217908 a426024d5d1574a054aa706cced129b79946ed1b
parent 217907 31b92e349f6a5dd0e66d3b223e83b3b2099b5037
child 217909 6283ef6b1257a07bd7be03c44dd1c5a505deb20b
push id27896
push userphilringnalda@gmail.com
push dateFri, 28 Nov 2014 01:33:57 +0000
treeherderautoland@63abc656b865 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgerv, mcmanus
bugs1054739
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1054739 - Normalize language tags when setting the Accept-Language header. r=gerv,mcmanus
netwerk/protocol/http/nsHttpHandler.cpp
netwerk/test/unit/test_header_Accept-Language_case.js
netwerk/test/unit/xpcshell.ini
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -1514,16 +1514,35 @@ nsHttpHandler::PrefsChanged(nsIPrefBranc
 void
 nsHttpHandler::TimerCallback(nsITimer * aTimer, void * aClosure)
 {
     nsRefPtr<nsHttpHandler> thisObject = static_cast<nsHttpHandler*>(aClosure);
     if (!thisObject->mPipeliningEnabled)
         thisObject->mCapabilities &= ~NS_HTTP_ALLOW_PIPELINING;
 }
 
+static void
+NormalizeLanguageTag(char *code)
+{
+    bool is_region = false;
+    while (*code != '\0')
+    {
+        if (*code == '-') {
+            is_region = true;
+        } else {
+            if (is_region) {
+                *code = nsCRT::ToUpper(*code);
+            } else {
+                *code = nsCRT::ToLower(*code);
+            }
+        }
+        code++;
+    }
+}
+
 /**
  *  Allocates a C string into that contains a ISO 639 language list
  *  notated with HTTP "q" values for output with a HTTP Accept-Language
  *  header. Previous q values will be stripped because the order of
  *  the langs imply the q value. The q values are calculated by dividing
  *  1.0 amongst the number of languages present.
  *
  *  Ex: passing: "en, ja"
@@ -1569,16 +1588,18 @@ PrepareAcceptLanguages(const char *i_Acc
     {
         token = net_FindCharNotInSet(token, HTTP_LWS);
         char* trim;
         trim = net_FindCharInSet(token, ";" HTTP_LWS);
         if (trim != (char*)0)  // remove "; q=..." if present
             *trim = '\0';
 
         if (*token != '\0') {
+            NormalizeLanguageTag(token);
+
             comma = count_n++ != 0 ? "," : ""; // delimiter if not first item
             uint32_t u = QVAL_TO_UINT(q);
 
             // Only display q-value if less than 1.00.
             if (u < 100) {
                 const char *qval_str;
 
                 // With a small number of languages, one decimal place is enough to prevent duplicate q-values.
new file mode 100644
--- /dev/null
+++ b/netwerk/test/unit/test_header_Accept-Language_case.js
@@ -0,0 +1,32 @@
+var testpath = "/bug1054739";
+
+function run_test() {
+  let intlPrefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService).getBranch("intl.");
+
+  let oldAcceptLangPref = intlPrefs.getCharPref("accept_languages");
+
+  let testData = [
+    ["de, en-US, en",   "de,en-US;q=0.7,en;q=0.3"],
+    ["de,en-us,en",     "de,en-US;q=0.7,en;q=0.3"],
+    ["en-US, en",       "en-US,en;q=0.5"],
+    ["EN-US;q=0.2, EN", "en-US,en;q=0.5"],
+  ];
+
+  for (let i = 0; i < testData.length; i++) {
+    let acceptLangPref = testData[i][0];
+    let expectedHeader = testData[i][1];
+
+    intlPrefs.setCharPref("accept_languages", acceptLangPref);
+    let acceptLangHeader = setupChannel(testpath).getRequestHeader("Accept-Language");
+    equal(acceptLangHeader, expectedHeader);
+  }
+
+  intlPrefs.setCharPref("accept_languages", oldAcceptLangPref);
+}
+
+function setupChannel(path) {
+  let ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
+  let chan = ios.newChannel("http://localhost:4444" + path, "", null);
+  chan.QueryInterface(Ci.nsIHttpChannel);
+  return chan;
+}
--- a/netwerk/test/unit/xpcshell.ini
+++ b/netwerk/test/unit/xpcshell.ini
@@ -193,16 +193,17 @@ skip-if = bits != 32
 [test_file_partial_inputstream.js]
 [test_file_protocol.js]
 [test_filestreams.js]
 [test_freshconnection.js]
 [test_gre_resources.js]
 [test_gzipped_206.js]
 [test_head.js]
 [test_header_Accept-Language.js]
+[test_header_Accept-Language_case.js]
 [test_headers.js]
 [test_http_headers.js]
 [test_httpauth.js]
 [test_httpcancel.js]
 [test_httpResponseTimeout.js]
 [test_httpsuspend.js]
 [test_idnservice.js]
 [test_idn_urls.js]