Zotero.HTTP.request(): Process headers case insensitively
Using the Headers class from the Fetch API. Before, the added test would fail: `_requestInternal()`, not finding a header named `Content-Type` (case sensitive), would set it to `application/x-www-form-urlencoded`. XMLHttpRequest, upon being given both `content-type`: `application/json`) and `Content-Type`: `application/x-www-form-urlencoded`, would helpfully merge the two, producing `content-type`: `application/json, application/x-www-form-urlencoded`. That's obviously not the correct behavior.
This commit is contained in:
parent
86c56951df
commit
f6dd47dd1f
2 changed files with 41 additions and 22 deletions
|
@ -117,7 +117,7 @@ Zotero.HTTP = new function() {
|
||||||
* @param {nsIURI|String} url - URL to request
|
* @param {nsIURI|String} url - URL to request
|
||||||
* @param {Object} [options] Options for HTTP request:
|
* @param {Object} [options] Options for HTTP request:
|
||||||
* @param {String} [options.body] - The body of a POST request
|
* @param {String} [options.body] - The body of a POST request
|
||||||
* @param {Object} [options.headers] - Object of HTTP headers to send with the request
|
* @param {Object | Headers} [options.headers] - HTTP headers to send with the request
|
||||||
* @param {Boolean} [options.followRedirects = true] - Object of HTTP headers to send with the
|
* @param {Boolean} [options.followRedirects = true] - Object of HTTP headers to send with the
|
||||||
* request
|
* request
|
||||||
* @param {Zotero.CookieSandbox} [options.cookieSandbox] - The sandbox from which cookies should
|
* @param {Zotero.CookieSandbox} [options.cookieSandbox] - The sandbox from which cookies should
|
||||||
|
@ -343,22 +343,19 @@ Zotero.HTTP = new function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send headers
|
// Send headers
|
||||||
var headers = {};
|
var headers = new Headers(options?.headers || {});
|
||||||
if (options && options.headers) {
|
|
||||||
Object.assign(headers, options.headers);
|
|
||||||
}
|
|
||||||
var compressedBody = false;
|
var compressedBody = false;
|
||||||
if (options.body) {
|
if (options.body) {
|
||||||
if (!headers["Content-Type"]) {
|
if (!headers.get("Content-Type")) {
|
||||||
headers["Content-Type"] = "application/x-www-form-urlencoded";
|
headers.set("Content-Type", "application/x-www-form-urlencoded");
|
||||||
}
|
}
|
||||||
else if (headers["Content-Type"] == 'multipart/form-data') {
|
else if (headers.get("Content-Type") == 'multipart/form-data') {
|
||||||
// Allow XHR to set Content-Type with boundary for multipart/form-data
|
// Allow XHR to set Content-Type with boundary for multipart/form-data
|
||||||
delete headers["Content-Type"];
|
headers.delete("Content-Type");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.compressBody && this.isWriteMethod(method)) {
|
if (options.compressBody && this.isWriteMethod(method)) {
|
||||||
headers['Content-Encoding'] = 'gzip';
|
headers.set('Content-Encoding', 'gzip');
|
||||||
compressedBody = await Zotero.Utilities.Internal.gzip(options.body);
|
compressedBody = await Zotero.Utilities.Internal.gzip(options.body);
|
||||||
|
|
||||||
let oldLen = options.body.length;
|
let oldLen = options.body.length;
|
||||||
|
@ -368,23 +365,17 @@ Zotero.HTTP = new function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (options.debug) {
|
if (options.debug) {
|
||||||
if (headers["Zotero-API-Key"]) {
|
if (headers.has("Zotero-API-Key")) {
|
||||||
let dispHeaders = {};
|
let dispHeaders = new Headers(headers);
|
||||||
Object.assign(dispHeaders, headers);
|
dispHeaders.set("Zotero-API-Key", "[Not shown]");
|
||||||
if (dispHeaders["Zotero-API-Key"]) {
|
Zotero.debug({ ...dispHeaders.entries() });
|
||||||
dispHeaders["Zotero-API-Key"] = "[Not shown]";
|
|
||||||
}
|
|
||||||
Zotero.debug(dispHeaders);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Zotero.debug(headers);
|
Zotero.debug({ ...headers.entries() });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (var header in headers) {
|
for (var [header, value] of headers) {
|
||||||
// Convert numbers to string to make Sinon happy
|
// Convert numbers to string to make Sinon happy
|
||||||
let value = typeof headers[header] == 'number'
|
|
||||||
? headers[header].toString()
|
|
||||||
: headers[header]
|
|
||||||
xmlhttp.setRequestHeader(header, value);
|
xmlhttp.setRequestHeader(header, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,20 @@ describe("Zotero.HTTP", function () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
httpd.registerPathHandler(
|
||||||
|
'/requireJSON',
|
||||||
|
{
|
||||||
|
handle(request, response) {
|
||||||
|
if (request.getHeader('Content-Type') == 'application/json') {
|
||||||
|
response.setStatusLine(null, 200, "OK");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
response.setStatusLine(null, 400, "Bad Request");
|
||||||
|
}
|
||||||
|
response.write('JSON required');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
|
@ -124,6 +138,20 @@ describe("Zotero.HTTP", function () {
|
||||||
server.respond();
|
server.respond();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should process headers case insensitively", async function () {
|
||||||
|
Zotero.HTTP.mock = null;
|
||||||
|
var req = await Zotero.HTTP.request(
|
||||||
|
'GET',
|
||||||
|
baseURL + 'requireJSON',
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'content-type': 'application/json'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert.equal(req.status, 200);
|
||||||
|
});
|
||||||
|
|
||||||
describe("Retries", function () {
|
describe("Retries", function () {
|
||||||
var spy;
|
var spy;
|
||||||
var delayStub;
|
var delayStub;
|
||||||
|
|
Loading…
Reference in a new issue