NetworkRequest.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965
  1. /*
  2. * Copyright (C) 2012 Google Inc. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are
  6. * met:
  7. *
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above
  11. * copyright notice, this list of conditions and the following disclaimer
  12. * in the documentation and/or other materials provided with the
  13. * distribution.
  14. * * Neither the name of Google Inc. nor the names of its
  15. * contributors may be used to endorse or promote products derived from
  16. * this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. /**
  31. * @constructor
  32. * @extends {WebInspector.Object}
  33. * @implements {WebInspector.ContentProvider}
  34. * @param {NetworkAgent.RequestId} requestId
  35. * @param {string} url
  36. * @param {string} documentURL
  37. * @param {NetworkAgent.FrameId} frameId
  38. * @param {NetworkAgent.LoaderId} loaderId
  39. */
  40. WebInspector.NetworkRequest = function(requestId, url, documentURL, frameId, loaderId)
  41. {
  42. this._requestId = requestId;
  43. this.url = url;
  44. this._documentURL = documentURL;
  45. this._frameId = frameId;
  46. this._loaderId = loaderId;
  47. this._startTime = -1;
  48. this._endTime = -1;
  49. this.statusCode = 0;
  50. this.statusText = "";
  51. this.requestMethod = "";
  52. this.requestTime = 0;
  53. this.receiveHeadersEnd = 0;
  54. this._type = WebInspector.resourceTypes.Other;
  55. this._contentEncoded = false;
  56. this._pendingContentCallbacks = [];
  57. this._frames = [];
  58. }
  59. WebInspector.NetworkRequest.Events = {
  60. FinishedLoading: "FinishedLoading",
  61. TimingChanged: "TimingChanged",
  62. RequestHeadersChanged: "RequestHeadersChanged",
  63. ResponseHeadersChanged: "ResponseHeadersChanged",
  64. }
  65. /** @enum {string} */
  66. WebInspector.NetworkRequest.InitiatorType = {
  67. Other: "other",
  68. Parser: "parser",
  69. Redirect: "redirect",
  70. Script: "script"
  71. }
  72. /** @typedef {{name: string, value: string}} */
  73. WebInspector.NetworkRequest.NameValue;
  74. WebInspector.NetworkRequest.prototype = {
  75. /**
  76. * @return {NetworkAgent.RequestId}
  77. */
  78. get requestId()
  79. {
  80. return this._requestId;
  81. },
  82. set requestId(requestId)
  83. {
  84. this._requestId = requestId;
  85. },
  86. /**
  87. * @return {string}
  88. */
  89. get url()
  90. {
  91. return this._url;
  92. },
  93. set url(x)
  94. {
  95. if (this._url === x)
  96. return;
  97. this._url = x;
  98. this._parsedURL = new WebInspector.ParsedURL(x);
  99. delete this._parsedQueryParameters;
  100. delete this._name;
  101. delete this._path;
  102. },
  103. /**
  104. * @return {string}
  105. */
  106. get documentURL()
  107. {
  108. return this._documentURL;
  109. },
  110. get parsedURL()
  111. {
  112. return this._parsedURL;
  113. },
  114. /**
  115. * @return {NetworkAgent.FrameId}
  116. */
  117. get frameId()
  118. {
  119. return this._frameId;
  120. },
  121. /**
  122. * @return {NetworkAgent.LoaderId}
  123. */
  124. get loaderId()
  125. {
  126. return this._loaderId;
  127. },
  128. /**
  129. * @return {number}
  130. */
  131. get startTime()
  132. {
  133. return this._startTime || -1;
  134. },
  135. set startTime(x)
  136. {
  137. this._startTime = x;
  138. },
  139. /**
  140. * @return {number}
  141. */
  142. get responseReceivedTime()
  143. {
  144. return this._responseReceivedTime || -1;
  145. },
  146. set responseReceivedTime(x)
  147. {
  148. this._responseReceivedTime = x;
  149. },
  150. /**
  151. * @return {number}
  152. */
  153. get endTime()
  154. {
  155. return this._endTime || -1;
  156. },
  157. set endTime(x)
  158. {
  159. if (this.timing && this.timing.requestTime) {
  160. // Check against accurate responseReceivedTime.
  161. this._endTime = Math.max(x, this.responseReceivedTime);
  162. } else {
  163. // Prefer endTime since it might be from the network stack.
  164. this._endTime = x;
  165. if (this._responseReceivedTime > x)
  166. this._responseReceivedTime = x;
  167. }
  168. },
  169. /**
  170. * @return {number}
  171. */
  172. get duration()
  173. {
  174. if (this._endTime === -1 || this._startTime === -1)
  175. return -1;
  176. return this._endTime - this._startTime;
  177. },
  178. /**
  179. * @return {number}
  180. */
  181. get latency()
  182. {
  183. if (this._responseReceivedTime === -1 || this._startTime === -1)
  184. return -1;
  185. return this._responseReceivedTime - this._startTime;
  186. },
  187. /**
  188. * @return {number}
  189. */
  190. get receiveDuration()
  191. {
  192. if (this._endTime === -1 || this._responseReceivedTime === -1)
  193. return -1;
  194. return this._endTime - this._responseReceivedTime;
  195. },
  196. /**
  197. * @return {number}
  198. */
  199. get resourceSize()
  200. {
  201. return this._resourceSize || 0;
  202. },
  203. set resourceSize(x)
  204. {
  205. this._resourceSize = x;
  206. },
  207. /**
  208. * @return {number}
  209. */
  210. get transferSize()
  211. {
  212. if (this.cached)
  213. return 0;
  214. if (this.statusCode === 304) // Not modified
  215. return this.responseHeadersSize;
  216. if (this._transferSize !== undefined)
  217. return this._transferSize;
  218. // If we did not receive actual transfer size from network
  219. // stack, we prefer using Content-Length over resourceSize as
  220. // resourceSize may differ from actual transfer size if platform's
  221. // network stack performed decoding (e.g. gzip decompression).
  222. // The Content-Length, though, is expected to come from raw
  223. // response headers and will reflect actual transfer length.
  224. // This won't work for chunked content encoding, so fall back to
  225. // resourceSize when we don't have Content-Length. This still won't
  226. // work for chunks with non-trivial encodings. We need a way to
  227. // get actual transfer size from the network stack.
  228. var bodySize = Number(this.responseHeaderValue("Content-Length") || this.resourceSize);
  229. return this.responseHeadersSize + bodySize;
  230. },
  231. /**
  232. * @param {number} x
  233. */
  234. increaseTransferSize: function(x)
  235. {
  236. this._transferSize = (this._transferSize || 0) + x;
  237. },
  238. /**
  239. * @return {boolean}
  240. */
  241. get finished()
  242. {
  243. return this._finished;
  244. },
  245. set finished(x)
  246. {
  247. if (this._finished === x)
  248. return;
  249. this._finished = x;
  250. if (x) {
  251. this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.FinishedLoading, this);
  252. if (this._pendingContentCallbacks.length)
  253. this._innerRequestContent();
  254. }
  255. },
  256. /**
  257. * @return {boolean}
  258. */
  259. get failed()
  260. {
  261. return this._failed;
  262. },
  263. set failed(x)
  264. {
  265. this._failed = x;
  266. },
  267. /**
  268. * @return {boolean}
  269. */
  270. get canceled()
  271. {
  272. return this._canceled;
  273. },
  274. set canceled(x)
  275. {
  276. this._canceled = x;
  277. },
  278. /**
  279. * @return {boolean}
  280. */
  281. get cached()
  282. {
  283. return this._cached;
  284. },
  285. set cached(x)
  286. {
  287. this._cached = x;
  288. if (x)
  289. delete this._timing;
  290. },
  291. /**
  292. * @return {NetworkAgent.ResourceTiming|undefined}
  293. */
  294. get timing()
  295. {
  296. return this._timing;
  297. },
  298. set timing(x)
  299. {
  300. if (x && !this._cached) {
  301. // Take startTime and responseReceivedTime from timing data for better accuracy.
  302. // Timing's requestTime is a baseline in seconds, rest of the numbers there are ticks in millis.
  303. this._startTime = x.requestTime;
  304. this._responseReceivedTime = x.requestTime + x.receiveHeadersEnd / 1000.0;
  305. this._timing = x;
  306. this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.TimingChanged, this);
  307. }
  308. },
  309. /**
  310. * @return {string}
  311. */
  312. get mimeType()
  313. {
  314. return this._mimeType;
  315. },
  316. set mimeType(x)
  317. {
  318. this._mimeType = x;
  319. },
  320. /**
  321. * @return {string}
  322. */
  323. get displayName()
  324. {
  325. return this._parsedURL.displayName;
  326. },
  327. name: function()
  328. {
  329. if (this._name)
  330. return this._name;
  331. this._parseNameAndPathFromURL();
  332. return this._name;
  333. },
  334. path: function()
  335. {
  336. if (this._path)
  337. return this._path;
  338. this._parseNameAndPathFromURL();
  339. return this._path;
  340. },
  341. _parseNameAndPathFromURL: function()
  342. {
  343. if (this._parsedURL.isDataURL()) {
  344. this._name = this._parsedURL.dataURLDisplayName();
  345. this._path = "";
  346. } else if (this._parsedURL.isAboutBlank()) {
  347. this._name = this._parsedURL.url;
  348. this._path = "";
  349. } else {
  350. this._path = this._parsedURL.host + this._parsedURL.folderPathComponents;
  351. this._path = this._path.trimURL(WebInspector.inspectedPageDomain ? WebInspector.inspectedPageDomain : "");
  352. if (this._parsedURL.lastPathComponent || this._parsedURL.queryParams)
  353. this._name = this._parsedURL.lastPathComponent + (this._parsedURL.queryParams ? "?" + this._parsedURL.queryParams : "");
  354. else if (this._parsedURL.folderPathComponents) {
  355. this._name = this._parsedURL.folderPathComponents.substring(this._parsedURL.folderPathComponents.lastIndexOf("/") + 1) + "/";
  356. this._path = this._path.substring(0, this._path.lastIndexOf("/"));
  357. } else {
  358. this._name = this._parsedURL.host;
  359. this._path = "";
  360. }
  361. }
  362. },
  363. /**
  364. * @return {string}
  365. */
  366. get folder()
  367. {
  368. var path = this._parsedURL.path;
  369. var indexOfQuery = path.indexOf("?");
  370. if (indexOfQuery !== -1)
  371. path = path.substring(0, indexOfQuery);
  372. var lastSlashIndex = path.lastIndexOf("/");
  373. return lastSlashIndex !== -1 ? path.substring(0, lastSlashIndex) : "";
  374. },
  375. /**
  376. * @return {WebInspector.ResourceType}
  377. */
  378. get type()
  379. {
  380. return this._type;
  381. },
  382. set type(x)
  383. {
  384. this._type = x;
  385. },
  386. /**
  387. * @return {string}
  388. */
  389. get domain()
  390. {
  391. return this._parsedURL.host;
  392. },
  393. /**
  394. * @return {?WebInspector.NetworkRequest}
  395. */
  396. get redirectSource()
  397. {
  398. if (this.redirects && this.redirects.length > 0)
  399. return this.redirects[this.redirects.length - 1];
  400. return this._redirectSource;
  401. },
  402. set redirectSource(x)
  403. {
  404. this._redirectSource = x;
  405. delete this._initiatorInfo;
  406. },
  407. /**
  408. * @return {!Array.<!WebInspector.NetworkRequest.NameValue>}
  409. */
  410. get requestHeaders()
  411. {
  412. return this._requestHeaders || [];
  413. },
  414. set requestHeaders(x)
  415. {
  416. this._requestHeaders = x;
  417. delete this._sortedRequestHeaders;
  418. delete this._requestCookies;
  419. this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.RequestHeadersChanged);
  420. },
  421. /**
  422. * @return {string}
  423. */
  424. get requestHeadersText()
  425. {
  426. if (typeof this._requestHeadersText === "undefined") {
  427. this._requestHeadersText = this.requestMethod + " " + this.url + " HTTP/1.1\r\n";
  428. for (var i = 0; i < this.requestHeaders.length; ++i)
  429. this._requestHeadersText += this.requestHeaders[i].name + ": " + this.requestHeaders[i].value + "\r\n";
  430. }
  431. return this._requestHeadersText;
  432. },
  433. set requestHeadersText(x)
  434. {
  435. this._requestHeadersText = x;
  436. this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.RequestHeadersChanged);
  437. },
  438. /**
  439. * @return {number}
  440. */
  441. get requestHeadersSize()
  442. {
  443. return this.requestHeadersText.length;
  444. },
  445. /**
  446. * @return {!Array.<!WebInspector.NetworkRequest.NameValue>}
  447. */
  448. get sortedRequestHeaders()
  449. {
  450. if (this._sortedRequestHeaders !== undefined)
  451. return this._sortedRequestHeaders;
  452. this._sortedRequestHeaders = [];
  453. this._sortedRequestHeaders = this.requestHeaders.slice();
  454. this._sortedRequestHeaders.sort(function(a,b) { return a.name.toLowerCase().compareTo(b.name.toLowerCase()) });
  455. return this._sortedRequestHeaders;
  456. },
  457. /**
  458. * @param {string} headerName
  459. * @return {string|undefined}
  460. */
  461. requestHeaderValue: function(headerName)
  462. {
  463. return this._headerValue(this.requestHeaders, headerName);
  464. },
  465. /**
  466. * @return {Array.<WebInspector.Cookie>}
  467. */
  468. get requestCookies()
  469. {
  470. if (!this._requestCookies)
  471. this._requestCookies = WebInspector.CookieParser.parseCookie(this.requestHeaderValue("Cookie"));
  472. return this._requestCookies;
  473. },
  474. /**
  475. * @return {string|undefined}
  476. */
  477. get requestFormData()
  478. {
  479. return this._requestFormData;
  480. },
  481. set requestFormData(x)
  482. {
  483. this._requestFormData = x;
  484. delete this._parsedFormParameters;
  485. },
  486. /**
  487. * @return {string|undefined}
  488. */
  489. get requestHttpVersion()
  490. {
  491. var firstLine = this.requestHeadersText.split(/\r\n/)[0];
  492. var match = firstLine.match(/(HTTP\/\d+\.\d+)$/);
  493. return match ? match[1] : undefined;
  494. },
  495. /**
  496. * @return {!Array.<!WebInspector.NetworkRequest.NameValue>}
  497. */
  498. get responseHeaders()
  499. {
  500. return this._responseHeaders || [];
  501. },
  502. set responseHeaders(x)
  503. {
  504. this._responseHeaders = x;
  505. delete this._sortedResponseHeaders;
  506. delete this._responseCookies;
  507. this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.ResponseHeadersChanged);
  508. },
  509. /**
  510. * @return {string}
  511. */
  512. get responseHeadersText()
  513. {
  514. if (typeof this._responseHeadersText === "undefined") {
  515. this._responseHeadersText = "HTTP/1.1 " + this.statusCode + " " + this.statusText + "\r\n";
  516. for (var i = 0; i < this.responseHeaders.length; ++i)
  517. this._responseHeadersText += this.responseHeaders[i].name + ": " + this.responseHeaders[i].value + "\r\n";
  518. }
  519. return this._responseHeadersText;
  520. },
  521. set responseHeadersText(x)
  522. {
  523. this._responseHeadersText = x;
  524. this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.ResponseHeadersChanged);
  525. },
  526. /**
  527. * @return {number}
  528. */
  529. get responseHeadersSize()
  530. {
  531. return this.responseHeadersText.length;
  532. },
  533. /**
  534. * @return {!Array.<!WebInspector.NetworkRequest.NameValue>}
  535. */
  536. get sortedResponseHeaders()
  537. {
  538. if (this._sortedResponseHeaders !== undefined)
  539. return this._sortedResponseHeaders;
  540. this._sortedResponseHeaders = [];
  541. this._sortedResponseHeaders = this.responseHeaders.slice();
  542. this._sortedResponseHeaders.sort(function(a, b) { return a.name.toLowerCase().compareTo(b.name.toLowerCase()); });
  543. return this._sortedResponseHeaders;
  544. },
  545. /**
  546. * @param {string} headerName
  547. * @return {string|undefined}
  548. */
  549. responseHeaderValue: function(headerName)
  550. {
  551. return this._headerValue(this.responseHeaders, headerName);
  552. },
  553. /**
  554. * @return {Array.<WebInspector.Cookie>}
  555. */
  556. get responseCookies()
  557. {
  558. if (!this._responseCookies)
  559. this._responseCookies = WebInspector.CookieParser.parseSetCookie(this.responseHeaderValue("Set-Cookie"));
  560. return this._responseCookies;
  561. },
  562. /**
  563. * @return {?string}
  564. */
  565. queryString: function()
  566. {
  567. if (this._queryString)
  568. return this._queryString;
  569. var queryString = this.url.split("?", 2)[1];
  570. if (!queryString)
  571. return null;
  572. this._queryString = queryString.split("#", 2)[0];
  573. return this._queryString;
  574. },
  575. /**
  576. * @return {?Array.<!WebInspector.NetworkRequest.NameValue>}
  577. */
  578. get queryParameters()
  579. {
  580. if (this._parsedQueryParameters)
  581. return this._parsedQueryParameters;
  582. var queryString = this.queryString();
  583. if (!queryString)
  584. return null;
  585. this._parsedQueryParameters = this._parseParameters(queryString);
  586. return this._parsedQueryParameters;
  587. },
  588. /**
  589. * @return {?Array.<!WebInspector.NetworkRequest.NameValue>}
  590. */
  591. get formParameters()
  592. {
  593. if (this._parsedFormParameters)
  594. return this._parsedFormParameters;
  595. if (!this.requestFormData)
  596. return null;
  597. var requestContentType = this.requestContentType();
  598. if (!requestContentType || !requestContentType.match(/^application\/x-www-form-urlencoded\s*(;.*)?$/i))
  599. return null;
  600. this._parsedFormParameters = this._parseParameters(this.requestFormData);
  601. return this._parsedFormParameters;
  602. },
  603. /**
  604. * @return {string|undefined}
  605. */
  606. get responseHttpVersion()
  607. {
  608. var match = this.responseHeadersText.match(/^(HTTP\/\d+\.\d+)/);
  609. return match ? match[1] : undefined;
  610. },
  611. /**
  612. * @param {string} queryString
  613. * @return {!Array.<!WebInspector.NetworkRequest.NameValue>}
  614. */
  615. _parseParameters: function(queryString)
  616. {
  617. function parseNameValue(pair)
  618. {
  619. var splitPair = pair.split("=", 2);
  620. return {name: splitPair[0], value: splitPair[1] || ""};
  621. }
  622. return queryString.split("&").map(parseNameValue);
  623. },
  624. /**
  625. * @param {!Array.<!WebInspector.NetworkRequest.NameValue>} headers
  626. * @param {string} headerName
  627. * @return {string|undefined}
  628. */
  629. _headerValue: function(headers, headerName)
  630. {
  631. headerName = headerName.toLowerCase();
  632. var values = [];
  633. for (var i = 0; i < headers.length; ++i) {
  634. if (headers[i].name.toLowerCase() === headerName)
  635. values.push(headers[i].value);
  636. }
  637. if (!values.length)
  638. return undefined;
  639. // Set-Cookie values should be separated by '\n', not comma, otherwise cookies could not be parsed.
  640. if (headerName === "set-cookie")
  641. return values.join("\n");
  642. return values.join(", ");
  643. },
  644. /**
  645. * @return {?string|undefined}
  646. */
  647. get content()
  648. {
  649. return this._content;
  650. },
  651. /**
  652. * @return {boolean}
  653. */
  654. get contentEncoded()
  655. {
  656. return this._contentEncoded;
  657. },
  658. /**
  659. * @return {string}
  660. */
  661. contentURL: function()
  662. {
  663. return this._url;
  664. },
  665. /**
  666. * @return {WebInspector.ResourceType}
  667. */
  668. contentType: function()
  669. {
  670. return this._type;
  671. },
  672. /**
  673. * @param {function(?string, boolean, string)} callback
  674. */
  675. requestContent: function(callback)
  676. {
  677. // We do not support content retrieval for WebSockets at the moment.
  678. // Since WebSockets are potentially long-living, fail requests immediately
  679. // to prevent caller blocking until resource is marked as finished.
  680. if (this.type === WebInspector.resourceTypes.WebSocket) {
  681. callback(null, false, this._mimeType);
  682. return;
  683. }
  684. if (typeof this._content !== "undefined") {
  685. callback(this.content || null, this._contentEncoded, this.type.canonicalMimeType());
  686. return;
  687. }
  688. this._pendingContentCallbacks.push(callback);
  689. if (this.finished)
  690. this._innerRequestContent();
  691. },
  692. /**
  693. * @param {string} query
  694. * @param {boolean} caseSensitive
  695. * @param {boolean} isRegex
  696. * @param {function(Array.<WebInspector.ContentProvider.SearchMatch>)} callback
  697. */
  698. searchInContent: function(query, caseSensitive, isRegex, callback)
  699. {
  700. callback([]);
  701. },
  702. /**
  703. * @return {boolean}
  704. */
  705. isHttpFamily: function()
  706. {
  707. return !!this.url.match(/^https?:/i);
  708. },
  709. /**
  710. * @return {string|undefined}
  711. */
  712. requestContentType: function()
  713. {
  714. return this.requestHeaderValue("Content-Type");
  715. },
  716. /**
  717. * @return {boolean}
  718. */
  719. isPingRequest: function()
  720. {
  721. return "text/ping" === this.requestContentType();
  722. },
  723. /**
  724. * @return {boolean}
  725. */
  726. hasErrorStatusCode: function()
  727. {
  728. return this.statusCode >= 400;
  729. },
  730. /**
  731. * @param {Element} image
  732. */
  733. populateImageSource: function(image)
  734. {
  735. /**
  736. * @this {WebInspector.NetworkRequest}
  737. * @param {?string} content
  738. * @param {boolean} contentEncoded
  739. * @param {string} mimeType
  740. */
  741. function onResourceContent(content, contentEncoded, mimeType)
  742. {
  743. var imageSrc = this.asDataURL();
  744. if (imageSrc === null)
  745. imageSrc = this.url;
  746. image.src = imageSrc;
  747. }
  748. this.requestContent(onResourceContent.bind(this));
  749. },
  750. /**
  751. * @return {?string}
  752. */
  753. asDataURL: function()
  754. {
  755. return WebInspector.contentAsDataURL(this._content, this.mimeType, this._contentEncoded);
  756. },
  757. _innerRequestContent: function()
  758. {
  759. if (this._contentRequested)
  760. return;
  761. this._contentRequested = true;
  762. /**
  763. * @param {?Protocol.Error} error
  764. * @param {string} content
  765. * @param {boolean} contentEncoded
  766. */
  767. function onResourceContent(error, content, contentEncoded)
  768. {
  769. this._content = error ? null : content;
  770. this._contentEncoded = contentEncoded;
  771. var callbacks = this._pendingContentCallbacks.slice();
  772. for (var i = 0; i < callbacks.length; ++i)
  773. callbacks[i](this._content, this._contentEncoded, this._mimeType);
  774. this._pendingContentCallbacks.length = 0;
  775. delete this._contentRequested;
  776. }
  777. NetworkAgent.getResponseBody(this._requestId, onResourceContent.bind(this));
  778. },
  779. /**
  780. * @return {{type: WebInspector.NetworkRequest.InitiatorType, url: string, source: string, lineNumber: number}}
  781. */
  782. initiatorInfo: function()
  783. {
  784. if (this._initiatorInfo)
  785. return this._initiatorInfo;
  786. var type = WebInspector.NetworkRequest.InitiatorType.Other;
  787. var url = "";
  788. var lineNumber = -Infinity;
  789. if (this.redirectSource) {
  790. type = WebInspector.NetworkRequest.InitiatorType.Redirect;
  791. url = this.redirectSource.url;
  792. } else if (this.initiator) {
  793. if (this.initiator.type === NetworkAgent.InitiatorType.Parser) {
  794. type = WebInspector.NetworkRequest.InitiatorType.Parser;
  795. url = this.initiator.url;
  796. lineNumber = this.initiator.lineNumber;
  797. } else if (this.initiator.type === NetworkAgent.InitiatorType.Script) {
  798. var topFrame = this.initiator.stackTrace[0];
  799. if (topFrame.url) {
  800. type = WebInspector.NetworkRequest.InitiatorType.Script;
  801. url = topFrame.url;
  802. lineNumber = topFrame.lineNumber;
  803. }
  804. }
  805. }
  806. this._initiatorInfo = {type: type, url: url, source: WebInspector.displayNameForURL(url), lineNumber: lineNumber};
  807. return this._initiatorInfo;
  808. },
  809. /**
  810. * @return {!Array.<!Object>}
  811. */
  812. frames: function()
  813. {
  814. return this._frames;
  815. },
  816. /**
  817. * @param {number} position
  818. * @return {Object|undefined}
  819. */
  820. frame: function(position)
  821. {
  822. return this._frames[position];
  823. },
  824. /**
  825. * @param {string} errorMessage
  826. * @param {number} time
  827. */
  828. addFrameError: function(errorMessage, time)
  829. {
  830. this._pushFrame({errorMessage: errorMessage, time: time});
  831. },
  832. /**
  833. * @param {!NetworkAgent.WebSocketFrame} response
  834. * @param {number} time
  835. * @param {boolean} sent
  836. */
  837. addFrame: function(response, time, sent)
  838. {
  839. response.time = time;
  840. if (sent)
  841. response.sent = sent;
  842. this._pushFrame(response);
  843. },
  844. /**
  845. * @param {!Object} frameOrError
  846. */
  847. _pushFrame: function(frameOrError)
  848. {
  849. if (this._frames.length >= 100)
  850. this._frames.splice(0, 10);
  851. this._frames.push(frameOrError);
  852. },
  853. __proto__: WebInspector.Object.prototype
  854. }