ParsedURL.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above
  12. * copyright notice, this list of conditions and the following disclaimer
  13. * in the documentation and/or other materials provided with the
  14. * distribution.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS
  17. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  18. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  19. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC.
  20. * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  21. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  22. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  26. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. /**
  29. * @constructor
  30. * @param {string} url
  31. */
  32. WebInspector.ParsedURL = function(url)
  33. {
  34. this.isValid = false;
  35. this.url = url;
  36. this.scheme = "";
  37. this.host = "";
  38. this.port = "";
  39. this.path = "";
  40. this.queryParams = "";
  41. this.fragment = "";
  42. this.folderPathComponents = "";
  43. this.lastPathComponent = "";
  44. // RegExp groups:
  45. // 1 - scheme (using the RFC3986 grammar)
  46. // 2 - hostname
  47. // 3 - ?port
  48. // 4 - ?path
  49. // 5 - ?fragment
  50. var match = url.match(/^([A-Za-z][A-Za-z0-9+.-]*):\/\/([^\/:]*)(?::([\d]+))?(?:(\/[^#]*)(?:#(.*))?)?$/i);
  51. if (match) {
  52. this.isValid = true;
  53. this.scheme = match[1].toLowerCase();
  54. this.host = match[2];
  55. this.port = match[3];
  56. this.path = match[4] || "/";
  57. this.fragment = match[5];
  58. } else {
  59. if (this.url.startsWith("data:")) {
  60. this.scheme = "data";
  61. return;
  62. }
  63. if (this.url === "about:blank") {
  64. this.scheme = "about";
  65. return;
  66. }
  67. this.path = this.url;
  68. }
  69. // First cut the query params.
  70. var path = this.path;
  71. var indexOfQuery = path.indexOf("?");
  72. if (indexOfQuery !== -1) {
  73. this.queryParams = path.substring(indexOfQuery + 1)
  74. path = path.substring(0, indexOfQuery);
  75. }
  76. // Then take last path component.
  77. var lastSlashIndex = path.lastIndexOf("/");
  78. if (lastSlashIndex !== -1) {
  79. this.folderPathComponents = path.substring(0, lastSlashIndex);
  80. this.lastPathComponent = path.substring(lastSlashIndex + 1);
  81. } else
  82. this.lastPathComponent = path;
  83. }
  84. /**
  85. * @param {string} url
  86. * @return {Array.<string>}
  87. */
  88. WebInspector.ParsedURL.splitURL = function(url)
  89. {
  90. var parsedURL = new WebInspector.ParsedURL(url);
  91. var origin;
  92. var folderPath;
  93. var name;
  94. if (parsedURL.isValid) {
  95. origin = parsedURL.scheme + "://" + parsedURL.host;
  96. if (parsedURL.port)
  97. origin += ":" + parsedURL.port;
  98. folderPath = parsedURL.folderPathComponents;
  99. name = parsedURL.lastPathComponent;
  100. if (parsedURL.queryParams)
  101. name += "?" + parsedURL.queryParams;
  102. } else {
  103. origin = "";
  104. folderPath = "";
  105. name = url;
  106. }
  107. var result = [origin];
  108. var splittedPath = folderPath.split("/");
  109. for (var i = 1; i < splittedPath.length; ++i)
  110. result.push(splittedPath[i]);
  111. result.push(name);
  112. return result;
  113. }
  114. /**
  115. * @param {string} baseURL
  116. * @param {string} href
  117. * @return {?string}
  118. */
  119. WebInspector.ParsedURL.completeURL = function(baseURL, href)
  120. {
  121. if (href) {
  122. // Return special URLs as-is.
  123. var trimmedHref = href.trim();
  124. if (trimmedHref.startsWith("data:") || trimmedHref.startsWith("blob:") || trimmedHref.startsWith("javascript:"))
  125. return href;
  126. // Return absolute URLs as-is.
  127. var parsedHref = trimmedHref.asParsedURL();
  128. if (parsedHref && parsedHref.scheme)
  129. return trimmedHref;
  130. } else
  131. return baseURL;
  132. var parsedURL = baseURL.asParsedURL();
  133. if (parsedURL) {
  134. if (parsedURL.isDataURL())
  135. return href;
  136. var path = href;
  137. if (path.charAt(0) !== "/") {
  138. var basePath = parsedURL.path;
  139. // Trim off the query part of the basePath.
  140. var questionMarkIndex = basePath.indexOf("?");
  141. if (questionMarkIndex > 0)
  142. basePath = basePath.substring(0, questionMarkIndex);
  143. // A href of "?foo=bar" implies "basePath?foo=bar".
  144. // With "basePath?a=b" and "?foo=bar" we should get "basePath?foo=bar".
  145. var prefix;
  146. if (path.charAt(0) === "?") {
  147. var basePathCutIndex = basePath.indexOf("?");
  148. if (basePathCutIndex !== -1)
  149. prefix = basePath.substring(0, basePathCutIndex);
  150. else
  151. prefix = basePath;
  152. } else
  153. prefix = basePath.substring(0, basePath.lastIndexOf("/")) + "/";
  154. path = prefix + path;
  155. } else if (path.length > 1 && path.charAt(1) === "/") {
  156. // href starts with "//" which is a full URL with the protocol dropped (use the baseURL protocol).
  157. return parsedURL.scheme + ":" + path;
  158. }
  159. return parsedURL.scheme + "://" + parsedURL.host + (parsedURL.port ? (":" + parsedURL.port) : "") + path;
  160. }
  161. return null;
  162. }
  163. WebInspector.ParsedURL.prototype = {
  164. get displayName()
  165. {
  166. if (this._displayName)
  167. return this._displayName;
  168. if (this.isDataURL())
  169. return this.dataURLDisplayName();
  170. if (this.isAboutBlank())
  171. return this.url;
  172. this._displayName = this.lastPathComponent;
  173. if (!this._displayName && this.host)
  174. this._displayName = this.host + "/";
  175. if (!this._displayName && this.url)
  176. this._displayName = this.url.trimURL(WebInspector.inspectedPageDomain ? WebInspector.inspectedPageDomain : "");
  177. if (this._displayName === "/")
  178. this._displayName = this.url;
  179. return this._displayName;
  180. },
  181. dataURLDisplayName: function()
  182. {
  183. if (this._dataURLDisplayName)
  184. return this._dataURLDisplayName;
  185. if (!this.isDataURL())
  186. return "";
  187. this._dataURLDisplayName = this.url.trimEnd(20);
  188. return this._dataURLDisplayName;
  189. },
  190. isAboutBlank: function()
  191. {
  192. return this.url === "about:blank";
  193. },
  194. isDataURL: function()
  195. {
  196. return this.scheme === "data";
  197. }
  198. }
  199. /**
  200. * @return {?WebInspector.ParsedURL}
  201. */
  202. String.prototype.asParsedURL = function()
  203. {
  204. var parsedURL = new WebInspector.ParsedURL(this.toString());
  205. if (parsedURL.isValid)
  206. return parsedURL;
  207. return null;
  208. }