Bug 989417 - Use Task.spawn in Netmonitor code to improve code readability, r=rcampbell

This commit is contained in:
Victor Porof 2014-03-31 11:14:47 -04:00
Родитель 78b7a846a4
Коммит 3572271153
3 изменённых файлов: 221 добавлений и 243 удалений

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

@ -191,7 +191,7 @@ let NetMonitorController = {
* @return object
* A promise that is resolved when the monitor finishes connecting.
*/
connect: function() {
connect: Task.async(function*() {
if (this._connection) {
return this._connection;
}
@ -207,11 +207,9 @@ let NetMonitorController = {
this._startMonitoringTab(client, form, deferred.resolve);
}
return deferred.promise.then((result) => {
window.emit(EVENTS.CONNECTED);
return result;
});
},
yield deferred.promise;
window.emit(EVENTS.CONNECTED);
}),
/**
* Disconnects the debugger client and removes event handlers as necessary.

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

@ -528,6 +528,7 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
*/
copyAsCurl: function() {
let selected = this.selectedItem.attachment;
Task.spawn(function*() {
// Create a sanitized object for the Curl command generator.
let data = {
@ -595,8 +596,8 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
let selected = this.selectedItem.attachment;
let data = {
method: selected.method,
url: selected.url,
method: selected.method,
httpVersion: selected.httpVersion,
};
if (selected.requestHeaders) {
@ -1216,8 +1217,10 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
* The type of information that is to be updated.
* @param any aValue
* The new value to be shown.
* @return object
* A promise that is resolved once the information is displayed.
*/
updateMenuView: function(aItem, aKey, aValue) {
updateMenuView: Task.async(function*(aItem, aKey, aValue) {
let target = aItem.target || aItem;
switch (aKey) {
@ -1279,13 +1282,13 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
let { text, encoding } = aValue.content;
if (mimeType.contains("image/")) {
gNetwork.getString(text).then(aString => {
let node = $(".requests-menu-icon", aItem.target);
node.src = "data:" + mimeType + ";" + encoding + "," + aString;
node.setAttribute("type", "thumbnail");
node.removeAttribute("hidden");
window.emit(EVENTS.RESPONSE_IMAGE_THUMBNAIL_DISPLAYED);
});
let responseBody = yield gNetwork.getString(text);
let node = $(".requests-menu-icon", aItem.target);
node.src = "data:" + mimeType + ";" + encoding + "," + responseBody;
node.setAttribute("type", "thumbnail");
node.removeAttribute("hidden");
window.emit(EVENTS.RESPONSE_IMAGE_THUMBNAIL_DISPLAYED);
}
break;
}
@ -1297,7 +1300,7 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
break;
}
}
},
}),
/**
* Creates a waterfall representing timing information in a network request item view.
@ -1596,7 +1599,7 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
let resendElement = $("#request-menu-context-resend");
resendElement.hidden = !NetMonitorController.supportsCustomRequest ||
!selectedItem || selectedItem.attachment.isCustom;
!selectedItem || selectedItem.attachment.isCustom;
let copyUrlElement = $("#request-menu-context-copy-url");
copyUrlElement.hidden = !selectedItem;
@ -1777,17 +1780,17 @@ SidebarView.prototype = {
* @return object
* Returns a promise that resolves upon population of the subview.
*/
populate: function(aData) {
populate: Task.async(function*(aData) {
let isCustom = aData.isCustom;
let view = isCustom ?
NetMonitorView.CustomRequest :
NetMonitorView.NetworkDetails;
return view.populate(aData).then(() => {
$("#details-pane").selectedIndex = isCustom ? 0 : 1;
window.emit(EVENTS.SIDEBAR_POPULATED);
});
}
yield view.populate(aData);
$("#details-pane").selectedIndex = isCustom ? 0 : 1;
window.emit(EVENTS.SIDEBAR_POPULATED);
})
}
/**
@ -1825,29 +1828,22 @@ CustomRequestView.prototype = {
* @return object
* Returns a promise that resolves upon population the view.
*/
populate: function(aData) {
populate: Task.async(function*(aData) {
$("#custom-url-value").value = aData.url;
$("#custom-method-value").value = aData.method;
$("#custom-headers-value").value =
writeHeaderText(aData.requestHeaders.headers);
let view = this;
let postDataPromise = null;
this.updateCustomQuery(aData.url);
if (aData.requestHeaders) {
let headers = aData.requestHeaders.headers;
$("#custom-headers-value").value = writeHeaderText(headers);
}
if (aData.requestPostData) {
let body = aData.requestPostData.postData.text;
postDataPromise = gNetwork.getString(body).then(aString => {
$("#custom-postdata-value").value = aString;
});
} else {
postDataPromise = promise.resolve();
let postData = aData.requestPostData.postData.text;
$("#custom-postdata-value").value = yield gNetwork.getString(postData);
}
return postDataPromise
.then(() => view.updateCustomQuery(aData.url))
.then(() => window.emit(EVENTS.CUSTOMREQUESTVIEW_POPULATED));
},
window.emit(EVENTS.CUSTOMREQUESTVIEW_POPULATED);
}),
/**
* Handle user input in the custom request form.
@ -1895,7 +1891,7 @@ CustomRequestView.prototype = {
* Update the query string field based on the url.
*
* @param object aUrl
* url to extract query string from.
* The URL to extract query string from.
*/
updateCustomQuery: function(aUrl) {
let paramsArray = parseQueryString(nsIURL(aUrl).query);
@ -1911,7 +1907,7 @@ CustomRequestView.prototype = {
* Update the url based on the query string field.
*
* @param object aQueryText
* contents of the query string field.
* The contents of the query string field.
*/
updateCustomUrl: function(aQueryText) {
let params = parseQueryText(aQueryText);
@ -2123,20 +2119,14 @@ NetworkDetailsView.prototype = {
* @return object
* A promise that resolves when request headers are set.
*/
_setRequestHeaders: function(aHeadersResponse, aHeadersFromUploadStream) {
let outstanding = [];
_setRequestHeaders: Task.async(function*(aHeadersResponse, aHeadersFromUploadStream) {
if (aHeadersResponse && aHeadersResponse.headers.length) {
outstanding.push(
this._addHeaders(this._requestHeaders, aHeadersResponse));
yield this._addHeaders(this._requestHeaders, aHeadersResponse);
}
if (aHeadersFromUploadStream && aHeadersFromUploadStream.headers.length) {
outstanding.push(
this._addHeaders(this._requestHeadersFromUpload, aHeadersFromUploadStream));
yield this._addHeaders(this._requestHeadersFromUpload, aHeadersFromUploadStream);
}
return promise.all(outstanding);
},
}),
/**
* Sets the network response headers shown in this view.
@ -2146,13 +2136,12 @@ NetworkDetailsView.prototype = {
* @return object
* A promise that resolves when response headers are set.
*/
_setResponseHeaders: function(aResponse) {
_setResponseHeaders: Task.async(function*(aResponse) {
if (aResponse && aResponse.headers.length) {
aResponse.headers.sort((a, b) => a.name > b.name);
return this._addHeaders(this._responseHeaders, aResponse);
yield this._addHeaders(this._responseHeaders, aResponse);
}
return promise.resolve();
},
}),
/**
* Populates the headers container in this view with the specified data.
@ -2164,18 +2153,20 @@ NetworkDetailsView.prototype = {
* @return object
* A promise that resolves when headers are added.
*/
_addHeaders: function(aName, aResponse) {
_addHeaders: Task.async(function*(aName, aResponse) {
let kb = aResponse.headersSize / 1024;
let size = L10N.numberWithDecimals(kb, HEADERS_SIZE_DECIMALS);
let text = L10N.getFormatStr("networkMenu.sizeKB", size);
let headersScope = this._headers.addScope(aName + " (" + text + ")");
headersScope.expanded = true;
return promise.all(aResponse.headers.map(header => {
for (let header of aResponse.headers) {
let headerVar = headersScope.addItem(header.name, {}, true);
return gNetwork.getString(header.value).then(aString => headerVar.setGrip(aString));
}));
},
let headerValue = yield gNetwork.getString(header.value);
headerVar.setGrip(headerValue);
}
}),
/**
* Sets the network request cookies shown in this view.
@ -2185,13 +2176,12 @@ NetworkDetailsView.prototype = {
* @return object
* A promise that is resolved when the request cookies are set.
*/
_setRequestCookies: function(aResponse) {
_setRequestCookies: Task.async(function*(aResponse) {
if (aResponse && aResponse.cookies.length) {
aResponse.cookies.sort((a, b) => a.name > b.name);
return this._addCookies(this._requestCookies, aResponse);
yield this._addCookies(this._requestCookies, aResponse);
}
return promise.resolve();
},
}),
/**
* Sets the network response cookies shown in this view.
@ -2201,12 +2191,11 @@ NetworkDetailsView.prototype = {
* @return object
* A promise that is resolved when the response cookies are set.
*/
_setResponseCookies: function(aResponse) {
_setResponseCookies: Task.async(function*(aResponse) {
if (aResponse && aResponse.cookies.length) {
return this._addCookies(this._responseCookies, aResponse);
yield this._addCookies(this._responseCookies, aResponse);
}
return promise.resolve();
},
}),
/**
* Populates the cookies container in this view with the specified data.
@ -2218,35 +2207,34 @@ NetworkDetailsView.prototype = {
* @return object
* Returns a promise that resolves upon the adding of cookies.
*/
_addCookies: function(aName, aResponse) {
_addCookies: Task.async(function*(aName, aResponse) {
let cookiesScope = this._cookies.addScope(aName);
cookiesScope.expanded = true;
return promise.all(aResponse.cookies.map(cookie => {
for (let cookie of aResponse.cookies) {
let cookieVar = cookiesScope.addItem(cookie.name, {}, true);
return gNetwork.getString(cookie.value).then(aString => {
cookieVar.setGrip(aString);
let cookieValue = yield gNetwork.getString(cookie.value);
cookieVar.setGrip(cookieValue);
// By default the cookie name and value are shown. If this is the only
// information available, then nothing else is to be displayed.
let cookieProps = Object.keys(cookie);
if (cookieProps.length == 2) {
return;
}
// By default the cookie name and value are shown. If this is the only
// information available, then nothing else is to be displayed.
let cookieProps = Object.keys(cookie);
if (cookieProps.length == 2) {
return;
}
// Display any other information other than the cookie name and value
// which may be available.
let rawObject = Object.create(null);
let otherProps = cookieProps.filter(e => e != "name" && e != "value");
for (let prop of otherProps) {
rawObject[prop] = cookie[prop];
}
cookieVar.populate(rawObject);
cookieVar.twisty = true;
cookieVar.expanded = true;
});
}));
},
// Display any other information other than the cookie name and value
// which may be available.
let rawObject = Object.create(null);
let otherProps = cookieProps.filter(e => e != "name" && e != "value");
for (let prop of otherProps) {
rawObject[prop] = cookie[prop];
}
cookieVar.populate(rawObject);
cookieVar.twisty = true;
cookieVar.expanded = true;
}
}),
/**
* Sets the network request get params shown in this view.
@ -2273,59 +2261,58 @@ NetworkDetailsView.prototype = {
* @return object
* A promise that is resolved when the request post params are set.
*/
_setRequestPostParams: function(aHeadersResponse, aHeadersFromUploadStream, aPostDataResponse) {
_setRequestPostParams: Task.async(function*(aHeadersResponse, aHeadersFromUploadStream, aPostDataResponse) {
if (!aHeadersResponse || !aHeadersFromUploadStream || !aPostDataResponse) {
return promise.resolve();
return;
}
let { headers: requestHeaders } = aHeadersResponse;
let { headers: payloadHeaders } = aHeadersFromUploadStream;
let allHeaders = [...payloadHeaders, ...requestHeaders];
let contentTypeHeader = allHeaders.filter(e => e.name.toLowerCase() == "content-type")[0];
let contentTypeHeader = allHeaders.find(e => e.name.toLowerCase() == "content-type");
let contentTypeLongString = contentTypeHeader ? contentTypeHeader.value : "";
let postDataLongString = aPostDataResponse.postData.text;
return promise.all([
gNetwork.getString(postDataLongString),
gNetwork.getString(contentTypeLongString)
])
.then(([aPostData, aContentType]) => {
// Handle query strings (e.g. "?foo=bar&baz=42").
if (aContentType.contains("x-www-form-urlencoded")) {
for (let section of aPostData.split(/\r\n|\r|\n/)) {
// Before displaying it, make sure this section of the POST data
// isn't a line containing upload stream headers.
if (payloadHeaders.every(header => !section.startsWith(header.name))) {
this._addParams(this._paramsFormData, section);
}
let postData = yield gNetwork.getString(postDataLongString);
let contentType = yield gNetwork.getString(contentTypeLongString);
// Handle query strings (e.g. "?foo=bar&baz=42").
if (contentType.contains("x-www-form-urlencoded")) {
for (let section of postData.split(/\r\n|\r|\n/)) {
// Before displaying it, make sure this section of the POST data
// isn't a line containing upload stream headers.
if (payloadHeaders.every(header => !section.startsWith(header.name))) {
this._addParams(this._paramsFormData, section);
}
}
// Handle actual forms ("multipart/form-data" content type).
else {
// This is really awkward, but hey, it works. Let's show an empty
// scope in the params view and place the source editor containing
// the raw post data directly underneath.
$("#request-params-box").removeAttribute("flex");
let paramsScope = this._params.addScope(this._paramsPostPayload);
paramsScope.expanded = true;
paramsScope.locked = true;
}
// Handle actual forms ("multipart/form-data" content type).
else {
// This is really awkward, but hey, it works. Let's show an empty
// scope in the params view and place the source editor containing
// the raw post data directly underneath.
$("#request-params-box").removeAttribute("flex");
let paramsScope = this._params.addScope(this._paramsPostPayload);
paramsScope.expanded = true;
paramsScope.locked = true;
$("#request-post-data-textarea-box").hidden = false;
return NetMonitorView.editor("#request-post-data-textarea").then(aEditor => {
// Most POST bodies are usually JSON, so they can be neatly
// syntax highlighted as JS. Otheriwse, fall back to plain text.
try {
JSON.parse(aPostData);
aEditor.setMode(Editor.modes.js);
} catch (e) {
aEditor.setMode(Editor.modes.text);
} finally {
aEditor.setText(aPostData);
}
});
$("#request-post-data-textarea-box").hidden = false;
let editor = yield NetMonitorView.editor("#request-post-data-textarea");
// Most POST bodies are usually JSON, so they can be neatly
// syntax highlighted as JS. Otheriwse, fall back to plain text.
try {
JSON.parse(postData);
editor.setMode(Editor.modes.js);
} catch (e) {
editor.setMode(Editor.modes.text);
} finally {
editor.setText(postData);
}
}).then(() => window.emit(EVENTS.REQUEST_POST_PARAMS_DISPLAYED));
},
}
window.emit(EVENTS.REQUEST_POST_PARAMS_DISPLAYED);
}),
/**
* Populates the params container in this view with the specified data.
@ -2357,118 +2344,112 @@ NetworkDetailsView.prototype = {
* @param object aResponse
* The message received from the server.
* @return object
* A promise that is resolved when the response body is set
* A promise that is resolved when the response body is set.
*/
_setResponseBody: function(aUrl, aResponse) {
_setResponseBody: Task.async(function*(aUrl, aResponse) {
if (!aResponse) {
return promise.resolve();
return;
}
let { mimeType, text, encoding } = aResponse.content;
let responseBody = yield gNetwork.getString(text);
return gNetwork.getString(text).then(aString => {
// Handle json, which we tentatively identify by checking the MIME type
// for "json" after any word boundary. This works for the standard
// "application/json", and also for custom types like "x-bigcorp-json".
// Additionally, we also directly parse the response text content to
// verify whether it's json or not, to handle responses incorrectly
// labeled as text/plain instead.
let jsonMimeType, jsonObject, jsonObjectParseError;
try {
// Test the mime type *and* parse the string, because "JSONP" responses
// (json with callback) aren't actually valid json.
jsonMimeType = /\bjson/.test(mimeType);
jsonObject = JSON.parse(aString);
} catch (e) {
jsonObjectParseError = e;
}
if (jsonMimeType || jsonObject) {
// Extract the actual json substring in case this might be a "JSONP".
// This regex basically parses a function call and captures the
// function name and arguments in two separate groups.
let jsonpRegex = /^\s*([\w$]+)\s*\(\s*([^]*)\s*\)\s*;?\s*$/;
let [_, callbackPadding, jsonpString] = aString.match(jsonpRegex) || [];
// Handle json, which we tentatively identify by checking the MIME type
// for "json" after any word boundary. This works for the standard
// "application/json", and also for custom types like "x-bigcorp-json".
// Additionally, we also directly parse the response text content to
// verify whether it's json or not, to handle responses incorrectly
// labeled as text/plain instead.
let jsonMimeType, jsonObject, jsonObjectParseError;
try {
jsonMimeType = /\bjson/.test(mimeType);
jsonObject = JSON.parse(responseBody);
} catch (e) {
jsonObjectParseError = e;
}
if (jsonMimeType || jsonObject) {
// Extract the actual json substring in case this might be a "JSONP".
// This regex basically parses a function call and captures the
// function name and arguments in two separate groups.
let jsonpRegex = /^\s*([\w$]+)\s*\(\s*([^]*)\s*\)\s*;?\s*$/;
let [_, callbackPadding, jsonpString] = responseBody.match(jsonpRegex) || [];
// Make sure this is a valid JSON object first. If so, nicely display
// the parsing results in a variables view. Otherwise, simply show
// the contents as plain text.
if (callbackPadding && jsonpString) {
try {
jsonObject = JSON.parse(jsonpString);
} catch (e) {
jsonObjectParseError = e;
}
}
// Valid JSON or JSONP.
if (jsonObject) {
$("#response-content-json-box").hidden = false;
let jsonScopeName = callbackPadding
? L10N.getFormatStr("jsonpScopeName", callbackPadding)
: L10N.getStr("jsonScopeName");
return this._json.controller.setSingleVariable({
label: jsonScopeName,
rawObject: jsonObject,
}).expanded;
}
// Malformed JSON.
else {
$("#response-content-textarea-box").hidden = false;
let infoHeader = $("#response-content-info-header");
infoHeader.setAttribute("value", jsonObjectParseError);
infoHeader.setAttribute("tooltiptext", jsonObjectParseError);
infoHeader.hidden = false;
return NetMonitorView.editor("#response-content-textarea").then(aEditor => {
aEditor.setMode(Editor.modes.js);
aEditor.setText(aString);
});
// Make sure this is a valid JSON object first. If so, nicely display
// the parsing results in a variables view. Otherwise, simply show
// the contents as plain text.
if (callbackPadding && jsonpString) {
try {
jsonObject = JSON.parse(jsonpString);
} catch (e) {
jsonObjectParseError = e;
}
}
// Handle images.
else if (mimeType.contains("image/")) {
$("#response-content-image-box").setAttribute("align", "center");
$("#response-content-image-box").setAttribute("pack", "center");
$("#response-content-image-box").hidden = false;
$("#response-content-image").src =
"data:" + mimeType + ";" + encoding + "," + aString;
// Immediately display additional information about the image:
// file name, mime type and encoding.
$("#response-content-image-name-value").setAttribute("value", nsIURL(aUrl).fileName);
$("#response-content-image-mime-value").setAttribute("value", mimeType);
$("#response-content-image-encoding-value").setAttribute("value", encoding);
// Valid JSON or JSONP.
if (jsonObject) {
$("#response-content-json-box").hidden = false;
let jsonScopeName = callbackPadding
? L10N.getFormatStr("jsonpScopeName", callbackPadding)
: L10N.getStr("jsonScopeName");
// Wait for the image to load in order to display the width and height.
$("#response-content-image").onload = e => {
// XUL images are majestic so they don't bother storing their dimensions
// in width and height attributes like the rest of the folk. Hack around
// this by getting the bounding client rect and subtracting the margins.
let { width, height } = e.target.getBoundingClientRect();
let dimensions = (width - 2) + " x " + (height - 2);
$("#response-content-image-dimensions-value").setAttribute("value", dimensions);
};
let jsonVar = { label: jsonScopeName, rawObject: jsonObject };
yield this._json.controller.setSingleVariable(jsonVar).expanded;
}
// Handle anything else.
// Malformed JSON.
else {
$("#response-content-textarea-box").hidden = false;
return NetMonitorView.editor("#response-content-textarea").then(aEditor => {
aEditor.setMode(Editor.modes.text);
aEditor.setText(aString);
let infoHeader = $("#response-content-info-header");
infoHeader.setAttribute("value", jsonObjectParseError);
infoHeader.setAttribute("tooltiptext", jsonObjectParseError);
infoHeader.hidden = false;
// Maybe set a more appropriate mode in the Source Editor if possible,
// but avoid doing this for very large files.
if (aString.length < SOURCE_SYNTAX_HIGHLIGHT_MAX_FILE_SIZE) {
for (let key in CONTENT_MIME_TYPE_MAPPINGS) {
if (mimeType.contains(key)) {
aEditor.setMode(CONTENT_MIME_TYPE_MAPPINGS[key]);
break;
}
}
}
});
let editor = yield NetMonitorView.editor("#response-content-textarea");
editor.setMode(Editor.modes.js);
editor.setText(responseBody);
}
}).then(() => window.emit(EVENTS.RESPONSE_BODY_DISPLAYED));
},
}
// Handle images.
else if (mimeType.contains("image/")) {
$("#response-content-image-box").setAttribute("align", "center");
$("#response-content-image-box").setAttribute("pack", "center");
$("#response-content-image-box").hidden = false;
$("#response-content-image").src =
"data:" + mimeType + ";" + encoding + "," + responseBody;
// Immediately display additional information about the image:
// file name, mime type and encoding.
$("#response-content-image-name-value").setAttribute("value", nsIURL(aUrl).fileName);
$("#response-content-image-mime-value").setAttribute("value", mimeType);
$("#response-content-image-encoding-value").setAttribute("value", encoding);
// Wait for the image to load in order to display the width and height.
$("#response-content-image").onload = e => {
// XUL images are majestic so they don't bother storing their dimensions
// in width and height attributes like the rest of the folk. Hack around
// this by getting the bounding client rect and subtracting the margins.
let { width, height } = e.target.getBoundingClientRect();
let dimensions = (width - 2) + " x " + (height - 2);
$("#response-content-image-dimensions-value").setAttribute("value", dimensions);
};
}
// Handle anything else.
else {
$("#response-content-textarea-box").hidden = false;
let editor = yield NetMonitorView.editor("#response-content-textarea");
editor.setMode(Editor.modes.text);
editor.setText(responseBody);
// Maybe set a more appropriate mode in the Source Editor if possible,
// but avoid doing this for very large files.
if (responseBody.length < SOURCE_SYNTAX_HIGHLIGHT_MAX_FILE_SIZE) {
let mapping = Object.keys(CONTENT_MIME_TYPE_MAPPINGS).find(key => mimeType.contains(key));
if (mapping) {
editor.setMode(CONTENT_MIME_TYPE_MAPPINGS[mapping]);
}
}
}
window.emit(EVENTS.RESPONSE_BODY_DISPLAYED);
}),
/**
* Sets the timings information shown in this view.
@ -2545,23 +2526,22 @@ NetworkDetailsView.prototype = {
* @param object aResponse
* The message received from the server.
* @return object
* A promise that is resolved when the response body is set
* A promise that is resolved when the html preview is rendered.
*/
_setHtmlPreview: function(aResponse) {
_setHtmlPreview: Task.async(function*(aResponse) {
if (!aResponse) {
return promise.resolve();
}
let { text } = aResponse.content;
let responseBody = yield gNetwork.getString(text);
// Always disable JS when previewing HTML responses.
let iframe = $("#response-preview");
iframe.contentDocument.docShell.allowJavascript = false;
iframe.contentDocument.documentElement.innerHTML = responseBody;
return gNetwork.getString(text).then(aString => {
// Always disable JS when previewing HTML responses.
iframe.contentDocument.docShell.allowJavascript = false;
iframe.contentDocument.documentElement.innerHTML = aString;
window.emit(EVENTS.RESPONSE_HTML_PREVIEW_DISPLAYED);
});
},
window.emit(EVENTS.RESPONSE_HTML_PREVIEW_DISPLAYED);
}),
_dataSrc: null,
_headers: null,

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

@ -184,7 +184,7 @@ this.CurlUtils = {
let contentType = this.findHeader(aData.headers, "content-type");
return (contentType &&
return (contentType &&
contentType.toLowerCase().contains("multipart/form-data;"));
},
@ -228,7 +228,7 @@ this.CurlUtils = {
/**
* Returns the boundary string for a multipart request.
*
*
* @param string aData
* The data source. See the description in the Curl object.
* @return string
@ -243,7 +243,7 @@ this.CurlUtils = {
return contentType.match(boundaryRe)[1];
}
// Temporary workaround. As of 2014-03-11 the requestHeaders array does not
// always contain the Content-Type header for mulitpart requests. See bug 978144.
// always contain the Content-Type header for mulitpart requests. See bug 978144.
// Find the header from the request payload.
let boundaryString = aData.postDataText.match(boundaryRe)[1];
if (boundaryString) {
@ -393,4 +393,4 @@ this.CurlUtils = {
.replace(/\\/g, "\\\\")
.replace(/[\r\n]+/g, "\"^$&\"") + "\"";
}
};
};