OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2010 Google Inc. All rights reserved. | 2 * Copyright (C) 2010 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
11 * copyright notice, this list of conditions and the following disclaimer | 11 * copyright notice, this list of conditions and the following disclaimer |
12 * in the documentation and/or other materials provided with the | 12 * in the documentation and/or other materials provided with the |
13 * distribution. | 13 * distribution. |
14 * * Neither the name of Google Inc. nor the names of its | 14 * * Neither the name of Google Inc. nor the names of its |
15 * contributors may be used to endorse or promote products derived from | 15 * contributors may be used to endorse or promote products derived from |
16 * this software without specific prior written permission. | 16 * this software without specific prior written permission. |
17 * | 17 * |
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 */ | 29 */ |
30 | |
31 // Ideally, we would rely on platform support for parsing a cookie, since | 30 // Ideally, we would rely on platform support for parsing a cookie, since |
32 // this would save us from any potential inconsistency. However, exposing | 31 // this would save us from any potential inconsistency. However, exposing |
33 // platform cookie parsing logic would require quite a bit of additional | 32 // platform cookie parsing logic would require quite a bit of additional |
34 // plumbing, and at least some platforms lack support for parsing Cookie, | 33 // 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 | 34 // which is in a format slightly different from Set-Cookie and is normally |
36 // only required on the server side. | 35 // only required on the server side. |
37 | 36 |
38 /** | 37 /** |
39 * @constructor | 38 * @unrestricted |
40 * @param {!WebInspector.Target} target | |
41 */ | 39 */ |
42 WebInspector.CookieParser = function(target) | 40 WebInspector.CookieParser = class { |
43 { | 41 /** |
| 42 * @param {!WebInspector.Target} target |
| 43 */ |
| 44 constructor(target) { |
44 this._target = target; | 45 this._target = target; |
| 46 } |
| 47 |
| 48 /** |
| 49 * @param {!WebInspector.Target} target |
| 50 * @param {string|undefined} header |
| 51 * @return {?Array.<!WebInspector.Cookie>} |
| 52 */ |
| 53 static parseCookie(target, header) { |
| 54 return (new WebInspector.CookieParser(target)).parseCookie(header); |
| 55 } |
| 56 |
| 57 /** |
| 58 * @param {!WebInspector.Target} target |
| 59 * @param {string|undefined} header |
| 60 * @return {?Array.<!WebInspector.Cookie>} |
| 61 */ |
| 62 static parseSetCookie(target, header) { |
| 63 return (new WebInspector.CookieParser(target)).parseSetCookie(header); |
| 64 } |
| 65 |
| 66 /** |
| 67 * @return {!Array.<!WebInspector.Cookie>} |
| 68 */ |
| 69 cookies() { |
| 70 return this._cookies; |
| 71 } |
| 72 |
| 73 /** |
| 74 * @param {string|undefined} cookieHeader |
| 75 * @return {?Array.<!WebInspector.Cookie>} |
| 76 */ |
| 77 parseCookie(cookieHeader) { |
| 78 if (!this._initialize(cookieHeader)) |
| 79 return null; |
| 80 |
| 81 for (var kv = this._extractKeyValue(); kv; kv = this._extractKeyValue()) { |
| 82 if (kv.key.charAt(0) === '$' && this._lastCookie) |
| 83 this._lastCookie.addAttribute(kv.key.slice(1), kv.value); |
| 84 else if (kv.key.toLowerCase() !== '$version' && typeof kv.value === 'strin
g') |
| 85 this._addCookie(kv, WebInspector.Cookie.Type.Request); |
| 86 this._advanceAndCheckCookieDelimiter(); |
| 87 } |
| 88 this._flushCookie(); |
| 89 return this._cookies; |
| 90 } |
| 91 |
| 92 /** |
| 93 * @param {string|undefined} setCookieHeader |
| 94 * @return {?Array.<!WebInspector.Cookie>} |
| 95 */ |
| 96 parseSetCookie(setCookieHeader) { |
| 97 if (!this._initialize(setCookieHeader)) |
| 98 return null; |
| 99 for (var kv = this._extractKeyValue(); kv; kv = this._extractKeyValue()) { |
| 100 if (this._lastCookie) |
| 101 this._lastCookie.addAttribute(kv.key, kv.value); |
| 102 else |
| 103 this._addCookie(kv, WebInspector.Cookie.Type.Response); |
| 104 if (this._advanceAndCheckCookieDelimiter()) |
| 105 this._flushCookie(); |
| 106 } |
| 107 this._flushCookie(); |
| 108 return this._cookies; |
| 109 } |
| 110 |
| 111 /** |
| 112 * @param {string|undefined} headerValue |
| 113 * @return {boolean} |
| 114 */ |
| 115 _initialize(headerValue) { |
| 116 this._input = headerValue; |
| 117 if (typeof headerValue !== 'string') |
| 118 return false; |
| 119 this._cookies = []; |
| 120 this._lastCookie = null; |
| 121 this._originalInputLength = this._input.length; |
| 122 return true; |
| 123 } |
| 124 |
| 125 _flushCookie() { |
| 126 if (this._lastCookie) |
| 127 this._lastCookie.setSize(this._originalInputLength - this._input.length -
this._lastCookiePosition); |
| 128 this._lastCookie = null; |
| 129 } |
| 130 |
| 131 /** |
| 132 * @return {?WebInspector.CookieParser.KeyValue} |
| 133 */ |
| 134 _extractKeyValue() { |
| 135 if (!this._input || !this._input.length) |
| 136 return null; |
| 137 // Note: RFCs offer an option for quoted values that may contain commas and
semicolons. |
| 138 // Many browsers/platforms do not support this, however (see http://webkit.o
rg/b/16699 |
| 139 // and http://crbug.com/12361). The logic below matches latest versions of I
E, Firefox, |
| 140 // Chrome and Safari on some old platforms. The latest version of Safari sup
ports quoted |
| 141 // cookie values, though. |
| 142 var keyValueMatch = /^[ \t]*([^\s=;]+)[ \t]*(?:=[ \t]*([^;\n]*))?/.exec(this
._input); |
| 143 if (!keyValueMatch) { |
| 144 console.log('Failed parsing cookie header before: ' + this._input); |
| 145 return null; |
| 146 } |
| 147 |
| 148 var result = new WebInspector.CookieParser.KeyValue( |
| 149 keyValueMatch[1], keyValueMatch[2] && keyValueMatch[2].trim(), this._ori
ginalInputLength - this._input.length); |
| 150 this._input = this._input.slice(keyValueMatch[0].length); |
| 151 return result; |
| 152 } |
| 153 |
| 154 /** |
| 155 * @return {boolean} |
| 156 */ |
| 157 _advanceAndCheckCookieDelimiter() { |
| 158 var match = /^\s*[\n;]\s*/.exec(this._input); |
| 159 if (!match) |
| 160 return false; |
| 161 this._input = this._input.slice(match[0].length); |
| 162 return match[0].match('\n') !== null; |
| 163 } |
| 164 |
| 165 /** |
| 166 * @param {!WebInspector.CookieParser.KeyValue} keyValue |
| 167 * @param {!WebInspector.Cookie.Type} type |
| 168 */ |
| 169 _addCookie(keyValue, type) { |
| 170 if (this._lastCookie) |
| 171 this._lastCookie.setSize(keyValue.position - this._lastCookiePosition); |
| 172 // Mozilla bug 169091: Mozilla, IE and Chrome treat single token (w/o "=") a
s |
| 173 // specifying a value for a cookie with empty name. |
| 174 this._lastCookie = typeof keyValue.value === 'string' ? |
| 175 new WebInspector.Cookie(this._target, keyValue.key, keyValue.value, type
) : |
| 176 new WebInspector.Cookie(this._target, '', keyValue.key, type); |
| 177 this._lastCookiePosition = keyValue.position; |
| 178 this._cookies.push(this._lastCookie); |
| 179 } |
45 }; | 180 }; |
46 | 181 |
47 /** | 182 /** |
48 * @constructor | 183 * @unrestricted |
49 * @param {string} key | |
50 * @param {string|undefined} value | |
51 * @param {number} position | |
52 */ | 184 */ |
53 WebInspector.CookieParser.KeyValue = function(key, value, position) | 185 WebInspector.CookieParser.KeyValue = class { |
54 { | 186 /** |
| 187 * @param {string} key |
| 188 * @param {string|undefined} value |
| 189 * @param {number} position |
| 190 */ |
| 191 constructor(key, value, position) { |
55 this.key = key; | 192 this.key = key; |
56 this.value = value; | 193 this.value = value; |
57 this.position = position; | 194 this.position = position; |
| 195 } |
58 }; | 196 }; |
59 | 197 |
60 WebInspector.CookieParser.prototype = { | |
61 /** | |
62 * @return {!Array.<!WebInspector.Cookie>} | |
63 */ | |
64 cookies: function() | |
65 { | |
66 return this._cookies; | |
67 }, | |
68 | |
69 /** | |
70 * @param {string|undefined} cookieHeader | |
71 * @return {?Array.<!WebInspector.Cookie>} | |
72 */ | |
73 parseCookie: function(cookieHeader) | |
74 { | |
75 if (!this._initialize(cookieHeader)) | |
76 return null; | |
77 | |
78 for (var kv = this._extractKeyValue(); kv; kv = this._extractKeyValue())
{ | |
79 if (kv.key.charAt(0) === "$" && this._lastCookie) | |
80 this._lastCookie.addAttribute(kv.key.slice(1), kv.value); | |
81 else if (kv.key.toLowerCase() !== "$version" && typeof kv.value ===
"string") | |
82 this._addCookie(kv, WebInspector.Cookie.Type.Request); | |
83 this._advanceAndCheckCookieDelimiter(); | |
84 } | |
85 this._flushCookie(); | |
86 return this._cookies; | |
87 }, | |
88 | |
89 /** | |
90 * @param {string|undefined} setCookieHeader | |
91 * @return {?Array.<!WebInspector.Cookie>} | |
92 */ | |
93 parseSetCookie: function(setCookieHeader) | |
94 { | |
95 if (!this._initialize(setCookieHeader)) | |
96 return null; | |
97 for (var kv = this._extractKeyValue(); kv; kv = this._extractKeyValue())
{ | |
98 if (this._lastCookie) | |
99 this._lastCookie.addAttribute(kv.key, kv.value); | |
100 else | |
101 this._addCookie(kv, WebInspector.Cookie.Type.Response); | |
102 if (this._advanceAndCheckCookieDelimiter()) | |
103 this._flushCookie(); | |
104 } | |
105 this._flushCookie(); | |
106 return this._cookies; | |
107 }, | |
108 | |
109 /** | |
110 * @param {string|undefined} headerValue | |
111 * @return {boolean} | |
112 */ | |
113 _initialize: function(headerValue) | |
114 { | |
115 this._input = headerValue; | |
116 if (typeof headerValue !== "string") | |
117 return false; | |
118 this._cookies = []; | |
119 this._lastCookie = null; | |
120 this._originalInputLength = this._input.length; | |
121 return true; | |
122 }, | |
123 | |
124 _flushCookie: function() | |
125 { | |
126 if (this._lastCookie) | |
127 this._lastCookie.setSize(this._originalInputLength - this._input.len
gth - this._lastCookiePosition); | |
128 this._lastCookie = null; | |
129 }, | |
130 | |
131 /** | |
132 * @return {?WebInspector.CookieParser.KeyValue} | |
133 */ | |
134 _extractKeyValue: function() | |
135 { | |
136 if (!this._input || !this._input.length) | |
137 return null; | |
138 // Note: RFCs offer an option for quoted values that may contain commas
and semicolons. | |
139 // Many browsers/platforms do not support this, however (see http://webk
it.org/b/16699 | |
140 // and http://crbug.com/12361). The logic below matches latest versions
of IE, Firefox, | |
141 // Chrome and Safari on some old platforms. The latest version of Safari
supports quoted | |
142 // cookie values, though. | |
143 var keyValueMatch = /^[ \t]*([^\s=;]+)[ \t]*(?:=[ \t]*([^;\n]*))?/.exec(
this._input); | |
144 if (!keyValueMatch) { | |
145 console.log("Failed parsing cookie header before: " + this._input); | |
146 return null; | |
147 } | |
148 | |
149 var result = new WebInspector.CookieParser.KeyValue(keyValueMatch[1], ke
yValueMatch[2] && keyValueMatch[2].trim(), this._originalInputLength - this._inp
ut.length); | |
150 this._input = this._input.slice(keyValueMatch[0].length); | |
151 return result; | |
152 }, | |
153 | |
154 /** | |
155 * @return {boolean} | |
156 */ | |
157 _advanceAndCheckCookieDelimiter: function() | |
158 { | |
159 var match = /^\s*[\n;]\s*/.exec(this._input); | |
160 if (!match) | |
161 return false; | |
162 this._input = this._input.slice(match[0].length); | |
163 return match[0].match("\n") !== null; | |
164 }, | |
165 | |
166 /** | |
167 * @param {!WebInspector.CookieParser.KeyValue} keyValue | |
168 * @param {!WebInspector.Cookie.Type} type | |
169 */ | |
170 _addCookie: function(keyValue, type) | |
171 { | |
172 if (this._lastCookie) | |
173 this._lastCookie.setSize(keyValue.position - this._lastCookiePositio
n); | |
174 // Mozilla bug 169091: Mozilla, IE and Chrome treat single token (w/o "=
") as | |
175 // specifying a value for a cookie with empty name. | |
176 this._lastCookie = typeof keyValue.value === "string" ? new WebInspector
.Cookie(this._target, keyValue.key, keyValue.value, type) : | |
177 new WebInspector.Cookie(this._target, "", keyValue.key, type); | |
178 this._lastCookiePosition = keyValue.position; | |
179 this._cookies.push(this._lastCookie); | |
180 } | |
181 }; | |
182 | 198 |
183 /** | 199 /** |
184 * @param {!WebInspector.Target} target | 200 * @unrestricted |
185 * @param {string|undefined} header | |
186 * @return {?Array.<!WebInspector.Cookie>} | |
187 */ | 201 */ |
188 WebInspector.CookieParser.parseCookie = function(target, header) | 202 WebInspector.Cookie = class { |
189 { | 203 /** |
190 return (new WebInspector.CookieParser(target)).parseCookie(header); | 204 * @param {!WebInspector.Target} target |
191 }; | 205 * @param {string} name |
192 | 206 * @param {string} value |
193 /** | 207 * @param {?WebInspector.Cookie.Type} type |
194 * @param {!WebInspector.Target} target | 208 */ |
195 * @param {string|undefined} header | 209 constructor(target, name, value, type) { |
196 * @return {?Array.<!WebInspector.Cookie>} | |
197 */ | |
198 WebInspector.CookieParser.parseSetCookie = function(target, header) | |
199 { | |
200 return (new WebInspector.CookieParser(target)).parseSetCookie(header); | |
201 }; | |
202 | |
203 /** | |
204 * @constructor | |
205 * @param {!WebInspector.Target} target | |
206 * @param {string} name | |
207 * @param {string} value | |
208 * @param {?WebInspector.Cookie.Type} type | |
209 */ | |
210 WebInspector.Cookie = function(target, name, value, type) | |
211 { | |
212 this._target = target; | 210 this._target = target; |
213 this._name = name; | 211 this._name = name; |
214 this._value = value; | 212 this._value = value; |
215 this._type = type; | 213 this._type = type; |
216 this._attributes = {}; | 214 this._attributes = {}; |
217 }; | 215 } |
218 | 216 |
219 WebInspector.Cookie.prototype = { | 217 /** |
220 /** | 218 * @return {string} |
221 * @return {string} | 219 */ |
222 */ | 220 name() { |
223 name: function() | 221 return this._name; |
224 { | 222 } |
225 return this._name; | 223 |
226 }, | 224 /** |
227 | 225 * @return {string} |
228 /** | 226 */ |
229 * @return {string} | 227 value() { |
230 */ | 228 return this._value; |
231 value: function() | 229 } |
232 { | 230 |
233 return this._value; | 231 /** |
234 }, | 232 * @return {?WebInspector.Cookie.Type} |
235 | 233 */ |
236 /** | 234 type() { |
237 * @return {?WebInspector.Cookie.Type} | 235 return this._type; |
238 */ | 236 } |
239 type: function() | 237 |
240 { | 238 /** |
241 return this._type; | 239 * @return {boolean} |
242 }, | 240 */ |
243 | 241 httpOnly() { |
244 /** | 242 return 'httponly' in this._attributes; |
245 * @return {boolean} | 243 } |
246 */ | 244 |
247 httpOnly: function() | 245 /** |
248 { | 246 * @return {boolean} |
249 return "httponly" in this._attributes; | 247 */ |
250 }, | 248 secure() { |
251 | 249 return 'secure' in this._attributes; |
252 /** | 250 } |
253 * @return {boolean} | 251 |
254 */ | 252 /** |
255 secure: function() | 253 * @return {string} |
256 { | 254 */ |
257 return "secure" in this._attributes; | 255 sameSite() { |
258 }, | 256 return this._attributes['samesite']; |
259 | 257 } |
260 /** | 258 |
261 * @return {string} | 259 /** |
262 */ | 260 * @return {boolean} |
263 sameSite: function() | 261 */ |
264 { | 262 session() { |
265 return this._attributes["samesite"]; | 263 // RFC 2965 suggests using Discard attribute to mark session cookies, but th
is does not seem to be widely used. |
266 }, | 264 // Check for absence of explicitly max-age or expiry date instead. |
267 | 265 return !('expires' in this._attributes || 'max-age' in this._attributes); |
268 /** | 266 } |
269 * @return {boolean} | 267 |
270 */ | 268 /** |
271 session: function() | 269 * @return {string} |
272 { | 270 */ |
273 // RFC 2965 suggests using Discard attribute to mark session cookies, bu
t this does not seem to be widely used. | 271 path() { |
274 // Check for absence of explicitly max-age or expiry date instead. | 272 return this._attributes['path']; |
275 return !("expires" in this._attributes || "max-age" in this._attributes)
; | 273 } |
276 }, | 274 |
277 | 275 /** |
278 /** | 276 * @return {string} |
279 * @return {string} | 277 */ |
280 */ | 278 port() { |
281 path: function() | 279 return this._attributes['port']; |
282 { | 280 } |
283 return this._attributes["path"]; | 281 |
284 }, | 282 /** |
285 | 283 * @return {string} |
286 /** | 284 */ |
287 * @return {string} | 285 domain() { |
288 */ | 286 return this._attributes['domain']; |
289 port: function() | 287 } |
290 { | 288 |
291 return this._attributes["port"]; | 289 /** |
292 }, | 290 * @return {string} |
293 | 291 */ |
294 /** | 292 expires() { |
295 * @return {string} | 293 return this._attributes['expires']; |
296 */ | 294 } |
297 domain: function() | 295 |
298 { | 296 /** |
299 return this._attributes["domain"]; | 297 * @return {string} |
300 }, | 298 */ |
301 | 299 maxAge() { |
302 /** | 300 return this._attributes['max-age']; |
303 * @return {string} | 301 } |
304 */ | 302 |
305 expires: function() | 303 /** |
306 { | 304 * @return {number} |
307 return this._attributes["expires"]; | 305 */ |
308 }, | 306 size() { |
309 | 307 return this._size; |
310 /** | 308 } |
311 * @return {string} | 309 |
312 */ | 310 /** |
313 maxAge: function() | 311 * @param {number} size |
314 { | 312 */ |
315 return this._attributes["max-age"]; | 313 setSize(size) { |
316 }, | 314 this._size = size; |
317 | 315 } |
318 /** | 316 |
319 * @return {number} | 317 /** |
320 */ | 318 * @return {?Date} |
321 size: function() | 319 */ |
322 { | 320 expiresDate(requestDate) { |
323 return this._size; | 321 // RFC 6265 indicates that the max-age attribute takes precedence over the e
xpires attribute |
324 }, | 322 if (this.maxAge()) { |
325 | 323 var targetDate = requestDate === null ? new Date() : requestDate; |
326 /** | 324 return new Date(targetDate.getTime() + 1000 * this.maxAge()); |
327 * @param {number} size | |
328 */ | |
329 setSize: function(size) | |
330 { | |
331 this._size = size; | |
332 }, | |
333 | |
334 /** | |
335 * @return {?Date} | |
336 */ | |
337 expiresDate: function(requestDate) | |
338 { | |
339 // RFC 6265 indicates that the max-age attribute takes precedence over t
he expires attribute | |
340 if (this.maxAge()) { | |
341 var targetDate = requestDate === null ? new Date() : requestDate; | |
342 return new Date(targetDate.getTime() + 1000 * this.maxAge()); | |
343 } | |
344 | |
345 if (this.expires()) | |
346 return new Date(this.expires()); | |
347 | |
348 return null; | |
349 }, | |
350 | |
351 /** | |
352 * @return {!Object} | |
353 */ | |
354 attributes: function() | |
355 { | |
356 return this._attributes; | |
357 }, | |
358 | |
359 /** | |
360 * @param {string} key | |
361 * @param {string=} value | |
362 */ | |
363 addAttribute: function(key, value) | |
364 { | |
365 this._attributes[key.toLowerCase()] = value; | |
366 }, | |
367 | |
368 /** | |
369 * @param {function(?Protocol.Error)=} callback | |
370 */ | |
371 remove: function(callback) | |
372 { | |
373 this._target.networkAgent().deleteCookie(this.name(), (this.secure() ? "
https://" : "http://") + this.domain() + this.path(), callback); | |
374 } | 325 } |
| 326 |
| 327 if (this.expires()) |
| 328 return new Date(this.expires()); |
| 329 |
| 330 return null; |
| 331 } |
| 332 |
| 333 /** |
| 334 * @return {!Object} |
| 335 */ |
| 336 attributes() { |
| 337 return this._attributes; |
| 338 } |
| 339 |
| 340 /** |
| 341 * @param {string} key |
| 342 * @param {string=} value |
| 343 */ |
| 344 addAttribute(key, value) { |
| 345 this._attributes[key.toLowerCase()] = value; |
| 346 } |
| 347 |
| 348 /** |
| 349 * @param {function(?Protocol.Error)=} callback |
| 350 */ |
| 351 remove(callback) { |
| 352 this._target.networkAgent().deleteCookie( |
| 353 this.name(), (this.secure() ? 'https://' : 'http://') + this.domain() +
this.path(), callback); |
| 354 } |
375 }; | 355 }; |
376 | 356 |
377 /** | 357 /** |
378 * @enum {number} | 358 * @enum {number} |
379 */ | 359 */ |
380 WebInspector.Cookie.Type = { | 360 WebInspector.Cookie.Type = { |
381 Request: 0, | 361 Request: 0, |
382 Response: 1 | 362 Response: 1 |
383 }; | 363 }; |
384 | 364 |
385 WebInspector.Cookies = {}; | 365 WebInspector.Cookies = {}; |
386 | 366 |
387 /** | 367 /** |
388 * @param {function(!Array.<!WebInspector.Cookie>)} callback | 368 * @param {function(!Array.<!WebInspector.Cookie>)} callback |
389 */ | 369 */ |
390 WebInspector.Cookies.getCookiesAsync = function(callback) | 370 WebInspector.Cookies.getCookiesAsync = function(callback) { |
391 { | 371 var allCookies = []; |
392 var allCookies = []; | 372 /** |
393 /** | 373 * @param {!WebInspector.Target} target |
394 * @param {!WebInspector.Target} target | 374 * @param {?Protocol.Error} error |
395 * @param {?Protocol.Error} error | 375 * @param {!Array.<!NetworkAgent.Cookie>} cookies |
396 * @param {!Array.<!NetworkAgent.Cookie>} cookies | 376 */ |
397 */ | 377 function mycallback(target, error, cookies) { |
398 function mycallback(target, error, cookies) | 378 if (error) { |
399 { | 379 console.error(error); |
400 if (error) { | 380 return; |
401 console.error(error); | |
402 return; | |
403 } | |
404 for (var i = 0; i < cookies.length; ++i) | |
405 allCookies.push(WebInspector.Cookies._parseProtocolCookie(target, co
okies[i])); | |
406 } | 381 } |
| 382 for (var i = 0; i < cookies.length; ++i) |
| 383 allCookies.push(WebInspector.Cookies._parseProtocolCookie(target, cookies[
i])); |
| 384 } |
407 | 385 |
408 var barrier = new CallbackBarrier(); | 386 var barrier = new CallbackBarrier(); |
409 for (var target of WebInspector.targetManager.targets(WebInspector.Target.Ca
pability.Network)) | 387 for (var target of WebInspector.targetManager.targets(WebInspector.Target.Capa
bility.Network)) |
410 target.networkAgent().getCookies(barrier.createCallback(mycallback.bind(
null, target))); | 388 target.networkAgent().getCookies(barrier.createCallback(mycallback.bind(null
, target))); |
411 barrier.callWhenDone(callback.bind(null, allCookies)); | 389 barrier.callWhenDone(callback.bind(null, allCookies)); |
412 }; | 390 }; |
413 | 391 |
414 /** | 392 /** |
415 * @param {!WebInspector.Target} target | 393 * @param {!WebInspector.Target} target |
416 * @param {!NetworkAgent.Cookie} protocolCookie | 394 * @param {!NetworkAgent.Cookie} protocolCookie |
417 * @return {!WebInspector.Cookie} | 395 * @return {!WebInspector.Cookie} |
418 */ | 396 */ |
419 WebInspector.Cookies._parseProtocolCookie = function(target, protocolCookie) | 397 WebInspector.Cookies._parseProtocolCookie = function(target, protocolCookie) { |
420 { | 398 var cookie = new WebInspector.Cookie(target, protocolCookie.name, protocolCook
ie.value, null); |
421 var cookie = new WebInspector.Cookie(target, protocolCookie.name, protocolCo
okie.value, null); | 399 cookie.addAttribute('domain', protocolCookie['domain']); |
422 cookie.addAttribute("domain", protocolCookie["domain"]); | 400 cookie.addAttribute('path', protocolCookie['path']); |
423 cookie.addAttribute("path", protocolCookie["path"]); | 401 cookie.addAttribute('port', protocolCookie['port']); |
424 cookie.addAttribute("port", protocolCookie["port"]); | 402 if (protocolCookie['expires']) |
425 if (protocolCookie["expires"]) | 403 cookie.addAttribute('expires', protocolCookie['expires']); |
426 cookie.addAttribute("expires", protocolCookie["expires"]); | 404 if (protocolCookie['httpOnly']) |
427 if (protocolCookie["httpOnly"]) | 405 cookie.addAttribute('httpOnly'); |
428 cookie.addAttribute("httpOnly"); | 406 if (protocolCookie['secure']) |
429 if (protocolCookie["secure"]) | 407 cookie.addAttribute('secure'); |
430 cookie.addAttribute("secure"); | 408 if (protocolCookie['sameSite']) |
431 if (protocolCookie["sameSite"]) | 409 cookie.addAttribute('sameSite', protocolCookie['sameSite']); |
432 cookie.addAttribute("sameSite", protocolCookie["sameSite"]); | 410 cookie.setSize(protocolCookie['size']); |
433 cookie.setSize(protocolCookie["size"]); | 411 return cookie; |
434 return cookie; | |
435 }; | 412 }; |
436 | 413 |
437 /** | 414 /** |
438 * @param {!WebInspector.Cookie} cookie | 415 * @param {!WebInspector.Cookie} cookie |
439 * @param {string} resourceURL | 416 * @param {string} resourceURL |
440 * @return {boolean} | 417 * @return {boolean} |
441 */ | 418 */ |
442 WebInspector.Cookies.cookieMatchesResourceURL = function(cookie, resourceURL) | 419 WebInspector.Cookies.cookieMatchesResourceURL = function(cookie, resourceURL) { |
443 { | 420 var url = resourceURL.asParsedURL(); |
444 var url = resourceURL.asParsedURL(); | 421 if (!url || !WebInspector.Cookies.cookieDomainMatchesResourceDomain(cookie.dom
ain(), url.host)) |
445 if (!url || !WebInspector.Cookies.cookieDomainMatchesResourceDomain(cookie.d
omain(), url.host)) | 422 return false; |
446 return false; | 423 return ( |
447 return (url.path.startsWith(cookie.path()) | 424 url.path.startsWith(cookie.path()) && (!cookie.port() || url.port === cook
ie.port()) && |
448 && (!cookie.port() || url.port === cookie.port()) | 425 (!cookie.secure() || url.scheme === 'https')); |
449 && (!cookie.secure() || url.scheme === "https")); | |
450 }; | 426 }; |
451 | 427 |
452 /** | 428 /** |
453 * @param {string} cookieDomain | 429 * @param {string} cookieDomain |
454 * @param {string} resourceDomain | 430 * @param {string} resourceDomain |
455 * @return {boolean} | 431 * @return {boolean} |
456 */ | 432 */ |
457 WebInspector.Cookies.cookieDomainMatchesResourceDomain = function(cookieDomain,
resourceDomain) | 433 WebInspector.Cookies.cookieDomainMatchesResourceDomain = function(cookieDomain,
resourceDomain) { |
458 { | 434 if (cookieDomain.charAt(0) !== '.') |
459 if (cookieDomain.charAt(0) !== ".") | 435 return resourceDomain === cookieDomain; |
460 return resourceDomain === cookieDomain; | 436 return !!resourceDomain.match(new RegExp('^([^\\.]+\\.)*' + cookieDomain.subst
ring(1).escapeForRegExp() + '$', 'i')); |
461 return !!resourceDomain.match(new RegExp("^([^\\.]+\\.)*" + cookieDomain.sub
string(1).escapeForRegExp() + "$", "i")); | |
462 }; | 437 }; |
OLD | NEW |