1 //==========================================================================
4 // Summary: Implements an HttpServer to be used by the HttpServerChannel class
7 // Classes: internal sealed HttpServer
8 // internal sealed ReqMessageParser
9 // private RequestArguments
12 // Ahmad Tantawy popsito82@hotmail.com
13 // Ahmad Kadry kadrianoz@hotmail.com
14 // Hussein Mehanna hussein_mehanna@hotmail.com
16 //==========================================================================
19 // Permission is hereby granted, free of charge, to any person obtaining
20 // a copy of this software and associated documentation files (the
21 // "Software"), to deal in the Software without restriction, including
22 // without limitation the rights to use, copy, modify, merge, publish,
23 // distribute, sublicense, and/or sell copies of the Software, and to
24 // permit persons to whom the Software is furnished to do so, subject to
25 // the following conditions:
27 // The above copyright notice and this permission notice shall be
28 // included in all copies or substantial portions of the Software.
30 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
33 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
34 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
35 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
36 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39 using System.Net.Sockets;
41 using System.Text.RegularExpressions;
42 using System.Collections;
44 using System.Runtime.Remoting.Channels;
47 using System.Runtime.Remoting.Messaging;
49 namespace System.Runtime.Remoting.Channels.Http
52 internal class RequestArguments
54 public RequestArguments (Socket socket, HttpServerTransportSink sink)
56 NetworkStream ns = new NetworkStream (socket);
62 public Stream InputStream;
63 public Stream OutputStream;
64 public HttpServerTransportSink Sink;
67 internal sealed class HttpServer
69 public static void ProcessRequest (object reqInfo)
71 if(reqInfo as RequestArguments == null)
74 RequestArguments reqArg = (RequestArguments)reqInfo;
76 //Step (1) Start Reciceve the header
77 ArrayList Headers = RecieveHeader (reqArg);
79 //Step (2) Start Parse the header
80 IDictionary HeaderFields = new Hashtable();
81 IDictionary CustomHeaders = new Hashtable();
82 if (!ParseHeader (reqArg, Headers, HeaderFields, CustomHeaders))
86 if (!CheckRequest (reqArg, HeaderFields, CustomHeaders))
89 //Step (4) Recieve the entity body
92 object len = HeaderFields["content-length"];
95 buffer = new byte [(int)len];
96 if (!RecieveEntityBody (reqArg, buffer))
100 buffer = new byte [0];
103 SendRequestForChannel (reqArg, HeaderFields, CustomHeaders, buffer);
106 private static ArrayList RecieveHeader (RequestArguments reqArg)
108 bool bLastLine = false;
109 bool bEndOfLine = false;
111 byte[] buffer = new byte[1024];
112 ArrayList Headers = new ArrayList();
114 Stream ist = reqArg.InputStream;
119 //recieve line by line
123 //Step (1) is it an empty line?
124 ist.Read (buffer, index, 1);
126 if(buffer[index++]==13)
128 ist.Read (buffer, index, 1);
133 //Step (2) recieve line bytes
136 ist.Read (buffer, index, 1);
138 if(buffer [index++]==13)
141 ist.Read (buffer,index,1);
145 //Step (3) convert bytes to a string
149 Headers.Add (Encoding.ASCII.GetString (buffer,0,index));
156 private static bool ParseHeader (RequestArguments reqArg, ArrayList Headers, IDictionary HeaderFields, IDictionary CustomHeaders)
158 for (int i=0;i<Headers.Count;i++)
160 if (ReqMessageParser.ParseHeaderField ((string)Headers[i],HeaderFields))
163 if (!ReqMessageParser.IsCustomHeader((string)Headers[i],CustomHeaders ) )
165 SendResponse (reqArg, 400, null, null);
173 private static bool CheckRequest (RequestArguments reqArg, IDictionary HeaderFields, IDictionary CustomHeaders)
177 if (HeaderFields["expect"] as string == "100-continue")
178 SendResponse (reqArg, 100, null, null);
181 temp = HeaderFields["method"].ToString();
185 //Check for the content-length field
186 if (HeaderFields["content-length"]==null)
188 SendResponse (reqArg, 411, null, null);
195 private static bool RecieveEntityBody (RequestArguments reqArg, byte[] buffer)
200 while (nr < buffer.Length)
201 nr += reqArg.InputStream.Read (buffer, nr, buffer.Length - nr);
203 catch (SocketException e)
207 case 10060 : //TimeOut
208 SendResponse (reqArg, 408, null, null);
220 private static bool SendRequestForChannel (RequestArguments reqArg, IDictionary HeaderFields, IDictionary CustomHeaders, byte[] buffer)
222 TransportHeaders THeaders = new TransportHeaders();
224 Stream stream = new MemoryStream(buffer);
226 if(stream.Position !=0)
227 stream.Seek(0,SeekOrigin.Begin);
229 THeaders[CommonTransportKeys.RequestUri] = FixURI((string)HeaderFields["request-url"]);
230 THeaders[CommonTransportKeys.ContentType]= HeaderFields["content-type"];
231 THeaders[CommonTransportKeys.RequestVerb]= HeaderFields["method"];
232 THeaders[CommonTransportKeys.HttpVersion] = HeaderFields["http-version"];
233 THeaders[CommonTransportKeys.UserAgent] = HeaderFields["user-agent"];
234 THeaders[CommonTransportKeys.Host] = HeaderFields["host"];
235 THeaders[CommonTransportKeys.SoapAction] = HeaderFields["SOAPAction"];
237 foreach(DictionaryEntry DictEntry in CustomHeaders)
239 THeaders[DictEntry.Key.ToString()] = DictEntry.Value.ToString();
242 reqArg.Sink.ServiceRequest (reqArg, stream, THeaders);
246 private static string FixURI(string RequestURI)
249 if(RequestURI.IndexOf ( '.' ) == -1)
252 return RequestURI.Substring(1);
256 public static void SendResponse (RequestArguments reqArg, int httpStatusCode, ITransportHeaders headers, Stream responseStream)
258 byte [] headersBuffer = null;
259 byte [] entityBuffer = null;
261 StringBuilder responseStr;
262 String reason = null;
264 if (headers != null && headers[CommonTransportKeys.HttpStatusCode] != null) {
265 // The formatter can override the result code
266 httpStatusCode = int.Parse ((string)headers [CommonTransportKeys.HttpStatusCode]);
267 reason = (string) headers [CommonTransportKeys.HttpReasonPhrase];
271 reason = GetReasonPhrase (httpStatusCode);
274 responseStr = new StringBuilder ("HTTP/1.0 " + httpStatusCode + " " + reason + "\r\n" );
278 foreach (DictionaryEntry entry in headers)
280 string key = entry.Key.ToString();
281 if (key != CommonTransportKeys.HttpStatusCode && key != CommonTransportKeys.HttpReasonPhrase)
282 responseStr.Append(key + ": " + entry.Value.ToString() + "\r\n");
286 responseStr.Append("Server: Mono Remoting, Mono CLR " + System.Environment.Version.ToString() + "\r\n");
288 if(responseStream != null && responseStream.Length!=0)
290 responseStr.Append("Content-Length: "+responseStream.Length.ToString()+"\r\n");
291 entityBuffer = new byte[responseStream.Length];
292 responseStream.Seek(0 , SeekOrigin.Begin);
293 responseStream.Read(entityBuffer,0,entityBuffer.Length);
296 responseStr.Append("Content-Length: 0\r\n");
298 responseStr.Append("X-Powered-By: Mono\r\n");
299 responseStr.Append("Connection: close\r\n");
300 responseStr.Append("\r\n");
302 headersBuffer = Encoding.ASCII.GetBytes (responseStr.ToString());
305 reqArg.OutputStream.Write (headersBuffer, 0, headersBuffer.Length);
307 if (entityBuffer != null)
308 reqArg.OutputStream.Write (entityBuffer, 0, entityBuffer.Length);
311 internal static string GetReasonPhrase (int HttpStatusCode)
313 switch (HttpStatusCode)
315 case 100 : return "Continue" ;
316 case 101 :return "Switching Protocols";
317 case 200 :return "OK";
318 case 201 :return "Created";
319 case 202 :return "Accepted";
320 case 203 :return "Non-Authoritative Information";
321 case 204 :return "No Content";
322 case 205 :return "Reset Content";
323 case 206 :return "Partial Content";
324 case 300 :return "Multiple Choices";
325 case 301 :return "Moved Permanently";
326 case 302 :return "Found";
327 case 303 :return "See Other";
328 case 304 :return "Not Modified";
329 case 305 :return "Use Proxy";
330 case 307 :return "Temporary Redirect";
332 case 400 :return "Bad Request";
333 case 401 :return "Unauthorized";
334 case 402 :return "Payment Required";
335 case 403 :return "Forbidden";
336 case 404 :return "Not Found";
337 case 405 :return "Method Not Allowed";
338 case 406 :return "Not Acceptable";
340 case 407 :return "Proxy Authentication Required";
341 case 408 :return "Request Time-out";
342 case 409 :return "Conflict";
343 case 410 :return "Gone";
344 case 411 :return "Length Required";
345 case 412 :return "Precondition Failed";
346 case 413 :return "Request Entity Too Large";
347 case 414 :return "Request-URI Too Large";
348 case 415 :return "Unsupported Media Type";
349 case 416 :return "Requested range not satisfiable";
350 case 417 :return "Expectation Failed";
352 case 500 :return "Internal Server Error";
353 case 501 :return "Not Implemented";
354 case 502 :return "Bad Gateway";
355 case 503 :return "Service Unavailable";
356 case 504 :return "Gateway Time-out";
357 case 505 :return "HTTP Version not supported";
366 internal sealed class ReqMessageParser
368 private const int nCountReq = 14;
369 private const int nCountEntity = 15;
371 private static bool bInitialized = false;
373 private static String [] ReqRegExpString = new String [nCountReq ];
374 private static String [] EntityRegExpString = new String[nCountEntity];
376 private static Regex [] ReqRegExp = new Regex[nCountReq];
377 private static Regex [] EntityRegExp = new Regex[nCountEntity];
381 public ReqMessageParser ()
385 public static bool ParseHeaderField(string buffer,IDictionary headers)
395 if(IsRequestField(buffer,headers))
397 if(IsEntityField(buffer,headers))
411 private static bool Initialize()
419 //Create all the Regular expressions
420 InitializeRequestRegExp();
421 InitiazeEntityRegExp();
423 for(int i=0;i<nCountReq;i++)
424 ReqRegExp[i] = new Regex(ReqRegExpString[i],RegexOptions.Compiled|RegexOptions.IgnoreCase);
426 for(int i=0;i<nCountEntity;i++)
427 EntityRegExp[i] = new Regex(EntityRegExpString[i],RegexOptions.Compiled|RegexOptions.IgnoreCase);
433 private static void InitializeRequestRegExp()
435 //Request Header Fields
437 ReqRegExpString[0] = "^accept(\\s*:\\s*)(?<accept>\\S+)(\\s*|)(\\s*)$";
438 ReqRegExpString[1] = "^accept-charset(\\s*:\\s*)(?<accept_charset>\\S+(\\s|\\S)*\\S)(\\s*)$";
439 ReqRegExpString[2] = "^accept-encoding(\\s*:\\s*)(?<accept_Encoding>\\S+(\\s|\\S)*\\S)(\\s*)$";
440 ReqRegExpString[3] = "^authorization(\\s*:\\s*)(?<authorization>\\S+(\\s|\\S)*\\S)(\\s*)$";
441 ReqRegExpString[4] = "^accept-language(\\s*:\\s*)(?<accept_Language>\\S+(\\s|\\S)*\\S)(\\s*)$";
442 ReqRegExpString[5] = "^from(\\s*:\\s*)(?<from>\\S+(\\s|\\S)*\\S)(\\s*)$";
443 ReqRegExpString[6] = "^host(\\s*:\\s*)(?<host>\\S+(\\s|\\S)*\\S)(\\s*)$";
444 ReqRegExpString[7] = "^if-modified-since(\\s*:\\s*)(?<if_modified>\\S+(\\s|\\S)*\\S)(\\s*)$";
445 ReqRegExpString[8] = "^proxy-authorization(\\s*:\\s*)(?<proxy_auth>\\S+(\\s|\\S)*\\S)(\\s*)$";
446 ReqRegExpString[9] = "^range(\\s*:\\s*)(?<range>\\S+(\\s|\\S)*\\S)(\\s*)$";
447 ReqRegExpString[10] = "^user-agent(\\s*:\\s*)(?<user_agent>\\S+(\\s|\\S)*\\S)(\\s*)$";
448 ReqRegExpString[11] = "^expect(\\s*:\\s*)(?<expect>\\S+(\\s|\\S)*\\S)(\\s*)$";
449 ReqRegExpString[12] = "^connection(\\s*:\\s*)(?<connection>\\S+(\\s|\\S)*\\S)(\\s*)$";
450 ReqRegExpString[13] = "^(?<method>\\w+)(\\s+)(?<request_url>\\S+)(\\s+)(?<http_version>\\S+)(\\s*)$";
451 // ReqRegExpString[14] = "";
454 private static void InitiazeEntityRegExp()
456 EntityRegExpString[0] = "^allow(\\s*:\\s*)(?<allow>[0-9]+)(\\s*)$";
457 EntityRegExpString[1] = "^content-encoding(\\s*:\\s*)(?<content_encoding>\\S+(\\s|\\S)*\\S)(\\s*)$";
458 EntityRegExpString[2] = "^content-language(\\s*:\\s*)(?<content_language>\\S+(\\s|\\S)*\\S)(\\s*)$";
459 EntityRegExpString[3] = "^content-length(\\s*:\\s*)(?<content_length>[0-9]+)(\\s*)$";
460 EntityRegExpString[4] = "^content-range(\\s*:\\s*)(?<content_range>\\S+(\\s|\\S)*\\S)(\\s*)$";
461 EntityRegExpString[5] = "^content-type(\\s*:\\s*)(?<content_type>\\S+(\\s|\\S)*\\S)(\\s*)$";
462 EntityRegExpString[6] = "^content-version(\\s*:\\s*)(?<content_version>\\S+(\\s|\\S)*\\S)(\\s*)$";
463 EntityRegExpString[7] = "^derived-from(\\s*:\\s*)(?<derived_from>\\S+(\\s|\\S)*\\S)(\\s*)$";
464 EntityRegExpString[8] = "^expires(\\s*:\\s*)(?<expires>\\S+(\\s|\\S)*\\S)(\\s*)$";//date
465 EntityRegExpString[9] = "^last-modified(\\s*:\\s*)(?<last_modified>\\S+(\\s|\\S)*\\S)(\\s*)$";//date
466 EntityRegExpString[10] = "^link(\\s*:\\s*)(?<link>\\S+(\\s|\\S)*\\S)(\\s*)$";
467 EntityRegExpString[11] = "^title(\\s*:\\s*)(?<title>\\S+(\\s|\\S)*\\S)(\\s*)$";
468 EntityRegExpString[12] = "^transfere-encoding(\\s*:\\s*)(?<transfere_encoding>\\S+(\\s|\\S)*\\S)(\\s*)$";
469 EntityRegExpString[13] = "^url-header(\\s*:\\s*)(?<url_header>\\S+(\\s|\\S)*\\S)(\\s*)$";
470 EntityRegExpString[14] = "^extension-header(\\s*:\\s*)(?<extension_header>\\S+(\\s|\\S)*\\S)(\\s*)$";
473 private static void CopyGroupNames(Regex regEx , Match m , IDictionary headers)
479 string [] ar = regEx.GetGroupNames();
480 GroupCollection gc = m.Groups;
482 for(int i=0;i<ar.Length;i++)
484 if(! char.IsLetter(ar[i],0))
487 headers.Add(ar[i],gc[ar[i]].Value);
492 private static bool IsRequestField(string buffer , IDictionary HeaderItems)
495 if(Request_accept(buffer , HeaderItems))
498 if(Request_accept_charset(buffer , HeaderItems))
501 if(Request_accept_encoding(buffer , HeaderItems))
504 if(Request_accept_language(buffer , HeaderItems))
507 if(Request_authorization(buffer , HeaderItems))
510 if(Request_connection(buffer , HeaderItems))
513 if(Request_expect(buffer , HeaderItems))
516 if(Request_from(buffer , HeaderItems))
519 if(Request_host(buffer , HeaderItems))
522 if(Request_modified(buffer , HeaderItems))
525 if(Request_proxy_authorization(buffer , HeaderItems))
528 if(Request_user_agent(buffer , HeaderItems))
531 if(Request_request_line(buffer , HeaderItems))
537 private static bool IsEntityField(string buffer , IDictionary HeaderItems)
539 if(Entity_allow(buffer , HeaderItems))
542 if(Entity_content_encoding(buffer , HeaderItems))
545 if(Entity_content_language(buffer , HeaderItems))
548 if(Entity_content_length(buffer , HeaderItems))
551 if(Entity_content_range(buffer , HeaderItems))
554 if(Entity_content_type(buffer , HeaderItems))
557 if(Entity_content_version(buffer , HeaderItems))
560 if(Entity_dervied_from(buffer , HeaderItems))
563 if(Entity_expires(buffer , HeaderItems))
566 if(Entity_extension_header(buffer , HeaderItems))
569 if(Entity_last_modified(buffer , HeaderItems))
572 if(Entity_link(buffer , HeaderItems))
575 if(Entity_title(buffer , HeaderItems))
578 if(Entity_transfere_encoding(buffer , HeaderItems))
581 if(Entity_url_header(buffer , HeaderItems))
588 public static bool IsCustomHeader(string buffer,IDictionary CustomHeader)
590 Regex CustomHeaderEx = new Regex("^(?<header>\\S+)(\\s*:\\s*)(?<field>\\S+(\\s|\\S)*\\S)(\\s*)",RegexOptions.Compiled);
592 Match m = CustomHeaderEx.Match(buffer);
596 CustomHeader.Add(m.Groups["header"].Value,m.Groups["field"].Value);
601 //********************************************************
603 private static bool Request_accept(string buffer,IDictionary HeaderItems)
605 Match m = ReqRegExp[0].Match(buffer);
609 HeaderItems.Add("accept",m.Groups["accept"].Value);
613 private static bool Request_accept_charset(string buffer,IDictionary HeaderItems)
615 Match m = ReqRegExp[1].Match(buffer);
619 HeaderItems.Add("accept-charset",m.Groups["accept_charset"].Value);
623 private static bool Request_accept_encoding(string buffer,IDictionary HeaderItems)
625 Match m = ReqRegExp[2].Match(buffer);
629 HeaderItems.Add("accept-encoding",m.Groups["accept_encoding"].Value);
632 private static bool Request_authorization(string buffer,IDictionary HeaderItems)
634 Match m = ReqRegExp[3].Match(buffer);
638 HeaderItems.Add("authorization",m.Groups["authorization"].Value);
641 private static bool Request_accept_language(string buffer,IDictionary HeaderItems)
643 Match m = ReqRegExp[4].Match(buffer);
647 HeaderItems.Add("accept-language",m.Groups["accept_language"].Value);
650 private static bool Request_from(string buffer,IDictionary HeaderItems)
652 Match m = ReqRegExp[5].Match(buffer);
656 HeaderItems.Add("from",m.Groups["from"].Value);
659 private static bool Request_host(string buffer,IDictionary HeaderItems)
661 Match m = ReqRegExp[6].Match(buffer);
665 HeaderItems.Add("host",m.Groups["host"].Value);
668 private static bool Request_modified(string buffer,IDictionary HeaderItems)
670 Match m = ReqRegExp[7].Match(buffer);
674 HeaderItems.Add("modified",m.Groups["modified"].Value);
677 private static bool Request_proxy_authorization(string buffer,IDictionary HeaderItems)
679 Match m = ReqRegExp[8].Match(buffer);
683 HeaderItems.Add("proxy-authorization",m.Groups["proxy_authorization"].Value);
686 private static bool Request_range(string buffer , IDictionary HeaderItems)
688 Match m = ReqRegExp[9].Match(buffer);
692 HeaderItems.Add("range",m.Groups["range"].Value);
696 private static bool Request_user_agent(string buffer,IDictionary HeaderItems)
698 Match m = ReqRegExp[10].Match(buffer);
702 HeaderItems.Add("user-agent",m.Groups["user_agent"].Value);
705 private static bool Request_expect(string buffer,IDictionary HeaderItems)
707 Match m = ReqRegExp[11].Match(buffer);
711 HeaderItems.Add("expect",m.Groups["expect"].Value);
715 private static bool Request_connection(string buffer,IDictionary HeaderItems)
717 Match m = ReqRegExp[12].Match(buffer);
721 HeaderItems.Add("connection",m.Groups["connection"].Value);
725 private static bool Request_request_line(string buffer, IDictionary HeaderItems)
727 Match m = ReqRegExp[13].Match(buffer);
730 //ReqRegExpString[13] = "(?<method>\\w+)(\\s+)(?<request_url>\\S+)(\\s+)(?<http_version>\\S+)";
732 HeaderItems.Add("method",m.Groups["method"].Value);
733 HeaderItems.Add("request-url",m.Groups["request_url"].Value);
734 HeaderItems.Add("http-version",m.Groups["http_version"].Value);
737 //********************************************************
740 //********************************************************
742 private static bool Entity_allow(string buffer,IDictionary HeaderItems)
744 Match m = EntityRegExp[0].Match(buffer);
748 HeaderItems.Add("allow",m.Groups["allow"].Value);
753 private static bool Entity_content_encoding(string buffer,IDictionary HeaderItems)
755 Match m = EntityRegExp[1].Match(buffer);
759 HeaderItems.Add("content-encoding",m.Groups["content_encoding"].Value);
762 private static bool Entity_content_language(string buffer,IDictionary HeaderItems)
764 Match m = EntityRegExp[2].Match(buffer);
768 HeaderItems.Add("content-language",m.Groups["content_language"].Value);
771 private static bool Entity_content_length(string buffer,IDictionary HeaderItems)
773 Match m = EntityRegExp[3].Match(buffer);
780 length = Int32.Parse(m.Groups["content_length"].ToString());
788 HeaderItems.Add("content-length",length);
791 private static bool Entity_content_range(string buffer,IDictionary HeaderItems)
793 Match m = EntityRegExp[4].Match(buffer);
797 HeaderItems.Add("content-range",m.Groups["content_range"].Value);
800 private static bool Entity_content_type(string buffer,IDictionary HeaderItems)
802 Match m = EntityRegExp[5].Match(buffer);
806 HeaderItems.Add("content-type",m.Groups["content_type"].Value);
810 private static bool Entity_content_version(string buffer,IDictionary HeaderItems)
812 Match m = EntityRegExp[6].Match(buffer);
816 HeaderItems.Add("content-version",m.Groups["content_version"].Value);
819 private static bool Entity_dervied_from(string buffer,IDictionary HeaderItems)
821 Match m = EntityRegExp[7].Match(buffer);
825 HeaderItems.Add("dervied-from",m.Groups["dervied_from"].Value);
828 private static bool Entity_expires(string buffer,IDictionary HeaderItems)
830 Match m = EntityRegExp[8].Match(buffer);
834 HeaderItems.Add("expires",m.Groups["expires"].Value);
837 private static bool Entity_last_modified(string buffer,IDictionary HeaderItems)
839 Match m = EntityRegExp[9].Match(buffer);
843 HeaderItems.Add("last-modified",m.Groups["last_modified"].Value);
846 private static bool Entity_link(string buffer,IDictionary HeaderItems)
848 Match m = EntityRegExp[10].Match(buffer);
852 HeaderItems.Add("link",m.Groups["link"].Value);
855 private static bool Entity_title(string buffer,IDictionary HeaderItems)
857 Match m = EntityRegExp[11].Match(buffer);
861 HeaderItems.Add("title",m.Groups["title"].Value);
865 private static bool Entity_transfere_encoding(string buffer,IDictionary HeaderItems)
867 Match m = EntityRegExp[12].Match(buffer);
871 HeaderItems.Add("transfere-encoding",m.Groups["transfere_encoding"].Value);
874 private static bool Entity_url_header(string buffer,IDictionary HeaderItems)
876 Match m = EntityRegExp[13].Match(buffer);
880 HeaderItems.Add("url-header",m.Groups["url_header"].Value);
884 private static bool Entity_extension_header(string buffer,IDictionary HeaderItems)
886 Match m = EntityRegExp[14].Match(buffer);
890 HeaderItems.Add("extension-header",m.Groups["extension_header"].Value);
894 //********************************************************