diff options
Diffstat (limited to 'devtools/client/netmonitor/request-list-context-menu.js')
-rw-r--r-- | devtools/client/netmonitor/request-list-context-menu.js | 357 |
1 files changed, 357 insertions, 0 deletions
diff --git a/devtools/client/netmonitor/request-list-context-menu.js b/devtools/client/netmonitor/request-list-context-menu.js new file mode 100644 index 000000000..215296265 --- /dev/null +++ b/devtools/client/netmonitor/request-list-context-menu.js @@ -0,0 +1,357 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* globals NetMonitorController, NetMonitorView, gNetwork */ + +"use strict"; + +const Services = require("Services"); +const { Task } = require("devtools/shared/task"); +const { Curl } = require("devtools/client/shared/curl"); +const { gDevTools } = require("devtools/client/framework/devtools"); +const Menu = require("devtools/client/framework/menu"); +const MenuItem = require("devtools/client/framework/menu-item"); +const { L10N } = require("./l10n"); +const { formDataURI, getFormDataSections } = require("./request-utils"); + +loader.lazyRequireGetter(this, "HarExporter", + "devtools/client/netmonitor/har/har-exporter", true); + +loader.lazyServiceGetter(this, "clipboardHelper", + "@mozilla.org/widget/clipboardhelper;1", "nsIClipboardHelper"); + +loader.lazyRequireGetter(this, "NetworkHelper", + "devtools/shared/webconsole/network-helper"); + +function RequestListContextMenu() {} + +RequestListContextMenu.prototype = { + get selectedItem() { + return NetMonitorView.RequestsMenu.selectedItem; + }, + + get items() { + return NetMonitorView.RequestsMenu.items; + }, + + /** + * Handle the context menu opening. Hide items if no request is selected. + * Since visible attribute only accept boolean value but the method call may + * return undefined, we use !! to force convert any object to boolean + */ + open({ screenX = 0, screenY = 0 } = {}) { + let selectedItem = this.selectedItem; + + let menu = new Menu(); + menu.append(new MenuItem({ + id: "request-menu-context-copy-url", + label: L10N.getStr("netmonitor.context.copyUrl"), + accesskey: L10N.getStr("netmonitor.context.copyUrl.accesskey"), + visible: !!selectedItem, + click: () => this.copyUrl(), + })); + + menu.append(new MenuItem({ + id: "request-menu-context-copy-url-params", + label: L10N.getStr("netmonitor.context.copyUrlParams"), + accesskey: L10N.getStr("netmonitor.context.copyUrlParams.accesskey"), + visible: !!(selectedItem && + NetworkHelper.nsIURL(selectedItem.attachment.url).query), + click: () => this.copyUrlParams(), + })); + + menu.append(new MenuItem({ + id: "request-menu-context-copy-post-data", + label: L10N.getStr("netmonitor.context.copyPostData"), + accesskey: L10N.getStr("netmonitor.context.copyPostData.accesskey"), + visible: !!(selectedItem && selectedItem.attachment.requestPostData), + click: () => this.copyPostData(), + })); + + menu.append(new MenuItem({ + id: "request-menu-context-copy-as-curl", + label: L10N.getStr("netmonitor.context.copyAsCurl"), + accesskey: L10N.getStr("netmonitor.context.copyAsCurl.accesskey"), + visible: !!(selectedItem && selectedItem.attachment), + click: () => this.copyAsCurl(), + })); + + menu.append(new MenuItem({ + type: "separator", + visible: !!selectedItem, + })); + + menu.append(new MenuItem({ + id: "request-menu-context-copy-request-headers", + label: L10N.getStr("netmonitor.context.copyRequestHeaders"), + accesskey: L10N.getStr("netmonitor.context.copyRequestHeaders.accesskey"), + visible: !!(selectedItem && selectedItem.attachment.requestHeaders), + click: () => this.copyRequestHeaders(), + })); + + menu.append(new MenuItem({ + id: "response-menu-context-copy-response-headers", + label: L10N.getStr("netmonitor.context.copyResponseHeaders"), + accesskey: L10N.getStr("netmonitor.context.copyResponseHeaders.accesskey"), + visible: !!(selectedItem && selectedItem.attachment.responseHeaders), + click: () => this.copyResponseHeaders(), + })); + + menu.append(new MenuItem({ + id: "request-menu-context-copy-response", + label: L10N.getStr("netmonitor.context.copyResponse"), + accesskey: L10N.getStr("netmonitor.context.copyResponse.accesskey"), + visible: !!(selectedItem && + selectedItem.attachment.responseContent && + selectedItem.attachment.responseContent.content.text && + selectedItem.attachment.responseContent.content.text.length !== 0), + click: () => this.copyResponse(), + })); + + menu.append(new MenuItem({ + id: "request-menu-context-copy-image-as-data-uri", + label: L10N.getStr("netmonitor.context.copyImageAsDataUri"), + accesskey: L10N.getStr("netmonitor.context.copyImageAsDataUri.accesskey"), + visible: !!(selectedItem && + selectedItem.attachment.responseContent && + selectedItem.attachment.responseContent.content + .mimeType.includes("image/")), + click: () => this.copyImageAsDataUri(), + })); + + menu.append(new MenuItem({ + type: "separator", + visible: !!selectedItem, + })); + + menu.append(new MenuItem({ + id: "request-menu-context-copy-all-as-har", + label: L10N.getStr("netmonitor.context.copyAllAsHar"), + accesskey: L10N.getStr("netmonitor.context.copyAllAsHar.accesskey"), + visible: !!this.items.length, + click: () => this.copyAllAsHar(), + })); + + menu.append(new MenuItem({ + id: "request-menu-context-save-all-as-har", + label: L10N.getStr("netmonitor.context.saveAllAsHar"), + accesskey: L10N.getStr("netmonitor.context.saveAllAsHar.accesskey"), + visible: !!this.items.length, + click: () => this.saveAllAsHar(), + })); + + menu.append(new MenuItem({ + type: "separator", + visible: !!selectedItem, + })); + + menu.append(new MenuItem({ + id: "request-menu-context-resend", + label: L10N.getStr("netmonitor.context.editAndResend"), + accesskey: L10N.getStr("netmonitor.context.editAndResend.accesskey"), + visible: !!(NetMonitorController.supportsCustomRequest && + selectedItem && + !selectedItem.attachment.isCustom), + click: () => NetMonitorView.RequestsMenu.cloneSelectedRequest(), + })); + + menu.append(new MenuItem({ + type: "separator", + visible: !!selectedItem, + })); + + menu.append(new MenuItem({ + id: "request-menu-context-newtab", + label: L10N.getStr("netmonitor.context.newTab"), + accesskey: L10N.getStr("netmonitor.context.newTab.accesskey"), + visible: !!selectedItem, + click: () => this.openRequestInTab() + })); + + menu.append(new MenuItem({ + id: "request-menu-context-perf", + label: L10N.getStr("netmonitor.context.perfTools"), + accesskey: L10N.getStr("netmonitor.context.perfTools.accesskey"), + visible: !!NetMonitorController.supportsPerfStats, + click: () => NetMonitorView.toggleFrontendMode() + })); + + menu.popup(screenX, screenY, NetMonitorController._toolbox); + return menu; + }, + + /** + * Opens selected item in a new tab. + */ + openRequestInTab() { + let win = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType); + let { url } = this.selectedItem.attachment; + win.openUILinkIn(url, "tab", { relatedToCurrent: true }); + }, + + /** + * Copy the request url from the currently selected item. + */ + copyUrl() { + clipboardHelper.copyString(this.selectedItem.attachment.url); + }, + + /** + * Copy the request url query string parameters from the currently + * selected item. + */ + copyUrlParams() { + let { url } = this.selectedItem.attachment; + let params = NetworkHelper.nsIURL(url).query.split("&"); + let string = params.join(Services.appinfo.OS === "WINNT" ? "\r\n" : "\n"); + clipboardHelper.copyString(string); + }, + + /** + * Copy the request form data parameters (or raw payload) from + * the currently selected item. + */ + copyPostData: Task.async(function* () { + let selected = this.selectedItem.attachment; + + // Try to extract any form data parameters. + let formDataSections = yield getFormDataSections( + selected.requestHeaders, + selected.requestHeadersFromUploadStream, + selected.requestPostData, + gNetwork.getString.bind(gNetwork)); + + let params = []; + formDataSections.forEach(section => { + let paramsArray = NetworkHelper.parseQueryString(section); + if (paramsArray) { + params = [...params, ...paramsArray]; + } + }); + + let string = params + .map(param => param.name + (param.value ? "=" + param.value : "")) + .join(Services.appinfo.OS === "WINNT" ? "\r\n" : "\n"); + + // Fall back to raw payload. + if (!string) { + let postData = selected.requestPostData.postData.text; + string = yield gNetwork.getString(postData); + if (Services.appinfo.OS !== "WINNT") { + string = string.replace(/\r/g, ""); + } + } + + clipboardHelper.copyString(string); + }), + + /** + * Copy a cURL command from the currently selected item. + */ + copyAsCurl: Task.async(function* () { + let selected = this.selectedItem.attachment; + + // Create a sanitized object for the Curl command generator. + let data = { + url: selected.url, + method: selected.method, + headers: [], + httpVersion: selected.httpVersion, + postDataText: null + }; + + // Fetch header values. + for (let { name, value } of selected.requestHeaders.headers) { + let text = yield gNetwork.getString(value); + data.headers.push({ name: name, value: text }); + } + + // Fetch the request payload. + if (selected.requestPostData) { + let postData = selected.requestPostData.postData.text; + data.postDataText = yield gNetwork.getString(postData); + } + + clipboardHelper.copyString(Curl.generateCommand(data)); + }), + + /** + * Copy the raw request headers from the currently selected item. + */ + copyRequestHeaders() { + let selected = this.selectedItem.attachment; + let rawHeaders = selected.requestHeaders.rawHeaders.trim(); + if (Services.appinfo.OS !== "WINNT") { + rawHeaders = rawHeaders.replace(/\r/g, ""); + } + clipboardHelper.copyString(rawHeaders); + }, + + /** + * Copy the raw response headers from the currently selected item. + */ + copyResponseHeaders() { + let selected = this.selectedItem.attachment; + let rawHeaders = selected.responseHeaders.rawHeaders.trim(); + if (Services.appinfo.OS !== "WINNT") { + rawHeaders = rawHeaders.replace(/\r/g, ""); + } + clipboardHelper.copyString(rawHeaders); + }, + + /** + * Copy image as data uri. + */ + copyImageAsDataUri() { + let selected = this.selectedItem.attachment; + let { mimeType, text, encoding } = selected.responseContent.content; + + gNetwork.getString(text).then(string => { + let data = formDataURI(mimeType, encoding, string); + clipboardHelper.copyString(data); + }); + }, + + /** + * Copy response data as a string. + */ + copyResponse() { + let selected = this.selectedItem.attachment; + let text = selected.responseContent.content.text; + + gNetwork.getString(text).then(string => { + clipboardHelper.copyString(string); + }); + }, + + /** + * Copy HAR from the network panel content to the clipboard. + */ + copyAllAsHar() { + let options = this.getDefaultHarOptions(); + return HarExporter.copy(options); + }, + + /** + * Save HAR from the network panel content to a file. + */ + saveAllAsHar() { + let options = this.getDefaultHarOptions(); + return HarExporter.save(options); + }, + + getDefaultHarOptions() { + let form = NetMonitorController._target.form; + let title = form.title || form.url; + + return { + getString: gNetwork.getString.bind(gNetwork), + view: NetMonitorView.RequestsMenu, + items: NetMonitorView.RequestsMenu.items, + title: title + }; + } +}; + +module.exports = RequestListContextMenu; |