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 {
47 public CookieParser (string header) : this (header, 0)
51 public CookieParser (string header, int position)
55 this.length = header.Length;
58 public IEnumerable<Cookie> Parse ()
60 while (pos < length) {
65 while ((pos < length) && (header [pos] != ','))
76 var name = GetCookieName ();
78 return new Cookie (name, string.Empty);
80 var value = string.Empty;
81 if (header [pos] == '=') {
83 value = GetCookieValue ();
86 var cookie = new Cookie (name, value);
90 } else if (header [pos] == ',') {
93 } else if ((header [pos++] != ';') || (pos >= length)) {
97 while (pos < length) {
98 var argName = GetCookieName ();
99 string argVal = string.Empty;
100 if ((pos < length) && (header [pos] == '=')) {
102 argVal = GetCookieValue ();
104 ProcessArg (cookie, argName, argVal);
108 if (header [pos] == ',') {
111 } else if (header [pos] != ';') {
121 void ProcessArg (Cookie cookie, string name, string val)
123 if ((name == null) || (name == string.Empty))
124 throw new InvalidOperationException ();
126 name = name.ToUpper ();
129 if (cookie.Comment == null)
130 cookie.Comment = val;
133 if (cookie.CommentUri == null)
134 cookie.CommentUri = new Uri (val);
137 cookie.Discard = true;
140 if (cookie.Domain == "")
144 cookie.HttpOnly = true;
146 case "MAX-AGE": // RFC Style Set-Cookie2
147 if (cookie.Expires == DateTime.MinValue) {
149 cookie.Expires = cookie.TimeStamp.AddSeconds (UInt32.Parse (val));
153 case "EXPIRES": // Netscape Style Set-Cookie
154 if (cookie.Expires != DateTime.MinValue)
157 if ((pos < length) && (header [pos] == ',') && IsWeekDay (val)) {
159 val = val + ", " + GetCookieValue ();
162 cookie.Expires = CookieParser.TryParseCookieExpires (val);
168 if (cookie.Port == null)
172 cookie.Secure = true;
176 cookie.Version = (int) UInt32.Parse (val);
182 string GetCookieName ()
185 while (k < length && Char.IsWhiteSpace (header [k]))
189 while (k < length && header [k] != ';' && header [k] != ',' && header [k] != '=')
193 return header.Substring (begin, k - begin).Trim ();
196 string GetCookieValue ()
202 while (k < length && Char.IsWhiteSpace (header [k]))
206 if (header [k] == '"'){
210 while (k < length && header [k] != '"')
213 for (j = ++k; j < length && header [j] != ';' && header [j] != ','; j++)
218 while (k < length && header [k] != ';' && header [k] != ',')
223 return header.Substring (begin, k - begin).Trim ();
226 static bool IsWeekDay (string value)
228 foreach (string day in weekDays) {
229 if (value.ToLower ().Equals (day))
235 static string[] weekDays =
236 new string[] { "mon", "tue", "wed", "thu", "fri", "sat", "sun",
237 "monday", "tuesday", "wednesday", "thursday",
238 "friday", "saturday", "sunday" };
240 static string[] cookieExpiresFormats =
242 "ddd, dd'-'MMM'-'yyyy HH':'mm':'ss 'GMT'",
243 "ddd, dd'-'MMM'-'yy HH':'mm':'ss 'GMT'" };
245 static DateTime TryParseCookieExpires (string value)
247 if (String.IsNullOrEmpty (value))
248 return DateTime.MinValue;
250 for (int i = 0; i < cookieExpiresFormats.Length; i++) {
252 DateTime cookieExpiresUtc = DateTime.ParseExact (value, cookieExpiresFormats [i], CultureInfo.InvariantCulture);
254 //convert UTC/GMT time to local time
255 cookieExpiresUtc = DateTime.SpecifyKind (cookieExpiresUtc, DateTimeKind.Utc);
256 return TimeZone.CurrentTimeZone.ToLocalTime (cookieExpiresUtc);
260 //If we can't parse Expires, use cookie as session cookie (expires is DateTime.MinValue)
261 return DateTime.MinValue;