2 * Copyright (C) 2010 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
31 // Ideally, we would rely on platform support for parsing a cookie, since
32 // this would save us from any potential inconsistency. However, exposing
33 // platform cookie parsing logic would require quite a bit of additional
34 // plumbing, and at least some platforms lack support for parsing Cookie,
35 // which is in a format slightly different from Set-Cookie and is normally
36 // only required on the server side.
41 WebInspector.CookieParser = function()
45 WebInspector.CookieParser.prototype = {
51 parseCookie: function(cookieHeader)
53 if (!this._initialize(cookieHeader))
56 for (var kv = this._extractKeyValue(); kv; kv = this._extractKeyValue()) {
57 if (kv.key.charAt(0) === "$" && this._lastCookie)
58 this._lastCookie.addAttribute(kv.key.slice(1), kv.value);
59 else if (kv.key.toLowerCase() !== "$version" && typeof kv.value === "string")
60 this._addCookie(kv, WebInspector.Cookie.Type.Request);
61 this._advanceAndCheckCookieDelimiter();
67 parseSetCookie: function(setCookieHeader)
69 if (!this._initialize(setCookieHeader))
71 for (var kv = this._extractKeyValue(); kv; kv = this._extractKeyValue()) {
73 this._lastCookie.addAttribute(kv.key, kv.value);
75 this._addCookie(kv, WebInspector.Cookie.Type.Response);
76 if (this._advanceAndCheckCookieDelimiter())
83 _initialize: function(headerValue)
85 this._input = headerValue;
86 if (typeof headerValue !== "string")
89 this._lastCookie = null;
90 this._originalInputLength = this._input.length;
94 _flushCookie: function()
97 this._lastCookie.size = this._originalInputLength - this._input.length - this._lastCookiePosition;
98 this._lastCookie = null;
101 _extractKeyValue: function()
103 if (!this._input || !this._input.length)
105 // Note: RFCs offer an option for quoted values that may contain commas and semicolons.
106 // Many browsers/platforms do not support this, however (see http://webkit.org/b/16699
107 // and http://crbug.com/12361). The logic below matches latest versions of IE, Firefox,
108 // Chrome and Safari on some old platforms. The latest version of Safari supports quoted
109 // cookie values, though.
110 var keyValueMatch = /^[ \t]*([^\s=;]+)[ \t]*(?:=[ \t]*([^;\n]*))?/.exec(this._input);
111 if (!keyValueMatch) {
112 console.log("Failed parsing cookie header before: " + this._input);
117 key: keyValueMatch[1],
118 value: keyValueMatch[2] && keyValueMatch[2].trim(),
119 position: this._originalInputLength - this._input.length
121 this._input = this._input.slice(keyValueMatch[0].length);
125 _advanceAndCheckCookieDelimiter: function()
127 var match = /^\s*[\n;]\s*/.exec(this._input);
130 this._input = this._input.slice(match[0].length);
131 return match[0].match("\n") !== null;
134 _addCookie: function(keyValue, type)
136 if (this._lastCookie)
137 this._lastCookie.size = keyValue.position - this._lastCookiePosition;
138 // Mozilla bug 169091: Mozilla, IE and Chrome treat single token (w/o "=") as
139 // specifying a value for a cookie with empty name.
140 this._lastCookie = keyValue.value ? new WebInspector.Cookie(keyValue.key, keyValue.value, type) :
141 new WebInspector.Cookie("", keyValue.key, type);
142 this._lastCookiePosition = keyValue.position;
143 this._cookies.push(this._lastCookie);
147 WebInspector.CookieParser.parseCookie = function(header)
149 return (new WebInspector.CookieParser()).parseCookie(header);
152 WebInspector.CookieParser.parseSetCookie = function(header)
154 return (new WebInspector.CookieParser()).parseSetCookie(header);
160 WebInspector.Cookie = function(name, value, type)
165 this._attributes = {};
168 WebInspector.Cookie.prototype = {
171 return "httponly" in this._attributes;
176 return "secure" in this._attributes;
181 // RFC 2965 suggests using Discard attribute to mark session cookies, but this does not seem to be widely used.
182 // Check for absence of explicity max-age or expiry date instead.
183 return !("expries" in this._attributes || "max-age" in this._attributes);
188 return this._attributes.path;
193 return this._attributes.domain;
196 expires: function(requestDate)
198 return this._attributes.expires ? new Date(this._attributes.expires) :
199 (this._attributes["max-age"] ? new Date(requestDate.getTime() + 1000 * this._attributes["max-age"]) : null);
204 return this._attributes;
207 addAttribute: function(key, value)
209 this._attributes[key.toLowerCase()] = value;
213 WebInspector.Cookie.Type = {