NetworkRequest.js 25 KB

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