author | Fred Lin <gasolin@mozilla.com> |
Mon, 17 Apr 2017 14:21:59 +0800 | |
changeset 354719 | 1163b1091f35b5e5ffff15233a6bf8a71c4a8984 |
parent 354718 | 1b60cc98d34fd9b7443c6e8ac71ebf0085776043 |
child 354720 | e6727c8b0f5ee42c2fa5430c7e5bf40bfbcaa96b |
push id | 31711 |
push user | cbook@mozilla.com |
push date | Tue, 25 Apr 2017 09:24:00 +0000 |
treeherder | mozilla-central@a30dc237c3a6 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | rickychien |
bugs | 1356957 |
milestone | 55.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
|
--- a/devtools/client/netmonitor/src/components/request-list-column-file.js +++ b/devtools/client/netmonitor/src/components/request-list-column-file.js @@ -35,17 +35,16 @@ const RequestListColumnFile = createClas return ( div({ className: "requests-list-column requests-list-file", title: urlDetails.unicodeUrl, }, img({ className: "requests-list-icon", src: responseContentDataUri, - "data-type": responseContentDataUri ? "thumbnail" : undefined, }), urlDetails.baseNameWithQuery ) ); } }); module.exports = RequestListColumnFile;
--- a/devtools/client/netmonitor/src/constants.js +++ b/devtools/client/netmonitor/src/constants.js @@ -88,28 +88,16 @@ const EVENTS = { UPDATING_EVENT_TIMINGS: "NetMonitor:NetworkEventUpdating:EventTimings", RECEIVED_EVENT_TIMINGS: "NetMonitor:NetworkEventUpdated:EventTimings", // When response content begins, updates and finishes receiving. STARTED_RECEIVING_RESPONSE: "NetMonitor:NetworkEventUpdating:ResponseStart", UPDATING_RESPONSE_CONTENT: "NetMonitor:NetworkEventUpdating:ResponseContent", RECEIVED_RESPONSE_CONTENT: "NetMonitor:NetworkEventUpdated:ResponseContent", - // When the request post params are displayed in the UI. - REQUEST_POST_PARAMS_DISPLAYED: "NetMonitor:RequestPostParamsAvailable", - - // When the image response thumbnail is displayed in the UI. - RESPONSE_IMAGE_THUMBNAIL_DISPLAYED: - "NetMonitor:ResponseImageThumbnailAvailable", - - // Fired when charts have been displayed in the PerformanceStatisticsView. - PLACEHOLDER_CHARTS_DISPLAYED: "NetMonitor:PlaceholderChartsDisplayed", - PRIMED_CACHE_CHART_DISPLAYED: "NetMonitor:PrimedChartsDisplayed", - EMPTY_CACHE_CHART_DISPLAYED: "NetMonitor:EmptyChartsDisplayed", - // Fired once the NetMonitorController establishes a connection to the debug // target. CONNECTED: "connected", }; const HEADERS = [ { name: "status",
--- a/devtools/client/netmonitor/src/netmonitor-controller.js +++ b/devtools/client/netmonitor/src/netmonitor-controller.js @@ -2,20 +2,17 @@ * 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/. */ "use strict"; const { TimelineFront } = require("devtools/shared/fronts/timeline"); const { CurlUtils } = require("devtools/client/shared/curl"); const { ACTIVITY_TYPE, EVENTS } = require("./constants"); -const { - getRequestById, - getDisplayedRequestById, -} = require("./selectors/index"); +const { getDisplayedRequestById } = require("./selectors/index"); const { fetchHeaders, formDataURI, } = require("./utils/request-utils"); const { getLongString, getWebConsoleClient, onFirefoxConnect, @@ -302,17 +299,16 @@ function NetworkEventsHandler() { this._onNetworkEvent = this._onNetworkEvent.bind(this); this._onNetworkEventUpdate = this._onNetworkEventUpdate.bind(this); this._onDocLoadingMarker = this._onDocLoadingMarker.bind(this); this._onRequestHeaders = this._onRequestHeaders.bind(this); this._onRequestCookies = this._onRequestCookies.bind(this); this._onRequestPostData = this._onRequestPostData.bind(this); this._onResponseHeaders = this._onResponseHeaders.bind(this); this._onResponseCookies = this._onResponseCookies.bind(this); - this._onResponseContent = this._onResponseContent.bind(this); this._onSecurityInfo = this._onSecurityInfo.bind(this); this._onEventTimings = this._onEventTimings.bind(this); } NetworkEventsHandler.prototype = { get client() { return NetMonitorController._target.client; }, @@ -423,125 +419,151 @@ NetworkEventsHandler.prototype = { fromCache, fromServiceWorker, }, true ) .then(() => window.emit(EVENTS.REQUEST_ADDED, id)); }, - async updateRequest(id, data) { - await this.actions.updateRequest(id, data, true); - let { - responseContent, - responseCookies, - responseHeaders, - requestCookies, - requestHeaders, - requestPostData, - } = data; - let request = getRequestById(window.gStore.getState(), id); - - if (requestHeaders && requestHeaders.headers && requestHeaders.headers.length) { - let headers = await fetchHeaders(requestHeaders, getLongString); - if (headers) { - await this.actions.updateRequest( - id, - { requestHeaders: headers }, - true, - ); - } - } - - if (responseHeaders && responseHeaders.headers && responseHeaders.headers.length) { - let headers = await fetchHeaders(responseHeaders, getLongString); - if (headers) { - await this.actions.updateRequest( - id, - { responseHeaders: headers }, - true, - ); - } - } - - if (request && responseContent && responseContent.content) { - let { mimeType } = request; - let { text, encoding } = responseContent.content; + async fetchImage(mimeType, responseContent) { + let payload = {}; + if (mimeType && responseContent && responseContent.content) { + let { encoding, text } = responseContent.content; let response = await getLongString(text); - let payload = {}; if (mimeType.includes("image/")) { payload.responseContentDataUri = formDataURI(mimeType, encoding, response); } responseContent.content.text = response; payload.responseContent = responseContent; - - await this.actions.updateRequest(id, payload, true); + } + return payload; + }, - if (mimeType.includes("image/")) { - window.emit(EVENTS.RESPONSE_IMAGE_THUMBNAIL_DISPLAYED); + async fetchRequestHeaders(requestHeaders) { + let payload = {}; + if (requestHeaders && requestHeaders.headers && requestHeaders.headers.length) { + let headers = await fetchHeaders(requestHeaders, getLongString); + if (headers) { + payload.requestHeaders = headers; } } + return payload; + }, - // Search the POST data upload stream for request headers and add - // them as a separate property, different from the classic headers. + async fetchResponseHeaders(responseHeaders) { + let payload = {}; + if (responseHeaders && responseHeaders.headers && responseHeaders.headers.length) { + let headers = await fetchHeaders(responseHeaders, getLongString); + if (headers) { + payload.responseHeaders = headers; + } + } + return payload; + }, + + // Search the POST data upload stream for request headers and add + // them as a separate property, different from the classic headers. + async fetchPostData(requestPostData) { + let payload = {}; if (requestPostData && requestPostData.postData) { let { text } = requestPostData.postData; let postData = await getLongString(text); const headers = CurlUtils.getHeadersFromMultipartText(postData); const headersSize = headers.reduce((acc, { name, value }) => { return acc + name.length + value.length + 2; }, 0); - let payload = {}; requestPostData.postData.text = postData; payload.requestPostData = Object.assign({}, requestPostData); payload.requestHeadersFromUploadStream = { headers, headersSize }; - - await this.actions.updateRequest(id, payload, true); } + return payload; + }, - // Fetch request and response cookies long value. - // Actor does not provide full sized cookie value when the value is too long - // To display values correctly, we need fetch them in each request. + async fetchResponseCookies(responseCookies) { + let payload = {}; + if (responseCookies) { + let resCookies = []; + // response store cookies in responseCookies or responseCookies.cookies + let cookies = responseCookies.cookies ? + responseCookies.cookies : responseCookies; + // make sure cookies is iterable + if (typeof cookies[Symbol.iterator] === "function") { + for (let cookie of cookies) { + resCookies.push(Object.assign({}, cookie, { + value: await getLongString(cookie.value), + })); + } + if (resCookies.length) { + payload.responseCookies = resCookies; + } + } + } + return payload; + }, + + // Fetch request and response cookies long value. + // Actor does not provide full sized cookie value when the value is too long + // To display values correctly, we need fetch them in each request. + async fetchRequestCookies(requestCookies) { + let payload = {}; if (requestCookies) { let reqCookies = []; // request store cookies in requestCookies or requestCookies.cookies let cookies = requestCookies.cookies ? requestCookies.cookies : requestCookies; // make sure cookies is iterable if (typeof cookies[Symbol.iterator] === "function") { for (let cookie of cookies) { reqCookies.push(Object.assign({}, cookie, { value: await getLongString(cookie.value), })); } if (reqCookies.length) { - await this.actions.updateRequest(id, { requestCookies: reqCookies }, true); + payload.requestCookies = reqCookies; } } } + return payload; + }, - if (responseCookies) { - let resCookies = []; - // response store cookies in responseCookies or responseCookies.cookies - let cookies = responseCookies.cookies ? - responseCookies.cookies : responseCookies; - // make sure cookies is iterable - if (typeof cookies[Symbol.iterator] === "function") { - for (let cookie of cookies) { - resCookies.push(Object.assign({}, cookie, { - value: await getLongString(cookie.value), - })); - } - if (resCookies.length) { - await this.actions.updateRequest(id, { responseCookies: resCookies }, true); - } - } - } + async updateRequest(id, data) { + let { + mimeType, + responseContent, + responseCookies, + responseHeaders, + requestCookies, + requestHeaders, + requestPostData, + } = data; + + // fetch request detail contents in parallel + let [ + imageObj, + requestHeadersObj, + responseHeadersObj, + postDataObj, + requestCookiesObj, + responseCookiesObj, + ] = await Promise.all([ + this.fetchImage(mimeType, responseContent), + this.fetchRequestHeaders(requestHeaders), + this.fetchResponseHeaders(responseHeaders), + this.fetchPostData(requestPostData), + this.fetchRequestCookies(requestCookies), + this.fetchResponseCookies(responseCookies), + ]); + + let payload = Object.assign({}, data, + imageObj, requestHeadersObj, responseHeadersObj, + postDataObj, requestCookiesObj, responseCookiesObj); + await this.actions.updateRequest(id, payload, true); }, /** * The "networkEventUpdate" message type handler. * * @param string type * Message type. * @param object packet @@ -563,19 +585,20 @@ NetworkEventsHandler.prototype = { case "requestPostData": this.webConsoleClient.getRequestPostData(actor, this._onRequestPostData); window.emit(EVENTS.UPDATING_REQUEST_POST_DATA, actor); break; case "securityInfo": this.updateRequest(actor, { securityState: networkInfo.securityInfo, + }).then(() => { + this.webConsoleClient.getSecurityInfo(actor, this._onSecurityInfo); + window.emit(EVENTS.UPDATING_SECURITY_INFO, actor); }); - this.webConsoleClient.getSecurityInfo(actor, this._onSecurityInfo); - window.emit(EVENTS.UPDATING_SECURITY_INFO, actor); break; case "responseHeaders": this.webConsoleClient.getResponseHeaders(actor, this._onResponseHeaders); window.emit(EVENTS.UPDATING_RESPONSE_HEADERS, actor); break; case "responseCookies": this.webConsoleClient.getResponseCookies(actor, @@ -585,35 +608,36 @@ NetworkEventsHandler.prototype = { case "responseStart": this.updateRequest(actor, { httpVersion: networkInfo.response.httpVersion, remoteAddress: networkInfo.response.remoteAddress, remotePort: networkInfo.response.remotePort, status: networkInfo.response.status, statusText: networkInfo.response.statusText, headersSize: networkInfo.response.headersSize + }).then(() => { + window.emit(EVENTS.STARTED_RECEIVING_RESPONSE, actor); }); - window.emit(EVENTS.STARTED_RECEIVING_RESPONSE, actor); break; case "responseContent": - this.updateRequest(actor, { - contentSize: networkInfo.response.bodySize, - transferredSize: networkInfo.response.transferredSize, - mimeType: networkInfo.response.content.mimeType - }); this.webConsoleClient.getResponseContent(actor, - this._onResponseContent); + this._onResponseContent.bind(this, { + contentSize: networkInfo.response.bodySize, + transferredSize: networkInfo.response.transferredSize, + mimeType: networkInfo.response.content.mimeType + })); window.emit(EVENTS.UPDATING_RESPONSE_CONTENT, actor); break; case "eventTimings": this.updateRequest(actor, { totalTime: networkInfo.totalTime + }).then(() => { + this.webConsoleClient.getEventTimings(actor, this._onEventTimings); + window.emit(EVENTS.UPDATING_EVENT_TIMINGS, actor); }); - this.webConsoleClient.getEventTimings(actor, this._onEventTimings); - window.emit(EVENTS.UPDATING_EVENT_TIMINGS, actor); break; } }, /** * Handles additional information received for a "requestHeaders" packet. * * @param object response @@ -695,23 +719,24 @@ NetworkEventsHandler.prototype = { }).then(() => { window.emit(EVENTS.RECEIVED_RESPONSE_COOKIES, response.from); }); }, /** * Handles additional information received for a "responseContent" packet. * + * @param object data + * The message received from the server event. * @param object response * The message received from the server. */ - _onResponseContent: function (response) { - this.updateRequest(response.from, { - responseContent: response - }).then(() => { + _onResponseContent: function (data, response) { + let payload = Object.assign({ responseContent: response }, data); + this.updateRequest(response.from, payload).then(() => { window.emit(EVENTS.RECEIVED_RESPONSE_CONTENT, response.from); }); }, /** * Handles additional information received for a "eventTimings" packet. * * @param object response
--- a/devtools/client/netmonitor/test/browser_net_icon-preview.js +++ b/devtools/client/netmonitor/test/browser_net_icon-preview.js @@ -4,74 +4,66 @@ "use strict"; /** * Tests if image responses show a thumbnail in the requests menu. */ add_task(function* () { let { tab, monitor } = yield initNetMonitor(CONTENT_TYPE_WITHOUT_CACHE_URL); + const SELECTOR = ".requests-list-icon[src]"; info("Starting test... "); let { document, gStore, windowRequire } = monitor.panelWin; let Actions = windowRequire("devtools/client/netmonitor/src/actions/index"); let { NetMonitorController } = windowRequire("devtools/client/netmonitor/src/netmonitor-controller"); - let { - ACTIVITY_TYPE, - EVENTS, - } = windowRequire("devtools/client/netmonitor/src/constants"); + let { ACTIVITY_TYPE } = windowRequire("devtools/client/netmonitor/src/constants"); gStore.dispatch(Actions.batchEnable(false)); - let wait = waitForEvents(); + let wait = waitForNetworkEvents(monitor, CONTENT_TYPE_WITHOUT_CACHE_REQUESTS); yield performRequests(); yield wait; + yield waitUntil(() => !!document.querySelector(SELECTOR)); info("Checking the image thumbnail when all items are shown."); checkImageThumbnail(); gStore.dispatch(Actions.sortBy("contentSize")); info("Checking the image thumbnail when all items are sorted."); checkImageThumbnail(); gStore.dispatch(Actions.toggleRequestFilterType("images")); info("Checking the image thumbnail when only images are shown."); checkImageThumbnail(); info("Reloading the debuggee and performing all requests again..."); - wait = waitForEvents(); + wait = waitForNetworkEvents(monitor, CONTENT_TYPE_WITHOUT_CACHE_REQUESTS); yield reloadAndPerformRequests(); yield wait; + yield waitUntil(() => !!document.querySelector(SELECTOR)); info("Checking the image thumbnail after a reload."); checkImageThumbnail(); yield teardown(monitor); - function waitForEvents() { - return promise.all([ - waitForNetworkEvents(monitor, CONTENT_TYPE_WITHOUT_CACHE_REQUESTS), - monitor.panelWin.once(EVENTS.RESPONSE_IMAGE_THUMBNAIL_DISPLAYED) - ]); - } - function performRequests() { return ContentTask.spawn(tab.linkedBrowser, {}, function* () { content.wrappedJSObject.performRequests(); }); } function* reloadAndPerformRequests() { yield NetMonitorController.triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED); yield performRequests(); } function checkImageThumbnail() { - is(document.querySelectorAll(".requests-list-icon[data-type=thumbnail]").length, 1, + is(document.querySelectorAll(SELECTOR).length, 1, "There should be only one image request with a thumbnail displayed."); - is(document.querySelector(".requests-list-icon[data-type=thumbnail]").src, - TEST_IMAGE_DATA_URI, + is(document.querySelector(SELECTOR).src, TEST_IMAGE_DATA_URI, "The image requests-list-icon thumbnail is displayed correctly."); - is(document.querySelector(".requests-list-icon[data-type=thumbnail]").hidden, false, + is(document.querySelector(SELECTOR).hidden, false, "The image requests-list-icon thumbnail should not be hidden."); } });
--- a/devtools/client/netmonitor/test/browser_net_image-tooltip.js +++ b/devtools/client/netmonitor/test/browser_net_image-tooltip.js @@ -6,53 +6,49 @@ const IMAGE_TOOLTIP_URL = EXAMPLE_URL + "html_image-tooltip-test-page.html"; const IMAGE_TOOLTIP_REQUESTS = 1; /** * Tests if image responses show a popup in the requests menu when hovered. */ add_task(function* test() { let { tab, monitor } = yield initNetMonitor(IMAGE_TOOLTIP_URL); + const SELECTOR = ".requests-list-icon[src]"; info("Starting test... "); let { document, gStore, windowRequire } = monitor.panelWin; let Actions = windowRequire("devtools/client/netmonitor/src/actions/index"); let { NetMonitorController } = windowRequire("devtools/client/netmonitor/src/netmonitor-controller"); - let { - ACTIVITY_TYPE, - EVENTS, - } = windowRequire("devtools/client/netmonitor/src/constants"); + let { ACTIVITY_TYPE } = windowRequire("devtools/client/netmonitor/src/constants"); let toolboxDoc = monitor.panelWin.parent.document; gStore.dispatch(Actions.batchEnable(false)); let onEvents = waitForNetworkEvents(monitor, IMAGE_TOOLTIP_REQUESTS); - let onThumbnail = monitor.panelWin.once(EVENTS.RESPONSE_IMAGE_THUMBNAIL_DISPLAYED); yield performRequests(); yield onEvents; - yield onThumbnail; + yield waitUntil(() => !!document.querySelector(SELECTOR)); info("Checking the image thumbnail after a few requests were made..."); yield showTooltipAndVerify(document.querySelectorAll(".request-list-item")[0]); // Hide tooltip before next test, to avoid the situation that tooltip covers // the icon for the request of the next test. info("Checking the image thumbnail gets hidden..."); yield hideTooltipAndVerify(document.querySelectorAll(".request-list-item")[0]); // +1 extra document reload onEvents = waitForNetworkEvents(monitor, IMAGE_TOOLTIP_REQUESTS + 1); - onThumbnail = monitor.panelWin.once(EVENTS.RESPONSE_IMAGE_THUMBNAIL_DISPLAYED); info("Reloading the debuggee and performing all requests again..."); yield NetMonitorController.triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED); yield performRequests(); yield onEvents; - yield onThumbnail; + yield waitUntil(() => !!document.querySelector(SELECTOR)); info("Checking the image thumbnail after a reload."); yield showTooltipAndVerify(document.querySelectorAll(".request-list-item")[1]); info("Checking if the image thumbnail is hidden when mouse leaves the menu widget"); let requestsListContents = document.querySelector(".requests-list-contents"); EventUtils.synthesizeMouse(requestsListContents, 0, 0, { type: "mouseout" }, monitor.panelWin);
--- a/devtools/client/netmonitor/test/browser_net_simple-request-data.js +++ b/devtools/client/netmonitor/test/browser_net_simple-request-data.js @@ -188,44 +188,26 @@ function test() { SIMPLE_SJS, { status: "200", statusText: "Och Aye" } ); }); - monitor.panelWin.once(EVENTS.UPDATING_RESPONSE_CONTENT, () => { + monitor.panelWin.once(EVENTS.RECEIVED_RESPONSE_CONTENT, () => { let requestItem = getSortedRequests(gStore.getState()).get(0); is(requestItem.transferredSize, "12", "The transferredSize data has an incorrect value."); is(requestItem.contentSize, "12", "The contentSize data has an incorrect value."); is(requestItem.mimeType, "text/plain; charset=utf-8", "The mimeType data has an incorrect value."); - verifyRequestItemTarget( - document, - getDisplayedRequests(gStore.getState()), - requestItem, - "GET", - SIMPLE_SJS, - { - type: "plain", - fullMimeType: "text/plain; charset=utf-8", - transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 12), - size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 12), - } - ); - }); - - monitor.panelWin.once(EVENTS.RECEIVED_RESPONSE_CONTENT, () => { - let requestItem = getSortedRequests(gStore.getState()).get(0); - ok(requestItem.responseContent, "There should be a responseContent data available."); // eslint-disable-next-line mozilla/no-cpows-in-tests is(requestItem.responseContent.content.mimeType, "text/plain; charset=utf-8", "The responseContent data has an incorrect |content.mimeType| property."); // eslint-disable-next-line mozilla/no-cpows-in-tests is(requestItem.responseContent.content.text,