summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/devtools/front_end/sdk/CookieParser.js
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/devtools/front_end/sdk/CookieParser.js')
-rw-r--r--chromium/third_party/WebKit/Source/devtools/front_end/sdk/CookieParser.js437
1 files changed, 437 insertions, 0 deletions
diff --git a/chromium/third_party/WebKit/Source/devtools/front_end/sdk/CookieParser.js b/chromium/third_party/WebKit/Source/devtools/front_end/sdk/CookieParser.js
new file mode 100644
index 00000000000..26110e4552d
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/devtools/front_end/sdk/CookieParser.js
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2010 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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.
+ */
+
+// Ideally, we would rely on platform support for parsing a cookie, since
+// this would save us from any potential inconsistency. However, exposing
+// platform cookie parsing logic would require quite a bit of additional
+// plumbing, and at least some platforms lack support for parsing Cookie,
+// which is in a format slightly different from Set-Cookie and is normally
+// only required on the server side.
+
+/**
+ * @constructor
+ */
+WebInspector.CookieParser = function()
+{
+}
+
+/**
+ * @constructor
+ * @param {string} key
+ * @param {string|undefined} value
+ * @param {number} position
+ */
+WebInspector.CookieParser.KeyValue = function(key, value, position)
+{
+ this.key = key;
+ this.value = value;
+ this.position = position;
+}
+
+WebInspector.CookieParser.prototype = {
+ /**
+ * @return {!Array.<!WebInspector.Cookie>}
+ */
+ cookies: function()
+ {
+ return this._cookies;
+ },
+
+ /**
+ * @param {string|undefined} cookieHeader
+ * @return {?Array.<!WebInspector.Cookie>}
+ */
+ parseCookie: function(cookieHeader)
+ {
+ if (!this._initialize(cookieHeader))
+ return null;
+
+ for (var kv = this._extractKeyValue(); kv; kv = this._extractKeyValue()) {
+ if (kv.key.charAt(0) === "$" && this._lastCookie)
+ this._lastCookie.addAttribute(kv.key.slice(1), kv.value);
+ else if (kv.key.toLowerCase() !== "$version" && typeof kv.value === "string")
+ this._addCookie(kv, WebInspector.Cookie.Type.Request);
+ this._advanceAndCheckCookieDelimiter();
+ }
+ this._flushCookie();
+ return this._cookies;
+ },
+
+ /**
+ * @param {string|undefined} setCookieHeader
+ * @return {?Array.<!WebInspector.Cookie>}
+ */
+ parseSetCookie: function(setCookieHeader)
+ {
+ if (!this._initialize(setCookieHeader))
+ return null;
+ for (var kv = this._extractKeyValue(); kv; kv = this._extractKeyValue()) {
+ if (this._lastCookie)
+ this._lastCookie.addAttribute(kv.key, kv.value);
+ else
+ this._addCookie(kv, WebInspector.Cookie.Type.Response);
+ if (this._advanceAndCheckCookieDelimiter())
+ this._flushCookie();
+ }
+ this._flushCookie();
+ return this._cookies;
+ },
+
+ /**
+ * @param {string|undefined} headerValue
+ * @return {boolean}
+ */
+ _initialize: function(headerValue)
+ {
+ this._input = headerValue;
+ if (typeof headerValue !== "string")
+ return false;
+ this._cookies = [];
+ this._lastCookie = null;
+ this._originalInputLength = this._input.length;
+ return true;
+ },
+
+ _flushCookie: function()
+ {
+ if (this._lastCookie)
+ this._lastCookie.setSize(this._originalInputLength - this._input.length - this._lastCookiePosition);
+ this._lastCookie = null;
+ },
+
+ /**
+ * @return {?WebInspector.CookieParser.KeyValue}
+ */
+ _extractKeyValue: function()
+ {
+ if (!this._input || !this._input.length)
+ return null;
+ // Note: RFCs offer an option for quoted values that may contain commas and semicolons.
+ // Many browsers/platforms do not support this, however (see http://webkit.org/b/16699
+ // and http://crbug.com/12361). The logic below matches latest versions of IE, Firefox,
+ // Chrome and Safari on some old platforms. The latest version of Safari supports quoted
+ // cookie values, though.
+ var keyValueMatch = /^[ \t]*([^\s=;]+)[ \t]*(?:=[ \t]*([^;\n]*))?/.exec(this._input);
+ if (!keyValueMatch) {
+ console.log("Failed parsing cookie header before: " + this._input);
+ return null;
+ }
+
+ var result = new WebInspector.CookieParser.KeyValue(keyValueMatch[1], keyValueMatch[2] && keyValueMatch[2].trim(), this._originalInputLength - this._input.length);
+ this._input = this._input.slice(keyValueMatch[0].length);
+ return result;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ _advanceAndCheckCookieDelimiter: function()
+ {
+ var match = /^\s*[\n;]\s*/.exec(this._input);
+ if (!match)
+ return false;
+ this._input = this._input.slice(match[0].length);
+ return match[0].match("\n") !== null;
+ },
+
+ /**
+ * @param {!WebInspector.CookieParser.KeyValue} keyValue
+ * @param {!WebInspector.Cookie.Type} type
+ */
+ _addCookie: function(keyValue, type)
+ {
+ if (this._lastCookie)
+ this._lastCookie.setSize(keyValue.position - this._lastCookiePosition);
+ // Mozilla bug 169091: Mozilla, IE and Chrome treat single token (w/o "=") as
+ // specifying a value for a cookie with empty name.
+ this._lastCookie = typeof keyValue.value === "string" ? new WebInspector.Cookie(keyValue.key, keyValue.value, type) :
+ new WebInspector.Cookie("", keyValue.key, type);
+ this._lastCookiePosition = keyValue.position;
+ this._cookies.push(this._lastCookie);
+ }
+};
+
+/**
+ * @param {string|undefined} header
+ * @return {?Array.<!WebInspector.Cookie>}
+ */
+WebInspector.CookieParser.parseCookie = function(header)
+{
+ return (new WebInspector.CookieParser()).parseCookie(header);
+}
+
+/**
+ * @param {string|undefined} header
+ * @return {?Array.<!WebInspector.Cookie>}
+ */
+WebInspector.CookieParser.parseSetCookie = function(header)
+{
+ return (new WebInspector.CookieParser()).parseSetCookie(header);
+}
+
+/**
+ * @constructor
+ * @param {string} name
+ * @param {string} value
+ * @param {?WebInspector.Cookie.Type} type
+ */
+WebInspector.Cookie = function(name, value, type)
+{
+ this._name = name;
+ this._value = value;
+ this._type = type;
+ this._attributes = {};
+}
+
+WebInspector.Cookie.prototype = {
+ /**
+ * @return {string}
+ */
+ name: function()
+ {
+ return this._name;
+ },
+
+ /**
+ * @return {string}
+ */
+ value: function()
+ {
+ return this._value;
+ },
+
+ /**
+ * @return {?WebInspector.Cookie.Type}
+ */
+ type: function()
+ {
+ return this._type;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ httpOnly: function()
+ {
+ return "httponly" in this._attributes;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ secure: function()
+ {
+ return "secure" in this._attributes;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ session: function()
+ {
+ // RFC 2965 suggests using Discard attribute to mark session cookies, but this does not seem to be widely used.
+ // Check for absence of explicitly max-age or expiry date instead.
+ return !("expires" in this._attributes || "max-age" in this._attributes);
+ },
+
+ /**
+ * @return {string}
+ */
+ path: function()
+ {
+ return this._attributes["path"];
+ },
+
+ /**
+ * @return {string}
+ */
+ port: function()
+ {
+ return this._attributes["port"];
+ },
+
+ /**
+ * @return {string}
+ */
+ domain: function()
+ {
+ return this._attributes["domain"];
+ },
+
+ /**
+ * @return {string}
+ */
+ expires: function()
+ {
+ return this._attributes["expires"];
+ },
+
+ /**
+ * @return {string}
+ */
+ maxAge: function()
+ {
+ return this._attributes["max-age"];
+ },
+
+ /**
+ * @return {number}
+ */
+ size: function()
+ {
+ return this._size;
+ },
+
+ /**
+ * @param {number} size
+ */
+ setSize: function(size)
+ {
+ this._size = size;
+ },
+
+ /**
+ * @return {?Date}
+ */
+ expiresDate: function(requestDate)
+ {
+ // RFC 6265 indicates that the max-age attribute takes precedence over the expires attribute
+ if (this.maxAge()) {
+ var targetDate = requestDate === null ? new Date() : requestDate;
+ return new Date(targetDate.getTime() + 1000 * this.maxAge());
+ }
+
+ if (this.expires())
+ return new Date(this.expires());
+
+ return null;
+ },
+
+ /**
+ * @return {!Object}
+ */
+ attributes: function()
+ {
+ return this._attributes;
+ },
+
+ /**
+ * @param {string} key
+ * @param {string=} value
+ */
+ addAttribute: function(key, value)
+ {
+ this._attributes[key.toLowerCase()] = value;
+ },
+
+ /**
+ * @param {function(?Protocol.Error)=} callback
+ */
+ remove: function(callback)
+ {
+ PageAgent.deleteCookie(this.name(), (this.secure() ? "https://" : "http://") + this.domain() + this.path(), callback);
+ }
+}
+
+/**
+ * @enum {number}
+ */
+WebInspector.Cookie.Type = {
+ Request: 0,
+ Response: 1
+};
+
+WebInspector.Cookies = {}
+
+/**
+ * @param {function(!Array.<!WebInspector.Cookie>)} callback
+ */
+WebInspector.Cookies.getCookiesAsync = function(callback)
+{
+ /**
+ * @param {?Protocol.Error} error
+ * @param {!Array.<!PageAgent.Cookie>} cookies
+ */
+ function mycallback(error, cookies)
+ {
+ if (error)
+ return;
+ callback(cookies.map(WebInspector.Cookies.buildCookieProtocolObject));
+ }
+
+ PageAgent.getCookies(mycallback);
+}
+
+/**
+ * @param {!PageAgent.Cookie} protocolCookie
+ * @return {!WebInspector.Cookie}
+ */
+WebInspector.Cookies.buildCookieProtocolObject = function(protocolCookie)
+{
+ var cookie = new WebInspector.Cookie(protocolCookie.name, protocolCookie.value, null);
+ cookie.addAttribute("domain", protocolCookie["domain"]);
+ cookie.addAttribute("path", protocolCookie["path"]);
+ cookie.addAttribute("port", protocolCookie["port"]);
+ if (protocolCookie["expires"])
+ cookie.addAttribute("expires", protocolCookie["expires"]);
+ if (protocolCookie["httpOnly"])
+ cookie.addAttribute("httpOnly");
+ if (protocolCookie["secure"])
+ cookie.addAttribute("secure");
+ cookie.setSize(protocolCookie["size"]);
+ return cookie;
+}
+
+/**
+ * @param {!WebInspector.Cookie} cookie
+ * @param {string} resourceURL
+ * @return {boolean}
+ */
+WebInspector.Cookies.cookieMatchesResourceURL = function(cookie, resourceURL)
+{
+ var url = resourceURL.asParsedURL();
+ if (!url || !WebInspector.Cookies.cookieDomainMatchesResourceDomain(cookie.domain(), url.host))
+ return false;
+ return (url.path.startsWith(cookie.path())
+ && (!cookie.port() || url.port == cookie.port())
+ && (!cookie.secure() || url.scheme === "https"));
+}
+
+/**
+ * @param {string} cookieDomain
+ * @param {string} resourceDomain
+ * @return {boolean}
+ */
+WebInspector.Cookies.cookieDomainMatchesResourceDomain = function(cookieDomain, resourceDomain)
+{
+ if (cookieDomain.charAt(0) !== '.')
+ return resourceDomain === cookieDomain;
+ return !!resourceDomain.match(new RegExp("^([^\\.]+\\.)*" + cookieDomain.substring(1).escapeForRegExp() + "$", "i"));
+}