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