Merge pull request #3389 from lambdageek/bug-43099
[mono.git] / mcs / class / referencesource / System.Web / HttpCacheVary.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="HttpCacheVary.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>                                                                
5 //------------------------------------------------------------------------------
6
7 /*
8  * Cache Vary class.  Wraps Vary header
9  * 
10  * Copyright (c) 1998 Microsoft Corporation
11  */
12
13 namespace System.Web {
14     using System.Text;
15     using System.Runtime.InteropServices;
16     using System.Web.Util;
17     using System.Security.Permissions;
18
19
20     /// <devdoc>
21     ///    <para>Indicates that a cache should contain multiple 
22     ///       representations for a particular Uri. This class is an encapsulation that
23     ///       provides a rich, type-safe way to set the Vary header.</para>
24     /// </devdoc>
25     public sealed class HttpCacheVaryByHeaders {
26         bool            _isModified;
27         bool            _varyStar;
28         HttpDictionary  _headers;
29
30         public HttpCacheVaryByHeaders() {
31             Reset();
32         }
33
34         internal void Reset() {
35             _isModified = false;
36             _varyStar = false;
37             _headers = null;
38         }
39
40         /// <summary>
41         /// Set the Headers in Cache Vary
42         /// </summary>
43         /// <param name="headers"></param>
44         public void SetHeaders(string[] headers) {
45
46             int i, n;
47
48             if (headers == null) {
49                 _isModified = false;
50                 _varyStar = false;
51                 _headers = null;
52             }
53             else {           
54                 _isModified = true;
55                 if (headers[0].Equals("*")) {
56                     Debug.Assert(headers.Length == 1, "headers.Length == 1");
57
58                     _varyStar = true;
59                     _headers = null;
60                 }
61                 else {
62                     _varyStar = false;
63                     _headers = new HttpDictionary();
64                     for (i = 0, n = headers.Length; i < n; i++) {
65                         _headers.SetValue(headers[i], headers[i]);
66                     }
67                 }
68             }
69         }
70
71         internal bool IsModified() {
72             return _isModified;
73         }
74
75         /*
76          * Construct header value string
77          */
78         internal String ToHeaderString() {
79             StringBuilder   s;
80             Object          item;
81             int             i, n;
82
83             if (_varyStar) {
84                 return "*";
85             }
86             else if (_headers != null) {
87                 s = new StringBuilder();
88
89                 for (i = 0, n = _headers.Size; i < n; i++) {
90                     item = _headers.GetValue(i);
91                     if (item != null) {
92                         HttpCachePolicy.AppendValueToHeader(s, (String)item);
93                     }
94                 }
95
96                 if (s.Length > 0)
97                     return s.ToString();
98             }
99
100             return null;
101         }
102  
103         /// <summary>
104         /// Get the Headers in Cache Vary
105         /// </summary>
106         /// <returns></returns>
107         public string[] GetHeaders() {
108             string[]    s = null;
109
110             Object      item;
111             int         i, j, c, n;
112
113             if (_varyStar) {
114                 return new string[1] {"*"};
115             }
116             else if (_headers != null) {
117                 n = _headers.Size;
118                 c = 0;
119                 for (i = 0; i < n; i++) {
120                     item = _headers.GetValue(i);
121                     if (item != null) {
122                         c++;
123                     }
124                 }
125
126                 if (c > 0) {
127                     s = new string[c];
128                     j = 0;
129                     for (i = 0; i < n; i++) {
130                         item = _headers.GetValue(i);
131                         if (item != null) {
132                             s[j] = (string) item;
133                             j++;
134                         }
135                     }
136
137                     Debug.Assert(j == c, "j == c");
138                 }
139             }
140
141             return s;
142         }
143   
144         //
145         // Public methods and properties
146         //
147
148
149         /// <devdoc>
150         ///    <para>Sets the "Vary: *" header and causes all other Vary:
151         ///       header information to be dropped.</para>
152         /// </devdoc>
153         public void VaryByUnspecifiedParameters() {
154             _isModified = true;
155             _varyStar = true;
156             _headers = null;
157         }
158
159         internal bool GetVaryByUnspecifiedParameters() {
160             return _varyStar;
161         }
162
163         /*
164          * Vary by accept types
165          */
166
167         /// <devdoc>
168         ///    <para>Retrieves or assigns a value indicating whether the cache should vary by Accept types. This causes the
169         ///       Vary: header to include an Accept field.</para>
170         /// </devdoc>
171         public bool AcceptTypes {
172             get { 
173                 return this["Accept"]; 
174             }
175
176             set {         
177                 _isModified = true;
178                 this["Accept"] = value; 
179             }
180         }
181
182         /*
183          * Vary by accept language
184          */
185
186         /// <devdoc>
187         ///    <para> Retrieves or assigns a Boolean value indicating whether
188         ///       the cache should vary by user language.</para>
189         /// </devdoc>
190         public bool UserLanguage {
191             get { 
192                 return this["Accept-Language"]; 
193             }
194
195             set { 
196                 _isModified = true;
197                 this["Accept-Language"] = value; 
198             }
199         }
200
201         /*
202          * Vary by user agent
203          */
204
205         /// <devdoc>
206         ///    <para> Retrieves or assigns a Boolean value indicating whether
207         ///       the cache should vary by user agent.</para>
208         /// </devdoc>
209         public bool UserAgent {
210             get {   
211                 return this["User-Agent"]; 
212             }
213
214             set { 
215                 _isModified = true;
216                 this["User-Agent"] = value; 
217             }
218         }
219
220         /*
221          * Vary by charset
222          */
223
224         /// <devdoc>
225         ///    <para> Retrieves or assigns a value indicating whether the
226         ///       cache should vary by browser character set.</para>
227         /// </devdoc>
228         public bool UserCharSet {
229             get { 
230                 return this["Accept-Charset"]; 
231             }
232
233             set { 
234                 _isModified = true;
235                 this["Accept-Charset"] = value; 
236             }
237         }
238
239         /*
240          * Vary by a given header
241          */
242
243         /// <devdoc>
244         ///    <para> Default property.
245         ///       Indexed property indicating that a cache should (or should not) vary according
246         ///       to a custom header.</para>
247         /// </devdoc>
248         public bool this[String header]
249         {
250             get {
251                 if (header == null) {
252                     throw new ArgumentNullException("header");
253                 }
254
255                 if (header.Equals("*")) {
256                     return _varyStar;
257                 }
258                 else {
259                     return (_headers != null && _headers.GetValue(header) != null);
260                 }
261             }
262
263             set {
264                 if (header == null) {
265                     throw new ArgumentNullException("header");
266                 }
267
268                 /*
269                  * Since adding a Vary header is more restrictive, we don't
270                  * want components to be able to set a Vary header to false
271                  * if another component has set it to true.
272                  */
273                 if (value == false) {
274                     return;
275                 }
276
277                 _isModified = true;
278
279                 if (header.Equals("*")) {
280                     VaryByUnspecifiedParameters();
281                 }
282                 else {
283                     // set value to header if true or null if false
284                     if (!_varyStar) {
285                         if (_headers == null) {
286                             _headers = new HttpDictionary();
287                         }
288
289                         _headers.SetValue(header, header);
290                     }
291                 }
292             }
293         }
294     }
295 }