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