2 // System.Net.CookieParser
5 // Lawrence Pit (loz@cable.a2000.nl)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // Daniel Nauck (dna(at)mono-project(dot)de)
9 // (c) 2002 Lawrence Pit
10 // (c) 2003 Ximian, Inc. (http://www.ximian.com)
11 // (c) 2008 Daniel Nauck
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System.Collections;
37 using System.Collections.Generic;
38 using System.Globalization;
40 namespace System.Net {
44 static readonly string[] cookieExpiresFormats =
46 "ddd, dd'-'MMM'-'yyyy HH':'mm':'ss 'GMT'",
47 "ddd, dd'-'MMM'-'yy HH':'mm':'ss 'GMT'" };
49 readonly string header;
53 public CookieParser (string header)
56 this.length = header.Length;
60 public IEnumerable<Cookie> Parse ()
62 while (pos < length) {
67 while ((pos < length) && (header [pos] != ','))
78 var name = GetCookieName ();
80 return new Cookie (name, string.Empty);
82 var value = string.Empty;
83 if (header [pos] == '=') {
85 value = GetCookieValue ();
88 var cookie = new Cookie (name, value);
92 } else if (header [pos] == ',') {
95 } else if ((header [pos++] != ';') || (pos >= length)) {
99 while (pos < length) {
100 var argName = GetCookieName ();
101 string argVal = string.Empty;
102 if ((pos < length) && (header [pos] == '=')) {
104 argVal = GetCookieValue ();
106 ProcessArg (cookie, argName, argVal);
110 if (header [pos] == ',') {
113 } else if (header [pos] != ';') {
123 void ProcessArg (Cookie cookie, string name, string val)
125 if ((name == null) || (name == string.Empty))
126 throw new InvalidOperationException ();
128 switch (name.ToUpperInvariant ()) {
130 if (cookie.Comment == null)
131 cookie.Comment = val;
134 if (cookie.CommentUri == null)
135 cookie.CommentUri = new Uri (val);
138 cookie.Discard = true;
141 if (cookie.Domain == "")
145 cookie.HttpOnly = true;
147 case "MAX-AGE": // RFC Style Set-Cookie2
148 if (cookie.Expires == DateTime.MinValue) {
150 cookie.Expires = cookie.TimeStamp.AddSeconds (UInt32.Parse (val));
154 case "EXPIRES": // Netscape Style Set-Cookie
155 if (cookie.Expires != DateTime.MinValue)
158 if ((pos < length) && (header [pos] == ',') && IsWeekDay (val)) {
160 val = val + ", " + GetCookieValue ();
163 cookie.Expires = TryParseCookieExpires (val);
169 if (cookie.Port == null)
173 cookie.Secure = true;
177 cookie.Version = (int) UInt32.Parse (val);
183 string GetCookieName ()
186 while (k < length && Char.IsWhiteSpace (header [k]))
190 while (k < length && header [k] != ';' && header [k] != ',' && header [k] != '=')
194 return header.Substring (begin, k - begin).Trim ();
197 string GetCookieValue ()
203 while (k < length && Char.IsWhiteSpace (header [k]))
207 if (header [k] == '"'){
211 while (k < length && header [k] != '"')
214 for (j = ++k; j < length && header [j] != ';' && header [j] != ','; j++)
219 while (k < length && header [k] != ';' && header [k] != ',')
224 return header.Substring (begin, k - begin).Trim ();
227 static bool IsWeekDay (string value)
229 switch (value.ToLowerInvariant ()) {
250 static DateTime TryParseCookieExpires (string value)
252 if (String.IsNullOrEmpty (value))
253 return DateTime.MinValue;
255 for (int i = 0; i < cookieExpiresFormats.Length; i++) {
257 DateTime cookieExpiresUtc = DateTime.ParseExact (value, cookieExpiresFormats [i], CultureInfo.InvariantCulture);
259 //convert UTC/GMT time to local time
260 cookieExpiresUtc = DateTime.SpecifyKind (cookieExpiresUtc, DateTimeKind.Utc);
261 return TimeZone.CurrentTimeZone.ToLocalTime (cookieExpiresUtc);
265 //If we can't parse Expires, use cookie as session cookie (expires is DateTime.MinValue)
266 return DateTime.MinValue;