MTSC  1.0.0
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 
137  private Dictionary<string, string> headers = new Dictionary<string, string>();
138 
139  #region Properties
140  public MethodEnum Method { get; set; }
141  public string RequestURI { get; set; }
142  public string RequestQuery { get; set; }
143  public byte[] Body { get; set; }
144  public StatusCodes StatusCode { get; set; }
145  #endregion
146  #region Constructors
147  public HttpMessage()
148  {
149  RequestQuery = string.Empty;
150  RequestURI = "/";
151  Method = MethodEnum.Get;
152  }
153  #endregion
154  #region Public Methods
155  public string this[string headerKey] { get => headers[headerKey]; set => headers[headerKey] = value; }
166  public string this[GeneralHeadersEnum headerKey] { get => headers[generalHeaders[(int)headerKey]]; set => headers[generalHeaders[(int)headerKey]] = value; }
172  public string this[ResponseHeadersEnum headerKey] { get => headers[responseHeaders[(int)headerKey]]; set => headers[responseHeaders[(int)headerKey]] = value; }
178  public string this[RequestHeadersEnum headerKey] { get => headers[requestHeaders[(int)headerKey]]; set => headers[requestHeaders[(int)headerKey]] = value; }
184  public string this[EntityHeadersEnum headerKey] { get => headers[entityHeaders[(int)headerKey]]; set => headers[entityHeaders[(int)headerKey]] = value; }
190  public void AddGeneralHeader(GeneralHeadersEnum header, string value)
191  {
192  headers[generalHeaders[(int)header]] = value;
193  }
199  public void AddRequestHeader(RequestHeadersEnum requestHeader, string value)
200  {
201  headers[requestHeaders[(int)requestHeader]] = value;
202  }
208  public void AddResponseHeader(ResponseHeadersEnum responseHeader, string value)
209  {
210  headers[responseHeaders[(int)responseHeader]] = value;
211  }
217  public void AddEntityHeaders(EntityHeadersEnum entityHeader, string value)
218  {
219  headers[entityHeaders[(int)entityHeader]] = value;
220  }
225  public byte[] GetRequest()
226  {
227  StringBuilder requestString = new StringBuilder();
228  requestString.Append(methods[(int)Method]).Append(SP).Append(RequestURI).Append('?').Append(RequestQuery).Append(SP).Append(HTTPVER).Append(CRLF);
229  foreach(KeyValuePair<string, string> header in headers)
230  {
231  requestString.Append(header.Key).Append(':').Append(SP).Append(header.Value).Append(CRLF);
232  }
233  requestString.Append(CRLF);
234  byte[] request = new byte[requestString.Length + (Body == null ? 0 : Body.Length)];
235  byte[] requestBytes = ASCIIEncoding.ASCII.GetBytes(requestString.ToString());
236  Array.Copy(requestBytes, 0, request, 0, requestBytes.Length);
237  if (Body != null)
238  {
239  Array.Copy(Body, 0, request, requestBytes.Length, Body.Length);
240  }
241  return request;
242  }
247  public void ParseRequest(byte[] requestBytes)
248  {
249  /*
250  * Parse the bytes one by one, respecting the reference manual.
251  */
252  StringBuilder parseBuffer = new StringBuilder();
253  /*
254  * Keep the index of the byte array, to identify the message body.
255  * Step value indicates at what point the parsing algorithm currently is.
256  * Step 0 - Method, 1 - URI, 2 - Query, 3 - HTTPVer, 4 - Header, 5 - Value
257  */
258  int step = 0;
259  string headerKey = string.Empty;
260  string headerValue = string.Empty;
261  int bodyIndex = 0;
262  for(int i = 0; i < requestBytes.Length; i++)
263  {
264  if(step == 0)
265  {
266  Method = ParseMethod(requestBytes, ref i);
267  step++;
268  }
269  else if(step == 1)
270  {
271  RequestURI = ParseRequestURI(requestBytes, ref i);
272  if(requestBytes[i] == '?')
273  {
274  step++;
275  }
276  else
277  {
278  step += 2;
279  }
280  }
281  else if(step == 2)
282  {
283  RequestQuery = ParseRequestQuery(requestBytes, ref i);
284  step++;
285  }
286  else if (step == 3)
287  {
288  ParseHTTPVer(requestBytes, ref i);
289  step++;
290  }
291  else if (step == 4)
292  {
293  if(requestBytes[i] == CRLF[0])
294  {
295  continue;
296  }
297  else if(requestBytes[i] == CRLF[1])
298  {
299  bodyIndex = i;
300  break;
301  }
302  else
303  {
304  headerKey = ParseHeaderKey(requestBytes, ref i);
305  step++;
306  }
307  }
308  else if (step == 5)
309  {
310  if (requestBytes[i] == CRLF[0])
311  {
312  continue;
313  }
314  else if (requestBytes[i] == CRLF[1])
315  {
316  bodyIndex = i;
317  break;
318  }
319  else
320  {
321  headerValue = ParseHeaderValue(requestBytes, ref i);
322  headers.Add(headerKey, headerValue);
323  step--;
324  }
325  }
326  }
327  if(requestBytes.Length - bodyIndex > 1)
328  {
329  /*
330  * If the message contains a body, copy it into a different array
331  * and save it into the HTTP message;
332  */
333  this.Body = new byte[requestBytes.Length - bodyIndex];
334  Array.Copy(requestBytes, bodyIndex, this.Body, 0, this.Body.Length);
335  }
336  return;
337  }
345  public byte[] GetResponse(bool includeContentLengthHeader)
346  {
347  if (includeContentLengthHeader)
348  {
349  /*
350  * If there is a body, include the size of the body. If there is no body,
351  * set the value of the content length to 0.
352  */
353  this[EntityHeadersEnum.ContentLength] = Body == null ? "0" : Body.Length.ToString();
354  }
355  StringBuilder responseString = new StringBuilder();
356  responseString.Append(HTTPVER).Append(SP).Append((int)this.StatusCode).Append(SP).Append(this.StatusCode.ToString()).Append(CRLF);
357  foreach (KeyValuePair<string, string> header in headers)
358  {
359  responseString.Append(header.Key).Append(':').Append(SP).Append(header.Value).Append(CRLF);
360  }
361  responseString.Append(CRLF);
362  byte[] response = new byte[responseString.Length + (Body == null ? 0 : Body.Length)];
363  byte[] responseBytes = ASCIIEncoding.ASCII.GetBytes(responseString.ToString());
364  Array.Copy(responseBytes, 0, response, 0, responseBytes.Length);
365  if (Body != null)
366  {
367  Array.Copy(Body, 0, response, responseBytes.Length, Body.Length);
368  }
369  return response;
370  }
375  public void ParseResponse(byte[] responseBytes)
376  {
377  /*
378  * Parse the bytes one by one, respecting the reference manual.
379  */
380  StringBuilder parseBuffer = new StringBuilder();
381  /*
382  * Keep the index of the byte array, to identify the message body.
383  * Step value indicates at what point the parsing algorithm currently is.
384  * Step 0 - HTTPVer, 1 - StatusCodeInt, 2 - StatusCodeString, 3 - Header, 4 - Value
385  */
386  int step = 0;
387  string headerKey = string.Empty;
388  string headerValue = string.Empty;
389  int bodyIndex = 0;
390  for (int i = 0; i < responseBytes.Length; i++)
391  {
392  if (step == 0)
393  {
394  ParseHTTPVer(responseBytes, ref i);
395  step++;
396  }
397  else if (step == 1)
398  {
399  StatusCode = (StatusCodes)ParseResponseCode(responseBytes, ref i);
400  step++;
401  }
402  else if (step == 2)
403  {
404  if(StatusCode != ParseResponseCodeString(responseBytes, ref i))
405  {
406  throw new InvalidStatusCodeException("Status code value and text do not match!");
407  }
408  step++;
409  }
410  else if (step == 3)
411  {
412  if (responseBytes[i] == CRLF[0])
413  {
414  continue;
415  }
416  else if (responseBytes[i] == CRLF[1])
417  {
418  bodyIndex = i;
419  break;
420  }
421  else
422  {
423  headerKey = ParseHeaderKey(responseBytes, ref i);
424  step++;
425  }
426  }
427  else if (step == 4)
428  {
429  if (responseBytes[i] == CRLF[0])
430  {
431  continue;
432  }
433  else if (responseBytes[i] == CRLF[1])
434  {
435  bodyIndex = i;
436  break;
437  }
438  else
439  {
440  headerValue = ParseHeaderValue(responseBytes, ref i);
441  headers.Add(headerKey, headerValue);
442  step--;
443  }
444  }
445  }
446  if (responseBytes.Length - bodyIndex > 1)
447  {
448  /*
449  * If the message contains a body, copy it into a different array
450  * and save it into the HTTP message;
451  */
452  this.Body = new byte[responseBytes.Length - bodyIndex - 1];
453  Array.Copy(responseBytes, bodyIndex, this.Body, 0, this.Body.Length);
454  }
455  return;
456  }
462  public bool ContainsHeader(ResponseHeadersEnum header)
463  {
464  return ContainsHeader(responseHeaders[(int)header]);
465  }
471  public bool ContainsHeader(RequestHeadersEnum header)
472  {
473  return ContainsHeader(requestHeaders[(int)header]);
474  }
480  public bool ContainsHeader(GeneralHeadersEnum header)
481  {
482  return ContainsHeader(generalHeaders[(int)header]);
483  }
489  public bool ContainsHeader(string header)
490  {
491  return headers.ContainsKey(header);
492  }
497  public Dictionary<string, string> GetPostForm()
498  {
499  if (ContainsHeader("Content-Type") && Body != null)
500  {
501  if(this["Content-Type"] == "application/x-www-form-urlencoded")
502  {
503  Dictionary<string, string> returnDictionary = new Dictionary<string, string>();
504  /*
505  * Walk through the buffer and get the form contents.
506  * Step 0 - key, 1 - value.
507  */
508  string formKey = string.Empty;
509  int step = 0;
510  for(int i = 0; i < Body.Length; i++)
511  {
512  if(step == 0)
513  {
514  formKey = GetField(Body, ref i);
515  step++;
516  }
517  else
518  {
519  returnDictionary[formKey] = GetValue(Body, ref i);
520  step--;
521  }
522  }
523  return returnDictionary;
524  }
525  else if (this["Content-Type"].Contains("multipart/form-data"))
526  {
527  throw new NotImplementedException("Multipart posting not implemented");
528  }
529  else
530  {
531  return null;
532  }
533  }
534  else
535  {
536  return null;
537  }
538  }
539  #endregion
540  #region Private Methods
541  private MethodEnum GetMethod(string methodString)
542  {
543  int index = Array.IndexOf(methods, methodString.ToUpper());
544  return (MethodEnum)index;
545  }
546 
547  private MethodEnum ParseMethod(byte[] buffer, ref int index)
548  {
549  /*
550  * Get each character one by one. When meeting a SP character, parse the method, clear the buffer
551  * and continue with parsing the next step.
552  */
553  StringBuilder parseBuffer = new StringBuilder();
554  for (; index < buffer.Length; index++)
555  {
556  try
557  {
558  if (buffer[index] == (byte)SP)
559  {
560  string methodString = parseBuffer.ToString();
561  return GetMethod(methodString);
562  }
563  else
564  {
565  parseBuffer.Append((char)buffer[index]);
566  }
567  }
568  catch (Exception e)
569  {
570  throw new MethodInvalidException("Invalid request method. Buffer: " + parseBuffer.ToString(), e);
571  }
572  }
573  throw new MethodInvalidException("Invalid request method. Buffer: " + parseBuffer.ToString());
574  }
575 
576  private string ParseRequestURI(byte[] buffer, ref int index)
577  {
578  /*
579  * Get each character one by one. When meeting a SP character, parse the URI and clear the buffer.
580  */
581  StringBuilder parseBuffer = new StringBuilder();
582  for (; index < buffer.Length; index++)
583  {
584  try
585  {
586  if (buffer[index] == (byte)SP)
587  {
588  return parseBuffer.ToString();
589  }
590  if (buffer[index] == '?')
591  {
592  return parseBuffer.ToString();
593  }
594  else
595  {
596  parseBuffer.Append((char)buffer[index]);
597  }
598  }
599  catch (Exception e)
600  {
601  throw new InvalidRequestURIException("Invalid request URI. Buffer: " + parseBuffer.ToString(), e);
602  }
603  }
604  throw new InvalidRequestURIException("Invalid request URI. Buffer: " + parseBuffer.ToString());
605  }
606 
607  private string ParseRequestQuery(byte[] buffer, ref int index)
608  {
609  /*
610  * Get each character one by one. When meeting a SP character, parse the URI and clear the buffer.
611  */
612  StringBuilder parseBuffer = new StringBuilder();
613  for (; index < buffer.Length; index++)
614  {
615  try
616  {
617  if (buffer[index] == (byte)SP)
618  {
619  return parseBuffer.ToString();
620  }
621  else
622  {
623  parseBuffer.Append((char)buffer[index]);
624  }
625  }
626  catch (Exception e)
627  {
628  throw new InvalidRequestURIException("Invalid request query. Buffer: " + parseBuffer.ToString(), e);
629  }
630  }
631  throw new InvalidRequestURIException("Invalid request query. Buffer: " + parseBuffer.ToString());
632  }
633 
634  private void ParseHTTPVer(byte[] buffer, ref int index)
635  {
636  /*
637  * Get each character one by one. When meeting a LF character, parse the HTTPVer.
638  * Check if the HTTPVer matches the implementation version.
639  * If not, throw an exception.
640  */
641  StringBuilder parseBuffer = new StringBuilder();
642  for (; index < buffer.Length; index++)
643  {
644  try
645  {
646  if (buffer[index] == CRLF[1] || buffer[index] == SP)
647  {
648  string httpVer = parseBuffer.ToString();
649  if (httpVer != HTTPVER)
650  {
651  throw new InvalidHttpVersionException("Invalid HTTP version. Buffer: " + parseBuffer.ToString());
652  }
653  return;
654  }
655  else if(buffer[index] == CRLF[0])
656  {
657  /*
658  * If a termination character is detected, ignore it and wait for the full terminator.
659  */
660  continue;
661  }
662  else
663  {
664  parseBuffer.Append((char)buffer[index]);
665  }
666  }
667  catch (Exception e)
668  {
669  throw new InvalidHttpVersionException("Invalid HTTP version. Buffer: " + parseBuffer.ToString(), e);
670  }
671  }
672  }
673 
674  private string ParseHeaderKey(byte[] buffer, ref int index)
675  {
676  /*
677  * Get each character one by one. When meeting a ':' character, parse the header key.
678  */
679  StringBuilder parseBuffer = new StringBuilder();
680  for (; index < buffer.Length; index++)
681  {
682  try
683  {
684  if (buffer[index] == ':')
685  {
686  return parseBuffer.ToString();
687  }
688  else
689  {
690  parseBuffer.Append((char)buffer[index]);
691  }
692  }
693  catch (Exception e)
694  {
695  throw new InvalidHeaderException("Invalid Header key. Buffer: " + parseBuffer.ToString(), e);
696  }
697  }
698  throw new InvalidHeaderException("Invalid Header key. Buffer: " + parseBuffer.ToString());
699  }
700 
701  private string ParseHeaderValue(byte[] buffer, ref int index)
702  {
703  /*
704  * Get each character one by one. When meeting a LF character, parse the value.
705  */
706  StringBuilder parseBuffer = new StringBuilder();
707  for (; index < buffer.Length; index++)
708  {
709  try
710  {
711  if (buffer[index] == CRLF[1])
712  {
713  return parseBuffer.ToString().Trim();
714  }
715  else if (buffer[index] == CRLF[0])
716  {
717  /*
718  * If a termination character is detected, ignore it and wait for the full terminator.
719  */
720  continue;
721  }
722  else
723  {
724  parseBuffer.Append((char)buffer[index]);
725  }
726  }
727  catch (Exception e)
728  {
729  throw new InvalidHeaderException("Invalid header value. Buffer: " + parseBuffer.ToString(), e);
730  }
731  }
732  throw new InvalidHeaderException("Invalid header value. Buffer: " + parseBuffer.ToString());
733  }
734 
735  private int ParseResponseCode(byte[] buffer, ref int index)
736  {
737  /*
738  * Get each character one by one. When meeting a SP character, parse the value.
739  */
740  StringBuilder parseBuffer = new StringBuilder();
741  for (; index < buffer.Length; index++)
742  {
743  try
744  {
745  if (buffer[index] == SP)
746  {
747  return int.Parse(parseBuffer.ToString());
748  }
749  else
750  {
751  parseBuffer.Append((char)buffer[index]);
752  }
753  }
754  catch (Exception e)
755  {
756  throw new InvalidStatusCodeException("Invalid status code. Buffer: " + parseBuffer.ToString(), e);
757  }
758  }
759  throw new InvalidStatusCodeException("Invalid status code. Buffer: " + parseBuffer.ToString());
760  }
761 
762  private StatusCodes ParseResponseCodeString(byte[] buffer, ref int index)
763  {
764  /*
765  * Get each character one by one. When meeting a LF character, parse the value.
766  */
767  StringBuilder parseBuffer = new StringBuilder();
768  for (; index < buffer.Length; index++)
769  {
770  try
771  {
772  if (buffer[index] == CRLF[1])
773  {
774  return (StatusCodes)Enum.Parse(typeof(StatusCodes), parseBuffer.ToString().Trim());
775  }
776  else if (buffer[index] == CRLF[0])
777  {
778  /*
779  * If a termination character is detected, ignore it and wait for the full terminator.
780  */
781  continue;
782  }
783  else
784  {
785  parseBuffer.Append((char)buffer[index]);
786  }
787  }
788  catch (Exception e)
789  {
790  throw new InvalidStatusCodeException("Invalid status code. Buffer: " + parseBuffer.ToString(), e);
791  }
792  }
793  throw new InvalidHeaderException("Invalid status code. Buffer: " + parseBuffer.ToString());
794  }
795 
796  private string GetField(byte[] buffer, ref int index)
797  {
798  /*
799  * Get each character one by one. When meeting a LF character, parse the value.
800  */
801  StringBuilder parseBuffer = new StringBuilder();
802  for (; index < buffer.Length; index++)
803  {
804  try
805  {
806  if (buffer[index] == '=')
807  {
808  return parseBuffer.ToString().Trim();
809  }
810  else
811  {
812  parseBuffer.Append((char)buffer[index]);
813  }
814  }
815  catch (Exception e)
816  {
817  throw new InvalidPostFormException("Invalid form field. Buffer: " + parseBuffer.ToString(), e);
818  }
819  }
820  throw new InvalidHeaderException("Invalid form field. Buffer: " + parseBuffer.ToString());
821  }
822 
823  private string GetValue(byte[] buffer, ref int index)
824  {
825  /*
826  * Get each character one by one. When meeting a LF character, parse the value.
827  */
828  StringBuilder parseBuffer = new StringBuilder();
829  for (; index < buffer.Length; index++)
830  {
831  try
832  {
833  if (buffer[index] == '&')
834  {
835  return parseBuffer.ToString().Trim();
836  }
837  else
838  {
839  parseBuffer.Append((char)buffer[index]);
840  }
841  }
842  catch (Exception e)
843  {
844  throw new InvalidPostFormException("Invalid form field. Buffer: " + parseBuffer.ToString(), e);
845  }
846  }
847  return parseBuffer.ToString().Trim();
848  }
849  #endregion
850  }
851 }
bool ContainsHeader(GeneralHeadersEnum header)
Check if the message contains a header.
Definition: HttpMessage.cs:480
byte [] GetResponse(bool includeContentLengthHeader)
Build the response bytes based on the message contents.
Definition: HttpMessage.cs:345
bool ContainsHeader(RequestHeadersEnum header)
Check if the message contains a header.
Definition: HttpMessage.cs:471
void AddEntityHeaders(EntityHeadersEnum entityHeader, string value)
Add an entity header to the message.
Definition: HttpMessage.cs:217
byte [] GetRequest()
Build the request bytes based on the message contents.
Definition: HttpMessage.cs:225
Dictionary< string, string > GetPostForm()
Parse the body into a posted from respecting the reference manual.
Definition: HttpMessage.cs:497
Exception for invalid response status code.
bool ContainsHeader(string header)
Check if the message contains a header.
Definition: HttpMessage.cs:489
Exception for invalid post forms.
void AddResponseHeader(ResponseHeadersEnum responseHeader, string value)
Add a response header to the message.
Definition: HttpMessage.cs:208
bool ContainsHeader(ResponseHeadersEnum header)
Check if the message contains a header.
Definition: HttpMessage.cs:462
void AddGeneralHeader(GeneralHeadersEnum header, string value)
Add a general header to the message.
Definition: HttpMessage.cs:190
Exception in case of Invalid HTTP Version.
void AddRequestHeader(RequestHeadersEnum requestHeader, string value)
Add a request header to the message.
Definition: HttpMessage.cs:199
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:375
void ParseRequest(byte[] requestBytes)
Parse the received bytes and populate the message contents.
Definition: HttpMessage.cs:247