2 // System.Net.WebHeaderCollection (for 2.1 profile)
5 // Jb Evain <jbevain@novell.com>
6 // Sebastien Pouliot <sebastien@ximian.com>
7 // Lawrence Pit (loz@cable.a2000.nl)
8 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 // Miguel de Icaza (miguel@novell.com)
11 // Copyright 2003 Ximian, Inc. (http://www.ximian.com)
12 // (c) 2007, 2009-2010 Novell, Inc. (http://www.novell.com)
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39 using System.Collections;
40 using System.Collections.Generic;
42 namespace System.Net {
44 public sealed class WebHeaderCollection : IEnumerable {
46 Dictionary<string, string> headers;
49 public WebHeaderCollection ()
54 internal WebHeaderCollection (bool restrict)
57 headers = new Dictionary<string, string> (StringComparer.OrdinalIgnoreCase);
61 get { return headers.Count; }
64 public string [] AllKeys {
66 var keys = new string [headers.Count];
67 headers.Keys.CopyTo (keys, 0);
72 public string this [string header] {
75 throw new ArgumentNullException ("header");
78 headers.TryGetValue (header, out value);
83 throw new ArgumentNullException ("header");
84 if (!IsHeaderName (header))
85 throw new ArgumentException ("header");
88 ValidateHeader (header);
90 // null value are ignored (see moon-unit)
93 if (!IsHeaderValue (value))
94 throw new ArgumentException ("value");
96 headers [header] = value;
100 public string this [HttpRequestHeader header] {
101 get { return this [HttpRequestHeaderToString (header)]; }
103 string h = HttpRequestHeaderToString (header);
110 // some headers cannot be set using the "this" property but by using
111 // the right property of the Web[Request|Response]. However the value
112 // does end up in the collection (and can be read safely from there)
113 internal void SetHeader (string header, string value)
115 if (String.IsNullOrEmpty (value))
116 headers.Remove (header);
118 headers [header] = value;
121 internal void Clear ()
126 internal bool ContainsKey (string key)
128 return headers.ContainsKey (key);
131 IEnumerator IEnumerable.GetEnumerator ()
133 return headers.Keys.GetEnumerator ();
136 static string HttpResponseHeaderToString (HttpResponseHeader header)
139 case HttpResponseHeader.CacheControl: return "Cache-Control";
140 case HttpResponseHeader.Connection: return "Connection";
141 case HttpResponseHeader.Date: return "Date";
142 case HttpResponseHeader.KeepAlive: return "Keep-Alive";
143 case HttpResponseHeader.Pragma: return "Pragma";
144 case HttpResponseHeader.Trailer: return "Trailer";
145 case HttpResponseHeader.TransferEncoding: return "Transfer-Encoding";
146 case HttpResponseHeader.Upgrade: return "Upgrade";
147 case HttpResponseHeader.Via: return "Via";
148 case HttpResponseHeader.Warning: return "Warning";
149 case HttpResponseHeader.Allow: return "Allow";
150 case HttpResponseHeader.ContentLength: return "Content-Length";
151 case HttpResponseHeader.ContentType: return "Content-Type";
152 case HttpResponseHeader.ContentEncoding: return "Content-Encoding";
153 case HttpResponseHeader.ContentLanguage: return "Content-Language";
154 case HttpResponseHeader.ContentLocation: return "Content-Location";
155 case HttpResponseHeader.ContentMd5: return "Content-MD5";
156 case HttpResponseHeader.ContentRange: return "Content-Range";
157 case HttpResponseHeader.Expires: return "Expires";
158 case HttpResponseHeader.LastModified: return "Last-Modified";
159 case HttpResponseHeader.AcceptRanges: return "Accept-Ranges";
160 case HttpResponseHeader.Age: return "Age";
161 case HttpResponseHeader.ETag: return "ETag";
162 case HttpResponseHeader.Location: return "Location";
163 case HttpResponseHeader.ProxyAuthenticate: return "Proxy-Authenticate";
164 case HttpResponseHeader.RetryAfter: return "Retry-After";
165 case HttpResponseHeader.Server: return "Server";
166 case HttpResponseHeader.SetCookie: return "Set-Cookie";
167 case HttpResponseHeader.Vary: return "Vary";
168 case HttpResponseHeader.WwwAuthenticate: return "WWW-Authenticate";
170 throw new IndexOutOfRangeException ();
174 static string HttpRequestHeaderToString (HttpRequestHeader header)
177 case HttpRequestHeader.CacheControl: return "Cache-Control";
178 case HttpRequestHeader.Connection: return "Connection";
179 case HttpRequestHeader.Date: return "Date";
180 case HttpRequestHeader.KeepAlive: return "Keep-Alive";
181 case HttpRequestHeader.Pragma: return "Pragma";
182 case HttpRequestHeader.Trailer: return "Trailer";
183 case HttpRequestHeader.TransferEncoding: return "Transfer-Encoding";
184 case HttpRequestHeader.Upgrade: return "Upgrade";
185 case HttpRequestHeader.Via: return "Via";
186 case HttpRequestHeader.Warning: return "Warning";
187 case HttpRequestHeader.Allow: return "Allow";
188 case HttpRequestHeader.ContentLength: return "Content-Length";
189 case HttpRequestHeader.ContentType: return "Content-Type";
190 case HttpRequestHeader.ContentEncoding: return "Content-Encoding";
191 case HttpRequestHeader.ContentLanguage: return "Content-Language";
192 case HttpRequestHeader.ContentLocation: return "Content-Location";
193 case HttpRequestHeader.ContentMd5: return "Content-MD5";
194 case HttpRequestHeader.ContentRange: return "Content-Range";
195 case HttpRequestHeader.Expires: return "Expires";
196 case HttpRequestHeader.LastModified: return "Last-Modified";
197 case HttpRequestHeader.Accept: return "Accept";
198 case HttpRequestHeader.AcceptCharset: return "Accept-Charset";
199 case HttpRequestHeader.AcceptEncoding: return "Accept-Encoding";
200 case HttpRequestHeader.AcceptLanguage: return "Accept-Language";
201 case HttpRequestHeader.Authorization: return "Authorization";
202 case HttpRequestHeader.Cookie: return "Cookie";
203 case HttpRequestHeader.Expect: return "Expect";
204 case HttpRequestHeader.From: return "From";
205 case HttpRequestHeader.Host: return "Host";
206 case HttpRequestHeader.IfMatch: return "If-Match";
207 case HttpRequestHeader.IfModifiedSince: return "If-Modified-Since";
208 case HttpRequestHeader.IfNoneMatch: return "If-None-Match";
209 case HttpRequestHeader.IfRange: return "If-Range";
210 case HttpRequestHeader.IfUnmodifiedSince: return "If-Unmodified-Since";
211 case HttpRequestHeader.MaxForwards: return "Max-Forwards";
212 case HttpRequestHeader.ProxyAuthorization: return "Proxy-Authorization";
213 case HttpRequestHeader.Referer: return "Referer";
214 case HttpRequestHeader.Range: return "Range";
215 case HttpRequestHeader.Te: return "TE";
216 case HttpRequestHeader.Translate: return "Translate";
217 case HttpRequestHeader.UserAgent: return "User-Agent";
219 throw new IndexOutOfRangeException ();
223 internal static void ValidateHeader (string header)
225 switch (header.ToLowerInvariant ()) {
230 case "transfer-encoding":
235 case "content-length": // accepted by WebClient, copied to WebRequest.ContentLength (not headers)
236 case "content-type": // accepted by WebClient, copied to WebRequest.ContentType
237 case "content-location":
238 case "content-range":
239 case "last-modified":
240 case "accept": // accepted by WebClient, copied to HttpWebRequest.Accept
241 case "accept-charset":
242 case "accept-encoding":
243 case "accept-language":
247 case "if-modified-since":
252 // extra (not HttpRequestHeader defined) headers that are not accepted by SL2
253 // note: the HttpResponseHeader enum is not available in SL2
254 case "accept-ranges":
258 case "content-transfer-encoding":
266 case "proxy-authenticate":
267 case "proxy-connection":
270 case "request-range":
273 case "sec-headertest":
278 case "www-authenticate":
279 case "x-flash-version":
280 string msg = String.Format ("'{0}' cannot be modified", header);
281 throw new ArgumentException (msg, "header");
287 internal static bool IsHeaderValue (string value)
289 // TEXT any 8 bit value except CTL's (0-31 and 127)
290 // but including \r\n space and \t
291 // after a newline at least one space or \t must follow
292 // certain header fields allow comments ()
294 int len = value.Length;
295 for (int i = 0; i < len; i++) {
299 if (c < 0x20 && (c != '\r' && c != '\n' && c != '\t'))
301 if (c == '\r' && ++i < len) {
306 if (c == '\n' && ++i < len) {
308 if (c != ' ' && c != '\t')
316 internal static bool IsHeaderName (string name)
318 if (name == null || name.Length == 0)
321 int len = name.Length;
322 for (int i = 0; i < len; i++) {
324 if (c > 126 || !allowed_chars [(int) c])
331 static bool [] allowed_chars = new bool [126] {
332 false, false, false, false, false, false, false, false, false, false, false, false, false, false,
333 false, false, false, false, false, false, false, false, false, false, false, false, false, false,
334 false, false, false, false, false, true, false, true, true, true, true, false, false, false, true,
335 true, false, true, true, false, true, true, true, true, true, true, true, true, true, true, false,
336 false, false, false, false, false, false, true, true, true, true, true, true, true, true, true,
337 true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
338 false, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true,
339 true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,