Merge pull request #409 from Alkarex/patch-1
[mono.git] / mcs / class / System / System.Net / WebHeaderCollection.cs
1 //
2 // System.Net.WebHeaderCollection
3 //
4 // Authors:
5 //      Lawrence Pit (loz@cable.a2000.nl)
6 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //      Miguel de Icaza (miguel@novell.com)
8 //      Marek Safar (marek.safar@gmail.com)
9 //
10 // Copyright 2003 Ximian, Inc. (http://www.ximian.com)
11 // Copyright 2007 Novell, Inc. (http://www.novell.com)
12 // Copyright (C) 2011 Xamarin Inc (http://www.xamarin.com)
13 //
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34
35 using System;
36 using System.Collections;
37 using System.Collections.Generic;
38 using System.Collections.Specialized;
39 using System.Runtime.InteropServices;
40 using System.Runtime.Serialization;
41 using System.Text;
42     
43 // See RFC 2068 par 4.2 Message Headers
44     
45 namespace System.Net 
46 {
47 #if MOONLIGHT
48         internal class WebHeaderCollection : NameValueCollection, ISerializable {
49 #else
50         [Serializable]
51         [ComVisible(true)]
52         public class WebHeaderCollection : NameValueCollection, ISerializable {
53 #endif
54                 [Flags]
55                 internal enum HeaderInfo
56                 {
57                         Request = 1,
58                         Response = 1 << 1,
59                         MultiValue = 1 << 10
60                 }
61
62                 static readonly bool[] allowed_chars = {
63                         false, false, false, false, false, false, false, false, false, false, false, false, false, false,
64                         false, false, false, false, false, false, false, false, false, false, false, false, false, false,
65                         false, false, false, false, false, true, false, true, true, true, true, false, false, false, true,
66                         true, false, true, true, false, true, true, true, true, true, true, true, true, true, true, false,
67                         false, false, false, false, false, false, true, true, true, true, true, true, true, true, true,
68                         true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
69                         false, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true,
70                         true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
71                         false, true, false
72                 };
73
74                 static readonly Dictionary<string, HeaderInfo> headers;
75                 HeaderInfo? headerRestriction;
76                 HeaderInfo? headerConsistency;
77                 
78                 static WebHeaderCollection () 
79                 {
80                         headers = new Dictionary<string, HeaderInfo> (StringComparer.OrdinalIgnoreCase) {
81                                 { "Allow", HeaderInfo.MultiValue },
82                                 { "Accept", HeaderInfo.Request | HeaderInfo.MultiValue },
83                                 { "Accept-Charset", HeaderInfo.MultiValue },
84                                 { "Accept-Encoding", HeaderInfo.MultiValue },
85                                 { "Accept-Language", HeaderInfo.MultiValue },
86                                 { "Accept-Ranges", HeaderInfo.MultiValue },
87                                 { "Authorization", HeaderInfo.MultiValue },
88                                 { "Cache-Control", HeaderInfo.MultiValue },
89                                 { "Cookie", HeaderInfo.MultiValue },
90                                 { "Connection", HeaderInfo.Request | HeaderInfo.MultiValue },
91                                 { "Content-Encoding", HeaderInfo.MultiValue },
92                                 { "Content-Length", HeaderInfo.Request | HeaderInfo.Response },
93                                 { "Content-Type", HeaderInfo.Request },
94                                 { "Content-Language", HeaderInfo.MultiValue },
95                                 { "Date", HeaderInfo.Request },
96                                 { "Expect", HeaderInfo.Request | HeaderInfo.MultiValue},
97                                 { "Host", HeaderInfo.Request },
98                                 { "If-Match", HeaderInfo.MultiValue },
99                                 { "If-Modified-Since", HeaderInfo.Request },
100                                 { "If-None-Match", HeaderInfo.MultiValue },
101                                 { "Keep-Alive", HeaderInfo.Response },
102                                 { "Pragma", HeaderInfo.MultiValue },
103                                 { "Proxy-Authenticate", HeaderInfo.MultiValue },
104                                 { "Proxy-Authorization", HeaderInfo.MultiValue },
105                                 { "Proxy-Connection", HeaderInfo.Request | HeaderInfo.MultiValue },
106                                 { "Range", HeaderInfo.Request | HeaderInfo.MultiValue },
107                                 { "Referer", HeaderInfo.Request },
108                                 { "Set-Cookie", HeaderInfo.MultiValue },
109                                 { "Set-Cookie2", HeaderInfo.MultiValue },
110                                 { "TE", HeaderInfo.MultiValue },
111                                 { "Trailer", HeaderInfo.MultiValue },
112                                 { "Transfer-Encoding", HeaderInfo.Request | HeaderInfo.Response | HeaderInfo.MultiValue },
113                                 { "Upgrade", HeaderInfo.MultiValue },
114                                 { "User-Agent", HeaderInfo.Request },
115                                 { "Vary", HeaderInfo.MultiValue },
116                                 { "Via", HeaderInfo.MultiValue },
117                                 { "Warning", HeaderInfo.MultiValue },
118                                 { "WWW-Authenticate", HeaderInfo.Response | HeaderInfo. MultiValue }
119                         };
120                 }
121                 
122                 // Constructors
123                 
124                 public WebHeaderCollection ()
125                 {
126                 }
127                 
128                 protected WebHeaderCollection (SerializationInfo serializationInfo, 
129                                                StreamingContext streamingContext)
130                 {
131                         int count;
132
133                         try {
134                                 count = serializationInfo.GetInt32("Count");
135                                 for (int i = 0; i < count; i++) 
136                                         this.Add (serializationInfo.GetString (i.ToString ()),
137                                                   serializationInfo.GetString ((count + i).ToString ()));
138                         } catch (SerializationException){
139                                 count = serializationInfo.GetInt32("count");
140                                 for (int i = 0; i < count; i++) 
141                                         this.Add (serializationInfo.GetString ("k" + i),
142                                                   serializationInfo.GetString ("v" + i));
143                         }
144                         
145                 }
146
147                 internal WebHeaderCollection (HeaderInfo headerRestriction)
148                 {
149                         this.headerRestriction = headerRestriction;
150                 }               
151                 
152                 // Methods
153                 
154                 public void Add (string header)
155                 {
156                         if (header == null)
157                                 throw new ArgumentNullException ("header");
158                         int pos = header.IndexOf (':');
159                         if (pos == -1)
160                                 throw new ArgumentException ("no colon found", "header");
161
162                         this.Add (header.Substring (0, pos), header.Substring (pos + 1));
163                 }
164                 
165                 public override void Add (string name, string value)
166                 {
167                         if (name == null)
168                                 throw new ArgumentNullException ("name");
169
170                         CheckRestrictedHeader (name);
171                         this.AddWithoutValidate (name, value);
172                 }
173
174                 protected void AddWithoutValidate (string headerName, string headerValue)
175                 {
176                         if (!IsHeaderName (headerName))
177                                 throw new ArgumentException ("invalid header name: " + headerName, "headerName");
178                         if (headerValue == null)
179                                 headerValue = String.Empty;
180                         else
181                                 headerValue = headerValue.Trim ();
182                         if (!IsHeaderValue (headerValue))
183                                 throw new ArgumentException ("invalid header value: " + headerValue, "headerValue");
184                         
185                         AddValue (headerName, headerValue);
186                 }
187                         
188                 internal void AddValue (string headerName, string headerValue)
189                 {
190                         base.Add (headerName, headerValue);                     
191                 }
192
193                 internal string [] GetValues_internal (string header, bool split)
194                 {
195                         if (header == null)
196                                 throw new ArgumentNullException ("header");
197
198                         string [] values = base.GetValues (header);
199                         if (values == null || values.Length == 0)
200                                 return null;
201
202                         if (split && IsMultiValue (header)) {
203                                 List<string> separated = null;
204                                 foreach (var value in values) {
205                                         if (value.IndexOf (',') < 0)
206                                                 continue;
207
208                                         if (separated == null) {
209                                                 separated = new List<string> (values.Length + 1);
210                                                 foreach (var v in values) {
211                                                         if (v == value)
212                                                                 break;
213
214                                                         separated.Add (v);
215                                                 }
216                                         }
217
218                                         var slices = value.Split (',');
219                                         var slices_length = slices.Length;
220                                         if (value[value.Length - 1] == ',')
221                                                 --slices_length;
222
223                                         for (int i = 0; i < slices_length; ++i ) {
224                                                 separated.Add (slices[i].Trim ());
225                                         }
226                                 }
227
228                                 if (separated != null)
229                                         return separated.ToArray ();
230                         }
231
232                         return values;
233                 }
234
235                 public override string [] GetValues (string header)
236                 {
237                         return GetValues_internal (header, true);
238                 }
239
240                 public override string[] GetValues (int index)
241                 {
242                         string[] values = base.GetValues (index);
243
244                         if (values == null || values.Length == 0) {
245                                 return null;
246                         }
247                         
248                         return values;
249                 }
250
251                 public static bool IsRestricted (string headerName)
252                 {
253                         return IsRestricted (headerName, false);
254                 }
255
256                 public static bool IsRestricted (string headerName, bool response)
257                 {
258                         if (headerName == null)
259                                 throw new ArgumentNullException ("headerName");
260
261                         if (headerName.Length == 0)
262                                 throw new ArgumentException ("empty string", "headerName");
263
264                         if (!IsHeaderName (headerName))
265                                 throw new ArgumentException ("Invalid character in header");
266
267                         HeaderInfo info;
268                         if (!headers.TryGetValue (headerName, out info))
269                                 return false;
270
271                         var flag = response ? HeaderInfo.Response : HeaderInfo.Request;
272                         return (info & flag) != 0;
273                 }
274
275                 public override void OnDeserialization (object sender)
276                 {
277                 }
278
279                 public override void Remove (string name)
280                 {
281                         if (name == null)
282                                 throw new ArgumentNullException ("name");
283
284                         CheckRestrictedHeader (name);
285                         base.Remove (name);
286                 }
287
288                 public override void Set (string name, string value)
289                 {
290                         if (name == null)
291                                 throw new ArgumentNullException ("name");
292                         if (!IsHeaderName (name))
293                                 throw new ArgumentException ("invalid header name");
294                         if (value == null)
295                                 value = String.Empty;
296                         else
297                                 value = value.Trim ();
298                         if (!IsHeaderValue (value))
299                                 throw new ArgumentException ("invalid header value");
300
301                         CheckRestrictedHeader (name);
302                         base.Set (name, value);                 
303                 }
304
305                 public byte[] ToByteArray ()
306                 {
307                         return Encoding.UTF8.GetBytes(ToString ());
308                 }
309
310                 internal string ToStringMultiValue ()
311                 {
312                         StringBuilder sb = new StringBuilder();
313
314                         int count = base.Count;
315                         for (int i = 0; i < count ; i++) {
316                                 string key = GetKey (i);
317                                 if (IsMultiValue (key)) {
318                                         foreach (string v in GetValues (i)) {
319                                                 sb.Append (key)
320                                                   .Append (": ")
321                                                   .Append (v)
322                                                   .Append ("\r\n");
323                                         }
324                                 } else {
325                                         sb.Append (key)
326                                           .Append (": ")
327                                           .Append (Get (i))
328                                           .Append ("\r\n");
329                                 }
330                          }
331                         return sb.Append("\r\n").ToString();
332                 }
333
334                 public override string ToString ()
335                 {
336                         StringBuilder sb = new StringBuilder();
337
338                         int count = base.Count;
339                         for (int i = 0; i < count ; i++)
340                                 sb.Append (GetKey (i))
341                                   .Append (": ")
342                                   .Append (Get (i))
343                                   .Append ("\r\n");
344
345                         return sb.Append("\r\n").ToString();
346                 }
347 #if !TARGET_JVM
348                 void ISerializable.GetObjectData (SerializationInfo serializationInfo,
349                                                   StreamingContext streamingContext)
350                 {
351                         GetObjectData (serializationInfo, streamingContext);
352                 }
353 #endif
354                 public override void GetObjectData (SerializationInfo serializationInfo, StreamingContext streamingContext)
355                 {
356                         int count = base.Count;
357                         serializationInfo.AddValue ("Count", count);
358                         for (int i = 0; i < count; i++) {
359                                 serializationInfo.AddValue (i.ToString (), GetKey (i));
360                                 serializationInfo.AddValue ((count + i).ToString (), Get (i));
361                         }
362                 }
363
364                 public override string[] AllKeys {
365                         get {
366                                 return base.AllKeys;
367                         }
368                 }
369                 
370                 public override int Count {
371                         get {
372                                 return base.Count;
373                         }
374                 }
375
376                 public override KeysCollection Keys {
377                         get {
378                                 return base.Keys;
379                         }
380                 }
381
382                 public override string Get (int index)
383                 {
384                         return base.Get (index);
385                 }
386                 
387                 public override string Get (string name)
388                 {
389                         return base.Get (name);
390                 }
391                 
392                 public override string GetKey (int index)
393                 {
394                         return base.GetKey (index);
395                 }
396
397                 public void Add (HttpRequestHeader header, string value)
398                 {
399                         Add (RequestHeaderToString (header), value);
400                 }
401
402                 public void Remove (HttpRequestHeader header)
403                 {
404                         Remove (RequestHeaderToString (header));
405                 }
406
407                 public void Set (HttpRequestHeader header, string value)
408                 {
409                         Set (RequestHeaderToString (header), value);
410                 }
411
412                 public void Add (HttpResponseHeader header, string value)
413                 {
414                         Add (ResponseHeaderToString (header), value);
415                 }
416
417                 public void Remove (HttpResponseHeader header)
418                 {
419                         Remove (ResponseHeaderToString (header));
420                 }
421
422                 public void Set (HttpResponseHeader header, string value)
423                 {
424                         Set (ResponseHeaderToString (header), value);
425                 }
426
427                 public string this [HttpRequestHeader header] {
428                         get {
429                                 return Get (RequestHeaderToString (header));
430                         }
431                         
432                         set {
433                                 Set (header, value);
434                         }
435                 }
436
437                 public string this [HttpResponseHeader header] {
438                         get {
439                                 return Get (ResponseHeaderToString (header));
440                         }
441
442                         set {
443                                 Set (header, value);
444                         }
445                 }
446
447                 public override void Clear ()
448                 {
449                         base.Clear ();
450                 }
451
452                 public override IEnumerator GetEnumerator ()
453                 {
454                         return base.GetEnumerator ();
455                 }
456
457                 // Internal Methods
458                 
459                 // With this we don't check for invalid characters in header. See bug #55994.
460                 internal void SetInternal (string header)
461                 {
462                         int pos = header.IndexOf (':');
463                         if (pos == -1)
464                                 throw new ArgumentException ("no colon found", "header");                               
465
466                         SetInternal (header.Substring (0, pos), header.Substring (pos + 1));
467                 }
468
469                 internal void SetInternal (string name, string value)
470                 {
471                         if (value == null)
472                                 value = String.Empty;
473                         else
474                                 value = value.Trim ();
475                         if (!IsHeaderValue (value))
476                                 throw new ArgumentException ("invalid header value");
477
478                         if (IsMultiValue (name)) {
479                                 base.Add (name, value);
480                         } else {
481                                 base.Remove (name);
482                                 base.Set (name, value); 
483                         }
484                 }
485
486                 internal void RemoveAndAdd (string name, string value)
487                 {
488                         if (value == null)
489                                 value = String.Empty;
490                         else
491                                 value = value.Trim ();
492
493                         base.Remove (name);
494                         base.Set (name, value);
495                 }
496
497                 internal void RemoveInternal (string name)
498                 {
499                         if (name == null)
500                                 throw new ArgumentNullException ("name");
501                         base.Remove (name);
502                 }               
503                 
504                 // Private Methods
505
506                 string RequestHeaderToString (HttpRequestHeader value)
507                 {
508                         CheckHeaderConsistency (HeaderInfo.Request);
509
510                         switch (value) {
511                         case HttpRequestHeader.CacheControl:
512                                 return "Cache-Control";
513                         case HttpRequestHeader.Connection:
514                                 return "Connection";
515                         case HttpRequestHeader.Date:
516                                 return "Date";
517                         case HttpRequestHeader.KeepAlive:
518                                 return "Keep-Alive";
519                         case HttpRequestHeader.Pragma:
520                                 return "Pragma";
521                         case HttpRequestHeader.Trailer:
522                                 return "Trailer";
523                         case HttpRequestHeader.TransferEncoding:
524                                 return "Transfer-Encoding";
525                         case HttpRequestHeader.Upgrade:
526                                 return "Upgrade";
527                         case HttpRequestHeader.Via:
528                                 return "Via";
529                         case HttpRequestHeader.Warning:
530                                 return "Warning";
531                         case HttpRequestHeader.Allow:
532                                 return "Allow";
533                         case HttpRequestHeader.ContentLength:
534                                 return "Content-Length";
535                         case HttpRequestHeader.ContentType:
536                                 return "Content-Type";
537                         case HttpRequestHeader.ContentEncoding:
538                                 return "Content-Encoding";
539                         case HttpRequestHeader.ContentLanguage:
540                                 return "Content-Language";
541                         case HttpRequestHeader.ContentLocation:
542                                 return "Content-Location";
543                         case HttpRequestHeader.ContentMd5:
544                                 return "Content-MD5";
545                         case HttpRequestHeader.ContentRange:
546                                 return "Content-Range";
547                         case HttpRequestHeader.Expires:
548                                 return "Expires";
549                         case HttpRequestHeader.LastModified:
550                                 return "Last-Modified";
551                         case HttpRequestHeader.Accept:
552                                 return "Accept";
553                         case HttpRequestHeader.AcceptCharset:
554                                 return "Accept-Charset";
555                         case HttpRequestHeader.AcceptEncoding:
556                                 return "Accept-Encoding";
557                         case HttpRequestHeader.AcceptLanguage:
558                                 return "accept-language";
559                         case HttpRequestHeader.Authorization:
560                                 return "Authorization";
561                         case HttpRequestHeader.Cookie:
562                                 return "Cookie";
563                         case HttpRequestHeader.Expect:
564                                 return "Expect";
565                         case HttpRequestHeader.From:
566                                 return "From";
567                         case HttpRequestHeader.Host:
568                                 return "Host";
569                         case HttpRequestHeader.IfMatch:
570                                 return "If-Match";
571                         case HttpRequestHeader.IfModifiedSince:
572                                 return "If-Modified-Since";
573                         case HttpRequestHeader.IfNoneMatch:
574                                 return "If-None-Match";
575                         case HttpRequestHeader.IfRange:
576                                 return "If-Range";
577                         case HttpRequestHeader.IfUnmodifiedSince:
578                                 return "If-Unmodified-Since";
579                         case HttpRequestHeader.MaxForwards:
580                                 return "Max-Forwards";
581                         case HttpRequestHeader.ProxyAuthorization:
582                                 return "Proxy-Authorization";
583                         case HttpRequestHeader.Referer:
584                                 return "Referer";
585                         case HttpRequestHeader.Range:
586                                 return "Range";
587                         case HttpRequestHeader.Te:
588                                 return "TE";
589                         case HttpRequestHeader.Translate:
590                                 return "Translate";
591                         case HttpRequestHeader.UserAgent:
592                                 return "User-Agent";
593                         default:
594                                 throw new InvalidOperationException ();
595                         }
596                 }
597
598                 string ResponseHeaderToString (HttpResponseHeader value)
599                 {
600                         CheckHeaderConsistency (HeaderInfo.Response);
601
602                         switch (value) {
603                         case HttpResponseHeader.CacheControl:
604                                 return "Cache-Control";
605                         case HttpResponseHeader.Connection:
606                                 return "Connection";
607                         case HttpResponseHeader.Date:
608                                 return "Date";
609                         case HttpResponseHeader.KeepAlive:
610                                 return "Keep-Alive";
611                         case HttpResponseHeader.Pragma:
612                                 return "Pragma";
613                         case HttpResponseHeader.Trailer:
614                                 return "Trailer";
615                         case HttpResponseHeader.TransferEncoding:
616                                 return "Transfer-Encoding";
617                         case HttpResponseHeader.Upgrade:
618                                 return "Upgrade";
619                         case HttpResponseHeader.Via:
620                                 return "Via";
621                         case HttpResponseHeader.Warning:
622                                 return "Warning";
623                         case HttpResponseHeader.Allow:
624                                 return "Allow";
625                         case HttpResponseHeader.ContentLength:
626                                 return "Content-Length";
627                         case HttpResponseHeader.ContentType:
628                                 return "Content-Type";
629                         case HttpResponseHeader.ContentEncoding:
630                                 return "Content-Encoding";
631                         case HttpResponseHeader.ContentLanguage:
632                                 return "Content-Language";
633                         case HttpResponseHeader.ContentLocation:
634                                 return "Content-Location";
635                         case HttpResponseHeader.ContentMd5:
636                                 return "Content-MD5";
637                         case HttpResponseHeader.ContentRange:
638                                 return "Content-Range";
639                         case HttpResponseHeader.Expires:
640                                 return "Expires";
641                         case HttpResponseHeader.LastModified:
642                                 return "Last-Modified";
643                         case HttpResponseHeader.AcceptRanges:
644                                 return "Accept-Ranges";
645                         case HttpResponseHeader.Age:
646                                 return "Age";
647                         case HttpResponseHeader.ETag:
648                                 return "ETag";
649                         case HttpResponseHeader.Location:
650                                 return "Location";
651                         case HttpResponseHeader.ProxyAuthenticate:
652                                 return "Proxy-Authenticate";
653                         case HttpResponseHeader.RetryAfter:
654                                 return "Retry-After";
655                         case HttpResponseHeader.Server:
656                                 return "Server";
657                         case HttpResponseHeader.SetCookie:
658                                 return "Set-Cookie";
659                         case HttpResponseHeader.Vary:
660                                 return "Vary";
661                         case HttpResponseHeader.WwwAuthenticate:
662                                 return "WWW-Authenticate";
663                         default:
664                                 throw new InvalidOperationException ();
665                         }
666                 }
667
668                 void CheckRestrictedHeader (string headerName)
669                 {
670                         if (!headerRestriction.HasValue)
671                                 return;
672
673                         HeaderInfo info;
674                         if (!headers.TryGetValue (headerName, out info))
675                                 return;
676
677                         if ((info & headerRestriction.Value) != 0)
678                                 throw new ArgumentException ("This header must be modified with the appropiate property.");
679                 }
680
681                 void CheckHeaderConsistency (HeaderInfo value)
682                 {
683                         if (!headerConsistency.HasValue) {
684                                 headerConsistency = value;
685                                 return;
686                         }
687
688                         if ((headerConsistency & value) == 0)
689                                 throw new InvalidOperationException ();
690                 }
691                 
692                 internal static bool IsMultiValue (string headerName)
693                 {
694                         if (headerName == null)
695                                 return false;
696
697                         HeaderInfo info;
698                         return headers.TryGetValue (headerName, out info) && (info & HeaderInfo.MultiValue) != 0;
699                 }               
700                 
701                 internal static bool IsHeaderValue (string value)
702                 {
703                         // TEXT any 8 bit value except CTL's (0-31 and 127)
704                         //      but including \r\n space and \t
705                         //      after a newline at least one space or \t must follow
706                         //      certain header fields allow comments ()
707                                 
708                         int len = value.Length;
709                         for (int i = 0; i < len; i++) {                 
710                                 char c = value [i];
711                                 if (c == 127)
712                                         return false;
713                                 if (c < 0x20 && (c != '\r' && c != '\n' && c != '\t'))
714                                         return false;
715                                 if (c == '\n' && ++i < len) {
716                                         c = value [i];
717                                         if (c != ' ' && c != '\t')
718                                                 return false;
719                                 }
720                         }
721                         
722                         return true;
723                 }
724                 
725                 internal static bool IsHeaderName (string name)
726                 {
727                         if (name == null || name.Length == 0)
728                                 return false;
729
730                         int len = name.Length;
731                         for (int i = 0; i < len; i++) {                 
732                                 char c = name [i];
733                                 if (c > 126 || !allowed_chars [c])
734                                         return false;
735                         }
736                         
737                         return true;
738                 }
739         }
740 }