text: /*
   * Copyright (C) 2013, 2015 Apple 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.
   *
   * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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.
   */
  
  WI.ResourceDetailsSidebarPanel = class ResourceDetailsSidebarPanel extends WI.DetailsSidebarPanel
  {
      constructor()
      {
          super("resource-details", WI.UIString("Resource"));
  
          this.element.classList.add("resource");
  
          this._resource = null;
          this._needsToApplyResourceEventListeners = false;
          this._needsToRemoveResourceEventListeners = false;
      }
  
      // Public
  
      inspect(objects)
      {
          // Convert to a single item array if needed.
          if (!(objects instanceof Array))
              objects = [objects];
  
          var resourceToInspect = null;
  
          // Iterate over the objects to find a WI.Resource to inspect.
          for (let object of objects) {
              if (object instanceof WI.Resource) {
                  resourceToInspect = object;
                  break;
              }
  
              if (object instanceof WI.Frame) {
                  resourceToInspect = object.mainResource;
                  break;
              }
  
              // FIXME: <https://webkit.org/b/164427> Web Inspector: WorkerTarget's mainResource should be a Resource not a Script
              // If that was the case, then we could just have WorkerTreeElement contain the Resource and not a Script.
              if (object instanceof WI.Script && object.isMainResource() && object.resource) {
                  resourceToInspect = object.resource;
                  break;
              }
          }
  
          this.resource = resourceToInspect;
  
          return !!this._resource;
      }
  
      get resource()
      {
          return this._resource;
      }
  
      set resource(resource)
      {
          if (resource === this._resource)
              return;
  
          if (this._resource && this._needsToRemoveResourceEventListeners) {
              this._resource.removeEventListener(WI.Resource.Event.URLDidChange, this._refreshURL, this);
              this._resource.removeEventListener(WI.Resource.Event.MIMETypeDidChange, this._refreshMIMEType, this);
              this._resource.removeEventListener(WI.Resource.Event.TypeDidChange, this._refreshResourceType, this);
              this._resource.removeEventListener(WI.Resource.Event.LoadingDidFail, this._refreshErrorReason, this);
              this._resource.removeEventListener(WI.Resource.Event.RequestHeadersDidChange, this._refreshRequestHeaders, this);
              this._resource.removeEventListener(WI.Resource.Event.ResponseReceived, this._refreshRequestAndResponse, this);
              this._resource.removeEventListener(WI.Resource.Event.CacheStatusDidChange, this._refreshRequestAndResponse, this);
              this._resource.removeEventListener(WI.Resource.Event.SizeDidChange, this._refreshDecodedSize, this);
              this._resource.removeEventListener(WI.Resource.Event.TransferSizeDidChange, this._refreshTransferSize, this);
              this._resource.removeEventListener(WI.Resource.Event.InitiatedResourcesDidChange, this._refreshRelatedResourcesSection, this);
  
              this._needsToRemoveResourceEventListeners = false;
          }
  
          this._resource = resource;
  
          if (this._resource) {
              if (this.parentSidebar)
                  this._applyResourceEventListeners();
              else
                  this._needsToApplyResourceEventListeners = true;
          }
  
          this.needsLayout();
      }
  
      // Protected
  
      initialLayout()
      {
          super.initialLayout();
  
          this._typeMIMETypeRow = new WI.DetailsSectionSimpleRow(WI.UIString("MIME Type"));
          this._typeResourceTypeRow = new WI.DetailsSectionSimpleRow(WI.UIString("Resource Type"));
  
          this._typeSection = new WI.DetailsSection("resource-type", WI.UIString("Type"));
          this._typeSection.groups = [new WI.DetailsSectionGroup([this._typeMIMETypeRow, this._typeResourceTypeRow])];
  
          this._locationFullURLRow = new WI.DetailsSectionSimpleRow(WI.UIString("Full URL"));
          this._locationSchemeRow = new WI.DetailsSectionSimpleRow(WI.UIString("Scheme"));
          this._locationHostRow = new WI.DetailsSectionSimpleRow(WI.UIString("Host"));
          this._locationPortRow = new WI.DetailsSectionSimpleRow(WI.UIString("Port"));
          this._locationPathRow = new WI.DetailsSectionSimpleRow(WI.UIString("Path"));
          this._locationQueryStringRow = new WI.DetailsSectionSimpleRow(WI.UIString("Query String"));
          this._locationFragmentRow = new WI.DetailsSectionSimpleRow(WI.UIString("Fragment"));
          this._locationFilenameRow = new WI.DetailsSectionSimpleRow(WI.UIString("Filename"));
          this._initiatorRow = new WI.DetailsSectionSimpleRow(WI.UIString("Initiator"));
          this._initiatedRow = new WI.DetailsSectionSimpleRow(WI.UIString("Initiated"));
  
          var firstGroup = [this._locationFullURLRow];
          var secondGroup = [this._locationSchemeRow, this._locationHostRow, this._locationPortRow, this._locationPathRow, this._locationQueryStringRow, this._locationFragmentRow, this._locationFilenameRow];
          var thirdGroup = [this._initiatorRow, this._initiatedRow];
  
          this._fullURLGroup = new WI.DetailsSectionGroup(firstGroup);
          this._locationURLComponentsGroup = new WI.DetailsSectionGroup(secondGroup);
          this._relatedResourcesGroup = new WI.DetailsSectionGroup(thirdGroup);
  
          this._locationSection = new WI.DetailsSection("resource-location", WI.UIString("Location"), [this._fullURLGroup, this._locationURLComponentsGroup, this._relatedResourcesGroup]);
  
          this._queryParametersRow = new WI.DetailsSectionDataGridRow(null, WI.UIString("No Query Parameters"));
          this._queryParametersSection = new WI.DetailsSection("resource-query-parameters", WI.UIString("Query Parameters"));
          this._queryParametersSection.groups = [new WI.DetailsSectionGroup([this._queryParametersRow])];
  
          this._requestDataSection = new WI.DetailsSection("resource-request-data", WI.UIString("Request Data"));
  
          this._requestMethodRow = new WI.DetailsSectionSimpleRow(WI.UIString("Method"));
          this._protocolRow = new WI.DetailsSectionSimpleRow(WI.UIString("Protocol"));
          this._priorityRow = new WI.DetailsSectionSimpleRow(WI.UIString("Priority"));
          this._cachedRow = new WI.DetailsSectionSimpleRow(WI.UIString("Cached"));
  
          this._statusTextRow = new WI.DetailsSectionSimpleRow(WI.UIString("Status"));
          this._statusCodeRow = new WI.DetailsSectionSimpleRow(WI.UIString("Code"));
          this._errorReasonRow = new WI.DetailsSectionSimpleRow(WI.UIString("Error"));
  
          this._remoteAddressRow = new WI.DetailsSectionSimpleRow(WI.UIString("IP Address"));
          this._connectionIdentifierRow = new WI.DetailsSectionSimpleRow(WI.UIString("Connection ID"));
  
          this._encodedSizeRow = new WI.DetailsSectionSimpleRow(WI.UIString("Encoded"));
          this._decodedSizeRow = new WI.DetailsSectionSimpleRow(WI.UIString("Decoded"));
          this._transferSizeRow = new WI.DetailsSectionSimpleRow(WI.UIString("Transferred"));
  
          this._compressedRow = new WI.DetailsSectionSimpleRow(WI.UIString("Compressed"));
          this._compressionRow = new WI.DetailsSectionSimpleRow(WI.UIString("Compression"));
  
          let requestGroup = new WI.DetailsSectionGroup([this._requestMethodRow, this._protocolRow, this._priorityRow, this._cachedRow]);
          let statusGroup = new WI.DetailsSectionGroup([this._statusTextRow, this._statusCodeRow, this._errorReasonRow]);
          let connectionGroup = new WI.DetailsSectionGroup([this._remoteAddressRow, this._connectionIdentifierRow]);
          let sizeGroup = new WI.DetailsSectionGroup([this._encodedSizeRow, this._decodedSizeRow, this._transferSizeRow]);
          let compressionGroup = new WI.DetailsSectionGroup([this._compressedRow, this._compressionRow]);
  
          this._requestAndResponseSection = new WI.DetailsSection("resource-request-response", WI.UIString("Request & Response"));
          this._requestAndResponseSection.groups = [requestGroup, statusGroup, connectionGroup, sizeGroup, compressionGroup];
  
          this._requestHeadersRow = new WI.DetailsSectionDataGridRow(null, WI.UIString("No Request Headers"));
          this._requestHeadersSection = new WI.DetailsSection("resource-request-headers", WI.UIString("Request Headers"));
          this._requestHeadersSection.groups = [new WI.DetailsSectionGroup([this._requestHeadersRow])];
  
          this._responseHeadersRow = new WI.DetailsSectionDataGridRow(null, WI.UIString("No Response Headers"));
          this._responseHeadersSection = new WI.DetailsSection("resource-response-headers", WI.UIString("Response Headers"));
          this._responseHeadersSection.groups = [new WI.DetailsSectionGroup([this._responseHeadersRow])];
  
          // Rows for the "Image Size" section.
          this._imageWidthRow = new WI.DetailsSectionSimpleRow(WI.UIString("Width"));
          this._imageHeightRow = new WI.DetailsSectionSimpleRow(WI.UIString("Height"));
  
          // "Image Size" section where we display intrinsic metrics for image resources.
          this._imageSizeSection = new WI.DetailsSection("resource-type", WI.UIString("Image Size"));
          this._imageSizeSection.groups = [new WI.DetailsSectionGroup([this._imageWidthRow, this._imageHeightRow])];
  
          this.contentView.element.appendChild(this._typeSection.element);
          this.contentView.element.appendChild(this._locationSection.element);
          this.contentView.element.appendChild(this._requestAndResponseSection.element);
          this.contentView.element.appendChild(this._requestHeadersSection.element);
          this.contentView.element.appendChild(this._responseHeadersSection.element);
  
          if (this._needsToApplyResourceEventListeners) {
              this._applyResourceEventListeners();
  
              this._needsToApplyResourceEventListeners = false;
          }
      }
  
      layout()
      {
          super.layout();
  
          if (!this._resource)
              return;
  
          this._refreshURL();
          this._refreshMIMEType();
          this._refreshResourceType();
          this._refreshRequestAndResponse();
          this._refreshDecodedSize();
          this._refreshTransferSize();
          this._refreshRequestHeaders();
          this._refreshImageSizeSection();
          this._refreshRequestDataSection();
          this._refreshRelatedResourcesSection();
      }
  
      sizeDidChange()
      {
          super.sizeDidChange();
  
          // FIXME: <https://webkit.org/b/152269> Web Inspector: Convert DetailsSection classes to use View
          this._queryParametersRow.sizeDidChange();
          this._requestHeadersRow.sizeDidChange();
          this._responseHeadersRow.sizeDidChange();
      }
  
      // Private
  
      _refreshURL()
      {
          if (!this._resource)
              return;
  
          this._locationFullURLRow.value = this._resource.url.insertWordBreakCharacters();
  
          var urlComponents = this._resource.urlComponents;
          if (urlComponents.scheme) {
              this._locationSection.groups = [this._fullURLGroup, this._locationURLComponentsGroup, this._relatedResourcesGroup];
  
              this._locationSchemeRow.value = urlComponents.scheme ? urlComponents.scheme : null;
              this._locationHostRow.value = urlComponents.host ? urlComponents.host : null;
              this._locationPortRow.value = urlComponents.port ? urlComponents.port : null;
              this._locationPathRow.value = urlComponents.path ? urlComponents.path.insertWordBreakCharacters() : null;
              this._locationQueryStringRow.value = urlComponents.queryString ? urlComponents.queryString.insertWordBreakCharacters() : null;
              this._locationFragmentRow.value = urlComponents.fragment ? urlComponents.fragment.insertWordBreakCharacters() : null;
              this._locationFilenameRow.value = urlComponents.lastPathComponent ? urlComponents.lastPathComponent.insertWordBreakCharacters() : null;
          } else {
              this._locationSection.groups = [this._fullURLGroup, this._relatedResourcesGroup];
          }
  
          if (urlComponents.queryString) {
              // Ensure the "Query Parameters" section is displayed, right after the "Request & Response" section.
              this.contentView.element.insertBefore(this._queryParametersSection.element, this._requestAndResponseSection.element.nextSibling);
  
              this._queryParametersRow.dataGrid = this._createNameValueDataGrid(parseQueryString(urlComponents.queryString, true));
          } else {
              // Hide the "Query Parameters" section if we don't have a query string.
              var queryParametersSectionElement = this._queryParametersSection.element;
              if (queryParametersSectionElement.parentNode)
                  queryParametersSectionElement.parentNode.removeChild(queryParametersSectionElement);
          }
      }
  
      _refreshRelatedResourcesSection()
      {
          // Hide the section if we don't have anything to show.
          let groups = this._locationSection.groups;
          let isSectionVisible = groups.includes(this._relatedResourcesGroup);
          if (!this._resource.initiatorSourceCodeLocation && !this._resource.initiatedResources.length) {
              if (isSectionVisible) {
                  groups.remove(this._relatedResourcesGroup);
                  this._locationSection.groups = groups;
              }
              return;
          }
  
          if (!isSectionVisible) {
              groups.push(this._relatedResourcesGroup);
              this._locationSection.groups = groups;
          }
  
          let initiatorLocation = this._resource.initiatorSourceCodeLocation;
          if (initiatorLocation) {
              const options = {
                  dontFloat: true,
                  ignoreSearchTab: true,
              };
              this._initiatorRow.value = WI.createSourceCodeLocationLink(initiatorLocation, options);
          } else
              this._initiatorRow.value = null;
  
          let initiatedResources = this._resource.initiatedResources;
          if (initiatedResources.length) {
              let resourceLinkContainer = document.createElement("div");
              for (let resource of initiatedResources)
                  resourceLinkContainer.appendChild(WI.createResourceLink(resource));
  
              this._initiatedRow.value = resourceLinkContainer;
          } else
              this._initiatedRow.value = null;
      }
  
      _refreshResourceType()
      {
          if (!this._resource)
              return;
  
          this._typeResourceTypeRow.value = WI.Resource.displayNameForType(this._resource.type);
      }
  
      _refreshMIMEType()
      {
          if (!this._resource)
              return;
  
          this._typeMIMETypeRow.value = this._resource.mimeType;
      }
  
      _refreshErrorReason()
      {
          if (!this._resource)
              return;
  
          if (!this._resource.hadLoadingError()) {
              this._errorReasonRow.value = null;
              return;
          }
  
          if (this._resource.failureReasonText)
              this._errorReasonRow.value = this._resource.failureReasonText;
          else if (this._resource.statusCode >= 400)
              this._errorReasonRow.value = WI.UIString("Failure status code");
          else if (this._resource.canceled)
              this._errorReasonRow.value = WI.UIString("Load cancelled");
          else
              this._errorReasonRow.value = WI.UIString("Unknown error");
      }
  
      _refreshRequestAndResponse()
      {
          if (!this._resource)
              return;
  
          // If we don't have a value, we set an em-dash to keep the row from hiding.
          // This keeps the UI from shifting around as data comes in.
  
          this._requestMethodRow.value = this._resource.requestMethod || emDash;
  
          // COMPATIBILITY(iOS 10.3): Network load metrics were not previously available.
          if (window.NetworkAgent && NetworkAgent.hasEventParameter("loadingFinished", "metrics")) {
              let protocolDisplayName = WI.Resource.displayNameForProtocol(this._resource.protocol);
              this._protocolRow.value = protocolDisplayName || emDash;
              this._protocolRow.tooltip = protocolDisplayName ? this._resource.protocol : "";
              this._priorityRow.value = WI.Resource.displayNameForPriority(this._resource.priority) || emDash;
              this._remoteAddressRow.value = this._resource.remoteAddress || emDash;
              this._connectionIdentifierRow.value = this._resource.connectionIdentifier || emDash;
          }
  
          this._cachedRow.value = this._cachedRowValue();
  
          this._statusCodeRow.value = this._resource.statusCode || emDash;
          this._statusTextRow.value = this._resource.statusText || emDash;
          this._refreshErrorReason();
  
          this._refreshResponseHeaders();
          this._refreshCompressed();
      }
  
      _valueForSize(size)
      {
          // If we don't have a value, we set an em-dash to keep the row from hiding.
          // This keeps the UI from shifting around as data comes in.
          return size > 0 ? Number.bytesToString(size) : emDash;
      }
  
      _refreshCompressed()
      {
          if (this._resource.compressed) {
              this._compressedRow.value = WI.UIString("Yes");
              if (!this._resource.size)
                  this._compressionRow.value = emDash;
              else if (!isNaN(this._resource.networkEncodedSize))
                  this._compressionRow.value = this._resource.networkEncodedSize ? WI.UIString("%.2f\u00d7").format(this._resource.size / this._resource.networkEncodedSize) : emDash;
              else
                  this._compressionRow.value = this._resource.estimatedNetworkEncodedSize ? WI.UIString("%.2f\u00d7").format(this._resource.size / this._resource.estimatedNetworkEncodedSize) : emDash;
          } else {
              this._compressedRow.value = WI.UIString("No");
              this._compressionRow.value = null;
          }
      }
  
      _refreshDecodedSize()
      {
          if (!this._resource)
              return;
  
          let encodedSize = !isNaN(this._resource.networkEncodedSize) ? this._resource.networkEncodedSize : this._resource.estimatedNetworkEncodedSize;
          let decodedSize = !isNaN(this._resource.networkDecodedSize) ? this._resource.networkDecodedSize : this._resource.size;
  
          this._encodedSizeRow.value = this._valueForSize(encodedSize);
          this._decodedSizeRow.value = this._valueForSize(decodedSize);
  
          this._refreshCompressed();
      }
  
      _refreshTransferSize()
      {
          if (!this._resource)
              return;
  
          let encodedSize = !isNaN(this._resource.networkEncodedSize) ? this._resource.networkEncodedSize : this._resource.estimatedNetworkEncodedSize;
          let transferSize = !isNaN(this._resource.networkTotalTransferSize) ? this._resource.networkTotalTransferSize : this._resource.estimatedTotalTransferSize;
  
          this._encodedSizeRow.value = this._valueForSize(encodedSize);
          this._transferSizeRow.value = this._valueForSize(transferSize);
  
          this._refreshCompressed();
      }
  
      _refreshRequestHeaders()
      {
          if (!this._resource)
              return;
  
          this._requestHeadersRow.dataGrid = this._createNameValueDataGrid(this._resource.requestHeaders);
      }
  
      _refreshResponseHeaders()
      {
          if (!this._resource)
              return;
  
          this._responseHeadersRow.dataGrid = this._createNameValueDataGrid(this._resource.responseHeaders);
      }
  
      _createNameValueDataGrid(data)
      {
          if (!data || data instanceof Array ? !data.length : isEmptyObject(data))
              return null;
  
          var dataGrid = new WI.DataGrid({
              name: {title: WI.UIString("Name"), width: "30%", sortable: true},
              value: {title: WI.UIString("Value"), sortable: true}
          });
          dataGrid.copyTextDelimiter = ": ";
  
          function addDataGridNode(nodeValue)
          {
              console.assert(typeof nodeValue.name === "string");
              console.assert(!nodeValue.value || typeof nodeValue.value === "string");
  
              var node = new WI.DataGridNode({name: nodeValue.name, value: nodeValue.value || ""}, false);
              dataGrid.appendChild(node);
          }
  
          if (data instanceof Array) {
              for (var i = 0; i < data.length; ++i)
                  addDataGridNode(data[i]);
          } else {
              for (var name in data)
                  addDataGridNode({name, value: data[name] || ""});
          }
  
          dataGrid.addEventListener(WI.DataGrid.Event.SortChanged, sortDataGrid, this);
  
          function sortDataGrid()
          {
              var sortColumnIdentifier = dataGrid.sortColumnIdentifier;
  
              function comparator(a, b)
              {
                  var item1 = a.data[sortColumnIdentifier];
                  var item2 = b.data[sortColumnIdentifier];
                  return item1.extendedLocaleCompare(item2);
              }
  
              dataGrid.sortNodes(comparator);
          }
  
          return dataGrid;
      }
  
      _refreshImageSizeSection()
      {
          var resource = this._resource;
  
          if (!resource)
              return;
  
          function hideImageSection() {
              this._imageSizeSection.element.remove();
          }
  
          // Hide the section if we're not dealing with an image or if the load failed.
          if (resource.type !== WI.Resource.Type.Image || resource.failed) {
              hideImageSection.call(this);
              return;
          }
  
          // Ensure the section is displayed, right before the "Location" section.
          this.contentView.element.insertBefore(this._imageSizeSection.element, this._locationSection.element);
  
          // Get the metrics for this resource and fill in the metrics rows with that information.
          resource.getImageSize((size) => {
              if (size) {
                  this._imageWidthRow.value = WI.UIString("%dpx").format(size.width);
                  this._imageHeightRow.value = WI.UIString("%dpx").format(size.height);
              } else
                  hideImageSection.call(this);
          });
      }
  
      _cachedRowValue()
      {
          let responseSource = this._resource.responseSource;
          if (responseSource === WI.Resource.ResponseSource.MemoryCache || responseSource === WI.Resource.ResponseSource.DiskCache) {
              console.assert(this._resource.cached, "This resource has a cache responseSource it should also be marked as cached", this._resource);
              let span = document.createElement("span");
              let cacheType = document.createElement("span");
              cacheType.classList = "cache-type";
              cacheType.textContent = responseSource === WI.Resource.ResponseSource.MemoryCache ? WI.UIString("(Memory)") : WI.UIString("(Disk)");
              span.append(WI.UIString("Yes"), " ", cacheType);
              return span;
          }
  
          return this._resource.cached ? WI.UIString("Yes") : WI.UIString("No");
      }
  
      _goToRequestDataClicked()
      {
          const options = {
              ignoreSearchTab: true,
          };
          WI.showResourceRequest(this._resource, options);
      }
  
      _refreshRequestDataSection()
      {
          var resource = this._resource;
          if (!resource)
              return;
  
          // Hide the section if we're not dealing with a request with data.
          var requestData = resource.requestData;
          if (!requestData) {
              this._requestDataSection.element.remove();
              return;
          }
  
          // Ensure the section is displayed, right before the "Request Headers" section.
          this.contentView.element.insertBefore(this._requestDataSection.element, this._requestHeadersSection.element);
  
          var requestDataContentType = resource.requestDataContentType || "";
          if (requestDataContentType && requestDataContentType.match(/^application\/x-www-form-urlencoded\s*(;.*)?$/i)) {
              // Simple form data that should be parsable like a query string.
              var parametersRow = new WI.DetailsSectionDataGridRow(null, WI.UIString("No Parameters"));
              parametersRow.dataGrid = this._createNameValueDataGrid(parseQueryString(requestData, true));
  
              this._requestDataSection.groups = [new WI.DetailsSectionGroup([parametersRow])];
              return;
          }
  
          // Not simple form data, so we can really only show the size and type here.
          // FIXME: Add a go-to arrow here to show the data in the content browser.
  
          var mimeTypeComponents = parseMIMEType(requestDataContentType);
  
          var mimeType = mimeTypeComponents.type;
          var boundary = mimeTypeComponents.boundary;
          var encoding = mimeTypeComponents.encoding;
  
          var rows = [];
  
          var mimeTypeRow = new WI.DetailsSectionSimpleRow(WI.UIString("MIME Type"));
          mimeTypeRow.value = mimeType;
          rows.push(mimeTypeRow);
  
          if (boundary) {
              var boundryRow = new WI.DetailsSectionSimpleRow(WI.UIString("Boundary"));
              boundryRow.value = boundary;
              rows.push(boundryRow);
          }
  
          if (encoding) {
              var encodingRow = new WI.DetailsSectionSimpleRow(WI.UIString("Encoding"));
              encodingRow.value = encoding;
              rows.push(encodingRow);
          }
  
          var sizeValue = Number.bytesToString(requestData.length);
  
          var dataValue = document.createDocumentFragment();
  
          dataValue.append(sizeValue);
  
          var goToButton = dataValue.appendChild(WI.createGoToArrowButton());
          goToButton.addEventListener("click", this._goToRequestDataClicked.bind(this));
  
          var dataRow = new WI.DetailsSectionSimpleRow(WI.UIString("Data"));
          dataRow.value = dataValue;
          rows.push(dataRow);
  
          this._requestDataSection.groups = [new WI.DetailsSectionGroup(rows)];
      }
  
      _applyResourceEventListeners()
      {
          this._resource.addEventListener(WI.Resource.Event.URLDidChange, this._refreshURL, this);
          this._resource.addEventListener(WI.Resource.Event.MIMETypeDidChange, this._refreshMIMEType, this);
          this._resource.addEventListener(WI.Resource.Event.TypeDidChange, this._refreshResourceType, this);
          this._resource.addEventListener(WI.Resource.Event.LoadingDidFail, this._refreshErrorReason, this);
          this._resource.addEventListener(WI.Resource.Event.RequestHeadersDidChange, this._refreshRequestHeaders, this);
          this._resource.addEventListener(WI.Resource.Event.ResponseReceived, this._refreshRequestAndResponse, this);
          this._resource.addEventListener(WI.Resource.Event.CacheStatusDidChange, this._refreshRequestAndResponse, this);
          this._resource.addEventListener(WI.Resource.Event.SizeDidChange, this._refreshDecodedSize, this);
          this._resource.addEventListener(WI.Resource.Event.TransferSizeDidChange, this._refreshTransferSize, this);
          this._resource.addEventListener(WI.Resource.Event.InitiatedResourcesDidChange, this._refreshRelatedResourcesSection, this);
  
          this._needsToRemoveResourceEventListeners = true;
      }
  };
  