diff options
Diffstat (limited to 'chromium/third_party/WebKit/Source/devtools/front_end/common/ParsedURL.js')
-rw-r--r-- | chromium/third_party/WebKit/Source/devtools/front_end/common/ParsedURL.js | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/chromium/third_party/WebKit/Source/devtools/front_end/common/ParsedURL.js b/chromium/third_party/WebKit/Source/devtools/front_end/common/ParsedURL.js new file mode 100644 index 00000000000..6f5d66f245f --- /dev/null +++ b/chromium/third_party/WebKit/Source/devtools/front_end/common/ParsedURL.js @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY GOOGLE 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 GOOGLE 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. + */ + +/** + * @constructor + * @param {string} url + */ +WebInspector.ParsedURL = function(url) +{ + this.isValid = false; + this.url = url; + this.scheme = ""; + this.host = ""; + this.port = ""; + this.path = ""; + this.queryParams = ""; + this.fragment = ""; + this.folderPathComponents = ""; + this.lastPathComponent = ""; + + // RegExp groups: + // 1 - scheme (using the RFC3986 grammar) + // 2 - hostname + // 3 - ?port + // 4 - ?path + // 5 - ?fragment + var match = url.match(/^([A-Za-z][A-Za-z0-9+.-]*):\/\/([^\/:]*)(?::([\d]+))?(?:(\/[^#]*)(?:#(.*))?)?$/i); + if (match) { + this.isValid = true; + this.scheme = match[1].toLowerCase(); + this.host = match[2]; + this.port = match[3]; + this.path = match[4] || "/"; + this.fragment = match[5]; + } else { + if (this.url.startsWith("data:")) { + this.scheme = "data"; + return; + } + if (this.url === "about:blank") { + this.scheme = "about"; + return; + } + this.path = this.url; + } + + // First cut the query params. + var path = this.path; + var indexOfQuery = path.indexOf("?"); + if (indexOfQuery !== -1) { + this.queryParams = path.substring(indexOfQuery + 1) + path = path.substring(0, indexOfQuery); + } + + // Then take last path component. + var lastSlashIndex = path.lastIndexOf("/"); + if (lastSlashIndex !== -1) { + this.folderPathComponents = path.substring(0, lastSlashIndex); + this.lastPathComponent = path.substring(lastSlashIndex + 1); + } else + this.lastPathComponent = path; +} + +/** + * @param {string} url + * @return {!Array.<string>} + */ +WebInspector.ParsedURL.splitURL = function(url) +{ + var parsedURL = new WebInspector.ParsedURL(url); + var origin; + var folderPath; + var name; + if (parsedURL.isValid) { + origin = parsedURL.scheme + "://" + parsedURL.host; + if (parsedURL.port) + origin += ":" + parsedURL.port; + folderPath = parsedURL.folderPathComponents; + name = parsedURL.lastPathComponent; + if (parsedURL.queryParams) + name += "?" + parsedURL.queryParams; + } else { + origin = ""; + folderPath = ""; + name = url; + } + var result = [origin]; + var splittedPath = folderPath.split("/"); + for (var i = 1; i < splittedPath.length; ++i) { + if (!splittedPath[i]) + continue; + result.push(splittedPath[i]); + } + result.push(name); + return result; +} + + +/** + * http://tools.ietf.org/html/rfc3986#section-5.2.4 + * @param {string} path + * @return {string} + */ + +WebInspector.ParsedURL.normalizePath = function(path) +{ + if (path.indexOf("..") === -1 && path.indexOf('.') === -1) + return path; + + var normalizedSegments = []; + var segments = path.split("/"); + for (var i = 0; i < segments.length; i++) { + var segment = segments[i]; + if (segment === ".") + continue; + else if (segment === "..") + normalizedSegments.pop(); + else if (segment) + normalizedSegments.push(segment); + } + var normalizedPath = normalizedSegments.join("/"); + if (normalizedPath[normalizedPath.length - 1] === "/") + return normalizedPath; + if (path[0] === "/" && normalizedPath) + normalizedPath = "/" + normalizedPath; + if ((path[path.length - 1] === "/") || (segments[segments.length - 1] === ".") || (segments[segments.length - 1] === "..")) + normalizedPath = normalizedPath + "/"; + + return normalizedPath; +} + +/** + * @param {string} baseURL + * @param {string} href + * @return {?string} + */ +WebInspector.ParsedURL.completeURL = function(baseURL, href) +{ + if (href) { + // Return special URLs as-is. + var trimmedHref = href.trim(); + if (trimmedHref.startsWith("data:") || trimmedHref.startsWith("blob:") || trimmedHref.startsWith("javascript:")) + return href; + + // Return absolute URLs as-is. + var parsedHref = trimmedHref.asParsedURL(); + if (parsedHref && parsedHref.scheme) + return trimmedHref; + } else { + return baseURL; + } + + var parsedURL = baseURL.asParsedURL(); + if (parsedURL) { + if (parsedURL.isDataURL()) + return href; + var path = href; + + var query = path.indexOf("?"); + var postfix = ""; + if (query !== -1) { + postfix = path.substring(query); + path = path.substring(0, query); + } else { + var fragment = path.indexOf("#"); + if (fragment !== -1) { + postfix = path.substring(fragment); + path = path.substring(0, fragment); + } + } + + if (!path) { // empty path, must be postfix + var basePath = parsedURL.path; + if (postfix.charAt(0) === "?") { + // A href of "?foo=bar" implies "basePath?foo=bar". + // With "basePath?a=b" and "?foo=bar" we should get "basePath?foo=bar". + var baseQuery = parsedURL.path.indexOf("?"); + if (baseQuery !== -1) + basePath = basePath.substring(0, baseQuery); + } // else it must be a fragment + return parsedURL.scheme + "://" + parsedURL.host + (parsedURL.port ? (":" + parsedURL.port) : "") + basePath + postfix; + } else if (path.charAt(0) !== "/") { // relative path + var prefix = parsedURL.path; + var prefixQuery = prefix.indexOf("?"); + if (prefixQuery !== -1) + prefix = prefix.substring(0, prefixQuery); + prefix = prefix.substring(0, prefix.lastIndexOf("/")) + "/"; + path = prefix + path; + } else if (path.length > 1 && path.charAt(1) === "/") { + // href starts with "//" which is a full URL with the protocol dropped (use the baseURL protocol). + return parsedURL.scheme + ":" + path + postfix; + } // else absolute path + return parsedURL.scheme + "://" + parsedURL.host + (parsedURL.port ? (":" + parsedURL.port) : "") + WebInspector.ParsedURL.normalizePath(path) + postfix; + } + return null; +} + +WebInspector.ParsedURL.prototype = { + get displayName() + { + if (this._displayName) + return this._displayName; + + if (this.isDataURL()) + return this.dataURLDisplayName(); + if (this.isAboutBlank()) + return this.url; + + this._displayName = this.lastPathComponent; + if (!this._displayName) + this._displayName = (this.host || "") + "/"; + if (this._displayName === "/") + this._displayName = this.url; + return this._displayName; + }, + + /** + * @return {string} + */ + dataURLDisplayName: function() + { + if (this._dataURLDisplayName) + return this._dataURLDisplayName; + if (!this.isDataURL()) + return ""; + this._dataURLDisplayName = this.url.trimEnd(20); + return this._dataURLDisplayName; + }, + + /** + * @return {boolean} + */ + isAboutBlank: function() + { + return this.url === "about:blank"; + }, + + /** + * @return {boolean} + */ + isDataURL: function() + { + return this.scheme === "data"; + } +} + +/** + * @return {?WebInspector.ParsedURL} + */ +String.prototype.asParsedURL = function() +{ + var parsedURL = new WebInspector.ParsedURL(this.toString()); + if (parsedURL.isValid) + return parsedURL; + return null; +} |