1 // 2 // System.Web.HttpCookie.cs 3 // 4 // Author: 5 // Chris Toshok (toshok@novell.com) 6 // Katharina Bogad (bogad@cs.tum.edu) 7 // 8 9 // 10 // Copyright (C) 2005-2009 Novell, Inc (http://www.novell.com) 11 // 12 // Permission is hereby granted, free of charge, to any person obtaining 13 // a copy of this software and associated documentation files (the 14 // "Software"), to deal in the Software without restriction, including 15 // without limitation the rights to use, copy, modify, merge, publish, 16 // distribute, sublicense, and/or sell copies of the Software, and to 17 // permit persons to whom the Software is furnished to do so, subject to 18 // the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be 21 // included in all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 // 31 32 using System.Text; 33 using System.Collections.Specialized; 34 using System.Security.Permissions; 35 using System.Web.Configuration; 36 37 namespace System.Web 38 { 39 [Flags] 40 internal enum CookieFlags : byte { 41 Secure = 1, 42 HttpOnly = 2 43 } 44 45 // CAS - no InheritanceDemand here as the class is sealed 46 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] 47 public sealed class HttpCookie { 48 49 string path = "/"; 50 string domain; 51 DateTime expires = DateTime.MinValue; 52 string name; 53 CookieFlags flags = 0; 54 NameValueCollection values; 55 56 [Obsolete] HttpCookie(string name, string value, string path, DateTime expires)57 internal HttpCookie (string name, string value, string path, DateTime expires) 58 { 59 this.name = name; 60 this.values = new CookieNVC(); 61 this.Value = value; 62 this.path = path; 63 this.expires = expires; 64 } 65 HttpCookie(string name)66 public HttpCookie (string name) 67 { 68 this.name = name; 69 values = new CookieNVC(); 70 Value = ""; 71 72 HttpCookiesSection cookieConfig = (HttpCookiesSection) WebConfigurationManager.GetSection ("system.web/httpCookies"); 73 74 if(!string.IsNullOrWhiteSpace(cookieConfig.Domain)) 75 domain = cookieConfig.Domain; 76 77 if(cookieConfig.HttpOnlyCookies) 78 flags |= CookieFlags.HttpOnly; 79 80 if(cookieConfig.RequireSSL) 81 flags |= CookieFlags.Secure; 82 } 83 HttpCookie(string name, string value)84 public HttpCookie (string name, string value) 85 : this (name) 86 { 87 Value = value; 88 } 89 GetCookieHeaderValue()90 internal string GetCookieHeaderValue () 91 { 92 StringBuilder builder = new StringBuilder (); 93 94 builder.Append (name); 95 builder.Append ("="); 96 builder.Append (Value); 97 98 if (domain != null) { 99 builder.Append ("; domain="); 100 builder.Append (domain); 101 } 102 103 if (path != null) { 104 builder.Append ("; path="); 105 builder.Append (path); 106 } 107 108 if (expires != DateTime.MinValue) { 109 builder.Append ("; expires="); 110 builder.Append (expires.ToUniversalTime().ToString("r")); 111 } 112 113 if ((flags & CookieFlags.Secure) != 0) { 114 builder.Append ("; secure"); 115 } 116 117 if ((flags & CookieFlags.HttpOnly) != 0){ 118 builder.Append ("; HttpOnly"); 119 } 120 121 return builder.ToString (); 122 } 123 124 public string Domain { 125 get { 126 return domain; 127 } 128 set { 129 domain = value; 130 } 131 } 132 133 public DateTime Expires { 134 get { 135 return expires; 136 } 137 set { 138 expires = value; 139 } 140 } 141 142 public bool HasKeys { 143 get { 144 return values.HasKeys(); 145 } 146 } 147 148 149 public string this [ string key ] { 150 get { 151 return values [ key ]; 152 } 153 set { 154 values [ key ] = value; 155 } 156 } 157 158 public string Name { 159 get { 160 return name; 161 } 162 set { 163 name = value; 164 } 165 } 166 167 public string Path { 168 get { 169 return path; 170 } 171 set { 172 path = value; 173 } 174 } 175 176 public bool Secure { 177 get { 178 return (flags & CookieFlags.Secure) == CookieFlags.Secure; 179 } 180 set { 181 if (value) 182 flags |= CookieFlags.Secure; 183 else 184 flags &= ~CookieFlags.Secure; 185 } 186 } 187 188 public string Value { 189 get { 190 return HttpUtility.UrlDecode(values.ToString ()); 191 } 192 set { 193 values.Clear (); 194 195 if (value != null && value != "") { 196 string [] components = value.Split ('&'); 197 foreach (string kv in components){ 198 int pos = kv.IndexOf ('='); 199 if (pos == -1){ 200 values.Add (null, kv); 201 } else { 202 string key = kv.Substring (0, pos); 203 string val = kv.Substring (pos+1); 204 205 values.Add (key, val); 206 } 207 } 208 } 209 } 210 } 211 212 public NameValueCollection Values { 213 get { 214 return values; 215 } 216 } 217 218 public bool HttpOnly { 219 get { 220 return (flags & CookieFlags.HttpOnly) == CookieFlags.HttpOnly; 221 } 222 223 set { 224 if (value) 225 flags |= CookieFlags.HttpOnly; 226 else 227 flags &= ~CookieFlags.HttpOnly; 228 } 229 } 230 231 /* 232 * simple utility class that just overrides ToString 233 * to get the desired behavior for 234 * HttpCookie.Values 235 */ 236 [Serializable] 237 sealed class CookieNVC : NameValueCollection 238 { CookieNVC()239 public CookieNVC () 240 : base (StringComparer.OrdinalIgnoreCase) 241 { 242 } 243 ToString()244 public override string ToString () 245 { 246 StringBuilder builder = new StringBuilder (""); 247 248 bool first_key = true; 249 foreach (string key in Keys) { 250 if (!first_key) 251 builder.Append ("&"); 252 253 string[] vals = GetValues (key); 254 if(vals == null) 255 vals = new string[1] {String.Empty}; 256 257 bool first_val = true; 258 foreach (string v in vals) { 259 if (!first_val) 260 builder.Append ("&"); 261 262 if (key != null && key.Length > 0) { 263 builder.Append (HttpUtility.UrlEncode(key)); 264 builder.Append ("="); 265 } 266 if(v != null && v.Length > 0) 267 builder.Append (HttpUtility.UrlEncode(v)); 268 269 first_val = false; 270 } 271 first_key = false; 272 } 273 274 return builder.ToString(); 275 } 276 277 /* MS's implementation has the interesting quirk that if you do: 278 * cookie.Values[null] = "foo" 279 * it clears out the rest of the values. 280 */ Set(string name, string value)281 public override void Set (string name, string value) 282 { 283 if (this.IsReadOnly) 284 throw new NotSupportedException ("Collection is read-only"); 285 286 if (name == null) { 287 Clear(); 288 name = string.Empty; 289 } 290 // if (value == null) 291 // value = string.Empty; 292 293 base.Set (name, value); 294 } 295 } 296 } 297 } 298