MTSC  1.0.5
Build TCP servers out of modules with handlers for communication, exception and logging.
HttpMessage.cs
1 using MTSC.Exceptions;
2 using System;
3 using System.Collections.Generic;
4 using System.Text;
5 
6 namespace MTSC.Common.Http
7 {
8  public class HttpMessage
9  {
10  public enum StatusCodes
11  {
12  Continue = 100,
13  SwitchingProtocols = 101,
14  OK = 200,
15  Created = 201,
16  Accepted = 202,
17  NonAuthoritativeInformation = 203,
18  NoContent = 204,
19  ResetContent = 205,
20  PartialContent = 206,
21  MultipleChoices = 300,
22  MovedPermanently = 301,
23  Found = 302,
24  SeeOther = 303,
25  NotModified = 304,
26  UseProxy = 305,
27  TemporaryRedirect = 307,
28  BadRequest = 400,
29  Unauthorized = 401,
30  PaymentRequired = 402,
31  Forbidden = 403,
32  NotFound = 404,
33  MethodNotAllowed = 405,
34  NotAcceptable = 406,
35  ProxyAuthenticationRequired = 407,
36  RequestTimeout = 408,
37  Conflict = 409,
38  Gone = 410,
39  LengthRequired = 411,
40  PreconditionFailed = 412,
41  RequestEntityTooLarge = 413,
42  RequestURITooLarge = 414,
43  UnsupportedMediaType = 415,
44  RequestRangeNotSatisfiable = 416,
45  ExpectationFailed = 417,
46  InternalServerError = 500,
47  NotImplemented = 501,
48  BadGateway = 502,
49  ServiceUnavailable = 503,
50  GatewayTimeout = 504,
51  HTTPVersionNotSupported = 505
52  }
53  public enum MethodEnum
54  {
55  Options = 0,
56  Get = 1,
57  Head = 2,
58  Post = 3,
59  Put = 4,
60  Delete = 5,
61  Trace = 6,
62  Connect = 7,
63  ExtensionMethod = 8
64  }
65  public enum GeneralHeadersEnum
66  {
67  CacheControl = 0,
68  Connection = 1,
69  Date = 2,
70  Pragma = 3,
71  Trailer = 4,
72  TransferEncoding = 5,
73  Upgrade = 6,
74  Via = 7,
75  Warning = 8
76  }
77  public enum RequestHeadersEnum
78  {
79  Accept = 0,
80  AcceptCharset = 1,
81  AcceptEncoding = 2,
82  AcceptLanguage = 3,
83  Authorization = 4,
84  Expect = 5,
85  From = 6,
86  Host = 7,
87  IfMatch = 8,
88  IfModifiedSince = 9,
89  IfNoneMatch = 10,
90  IfRange = 11,
91  IfUnmodifiedSince = 12,
92  MaxForwards = 13,
93  ProxyAuthorization = 14,
94  Range = 15,
95  Referer = 16,
96  TE = 17,
97  UserAgent = 18
98  }
99  public enum ResponseHeadersEnum
100  {
101  AcceptRanges = 0,
102  Age = 1,
103  ETag = 2,
104  Location = 3,
105  ProxyAuthentication = 4,
106  RetryAfter = 5,
107  Server = 6,
108  Vary = 7,
109  WWWAuthenticate = 8
110  }
111  public enum EntityHeadersEnum
112  {
113  Allow = 0,
114  ContentEncoding = 1,
115  ContentLanguage = 2,
116  ContentLength = 3,
117  ContentLocation = 4,
118  ContentMD5 = 5,
119  ContentRange = 6,
120  ContentType = 7,
121  Expired = 8,
122  LastModified = 9
123  }
124  private static string[] methods = new string[] { "OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT", "extension-method" };
125  private static string[] generalHeaders = new string[] { "Cache-Control", "Connection", "Date", "Pragma", "Trailer", "Transfer-Encoding", "Upgrade", "Via", "Warning" };
126  private static string[] requestHeaders = new string[] { "Accept", "Accept-Charset", "Accept-Encoding", "Accept-Language", "Authorization", "Expect", "From", "Host", "If-Match",
127  "If-Modified-Since", "If-None-Match", "If-Range", "If-Unmodified-Since", "Max-Forwards", "Proxy-Authorizatio", "Range", "Referer", "TE", "User-Agent"};
128  private static string[] responseHeaders = new string[] { "Accept-Ranges", "Age", "ETag", "Location", "Retry-After", "Server", "Vary", "WWW-Authenticate" };
129  private static string[] entityHeaders = new string[] { "Allow", "Content-Encoding", "Content-Language", "Content-Length", "Content-Location", "Content-MD5", "Content-Range", "Content-Type",
130  "Expires", "Last-Modified" };
131 
132  private static char SP = ' ';
133  private static char HT = '\t';
134  private static string CRLF = "\r\n";
135  private static string HTTPVER = "HTTP/1.1";
136  private static string RequestCookieHeader = "Cookie";
137  private static string ResponseCookieHeader = "Set-Cookie";
138 
139  private Dictionary<string, string> headers = new Dictionary<string, string>();
140  private List<Cookie> cookies = new List<Cookie>();
141 
142  #region Properties
143  public MethodEnum Method { get; set; }
144  public string RequestURI { get; set; }
145  public string RequestQuery { get; set; }
146  public byte[] Body { get; set; }
147  public StatusCodes StatusCode { get; set; }
148  #endregion
149  #region Constructors
150  public HttpMessage()
151  {
152  RequestQuery = string.Empty;
153  RequestURI = "/";
154  Method = MethodEnum.Get;
155  }
156  #endregion
157  #region Public Methods
158  public string this[string headerKey] { get => headers[headerKey]; set => headers[headerKey] = value; }
169  public string this[GeneralHeadersEnum headerKey] { get => headers[generalHeaders[(int)headerKey]]; set => headers[generalHeaders[(int)headerKey]] = value; }
175  public string this[ResponseHeadersEnum headerKey] { get => headers[responseHeaders[(int)headerKey]]; set => headers[responseHeaders[(int)headerKey]] = value; }
181  public string this[RequestHeadersEnum headerKey] { get => headers[requestHeaders[(int)headerKey]]; set => headers[requestHeaders[(int)headerKey]] = value; }
187  public string this[EntityHeadersEnum headerKey] { get => headers[entityHeaders[(int)headerKey]]; set => headers[entityHeaders[(int)headerKey]] = value; }
191  public List<Cookie> Cookies { get => cookies; }
197  public void AddGeneralHeader(GeneralHeadersEnum header, string value)
198  {
199  headers[generalHeaders[(int)header]] = value;
200  }
206  public void AddRequestHeader(RequestHeadersEnum requestHeader, string value)
207  {
208  headers[requestHeaders[(int)requestHeader]] = value;
209  }
215  public void AddResponseHeader(ResponseHeadersEnum responseHeader, string value)
216  {
217  headers[responseHeaders[(int)responseHeader]] = value;
218  }
224  public void AddEntityHeaders(EntityHeadersEnum entityHeader, string value)
225  {
226  headers[entityHeaders[(int)entityHeader]] = value;
227  }
232  public byte[] BuildRequest()
233  {
234  StringBuilder requestString = new StringBuilder();
235  requestString.Append(methods[(int)Method]).Append(SP).Append(RequestURI).Append('?').Append(RequestQuery).Append(SP).Append(HTTPVER).Append(CRLF);
236  foreach(KeyValuePair<string, string> header in headers)
237  {
238  requestString.Append(header.Key).Append(':').Append(SP).Append(header.Value).Append(CRLF);
239  }
240  requestString.Append(CRLF);
241  if(Cookies.Count > 0)
242  {
243  requestString.Append(RequestCookieHeader).Append(':').Append(SP);
244  for(int i = 0; i < Cookies.Count; i++)
245  {
246  Cookie cookie = Cookies[i];
247  requestString.Append(cookie.BuildCookieString());
248  if(i < Cookies.Count - 1)
249  {
250  requestString.Append(';');
251  }
252  }
253  }
254  byte[] request = new byte[requestString.Length + (Body == null ? 0 : Body.Length)];
255  byte[] requestBytes = ASCIIEncoding.ASCII.GetBytes(requestString.ToString());
256  Array.Copy(requestBytes, 0, request, 0, requestBytes.Length);
257  if (Body != null)
258  {
259  Array.Copy(Body, 0, request, requestBytes.Length, Body.Length);
260  }
261  return request;
262  }
267  public void ParseRequest(byte[] requestBytes)
268  {
269  /*
270  * Parse the bytes one by one, respecting the reference manual.
271  */
272  StringBuilder parseBuffer = new StringBuilder();
273  /*
274  * Keep the index of the byte array, to identify the message body.
275  * Step value indicates at what point the parsing algorithm currently is.
276  * Step 0 - Method, 1 - URI, 2 - Query, 3 - HTTPVer, 4 - Header, 5 - Value
277  */
278  int step = 0;
279  string headerKey = string.Empty;
280  string headerValue = string.Empty;
281  int bodyIndex = 0;
282  for(int i = 0; i < requestBytes.Length; i++)
283  {
284  if(step == 0)
285  {
286  Method = ParseMethod(requestBytes, ref i);
287  step++;
288  }
289  else if(step == 1)
290  {
291  RequestURI = ParseRequestURI(requestBytes, ref i);
292  if(requestBytes[i] == '?')
293  {
294  step++;
295  }
296  else
297  {
298  step += 2;
299  }
300  }
301  else if(step == 2)
302  {
303  RequestQuery = ParseRequestQuery(requestBytes, ref i);
304  step++;
305  }
306  else if (step == 3)
307  {
308  ParseHTTPVer(requestBytes, ref i);
309  step++;
310  }
311  else if (step == 4)
312  {
313  if(requestBytes[i] == CRLF[0])
314  {
315  continue;
316  }
317  else if(requestBytes[i] == CRLF[1])
318  {
319  bodyIndex = i;
320  break;
321  }
322  else
323  {
324  headerKey = ParseHeaderKey(requestBytes, ref i);
325  step++;
326  }
327  }
328  else if (step == 5)
329  {
330  if (requestBytes[i] == CRLF[0])
331  {
332  continue;
333  }
334  else if (requestBytes[i] == CRLF[1])
335  {
336  bodyIndex = i;
337  break;
338  }
339  else
340  {
341  headerValue = ParseHeaderValue(requestBytes, ref i);
342  if (headerKey == RequestCookieHeader)
343  {
344  Cookies.Add(new Cookie(headerValue));
345  }
346  else
347  {
348  headers.Add(headerKey, headerValue);
349  }
350  step--;
351  }
352  }
353  }
354  if(requestBytes.Length - bodyIndex > 1)
355  {
356  /*
357  * If the message contains a body, copy it into a different array
358  * and save it into the HTTP message;
359  */
360  this.Body = new byte[requestBytes.Length - bodyIndex];
361  Array.Copy(requestBytes, bodyIndex, this.Body, 0, this.Body.Length);
362  }
363  return;
364  }
372  public byte[] BuildResponse(bool includeContentLengthHeader)
373  {
374  if (includeContentLengthHeader)
375  {
376  /*
377  * If there is a body, include the size of the body. If there is no body,
378  * set the value of the content length to 0.
379  */
380  this[EntityHeadersEnum.ContentLength] = Body == null ? "0" : Body.Length.ToString();
381  }
382  StringBuilder responseString = new StringBuilder();
383  responseString.Append(HTTPVER).Append(SP).Append((int)this.StatusCode).Append(SP).Append(this.StatusCode.ToString()).Append(CRLF);
384  foreach (KeyValuePair<string, string> header in headers)
385  {
386  responseString.Append(header.Key).Append(':').Append(SP).Append(header.Value).Append(CRLF);
387  }
388  responseString.Append(CRLF);
389  foreach(Cookie cookie in Cookies)
390  {
391  responseString.Append(ResponseCookieHeader).Append(':').Append(SP).Append(cookie.BuildCookieString()).Append(CRLF);
392  }
393  byte[] response = new byte[responseString.Length + (Body == null ? 0 : Body.Length)];
394  byte[] responseBytes = ASCIIEncoding.ASCII.GetBytes(responseString.ToString());
395  Array.Copy(responseBytes, 0, response, 0, responseBytes.Length);
396  if (Body != null)
397  {
398  Array.Copy(Body, 0, response, responseBytes.Length, Body.Length);
399  }
400  return response;
401  }
406  public void ParseResponse(byte[] responseBytes)
407  {
408  /*
409  * Parse the bytes one by one, respecting the reference manual.
410  */
411  StringBuilder parseBuffer = new StringBuilder();
412  /*
413  * Keep the index of the byte array, to identify the message body.
414  * Step value indicates at what point the parsing algorithm currently is.
415  * Step 0 - HTTPVer, 1 - StatusCodeInt, 2 - StatusCodeString, 3 - Header, 4 - Value
416  */
417  int step = 0;
418  string headerKey = string.Empty;
419  string headerValue = string.Empty;
420  int bodyIndex = 0;
421  for (int i = 0; i < responseBytes.Length; i++)
422  {
423  if (step == 0)
424  {
425  ParseHTTPVer(responseBytes, ref i);
426  step++;
427  }
428  else if (step == 1)
429  {
430  StatusCode = (StatusCodes)ParseResponseCode(responseBytes, ref i);
431  step++;
432  }
433  else if (step == 2)
434  {
435  if(StatusCode != ParseResponseCodeString(responseBytes, ref i))
436  {
437  throw new InvalidStatusCodeException("Status code value and text do not match!");
438  }
439  step++;
440  }
441  else if (step == 3)
442  {
443  if (responseBytes[i] == CRLF[0])
444  {
445  continue;
446  }
447  else if (responseBytes[i] == CRLF[1])
448  {
449  bodyIndex = i;
450  break;
451  }
452  else
453  {
454  headerKey = ParseHeaderKey(responseBytes, ref i);
455  step++;
456  }
457  }
458  else if (step == 4)
459  {
460  if (responseBytes[i] == CRLF[0])
461  {
462  continue;
463  }
464  else if (responseBytes[i] == CRLF[1])
465  {
466  bodyIndex = i;
467  break;
468  }
469  else
470  {
471  headerValue = ParseHeaderValue(responseBytes, ref i);
472  if (headerKey == ResponseCookieHeader)
473  {
474  Cookies.Add(new Cookie(headerValue));
475  }
476  else
477  {
478  headers.Add(headerKey, headerValue);
479  }
480  step--;
481  }
482  }
483  }
484  if (responseBytes.Length - bodyIndex > 1)
485  {
486  /*
487  * If the message contains a body, copy it into a different array
488  * and save it into the HTTP message;
489  */
490  this.Body = new byte[responseBytes.Length - bodyIndex - 1];
491  Array.Copy(responseBytes, bodyIndex, this.Body, 0, this.Body.Length);
492  }
493  return;
494  }
500  public bool ContainsHeader(ResponseHeadersEnum header)
501  {
502  return ContainsHeader(responseHeaders[(int)header]);
503  }
509  public bool ContainsHeader(RequestHeadersEnum header)
510  {
511  return ContainsHeader(requestHeaders[(int)header]);
512  }
518  public bool ContainsHeader(GeneralHeadersEnum header)
519  {
520  return ContainsHeader(generalHeaders[(int)header]);
521  }
527  public bool ContainsHeader(EntityHeadersEnum header)
528  {
529  return ContainsHeader(entityHeaders[(int)header]);
530  }
536  public bool ContainsHeader(string header)
537  {
538  return headers.ContainsKey(header);
539  }
544  public Dictionary<string, string> GetPostForm()
545  {
546  if (ContainsHeader("Content-Type") && Body != null)
547  {
548  if(this["Content-Type"] == "application/x-www-form-urlencoded")
549  {
550  Dictionary<string, string> returnDictionary = new Dictionary<string, string>();
551  /*
552  * Walk through the buffer and get the form contents.
553  * Step 0 - key, 1 - value.
554  */
555  string formKey = string.Empty;
556  int step = 0;
557  for(int i = 0; i < Body.Length; i++)
558  {
559  if(step == 0)
560  {
561  formKey = GetField(Body, ref i);
562  step++;
563  }
564  else
565  {
566  returnDictionary[formKey] = GetValue(Body, ref i);
567  step--;
568  }
569  }
570  return returnDictionary;
571  }
572  else if (this["Content-Type"].Contains("multipart/form-data"))
573  {
574  throw new NotImplementedException("Multipart posting not implemented");
575  }
576  else
577  {
578  return null;
579  }
580  }
581  else
582  {
583  return null;
584  }
585  }
586  #endregion
587  #region Private Methods
588  private MethodEnum GetMethod(string methodString)
589  {
590  int index = Array.IndexOf(methods, methodString.ToUpper());
591  return (MethodEnum)index;
592  }
593 
594  private MethodEnum ParseMethod(byte[] buffer, ref int index)
595  {
596  /*
597  * Get each character one by one. When meeting a SP character, parse the method, clear the buffer
598  * and continue with parsing the next step.
599  */
600  StringBuilder parseBuffer = new StringBuilder();
601  for (; index < buffer.Length; index++)
602  {
603  try
604  {
605  if (buffer[index] == (byte)SP)
606  {
607  string methodString = parseBuffer.ToString();
608  return GetMethod(methodString);
609  }
610  else
611  {
612  parseBuffer.Append((char)buffer[index]);
613  }
614  }
615  catch (Exception e)
616  {
617  throw new MethodInvalidException("Invalid request method. Buffer: " + parseBuffer.ToString(), e);
618  }
619  }
620  throw new MethodInvalidException("Invalid request method. Buffer: " + parseBuffer.ToString());
621  }
622 
623  private string ParseRequestURI(byte[] buffer, ref int index)
624  {
625  /*
626  * Get each character one by one. When meeting a SP character, parse the URI and clear the buffer.
627  */
628  StringBuilder parseBuffer = new StringBuilder();
629  for (; index < buffer.Length; index++)
630  {
631  try
632  {
633  if (buffer[index] == (byte)SP)
634  {
635  return parseBuffer.ToString();
636  }
637  if (buffer[index] == '?')
638  {
639  return parseBuffer.ToString();
640  }
641  else
642  {
643  parseBuffer.Append((char)buffer[index]);
644  }
645  }
646  catch (Exception e)
647  {
648  throw new InvalidRequestURIException("Invalid request URI. Buffer: " + parseBuffer.ToString(), e);
649  }
650  }
651  throw new InvalidRequestURIException("Invalid request URI. Buffer: " + parseBuffer.ToString());
652  }
653 
654  private string ParseRequestQuery(byte[] buffer, ref int index)
655  {
656  /*
657  * Get each character one by one. When meeting a SP character, parse the URI and clear the buffer.
658  */
659  StringBuilder parseBuffer = new StringBuilder();
660  for (; index < buffer.Length; index++)
661  {
662  try
663  {
664  if (buffer[index] == (byte)SP)
665  {
666  return parseBuffer.ToString();
667  }
668  else
669  {
670  parseBuffer.Append((char)buffer[index]);
671  }
672  }
673  catch (Exception e)
674  {
675  throw new InvalidRequestURIException("Invalid request query. Buffer: " + parseBuffer.ToString(), e);
676  }
677  }
678  throw new InvalidRequestURIException("Invalid request query. Buffer: " + parseBuffer.ToString());
679  }
680 
681  private void ParseHTTPVer(byte[] buffer, ref int index)
682  {
683  /*
684  * Get each character one by one. When meeting a LF character, parse the HTTPVer.
685  * Check if the HTTPVer matches the implementation version.
686  * If not, throw an exception.
687  */
688  StringBuilder parseBuffer = new StringBuilder();
689  for (; index < buffer.Length; index++)
690  {
691  try
692  {
693  if (buffer[index] == CRLF[1] || buffer[index] == SP)
694  {
695  string httpVer = parseBuffer.ToString();
696  if (httpVer != HTTPVER)
697  {
698  throw new InvalidHttpVersionException("Invalid HTTP version. Buffer: " + parseBuffer.ToString());
699  }
700  return;
701  }
702  else if(buffer[index] == CRLF[0])
703  {
704  /*
705  * If a termination character is detected, ignore it and wait for the full terminator.
706  */
707  continue;
708  }
709  else
710  {
711  parseBuffer.Append((char)buffer[index]);
712  }
713  }
714  catch (Exception e)
715  {
716  throw new InvalidHttpVersionException("Invalid HTTP version. Buffer: " + parseBuffer.ToString(), e);
717  }
718  }
719  }
720 
721  private string ParseHeaderKey(byte[] buffer, ref int index)
722  {
723  /*
724  * Get each character one by one. When meeting a ':' character, parse the header key.
725  */
726  StringBuilder parseBuffer = new StringBuilder();
727  for (; index < buffer.Length; index++)
728  {
729  try
730  {
731  if (buffer[index] == ':')
732  {
733  return parseBuffer.ToString();
734  }
735  else
736  {
737  parseBuffer.Append((char)buffer[index]);
738  }
739  }
740  catch (Exception e)
741  {
742  throw new InvalidHeaderException("Invalid Header key. Buffer: " + parseBuffer.ToString(), e);
743  }
744  }
745  throw new InvalidHeaderException("Invalid Header key. Buffer: " + parseBuffer.ToString());
746  }
747 
748  private string ParseHeaderValue(byte[] buffer, ref int index)
749  {
750  /*
751  * Get each character one by one. When meeting a LF character, parse the value.
752  */
753  StringBuilder parseBuffer = new StringBuilder();
754  for (; index < buffer.Length; index++)
755  {
756  try
757  {
758  if (buffer[index] == CRLF[1])
759  {
760  return parseBuffer.ToString().Trim();
761  }
762  else if (buffer[index] == CRLF[0])
763  {
764  /*
765  * If a termination character is detected, ignore it and wait for the full terminator.
766  */
767  continue;
768  }
769  else
770  {
771  parseBuffer.Append((char)buffer[index]);
772  }
773  }
774  catch (Exception e)
775  {
776  throw new InvalidHeaderException("Invalid header value. Buffer: " + parseBuffer.ToString(), e);
777  }
778  }
779  throw new InvalidHeaderException("Invalid header value. Buffer: " + parseBuffer.ToString());
780  }
781 
782  private int ParseResponseCode(byte[] buffer, ref int index)
783  {
784  /*
785  * Get each character one by one. When meeting a SP character, parse the value.
786  */
787  StringBuilder parseBuffer = new StringBuilder();
788  for (; index < buffer.Length; index++)
789  {
790  try
791  {
792  if (buffer[index] == SP)
793  {
794  return int.Parse(parseBuffer.ToString());
795  }
796  else
797  {
798  parseBuffer.Append((char)buffer[index]);
799  }
800  }
801  catch (Exception e)
802  {
803  throw new InvalidStatusCodeException("Invalid status code. Buffer: " + parseBuffer.ToString(), e);
804  }
805  }
806  throw new InvalidStatusCodeException("Invalid status code. Buffer: " + parseBuffer.ToString());
807  }
808 
809  private StatusCodes ParseResponseCodeString(byte[] buffer, ref int index)
810  {
811  /*
812  * Get each character one by one. When meeting a LF character, parse the value.
813  */
814  StringBuilder parseBuffer = new StringBuilder();
815  for (; index < buffer.Length; index++)
816  {
817  try
818  {
819  if (buffer[index] == CRLF[1])
820  {
821  return (StatusCodes)Enum.Parse(typeof(StatusCodes), parseBuffer.ToString().Trim());
822  }
823  else if (buffer[index] == CRLF[0])
824  {
825  /*
826  * If a termination character is detected, ignore it and wait for the full terminator.
827  */
828  continue;
829  }
830  else
831  {
832  parseBuffer.Append((char)buffer[index]);
833  }
834  }
835  catch (Exception e)
836  {
837  throw new InvalidStatusCodeException("Invalid status code. Buffer: " + parseBuffer.ToString(), e);
838  }
839  }
840  throw new InvalidHeaderException("Invalid status code. Buffer: " + parseBuffer.ToString());
841  }
842 
843  private string GetField(byte[] buffer, ref int index)
844  {
845  /*
846  * Get each character one by one. When meeting a LF character, parse the value.
847  */
848  StringBuilder parseBuffer = new StringBuilder();
849  for (; index < buffer.Length; index++)
850  {
851  try
852  {
853  if (buffer[index] == '=')
854  {
855  return parseBuffer.ToString().Trim();
856  }
857  else
858  {
859  parseBuffer.Append((char)buffer[index]);
860  }
861  }
862  catch (Exception e)
863  {
864  throw new InvalidPostFormException("Invalid form field. Buffer: " + parseBuffer.ToString(), e);
865  }
866  }
867  throw new InvalidHeaderException("Invalid form field. Buffer: " + parseBuffer.ToString());
868  }
869 
870  private string GetValue(byte[] buffer, ref int index)
871  {
872  /*
873  * Get each character one by one. When meeting a LF character, parse the value.
874  */
875  StringBuilder parseBuffer = new StringBuilder();
876  for (; index < buffer.Length; index++)
877  {
878  try
879  {
880  if (buffer[index] == '&')
881  {
882  return parseBuffer.ToString().Trim();
883  }
884  else
885  {
886  parseBuffer.Append((char)buffer[index]);
887  }
888  }
889  catch (Exception e)
890  {
891  throw new InvalidPostFormException("Invalid form field. Buffer: " + parseBuffer.ToString(), e);
892  }
893  }
894  return parseBuffer.ToString().Trim();
895  }
896  #endregion
897  }
898 }
bool ContainsHeader(GeneralHeadersEnum header)
Check if the message contains a header.
Definition: HttpMessage.cs:518
bool ContainsHeader(RequestHeadersEnum header)
Check if the message contains a header.
Definition: HttpMessage.cs:509
void AddEntityHeaders(EntityHeadersEnum entityHeader, string value)
Add an entity header to the message.
Definition: HttpMessage.cs:224
Dictionary< string, string > GetPostForm()
Parse the body into a posted from respecting the reference manual.
Definition: HttpMessage.cs:544
bool ContainsHeader(EntityHeadersEnum header)
Check if the message contains a header.
Definition: HttpMessage.cs:527
byte [] BuildRequest()
Build the request bytes based on the message contents.
Definition: HttpMessage.cs:232
Exception for invalid response status code.
bool ContainsHeader(string header)
Check if the message contains a header.
Definition: HttpMessage.cs:536
byte [] BuildResponse(bool includeContentLengthHeader)
Build the response bytes based on the message contents.
Definition: HttpMessage.cs:372
Exception for invalid post forms.
void AddResponseHeader(ResponseHeadersEnum responseHeader, string value)
Add a response header to the message.
Definition: HttpMessage.cs:215
bool ContainsHeader(ResponseHeadersEnum header)
Check if the message contains a header.
Definition: HttpMessage.cs:500
void AddGeneralHeader(GeneralHeadersEnum header, string value)
Add a general header to the message.
Definition: HttpMessage.cs:197
List< Cookie > Cookies
List of cookies.
Definition: HttpMessage.cs:191
Exception in case of Invalid HTTP Version.
void AddRequestHeader(RequestHeadersEnum requestHeader, string value)
Add a request header to the message.
Definition: HttpMessage.cs:206
Exception cause by an invalid request URI.
Definition: Client.cs:14
void ParseResponse(byte[] responseBytes)
Parse the received bytes and populate the message contents.
Definition: HttpMessage.cs:406
void ParseRequest(byte[] requestBytes)
Parse the received bytes and populate the message contents.
Definition: HttpMessage.cs:267