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