File: HttpCookie.cs

package info (click to toggle)
mono 6.14.1%2Bds2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,282,732 kB
  • sloc: cs: 11,182,461; xml: 2,850,281; ansic: 699,123; cpp: 122,919; perl: 58,604; javascript: 30,841; asm: 21,845; makefile: 19,602; sh: 10,973; python: 4,772; pascal: 925; sql: 859; sed: 16; php: 1
file content (480 lines) | stat: -rw-r--r-- 14,980 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
//------------------------------------------------------------------------------
// <copyright file="HttpCookie.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------

/*
 * HttpCookie - collection + name + path
 *
 * Copyright (c) 1998 Microsoft Corporation
 */

namespace System.Web {
    using System.Text;
    using System.Collections;
    using System.Collections.Specialized;
    using System.Globalization;
    using System.Security.Permissions;
    using System.Web.Configuration;
    using System.Web.Management;
    using Util;


    /// <devdoc>
    ///    <para>
    ///       Provides a type-safe way
    ///       to access multiple HTTP cookies.
    ///    </para>
    /// </devdoc>
    public sealed class HttpCookie {
        private String _name;
        private String _path = "/";
        private bool _secure;
        private bool _httpOnly;
        private String _domain;
        private bool _expirationSet;
        private DateTime _expires;
        private String _stringValue;
        private HttpValueCollection _multiValue;
        private bool _changed;
        private bool _added;

        internal HttpCookie() {
            _changed = true;
        }

        /*
         * Constructor - empty cookie with name
         */

        /// <devdoc>
        ///    <para>
        ///       Initializes a new instance of the <see cref='System.Web.HttpCookie'/>
        ///       class.
        ///    </para>
        /// </devdoc>
        public HttpCookie(String name) {
            _name = name;

            SetDefaultsFromConfig();
            _changed = true;
        }

        /*
         * Constructor - cookie with name and value
         */

        /// <devdoc>
        ///    <para>
        ///       Initializes a new instance of the <see cref='System.Web.HttpCookie'/>
        ///       class.
        ///    </para>
        /// </devdoc>
        public HttpCookie(String name, String value) {
            _name = name;
            _stringValue = value;

            SetDefaultsFromConfig();
            _changed = true;
        }

        private void SetDefaultsFromConfig() {
            HttpCookiesSection config = RuntimeConfig.GetConfig().HttpCookies;
            _secure = config.RequireSSL;
            _httpOnly = config.HttpOnlyCookies;
            
            if (config.Domain != null && config.Domain.Length > 0)
                _domain = config.Domain;
        }

        /*
         * Whether the cookie contents have changed
         */
        internal bool Changed {
            get { return _changed; }
            set { _changed = value; }
        }

        /*
         * Whether the cookie has been added
         */
        internal bool Added {
            get { return _added; }
            set { _added = value; }
        }

        // DevID 251951	Cookie is getting duplicated by ASP.NET when they are added via a native module
        // This flag is used to remember that this cookie came from an IIS Set-Header flag, 
        // so we don't duplicate it and send it back to IIS
        internal bool IsInResponseHeader {
            get;
            set;
        }

        /*
         * Cookie name
         */

        /// <devdoc>
        ///    <para>
        ///       Gets
        ///       or sets the name of cookie.
        ///    </para>
        /// </devdoc>
        public String Name {
            get { return _name;}
            set { 
                _name = value;
                _changed = true;
            }
        }

        /*
         * Cookie path
         */

        /// <devdoc>
        ///    <para>
        ///       Gets or sets the URL prefix to transmit with the
        ///       current cookie.
        ///    </para>
        /// </devdoc>
        public String Path {
            get { return _path;}
            set { 
                _path = value;
                _changed = true;
            }
        }

        /*
         * 'Secure' flag
         */

        /// <devdoc>
        ///    <para>
        ///       Indicates whether the cookie should be transmitted only over HTTPS.
        ///    </para>
        /// </devdoc>
        public bool Secure {
            get { return _secure;}
            set { 
                _secure = value;
                _changed = true;
            }
        }

        /// <summary>
        /// Determines whether this cookie is allowed to participate in output caching.
        /// </summary>
        /// <remarks>
        /// If a given HttpResponse contains one or more outbound cookies with Shareable = false (the default value),
        /// output caching will be suppressed for that response. This prevents cookies that contain potentially
        /// sensitive information, e.g. FormsAuth cookies, from being cached in the response and sent to multiple
        /// clients. If a developer wants to allow a response containing cookies to be cached, he should configure
        /// caching as normal for the response, e.g. via the OutputCache directive, MVC's [OutputCache] attribute,
        /// etc., and he should make sure that all outbound cookies are marked Shareable = true.
        /// </remarks>
        public bool Shareable {
            get;
            set; // don't need to set _changed flag since Set-Cookie header isn't affected by value of Shareable
        }

        /// <devdoc>
        ///    <para>
        ///       Indicates whether the cookie should have HttpOnly attribute
        ///    </para>
        /// </devdoc>
        public bool HttpOnly {
            get { return _httpOnly;}
            set { 
                _httpOnly = value;
                _changed = true;
            }
        }

        /*
         * Cookie domain
         */

        /// <devdoc>
        ///    <para>
        ///       Restricts domain cookie is to be used with.
        ///    </para>
        /// </devdoc>
        public String Domain {
            get { return _domain;}
            set { 
                _domain = value;
                _changed = true;
            }
        }

        /*
         * Cookie expiration
         */

        /// <devdoc>
        ///    <para>
        ///       Expiration time for cookie (in minutes).
        ///    </para>
        /// </devdoc>
        public DateTime Expires {
            get {
                return(_expirationSet ? _expires : DateTime.MinValue);
            }

            set {
                _expires = value;
                _expirationSet = true;
                _changed = true;
            }
        }

        /*
         * Cookie value as string
         */

        /// <devdoc>
        ///    <para>
        ///       Gets
        ///       or
        ///       sets an individual cookie value.
        ///    </para>
        /// </devdoc>
        public String Value {
            get {
                if (_multiValue != null)
                    return _multiValue.ToString(false);
                else
                    return _stringValue;
            }

            set {
                if (_multiValue != null) {
                    // reset multivalue collection to contain
                    // single keyless value
                    _multiValue.Reset();
                    _multiValue.Add(null, value);
                }
                else {
                    // remember as string
                    _stringValue = value;
                }
                _changed = true;
            }
        }

        /*
         * Checks is cookie has sub-keys
         */

        /// <devdoc>
        ///    <para>Gets a
        ///       value indicating whether the cookie has sub-keys.</para>
        /// </devdoc>
        public bool HasKeys {
            get { return Values.HasKeys();}
        }

        private bool SupportsHttpOnly(HttpContext context) {
            if (context != null && context.Request != null) {
                HttpBrowserCapabilities browser = context.Request.Browser;
                return (browser != null && (browser.Type != "IE5" || browser.Platform != "MacPPC"));
            }
            return false;
        }

        /*
         * Cookie values as multivalue collection
         */

        /// <devdoc>
        ///    <para>Gets individual key:value pairs within a single cookie object.</para>
        /// </devdoc>
        public NameValueCollection Values {
            get {
                if (_multiValue == null) {
                    // create collection on demand
                    _multiValue = new HttpValueCollection();

                    // convert existing string value into multivalue
                    if (_stringValue != null) {
                        if (_stringValue.IndexOf('&') >= 0 || _stringValue.IndexOf('=') >= 0)
                            _multiValue.FillFromString(_stringValue);
                        else
                            _multiValue.Add(null, _stringValue);

                        _stringValue = null;
                    }
                }

                _changed = true;

                return _multiValue;
            }
        }

        /*
         * Default indexed property -- lookup the multivalue collection
         */

        /// <devdoc>
        ///    <para>
        ///       Shortcut for HttpCookie$Values[key]. Required for ASP compatibility.
        ///    </para>
        /// </devdoc>
        public String this[String key]
        {
            get {
                return Values[key];
            }

            set {
                Values[key] = value;
                _changed = true;
            }
        }

        /// <summary>
        /// Converts the specified string representation of an HTTP cookie to HttpCookie
        /// </summary>
        /// <param name="input"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public static bool TryParse(string input, out HttpCookie result) {
            result = null;

            if (string.IsNullOrEmpty(input)) {
                return false;
            }

            // The substring before the first ';' is cookie-pair, with format of cookiename[=key1=val2&key2=val2&...]
            int dividerIndex = input.IndexOf(';');
            string cookiePair = dividerIndex >= 0 ? input.Substring(0, dividerIndex) : input;

            HttpCookie cookie = HttpRequest.CreateCookieFromString(cookiePair.Trim());

            // If there was no cookie name being created, stop parsing and return
            if (string.IsNullOrEmpty(cookie.Name)) {
                return false;
            }

            //
            // Parse the collections of cookie-av 
            // cookie-av = expires-av/max-age-av/domain-av/path-av/secure-av/httponly-av/extension-av
            // https://tools.ietf.org/html/rfc6265 

            while (dividerIndex >= 0 && dividerIndex < input.Length - 1) {
                int cookieAvStartIndex = dividerIndex + 1;
                dividerIndex = input.IndexOf(';', cookieAvStartIndex);
                string cookieAv = dividerIndex >= 0 ? input.Substring(cookieAvStartIndex, dividerIndex - cookieAvStartIndex).Trim() : input.Substring(cookieAvStartIndex).Trim();

                int assignmentIndex = cookieAv.IndexOf('=');
                string attributeName = assignmentIndex >= 0 ? cookieAv.Substring(0, assignmentIndex).Trim() : cookieAv;
                string attributeValue = assignmentIndex >= 0 && assignmentIndex < cookieAv.Length - 1 ? cookieAv.Substring(assignmentIndex + 1).Trim() : null;

                //
                // Parse supported cookie-av Attribute

                //
                // Expires
                if (StringUtil.EqualsIgnoreCase(attributeName, "Expires")) {
                    DateTime dt;
                    if (DateTime.TryParse(attributeValue, out dt)) {
                        cookie.Expires = dt;
                    }
                }
                //
                // Domain
                else if (attributeValue != null && StringUtil.EqualsIgnoreCase(attributeName, "Domain")) {
                    cookie.Domain = attributeValue;
                }
                //
                // Path
                else if (attributeValue != null && StringUtil.EqualsIgnoreCase(attributeName, "Path")) {
                    cookie.Path = attributeValue;
                }
                //
                // Secure
                else if (StringUtil.EqualsIgnoreCase(attributeName, "Secure")) {
                    cookie.Secure = true;
                }
                //
                // HttpOnly
                else if (StringUtil.EqualsIgnoreCase(attributeName, "HttpOnly")) {
                    cookie.HttpOnly = true;
                }
            }

            result = cookie;

            return true;
        }

        /*
         * Construct set-cookie header
         */
        internal HttpResponseHeader GetSetCookieHeader(HttpContext context) {
            StringBuilder s = new StringBuilder();

            // cookiename=
            if (!String.IsNullOrEmpty(_name)) {
                s.Append(_name);
                s.Append('=');
            }

            // key=value&...
            if (_multiValue != null)
                s.Append(_multiValue.ToString(false));
            else if (_stringValue != null)
                s.Append(_stringValue);

            // domain
            if (!String.IsNullOrEmpty(_domain)) {
                s.Append("; domain=");
                s.Append(_domain);
            }

            // expiration
            if (_expirationSet && _expires != DateTime.MinValue) {
                s.Append("; expires=");
                s.Append(HttpUtility.FormatHttpCookieDateTime(_expires));
            }

            // path
            if (!String.IsNullOrEmpty(_path)) {
                s.Append("; path=");
                s.Append(_path);
            }

            // secure
            if (_secure)
                s.Append("; secure");

            // httponly, Note: IE5 on the Mac doesn't support this
            if (_httpOnly && SupportsHttpOnly(context)) {
                s.Append("; HttpOnly");
            }

            // return as HttpResponseHeader
            return new HttpResponseHeader(HttpWorkerRequest.HeaderSetCookie, s.ToString());
        }
    }

    /////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////

    public enum HttpCookieMode {

        UseUri,          // cookieless=true

        UseCookies,      // cookieless=false

        AutoDetect,      // cookieless=AutoDetect; Probe if device is cookied

        UseDeviceProfile // cookieless=UseDeviceProfile; Base decision on caps
    }
}