diff options
Diffstat (limited to 'chromium/third_party/WebKit/Source/devtools/front_end/network/RequestHeadersView.js')
-rw-r--r-- | chromium/third_party/WebKit/Source/devtools/front_end/network/RequestHeadersView.js | 519 |
1 files changed, 519 insertions, 0 deletions
diff --git a/chromium/third_party/WebKit/Source/devtools/front_end/network/RequestHeadersView.js b/chromium/third_party/WebKit/Source/devtools/front_end/network/RequestHeadersView.js new file mode 100644 index 00000000000..8ad05d96783 --- /dev/null +++ b/chromium/third_party/WebKit/Source/devtools/front_end/network/RequestHeadersView.js @@ -0,0 +1,519 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) IBM Corp. 2009 All rights reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @constructor + * @extends {WebInspector.VBox} + * @param {!WebInspector.NetworkRequest} request + */ +WebInspector.RequestHeadersView = function(request) +{ + WebInspector.VBox.call(this); + this.registerRequiredCSS("resourceView.css"); + this.element.classList.add("resource-headers-view"); + + this._request = request; + + this._headersListElement = document.createElement("ol"); + this._headersListElement.className = "outline-disclosure"; + this.element.appendChild(this._headersListElement); + + this._headersTreeOutline = new TreeOutline(this._headersListElement); + this._headersTreeOutline.expandTreeElementsWhenArrowing = true; + + this._remoteAddressTreeElement = new TreeElement("", null, false); + this._remoteAddressTreeElement.selectable = false; + this._remoteAddressTreeElement.hidden = true; + this._headersTreeOutline.appendChild(this._remoteAddressTreeElement); + + this._urlTreeElement = new TreeElement("", null, false); + this._urlTreeElement.selectable = false; + this._headersTreeOutline.appendChild(this._urlTreeElement); + + this._requestMethodTreeElement = new TreeElement("", null, false); + this._requestMethodTreeElement.selectable = false; + this._headersTreeOutline.appendChild(this._requestMethodTreeElement); + + this._statusCodeTreeElement = new TreeElement("", null, false); + this._statusCodeTreeElement.selectable = false; + this._headersTreeOutline.appendChild(this._statusCodeTreeElement); + + this._requestHeadersTreeElement = new TreeElement("", null, true); + this._requestHeadersTreeElement.expanded = true; + this._requestHeadersTreeElement.selectable = false; + this._headersTreeOutline.appendChild(this._requestHeadersTreeElement); + + this._decodeRequestParameters = true; + + this._showRequestHeadersText = false; + this._showResponseHeadersText = false; + + this._queryStringTreeElement = new TreeElement("", null, true); + this._queryStringTreeElement.expanded = true; + this._queryStringTreeElement.selectable = false; + this._queryStringTreeElement.hidden = true; + this._headersTreeOutline.appendChild(this._queryStringTreeElement); + + this._formDataTreeElement = new TreeElement("", null, true); + this._formDataTreeElement.expanded = true; + this._formDataTreeElement.selectable = false; + this._formDataTreeElement.hidden = true; + this._headersTreeOutline.appendChild(this._formDataTreeElement); + + this._requestPayloadTreeElement = new TreeElement(WebInspector.UIString("Request Payload"), null, true); + this._requestPayloadTreeElement.expanded = true; + this._requestPayloadTreeElement.selectable = false; + this._requestPayloadTreeElement.hidden = true; + this._headersTreeOutline.appendChild(this._requestPayloadTreeElement); + + this._responseHeadersTreeElement = new TreeElement("", null, true); + this._responseHeadersTreeElement.expanded = true; + this._responseHeadersTreeElement.selectable = false; + this._headersTreeOutline.appendChild(this._responseHeadersTreeElement); +} + +WebInspector.RequestHeadersView.prototype = { + + wasShown: function() + { + this._request.addEventListener(WebInspector.NetworkRequest.Events.RemoteAddressChanged, this._refreshRemoteAddress, this); + this._request.addEventListener(WebInspector.NetworkRequest.Events.RequestHeadersChanged, this._refreshRequestHeaders, this); + this._request.addEventListener(WebInspector.NetworkRequest.Events.ResponseHeadersChanged, this._refreshResponseHeaders, this); + this._request.addEventListener(WebInspector.NetworkRequest.Events.FinishedLoading, this._refreshHTTPInformation, this); + + this._refreshURL(); + this._refreshQueryString(); + this._refreshRequestHeaders(); + this._refreshResponseHeaders(); + this._refreshHTTPInformation(); + this._refreshRemoteAddress(); + }, + + willHide: function() + { + this._request.removeEventListener(WebInspector.NetworkRequest.Events.RemoteAddressChanged, this._refreshRemoteAddress, this); + this._request.removeEventListener(WebInspector.NetworkRequest.Events.RequestHeadersChanged, this._refreshRequestHeaders, this); + this._request.removeEventListener(WebInspector.NetworkRequest.Events.ResponseHeadersChanged, this._refreshResponseHeaders, this); + this._request.removeEventListener(WebInspector.NetworkRequest.Events.FinishedLoading, this._refreshHTTPInformation, this); + }, + + /** + * @param {string} name + * @param {string} value + * @return {!DocumentFragment} + */ + _formatHeader: function(name, value) + { + var fragment = document.createDocumentFragment(); + fragment.createChild("div", "header-name").textContent = name + ":"; + fragment.createChild("div", "header-value source-code").textContent = value; + + return fragment; + }, + + /** + * @param {string} value + * @param {string} className + * @param {boolean} decodeParameters + * @return {!Element} + */ + _formatParameter: function(value, className, decodeParameters) + { + var errorDecoding = false; + + if (decodeParameters) { + value = value.replace(/\+/g, " "); + if (value.indexOf("%") >= 0) { + try { + value = decodeURIComponent(value); + } catch (e) { + errorDecoding = true; + } + } + } + var div = document.createElement("div"); + div.className = className; + if (errorDecoding) + div.createChild("span", "error-message").textContent = WebInspector.UIString("(unable to decode value)"); + else + div.textContent = value; + return div; + }, + + _refreshURL: function() + { + this._urlTreeElement.title = this._formatHeader(WebInspector.UIString("Request URL"), this._request.url); + }, + + _refreshQueryString: function() + { + var queryString = this._request.queryString(); + var queryParameters = this._request.queryParameters; + this._queryStringTreeElement.hidden = !queryParameters; + if (queryParameters) + this._refreshParams(WebInspector.UIString("Query String Parameters"), queryParameters, queryString, this._queryStringTreeElement); + }, + + _refreshFormData: function() + { + this._formDataTreeElement.hidden = true; + this._requestPayloadTreeElement.hidden = true; + + var formData = this._request.requestFormData; + if (!formData) + return; + + var formParameters = this._request.formParameters; + if (formParameters) { + this._formDataTreeElement.hidden = false; + this._refreshParams(WebInspector.UIString("Form Data"), formParameters, formData, this._formDataTreeElement); + } else { + this._requestPayloadTreeElement.hidden = false; + try { + var json = JSON.parse(formData); + this._refreshRequestJSONPayload(json, formData); + } catch (e) { + this._populateTreeElementWithSourceText(this._requestPayloadTreeElement, formData); + } + } + }, + + /** + * @param {!TreeElement} treeElement + * @param {?string} sourceText + */ + _populateTreeElementWithSourceText: function(treeElement, sourceText) + { + var sourceTextElement = document.createElement("span"); + sourceTextElement.classList.add("header-value"); + sourceTextElement.classList.add("source-code"); + sourceTextElement.textContent = String(sourceText || "").trim(); + + var sourceTreeElement = new TreeElement(sourceTextElement); + sourceTreeElement.selectable = false; + treeElement.removeChildren(); + treeElement.appendChild(sourceTreeElement); + }, + + /** + * @param {string} title + * @param {?Array.<!WebInspector.NetworkRequest.NameValue>} params + * @param {?string} sourceText + * @param {!TreeElement} paramsTreeElement + */ + _refreshParams: function(title, params, sourceText, paramsTreeElement) + { + paramsTreeElement.removeChildren(); + + paramsTreeElement.listItemElement.removeChildren(); + paramsTreeElement.listItemElement.appendChild(document.createTextNode(title)); + + var headerCount = document.createElement("span"); + headerCount.classList.add("header-count"); + headerCount.textContent = WebInspector.UIString(" (%d)", params.length); + paramsTreeElement.listItemElement.appendChild(headerCount); + + /** + * @param {?Event} event + * @this {WebInspector.RequestHeadersView} + */ + function toggleViewSource(event) + { + paramsTreeElement._viewSource = !paramsTreeElement._viewSource; + this._refreshParams(title, params, sourceText, paramsTreeElement); + } + + paramsTreeElement.listItemElement.appendChild(this._createViewSourceToggle(paramsTreeElement._viewSource, toggleViewSource.bind(this))); + + if (paramsTreeElement._viewSource) { + this._populateTreeElementWithSourceText(paramsTreeElement, sourceText); + return; + } + + var toggleTitle = this._decodeRequestParameters ? WebInspector.UIString("view URL encoded") : WebInspector.UIString("view decoded"); + var toggleButton = this._createToggleButton(toggleTitle); + toggleButton.addEventListener("click", this._toggleURLDecoding.bind(this), false); + paramsTreeElement.listItemElement.appendChild(toggleButton); + + for (var i = 0; i < params.length; ++i) { + var paramNameValue = document.createDocumentFragment(); + var name = this._formatParameter(params[i].name + ":", "header-name", this._decodeRequestParameters); + var value = this._formatParameter(params[i].value, "header-value source-code", this._decodeRequestParameters); + paramNameValue.appendChild(name); + paramNameValue.appendChild(value); + + var parmTreeElement = new TreeElement(paramNameValue, null, false); + parmTreeElement.selectable = false; + paramsTreeElement.appendChild(parmTreeElement); + } + }, + + /** + * @param {*} parsedObject + * @param {string} sourceText + */ + _refreshRequestJSONPayload: function(parsedObject, sourceText) + { + var treeElement = this._requestPayloadTreeElement; + treeElement.removeChildren(); + + var listItem = this._requestPayloadTreeElement.listItemElement; + listItem.removeChildren(); + listItem.appendChild(document.createTextNode(this._requestPayloadTreeElement.title)); + + /** + * @param {?Event} event + * @this {WebInspector.RequestHeadersView} + */ + function toggleViewSource(event) + { + treeElement._viewSource = !treeElement._viewSource; + this._refreshRequestJSONPayload(parsedObject, sourceText); + } + + listItem.appendChild(this._createViewSourceToggle(treeElement._viewSource, toggleViewSource.bind(this))); + if (treeElement._viewSource) { + this._populateTreeElementWithSourceText(this._requestPayloadTreeElement, sourceText); + } else { + var object = WebInspector.RemoteObject.fromLocalObject(parsedObject); + var section = new WebInspector.ObjectPropertiesSection(object, object.description); + section.expand(); + section.editable = false; + listItem.appendChild(section.element); + } + }, + + /** + * @param {boolean} viewSource + * @param {function(?Event)} handler + * @return {!Element} + */ + _createViewSourceToggle: function(viewSource, handler) + { + var viewSourceToggleTitle = viewSource ? WebInspector.UIString("view parsed") : WebInspector.UIString("view source"); + var viewSourceToggleButton = this._createToggleButton(viewSourceToggleTitle); + viewSourceToggleButton.addEventListener("click", handler, false); + return viewSourceToggleButton; + }, + + /** + * @param {?Event} event + */ + _toggleURLDecoding: function(event) + { + this._decodeRequestParameters = !this._decodeRequestParameters; + this._refreshQueryString(); + this._refreshFormData(); + }, + + _refreshRequestHeaders: function() + { + var treeElement = this._requestHeadersTreeElement; + + var headers = this._request.requestHeaders(); + headers = headers.slice(); + headers.sort(function(a, b) { return a.name.toLowerCase().compareTo(b.name.toLowerCase()) }); + var headersText = this._request.requestHeadersText(); + + if (this._showRequestHeadersText && headersText) + this._refreshHeadersText(WebInspector.UIString("Request Headers"), headers.length, headersText, treeElement); + else + this._refreshHeaders(WebInspector.UIString("Request Headers"), headers, treeElement, headersText === undefined); + + if (headersText) { + var toggleButton = this._createHeadersToggleButton(this._showRequestHeadersText); + toggleButton.addEventListener("click", this._toggleRequestHeadersText.bind(this), false); + treeElement.listItemElement.appendChild(toggleButton); + } + + this._refreshFormData(); + }, + + _refreshResponseHeaders: function() + { + var treeElement = this._responseHeadersTreeElement; + var headers = this._request.sortedResponseHeaders; + var headersText = this._request.responseHeadersText; + + if (this._showResponseHeadersText) + this._refreshHeadersText(WebInspector.UIString("Response Headers"), headers.length, headersText, treeElement); + else + this._refreshHeaders(WebInspector.UIString("Response Headers"), headers, treeElement); + + if (headersText) { + var toggleButton = this._createHeadersToggleButton(this._showResponseHeadersText); + toggleButton.addEventListener("click", this._toggleResponseHeadersText.bind(this), false); + treeElement.listItemElement.appendChild(toggleButton); + } + }, + + _refreshHTTPInformation: function() + { + var requestMethodElement = this._requestMethodTreeElement; + requestMethodElement.hidden = !this._request.statusCode; + var statusCodeElement = this._statusCodeTreeElement; + statusCodeElement.hidden = !this._request.statusCode; + + if (this._request.statusCode) { + var statusCodeFragment = document.createDocumentFragment(); + statusCodeFragment.createChild("div", "header-name").textContent = WebInspector.UIString("Status Code") + ":"; + + var statusCodeImage = statusCodeFragment.createChild("div", "resource-status-image"); + statusCodeImage.title = this._request.statusCode + " " + this._request.statusText; + + if (this._request.statusCode < 300 || this._request.statusCode === 304) + statusCodeImage.classList.add("green-ball"); + else if (this._request.statusCode < 400) + statusCodeImage.classList.add("orange-ball"); + else + statusCodeImage.classList.add("red-ball"); + + requestMethodElement.title = this._formatHeader(WebInspector.UIString("Request Method"), this._request.requestMethod); + + var statusTextElement = statusCodeFragment.createChild("div", "header-value source-code"); + var statusText = this._request.statusCode + " " + this._request.statusText; + if (this._request.cached) { + statusText += " " + WebInspector.UIString("(from cache)"); + statusTextElement.classList.add("status-from-cache"); + } + statusTextElement.textContent = statusText; + + statusCodeElement.title = statusCodeFragment; + } + }, + + /** + * @param {string} title + * @param {!TreeElement} headersTreeElement + * @param {number} headersLength + */ + _refreshHeadersTitle: function(title, headersTreeElement, headersLength) + { + headersTreeElement.listItemElement.removeChildren(); + headersTreeElement.listItemElement.createTextChild(title); + + var headerCount = WebInspector.UIString(" (%d)", headersLength); + headersTreeElement.listItemElement.createChild("span", "header-count").textContent = headerCount; + }, + + /** + * @param {string} title + * @param {!Array.<!WebInspector.NetworkRequest.NameValue>} headers + * @param {!TreeElement} headersTreeElement + * @param {boolean=} provisionalHeaders + */ + _refreshHeaders: function(title, headers, headersTreeElement, provisionalHeaders) + { + headersTreeElement.removeChildren(); + + var length = headers.length; + this._refreshHeadersTitle(title, headersTreeElement, length); + + if (provisionalHeaders) { + var cautionText = WebInspector.UIString("Provisional headers are shown"); + var cautionFragment = document.createDocumentFragment(); + cautionFragment.createChild("div", "warning-icon-small"); + cautionFragment.createChild("div", "caution").textContent = cautionText; + var cautionTreeElement = new TreeElement(cautionFragment); + cautionTreeElement.selectable = false; + headersTreeElement.appendChild(cautionTreeElement); + } + + headersTreeElement.hidden = !length && !provisionalHeaders; + for (var i = 0; i < length; ++i) { + var headerTreeElement = new TreeElement(this._formatHeader(headers[i].name, headers[i].value)); + headerTreeElement.selectable = false; + headersTreeElement.appendChild(headerTreeElement); + } + }, + + /** + * @param {string} title + * @param {number} count + * @param {string} headersText + * @param {!TreeElement} headersTreeElement + */ + _refreshHeadersText: function(title, count, headersText, headersTreeElement) + { + this._populateTreeElementWithSourceText(headersTreeElement, headersText); + this._refreshHeadersTitle(title, headersTreeElement, count); + }, + + _refreshRemoteAddress: function() + { + var remoteAddress = this._request.remoteAddress(); + var treeElement = this._remoteAddressTreeElement; + treeElement.hidden = !remoteAddress; + if (remoteAddress) + treeElement.title = this._formatHeader(WebInspector.UIString("Remote Address"), remoteAddress); + }, + + /** + * @param {?Event} event + */ + _toggleRequestHeadersText: function(event) + { + this._showRequestHeadersText = !this._showRequestHeadersText; + this._refreshRequestHeaders(); + }, + + /** + * @param {?Event} event + */ + _toggleResponseHeadersText: function(event) + { + this._showResponseHeadersText = !this._showResponseHeadersText; + this._refreshResponseHeaders(); + }, + + /** + * @param {string} title + * @return {!Element} + */ + _createToggleButton: function(title) + { + var button = document.createElement("span"); + button.classList.add("header-toggle"); + button.textContent = title; + return button; + }, + + /** + * @param {boolean} isHeadersTextShown + * @return {!Element} + */ + _createHeadersToggleButton: function(isHeadersTextShown) + { + var toggleTitle = isHeadersTextShown ? WebInspector.UIString("view parsed") : WebInspector.UIString("view source"); + return this._createToggleButton(toggleTitle); + }, + + __proto__: WebInspector.VBox.prototype +} |