public static Boolean TryParseI18NString(HTTPRequest HTTPRequest, JObject DescriptionJSON, out I18NString I18N, out HTTPResponse Response) { if (DescriptionJSON == null) { I18N = null; Response = new HTTPResponseBuilder(HTTPRequest) { HTTPStatusCode = HTTPStatusCode.BadRequest, ContentType = HTTPContentType.JSON_UTF8, Content = new JObject(new JProperty("description", "Invalid roaming network description!")).ToUTF8Bytes() }.AsImmutable(); return(false); } Languages Language; JValue Text; I18N = I18NString.Empty; foreach (var Description in DescriptionJSON) { if (!Enum.TryParse(Description.Key, out Language)) { I18N = null; Response = new HTTPResponseBuilder(HTTPRequest) { HTTPStatusCode = HTTPStatusCode.BadRequest, ContentType = HTTPContentType.JSON_UTF8, Content = new JObject(new JProperty("description", "Unknown or invalid language definition '" + Description.Key + "'!")).ToUTF8Bytes() }.AsImmutable(); return(false); } Text = Description.Value as JValue; if (Text == null) { I18N = null; Response = new HTTPResponseBuilder(HTTPRequest) { HTTPStatusCode = HTTPStatusCode.BadRequest, ContentType = HTTPContentType.JSON_UTF8, Content = new JObject(new JProperty("description", "Invalid description text!")).ToUTF8Bytes() }.AsImmutable(); return(false); } I18N.Add(Language, Text.Value <String>()); } Response = null; return(true); }
private HTTPResponse(HTTPRequest Request, TContent Content) : this(HTTPResponseBuilder.OK(Request), Content, false) { }
public Boolean ParseMandatory(String PropertyName, String PropertyDescription, String DefaultServerName, out DateTime Timestamp, HTTPRequest HTTPRequest, out HTTPResponse HTTPResponse) { Object JSONToken = null; Timestamp = DateTime.MinValue; if (TryGetValue(PropertyName, out JSONToken)) { if (JSONToken != null) { try { Timestamp = (DateTime)JSONToken; } catch (Exception) { HTTPResponse = new HTTPResponseBuilder(HTTPRequest) { HTTPStatusCode = HTTPStatusCode.BadRequest, Server = DefaultServerName, Date = DateTime.Now, ContentType = HTTPContentType.JSON_UTF8, Content = JSONObject.Create( new JProperty("description", "Invalid timestamp '" + JSONToken.ToString() + "'!") ).ToUTF8Bytes() }; return(false); } } HTTPResponse = null; return(true); } else { HTTPResponse = new HTTPResponseBuilder(HTTPRequest) { HTTPStatusCode = HTTPStatusCode.BadRequest, Server = DefaultServerName, Date = DateTime.Now, ContentType = HTTPContentType.JSON_UTF8, Content = JSONObject.Create( new JProperty("description", "Missing property '" + PropertyName + "'!") ).ToUTF8Bytes() }; return(false); } }
public Boolean ParseMandatory <T>(String PropertyName, String PropertyDescription, String DefaultServerName, PFunc <T> Parser, out T Value, HTTPRequest HTTPRequest, out HTTPResponse HTTPResponse) { Object JSONToken = null; if (!TryGetValue(PropertyName, out JSONToken)) { HTTPResponse = new HTTPResponseBuilder(HTTPRequest) { HTTPStatusCode = HTTPStatusCode.BadRequest, Server = DefaultServerName, Date = DateTime.Now, ContentType = HTTPContentType.JSON_UTF8, Content = JSONObject.Create( new JProperty("description", "Missing JSON property '" + PropertyName + "'!") ).ToUTF8Bytes() }; Value = default(T); return(false); } if (JSONToken != null) { if (!Parser(JSONToken.ToString(), out Value)) { HTTPResponse = new HTTPResponseBuilder(HTTPRequest) { HTTPStatusCode = HTTPStatusCode.BadRequest, Server = DefaultServerName, Date = DateTime.Now, ContentType = HTTPContentType.JSON_UTF8, Content = JSONObject.Create( new JProperty("description", "Unknown " + PropertyDescription + "!") ).ToUTF8Bytes() }; Value = default(T); return(false); } HTTPResponse = null; return(true); } Value = default(T); HTTPResponse = null; return(true); }
/// <summary> /// Create a new 200-OK HTTP response and apply the given delegate. /// </summary> /// <param name="Configurator">A delegate to configure the HTTP response.</param> public static HTTPResponseBuilder OK(HTTPRequest HTTPRequest, Action <HTTPResponseBuilder> Configurator = null) { var response = new HTTPResponseBuilder(HTTPRequest). SetHTTPStatusCode(HTTPStatusCode.OK); Configurator?.Invoke(response); return(response); }
public Boolean ParseMandatory(String PropertyName, String PropertyDescription, String DefaultServerName, out JToken JSON, HTTPRequest HTTPRequest, out HTTPResponse HTTPResponse) { Object JSONToken = null; if (PropertyName.IsNotNullOrEmpty()) { if (!TryGetValue(PropertyName, out JSONToken)) { HTTPResponse = new HTTPResponseBuilder(HTTPRequest) { HTTPStatusCode = HTTPStatusCode.BadRequest, Server = DefaultServerName, Date = DateTime.Now, ContentType = HTTPContentType.JSON_UTF8, Content = JSONObject.Create( new JProperty("description", "Missing JSON property '" + PropertyName + "'!") ).ToUTF8Bytes() }; JSON = new JValue(false); return(false); } } JSON = null; switch (JSONToken.GetType().Name) { case "String": JSON = new JValue(JSONToken); break; case "JObject": JSON = JObject.Parse(JSONToken.ToString()); break; case "JArray": JSON = JArray.Parse(JSONToken.ToString()); break; } // JSON = JToken.Parse(JSONToken.ToString()); HTTPResponse = null; return(true); }
/// <summary> /// Create a new 200-OK HTTP response and apply the given delegate. /// </summary> /// <param name="Configurator">A delegate to configure the HTTP response.</param> public static HTTPResponseBuilder OK(HTTPRequest HTTPRequest, Func <HTTPResponseBuilder, HTTPResponseBuilder> Configurator) { var response = new HTTPResponseBuilder(HTTPRequest);// (HTTPStatusCode.OK); if (Configurator != null) { return(Configurator(response)); } return(response); }
private void NotifyErrors(HTTPRequest HTTPRequest, TCPConnection TCPConnection, DateTime Timestamp, HTTPStatusCode HTTPStatusCode, HTTPRequest Request = null, HTTPResponse Response = null, String Error = null, Exception LastException = null, Boolean CloseConnection = true) { #region Call OnError delegates var ErrorLogLocal = ErrorLog; if (ErrorLogLocal != null) { ErrorLogLocal(this, Timestamp, Request, Response, Error, LastException); } #endregion #region Send error page to HTTP client var Content = String.Empty; if (Error != null) { Content += Error + Environment.NewLine; } if (LastException != null) { Content += LastException.Message + Environment.NewLine; } var _HTTPResponse = new HTTPResponseBuilder(HTTPRequest) { HTTPStatusCode = HTTPStatusCode, Date = Timestamp, Content = Content.ToUTF8Bytes() }; TCPConnection.WriteLineToResponseStream(_HTTPResponse.ToString()); if (CloseConnection) { TCPConnection.Close(); } #endregion }
public Boolean ParseOptionalN <T>(String PropertyName, String PropertyDescription, String DefaultServerName, PFunc <T> Parser, out T?Value, HTTPRequest HTTPRequest, out HTTPResponse HTTPResponse) where T : struct { Object JSONToken = null; Value = new T?(); if (TryGetValue(PropertyName, out JSONToken)) { if (JSONToken != null) { var JSONValue = JSONToken.ToString(); T _Value = default(T); if (JSONValue != null && !Parser(JSONValue, out _Value)) { HTTPResponse = new HTTPResponseBuilder(HTTPRequest) { HTTPStatusCode = HTTPStatusCode.BadRequest, Server = DefaultServerName, Date = DateTime.Now, ContentType = HTTPContentType.JSON_UTF8, Content = JSONObject.Create( new JProperty("description", "Unknown " + PropertyDescription + "!") ).ToUTF8Bytes() }; Value = new T?(); return(false); } Value = new T?(_Value); } } HTTPResponse = null; return(true); }
public Boolean ParseMandatory(IEnumerable <String> PropertyNames, String PropertyDescription, String DefaultServerName, out String Text, HTTPRequest HTTPRequest, out HTTPResponse HTTPResponse) { Object JSONToken = null; // Attention: JSONToken is a side-effect! var FirstMatchingPropertyName = PropertyNames. Where(propertyname => TryGetValue(propertyname, out JSONToken)). FirstOrDefault(); if (FirstMatchingPropertyName != null) { HTTPResponse = new HTTPResponseBuilder(HTTPRequest) { HTTPStatusCode = HTTPStatusCode.BadRequest, Server = DefaultServerName, Date = DateTime.Now, ContentType = HTTPContentType.JSON_UTF8, Content = JSONObject.Create( new JProperty("description", "Missing at least one of the following properties: " + PropertyNames.AggregateWith(", ") + "!") ).ToUTF8Bytes() }; Text = String.Empty; return(false); } if (JSONToken != null) { Text = JSONToken.ToString(); } else { Text = String.Empty; } HTTPResponse = null; return(true); }
public Boolean ParseOptional(IEnumerable <String> PropertyNames, String PropertyDescription, String DefaultServerName, out DateTime?Timestamp, HTTPRequest HTTPRequest, out HTTPResponse HTTPResponse) { Object JSONToken = null; Timestamp = DateTime.MinValue; // Attention: JSONToken is a side-effect! var FirstMatchingPropertyName = PropertyNames. Where(propertyname => TryGetValue(propertyname, out JSONToken)). FirstOrDefault(); if (FirstMatchingPropertyName != null) { if (JSONToken != null) { try { Timestamp = (DateTime)JSONToken; } catch (Exception) { HTTPResponse = new HTTPResponseBuilder(HTTPRequest) { HTTPStatusCode = HTTPStatusCode.BadRequest, Server = DefaultServerName, Date = DateTime.Now, ContentType = HTTPContentType.JSON_UTF8, Content = JSONObject.Create( new JProperty("description", "Invalid timestamp '" + JSONToken + "'!") ).ToUTF8Bytes() }; return(false); } } } HTTPResponse = null; return(true); }
public static Boolean TryParseUTF8StringRequestBody(this HTTPRequest Request, HTTPContentType ContentType, out String Text, out HTTPResponse HTTPResponse, Boolean AllowEmptyHTTPBody = false) { #region AllowEmptyHTTPBody Text = null; HTTPResponse = null; if (Request.ContentLength == 0 && AllowEmptyHTTPBody) { HTTPResponse = new HTTPResponseBuilder(Request) { HTTPStatusCode = HTTPStatusCode.OK, }; return(false); } #endregion #region Get text body var RequestBodyString = Request.GetRequestBodyAsUTF8String(ContentType, AllowEmptyHTTPBody); if (RequestBodyString.HasErrors) { HTTPResponse = RequestBodyString.Error; return(false); } #endregion Text = RequestBodyString.Data; return(true); }
public Boolean ParseOptional(String PropertyName, String DefaultServerName, out JObject JSON, HTTPRequest HTTPRequest, out HTTPResponse HTTPResponse) { Object JSONToken = null; if (TryGetValue(PropertyName, out JSONToken)) { JSON = JSONToken as JObject; if (JSON == null) { HTTPResponse = new HTTPResponseBuilder(HTTPRequest) { HTTPStatusCode = HTTPStatusCode.BadRequest, Server = DefaultServerName, Date = DateTime.Now, ContentType = HTTPContentType.JSON_UTF8, Content = JSONObject.Create( new JProperty("description", "JSON object expected!") ).ToUTF8Bytes() }; return(false); } HTTPResponse = null; return(true); } JSON = null; HTTPResponse = null; return(true); }
public Boolean ParseMandatory(String PropertyName, String PropertyDescription, String DefaultServerName, out String Text, HTTPRequest HTTPRequest, out HTTPResponse HTTPResponse) { Object JSONToken = null; if (PropertyName.IsNotNullOrEmpty()) { if (!TryGetValue(PropertyName, out JSONToken)) { HTTPResponse = new HTTPResponseBuilder(HTTPRequest) { HTTPStatusCode = HTTPStatusCode.BadRequest, Server = DefaultServerName, Date = DateTime.Now, ContentType = HTTPContentType.JSON_UTF8, Content = JSONObject.Create( new JProperty("description", "Missing JSON property '" + PropertyName + "'!") ).ToUTF8Bytes() }; Text = String.Empty; return(false); } } Text = JSONToken.ToString(); HTTPResponse = null; return(true); }
public static Boolean TryParseJObjectRequestBody(this HTTPRequest HTTPRequest, out JSONWrapper JSON, out HTTPResponse HTTPResponse, Boolean AllowEmptyHTTPBody = false, String JSONLDContext = null) { #region AllowEmptyHTTPBody JSON = null; HTTPResponse = null; if (HTTPRequest.ContentLength == 0 && AllowEmptyHTTPBody) { HTTPResponse = new HTTPResponseBuilder(HTTPRequest) { HTTPStatusCode = HTTPStatusCode.OK, }; return false; } #endregion #region Get text body var RequestBodyString = HTTPRequest.GetRequestBodyAsUTF8String(HTTPContentType.JSON_UTF8); if (RequestBodyString.HasErrors) { HTTPResponse = RequestBodyString.Error; return false; } #endregion #region Try to parse the JSON try { JSON = new JSONWrapper(RequestBodyString.Data); } catch (Exception e) { HTTPResponse = new HTTPResponseBuilder(HTTPRequest) { HTTPStatusCode = HTTPStatusCode.BadRequest, ContentType = HTTPContentType.JSON_UTF8, Content = JSONObject.Create( JSONLDContext.IsNotNullOrEmpty() ? new JProperty("context", JSONLDContext) : null, new JProperty("description", "Invalid JSON request body!"), new JProperty("hint", e.Message) ).ToUTF8Bytes() }; return false; } return true; #endregion }
/// <summary> /// Execute the given HTTP request and return its result. /// </summary> /// <param name="Request">A HTTP request.</param> /// <param name="RequestLogDelegate">A delegate for logging the HTTP request.</param> /// <param name="ResponseLogDelegate">A delegate for logging the HTTP request/response.</param> /// <param name="Timeout">An optional timeout.</param> /// <param name="CancellationToken">A cancellation token.</param> public async Task <HTTPResponse> Execute(HTTPRequest Request, ClientRequestLogHandler RequestLogDelegate = null, ClientResponseLogHandler ResponseLogDelegate = null, TimeSpan?Timeout = null, CancellationToken?CancellationToken = null) { #region Call the optional HTTP request log delegate try { RequestLogDelegate?.Invoke(DateTime.Now, this, Request); } catch (Exception e) { e.Log(nameof(HTTPClient) + "." + nameof(RequestLogDelegate)); } #endregion var task = Task <HTTPResponse> .Factory.StartNew(() => { HTTPResponse Response = null; try { if (Environment.MachineName.Contains("QUAD2QUANTOR") && Request.URI.Contains("eRoaming")) { throw new Exception("Catch me if you can!"); } Thread.CurrentThread.Priority = ThreadPriority.BelowNormal; #region Data var HTTPHeaderBytes = new Byte[0]; var sw = new Stopwatch(); if (!Timeout.HasValue) { Timeout = TimeSpan.FromSeconds(60); } #endregion #region Create TCP connection (possibly also do DNS lookups) if (TCPClient == null) { System.Net.IPEndPoint _FinalIPEndPoint = null; IIPAddress _ResolvedRemoteIPAddress = null; if (RemoteIPAddress == null) { if (Hostname.Trim() == "127.0.0.1") { _ResolvedRemoteIPAddress = IPv4Address.Localhost; } else { var RegExpr = new Regex(@"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b"); if (RegExpr.IsMatch(Hostname)) { _ResolvedRemoteIPAddress = IPv4Address.Parse(Hostname); } } #region DNS lookup... if (_ResolvedRemoteIPAddress == null) { try { var IPv4AddressTask = DNSClient. Query <A>(Hostname). ContinueWith(QueryTask => QueryTask.Result. Select(ARecord => ARecord.IPv4Address). FirstOrDefault()); IPv4AddressTask.Wait(); _ResolvedRemoteIPAddress = IPv4AddressTask.Result; } catch (Exception e) { Debug.WriteLine("[" + DateTime.Now + "] " + e.Message); } } #endregion } else { _ResolvedRemoteIPAddress = RemoteIPAddress; } _FinalIPEndPoint = new System.Net.IPEndPoint(new System.Net.IPAddress(_ResolvedRemoteIPAddress.GetBytes()), RemotePort.ToInt32()); sw.Start(); TCPClient = new TcpClient(); TCPClient.Connect(_FinalIPEndPoint); TCPClient.ReceiveTimeout = (Int32)Timeout.Value.TotalMilliseconds; } #endregion #region Create (Crypto-)Stream TCPStream = TCPClient.GetStream(); TCPStream.ReadTimeout = (Int32)Timeout.Value.TotalMilliseconds; TLSStream = RemoteCertificateValidator != null ? new SslStream(TCPStream, false, RemoteCertificateValidator) // ClientCertificateSelector, //EncryptionPolicy.RequireEncryption) : null; if (TLSStream != null) { TLSStream.ReadTimeout = (Int32)Timeout.Value.TotalMilliseconds; } HTTPStream = null; if (RemoteCertificateValidator != null) { HTTPStream = TLSStream; TLSStream.AuthenticateAsClient(Hostname);//, new X509CertificateCollection(new X509Certificate[] { ClientCert }), SslProtocols.Default, false); } else { HTTPStream = TCPStream; } HTTPStream.ReadTimeout = (Int32)Timeout.Value.TotalMilliseconds; #endregion #region Send Request HTTPStream.Write(String.Concat(Request.EntireRequestHeader, Environment.NewLine, Environment.NewLine). ToUTF8Bytes()); var RequestBodyLength = Request.HTTPBody == null ? Request.ContentLength.HasValue ? (Int32)Request.ContentLength.Value : 0 : Request.ContentLength.HasValue ? Math.Min((Int32)Request.ContentLength.Value, Request.HTTPBody.Length) : Request.HTTPBody.Length; if (RequestBodyLength > 0) { HTTPStream.Write(Request.HTTPBody, 0, RequestBodyLength); } var _MemoryStream = new MemoryStream(); var _Buffer = new Byte[10485760]; // 10 MBytes, a smaller value leads to read errors! #endregion #region Wait timeout for the server to react! //Debug.WriteLine("[" + DateTime.Now + "] HTTPClient timeout: " + Timeout.Value.ToString()); while (!TCPStream.DataAvailable) { if (sw.ElapsedMilliseconds >= Timeout.Value.TotalMilliseconds) { TCPClient.Close(); throw new Exception("[" + DateTime.Now + "] Could not read from the TCP stream for " + sw.ElapsedMilliseconds + "ms!"); } Thread.Sleep(1); } //Debug.WriteLine("[" + DateTime.Now + "] HTTPClient (" + TCPClient.Client.LocalEndPoint.ToString() + " -> " + RemoteSocket.ToString() + ") got first response after " + sw.ElapsedMilliseconds + "ms!"); #endregion #region Read the entire HTTP header, and maybe some of the HTTP body var CurrentDataLength = 0; do { #region When data available, write it to the buffer... while (TCPStream.DataAvailable) { CurrentDataLength = HTTPStream.Read(_Buffer, 0, _Buffer.Length); if (CurrentDataLength > -1) { _MemoryStream.Write(_Buffer, 0, CurrentDataLength); // Debug.WriteLine("[" + DateTime.Now + "] Read " + CurrentDataLength + " bytes from HTTP connection (" + TCPClient.Client.LocalEndPoint.ToString() + " -> " + RemoteSocket.ToString() + ") (" + sw.ElapsedMilliseconds + "ms)!"); } } #endregion #region Check if the entire HTTP header was already read into the buffer if (_MemoryStream.Length > 4) { var MemoryCopy = _MemoryStream.ToArray(); for (var pos = 3; pos < MemoryCopy.Length; pos++) { if (MemoryCopy[pos] == 0x0a && MemoryCopy[pos - 1] == 0x0d && MemoryCopy[pos - 2] == 0x0a && MemoryCopy[pos - 3] == 0x0d) { Array.Resize(ref HTTPHeaderBytes, pos - 3); Array.Copy(MemoryCopy, 0, HTTPHeaderBytes, 0, pos - 3); break; } } //if (HTTPHeaderBytes.Length > 0) // Debug.WriteLine("[" + DateTime.Now + "] End of (" + TCPClient.Client.LocalEndPoint.ToString() + " -> " + RemoteSocket.ToString() + ") HTTP header at " + HTTPHeaderBytes.Length + " bytes (" + sw.ElapsedMilliseconds + "ms)!"); } #endregion Thread.Sleep(1); } // Note: Delayed parts of the HTTP body may not be read into the buffer // => Must be read later! while (TCPStream.DataAvailable || ((sw.ElapsedMilliseconds < HTTPStream.ReadTimeout) && HTTPHeaderBytes.Length == 0)); //Debug.WriteLine("[" + DateTime.Now + "] Finally read " + _MemoryStream.Length + " bytes of HTTP client (" + TCPClient.Client.LocalEndPoint.ToString() + " -> " + RemoteSocket.ToString() + ") data (" + sw.ElapsedMilliseconds + "ms)!"); #endregion #region Copy HTTP header data and create HTTP response if (HTTPHeaderBytes.Length == 0) { throw new ApplicationException(DateTime.Now + " Could not find the end of the HTTP protocol header!"); } Response = HTTPResponse.Parse(HTTPHeaderBytes.ToUTF8String(), Request); #endregion #region Read 'Content-Length' bytes... // Copy only the number of bytes given within // the HTTP header element 'Content-Length'! if (Response.ContentLength.HasValue && Response.ContentLength.Value > 0) { _MemoryStream.Seek(HTTPHeaderBytes.Length + 4, SeekOrigin.Begin); var _Read = _MemoryStream.Read(_Buffer, 0, _Buffer.Length); var _StillToRead = (Int32)Response.ContentLength.Value - _Read; Response.HTTPBodyStream.Write(_Buffer, 0, _Read); var _CurrentBufferSize = 0; do { while (TCPStream.DataAvailable && _StillToRead > 0) { _CurrentBufferSize = Math.Min(_Buffer.Length, (Int32)_StillToRead); _Read = HTTPStream.Read(_Buffer, 0, _CurrentBufferSize); Response.HTTPBodyStream.Write(_Buffer, 0, _Read); _StillToRead -= _Read; } if (_StillToRead <= 0) { break; } Thread.Sleep(1); }while (sw.ElapsedMilliseconds < HTTPStream.ReadTimeout); Response.ContentStreamToArray(); } #endregion #region ...or read till timeout (e.g. for chunked transport)! else { try { _MemoryStream.Seek(HTTPHeaderBytes.Length + 4, SeekOrigin.Begin); Response.NewContentStream(); Response.HTTPBodyStream.Write(_Buffer, 0, _MemoryStream.Read(_Buffer, 0, _Buffer.Length)); var Retries = 0; while (Retries < 10) { while (TCPStream.DataAvailable) { Response.HTTPBodyStream.Write(_Buffer, 0, HTTPStream.Read(_Buffer, 0, _Buffer.Length)); Retries = 0; } Thread.Sleep(10); Retries++; } if (Response.TransferEncoding == "chunked") { //Debug.WriteLine(DateTime.Now + " Chunked encoding detected"); var TEContent = ((MemoryStream)Response.HTTPBodyStream).ToArray(); var TEString = TEContent.ToUTF8String(); var ReadBlockLength = true; var TEMemStram = new MemoryStream(); var LastPos = 0; var i = 0; do { if (i > 2 && ReadBlockLength && TEContent[i - 1] == '\n' && TEContent[i - 2] == '\r') { var len = TEContent.ReadTEBlockLength(LastPos, i - LastPos - 2); //Debug.WriteLine(DateTime.Now + " Chunked encoded block of length " + len + " bytes detected"); if (len == 0) { break; } if (i + len <= TEContent.Length) { TEMemStram.Write(TEContent, i, len); i = i + len; if (TEContent[i] == 0x0d) { i++; } if (i < TEContent.Length - 1) { if (TEContent[i] == 0x0a) { i++; } } else { } LastPos = i; ReadBlockLength = false; } else { // Reaching this point seems to be an endless loop! break; } } else { ReadBlockLength = true; i++; } } while (i < TEContent.Length); Response.ContentStreamToArray(TEMemStram); } else { Response.ContentStreamToArray(); } } catch (Exception e) { Debug.WriteLine(DateTime.Now + " " + e.Message); } } #endregion #region Close connection if requested! if (Response.Connection == null || Response.Connection == "close") { TCPClient.Close(); HTTPStream = null; TCPClient = null; } #endregion } catch (Exception e) { #region Create a HTTP response for the exception... while (e.InnerException != null) { e = e.InnerException; } Response = new HTTPResponseBuilder(Request, HTTPStatusCode.BadRequest) { ContentType = HTTPContentType.JSON_UTF8, Content = JSONObject.Create(new JProperty("Message", e.Message), new JProperty("StackTrace", e.StackTrace)). ToUTF8Bytes() }; #endregion } #region Call the optional HTTP response log delegate try { ResponseLogDelegate?.Invoke(DateTime.Now, this, Request, Response); } catch (Exception e2) { e2.Log(nameof(HTTPClient) + "." + nameof(ResponseLogDelegate)); } #endregion return(Response); }, TaskCreationOptions.AttachedToParent); return(await task); }
public static Boolean TryParseI18NString(HTTPRequest HTTPRequest, JObject DescriptionJSON, out I18NString I18N, out HTTPResponse Response) { if (DescriptionJSON == null) { I18N = null; Response = new HTTPResponseBuilder(HTTPRequest) { HTTPStatusCode = HTTPStatusCode.BadRequest, ContentType = HTTPContentType.JSON_UTF8, Content = new JObject(new JProperty("description", "Invalid roaming network description!")).ToUTF8Bytes() }.AsImmutable(); return false; } Languages Language; JValue Text; I18N = I18NString.Empty; foreach (var Description in DescriptionJSON) { if (!Enum.TryParse(Description.Key, out Language)) { I18N = null; Response = new HTTPResponseBuilder(HTTPRequest) { HTTPStatusCode = HTTPStatusCode.BadRequest, ContentType = HTTPContentType.JSON_UTF8, Content = new JObject(new JProperty("description", "Unknown or invalid language definition '" + Description.Key + "'!")).ToUTF8Bytes() }.AsImmutable(); return false; } Text = Description.Value as JValue; if (Text == null) { I18N = null; Response = new HTTPResponseBuilder(HTTPRequest) { HTTPStatusCode = HTTPStatusCode.BadRequest, ContentType = HTTPContentType.JSON_UTF8, Content = new JObject(new JProperty("description", "Invalid description text!")).ToUTF8Bytes() }.AsImmutable(); return false; } I18N.Add(Language, Text.Value<String>()); } Response = null; return true; }
/// <summary> /// Create a new 200-OK HTTP response and apply the given delegate. /// </summary> /// <param name="Configurator">A delegate to configure the HTTP response.</param> public static HTTPResponseBuilder OK(HTTPRequest HTTPRequest, Func<HTTPResponseBuilder, HTTPResponseBuilder> Configurator) { var response = new HTTPResponseBuilder(HTTPRequest);// (HTTPStatusCode.OK); if (Configurator != null) return Configurator(response); return response; }
/// <summary> /// Create a new 200-OK HTTP response and apply the given delegate. /// </summary> /// <param name="Configurator">A delegate to configure the HTTP response.</param> public static HTTPResponseBuilder OK(HTTPRequest HTTPRequest, Action<HTTPResponseBuilder> Configurator = null) { var response = new HTTPResponseBuilder(HTTPRequest). SetHTTPStatusCode(HTTPStatusCode.OK); Configurator?.Invoke(response); return response; }
public HTTPResponse HTTPErrorResponse(HTTPRequest HTTPRequest, HTTPStatusCode StatusCode, String Reason = null, String ETag = null) { #region Initial checks if (StatusCode == null) { return(HTTPErrorResponse(HTTPRequest, HTTPStatusCode.InternalServerError, "Calling the HTTPError lead to an error!")); } var Content = String.Empty; var ContentType = HTTPRequest.Accept.BestMatchingContentType(HTTPContentType.JSON_UTF8, HTTPContentType.HTML_UTF8, HTTPContentType.TEXT_UTF8, HTTPContentType.XML_UTF8); #endregion #region JSON_UTF8 // { // "error": { // "code" : 400 // "message" : "Bad Request" // "reason" : "The first paramter is not a valid number!" // } // } if (ContentType == HTTPContentType.JSON_UTF8) { Content = (Reason == null) ? "{\r\n \"error\":\r\n {\r\n \"code\": " + StatusCode.Code + ",\r\n \"message\": \"" + StatusCode.Name + "\"\r\n }\r\n}" : "{\r\n \"error\":\r\n {\r\n \"code\": " + StatusCode.Code + ",\r\n \"message\": \"" + StatusCode.Name + "\",\r\n \"reason\": \"" + Reason + "\"\r\n }\r\n}"; } #endregion #region HTML_UTF8 //<!doctype html> //<html> // <head> // <meta charset="UTF-8"> // <title>Error 400 - Bad Request</title> // </head> // <body> // <h1>Error 400 - Bad Request</h1> // The first paramter is not a valid number! // </body> //</html> else if (ContentType == HTTPContentType.HTML_UTF8) { Content = (Reason == null) ? "<!doctype html><html><head><meta charset=\"UTF-8\"><title>Error " + StatusCode.Code + " - " + StatusCode.Name + "</title></head><body><h1>Error " + StatusCode.Code + " - " + StatusCode.Name + "</h1></body></html>" : "<!doctype html><html><head><meta charset=\"UTF-8\"><title>Error " + StatusCode.Code + " - " + StatusCode.Name + "</title></head><body><h1>Error " + StatusCode.Code + " - " + StatusCode.Name + "</h1>" + Reason + "</body></html>"; } #endregion #region TEXT_UTF8 // Error 400 - Bad Request // The first paramter is not a valid number! else if (ContentType == HTTPContentType.TEXT_UTF8 || ContentType == HTTPContentType.ALL) { Content = (Reason == null) ? "Error " + StatusCode.Code + " - " + StatusCode.Name : "Error " + StatusCode.Code + " - " + StatusCode.Name + Environment.NewLine + Reason; } #endregion #region XML_UTF8 // <?xml version="1.0" encoding="UTF-8"?> // <error> // <code>400</code> // <message>Bad Request</message> // <reason>The first paramter is not a valid number!</message> // </error> else if (ContentType == HTTPContentType.XML_UTF8) { Content = (Reason == null) ? "<?xml version=\"1.0\" encoding=\"UTF-8\"?><error><code>" + StatusCode.Code + "</code><message>" + StatusCode.Name + "</message></error></xml>" : "<?xml version=\"1.0\" encoding=\"UTF-8\"?><error><code>" + StatusCode.Code + "</code><message>" + StatusCode.Name + "</message><reasons>" + Reason + "</reasons></error></xml>"; } #endregion var response = new HTTPResponseBuilder(HTTPRequest) { Date = DateTime.Now, HTTPStatusCode = StatusCode, CacheControl = "no-cache", Connection = "close", ContentType = ContentType, Content = Content.ToUTF8Bytes() }; if (ETag != null) { response.ETag = ETag; } return(response); }
/// <summary> /// Return a HTTP error response using the best-matching content type. /// </summary> /// <param name="HTTPRequest">The HTTP request.</param> /// <param name="StatusCode">A HTTP status code.</param> /// <param name="Reasons">Optional application side reasons for this error.</param> public static HTTPResponse HTTPErrorResponse_old(HTTPRequest HTTPRequest, HTTPStatusCode StatusCode, String Reasons = null) { #region Initial checks if (StatusCode == null) return HTTPErrorResponse_old(HTTPRequest, HTTPStatusCode.InternalServerError, "Calling the HTTPError lead to an error!"); var Content = String.Empty; var ContentType = HTTPRequest.Accept.BestMatchingContentType(HTTPContentType.JSON_UTF8, HTTPContentType.HTML_UTF8, HTTPContentType.TEXT_UTF8, HTTPContentType.XML_UTF8); #endregion #region JSON_UTF8 // { // "error": { // "code" : 400 // "message" : "Bad Request" // "reason" : "The first paramter is not a valid number!" // } // } if (ContentType == HTTPContentType.JSON_UTF8) Content = (Reasons == null) ? "{ \"error\": { \"code\" : " + StatusCode.Code + ", \"message\" : \"" + StatusCode.Name + "\" } }" : "{ \"error\": { \"code\" : " + StatusCode.Code + ", \"message\" : \"" + StatusCode.Name + "\", \"reasons\" : \"" + Reasons + "\" } }"; #endregion #region HTML_UTF8 //<!doctype html> //<html> // <head> // <meta charset="UTF-8"> // <title>Error 400 - Bad Request</title> // </head> // <body> // <h1>Error 400 - Bad Request</h1> // The first paramter is not a valid number! // </body> //</html> else if (ContentType == HTTPContentType.HTML_UTF8) Content = (Reasons == null) ? "<!doctype html><html><head><meta charset=\"UTF-8\"><title>Error " + StatusCode.Code + " - " + StatusCode.Name + "</title></head><body><h1>Error " + StatusCode.Code + " - " + StatusCode.Name + "</h1></body></html>" : "<!doctype html><html><head><meta charset=\"UTF-8\"><title>Error " + StatusCode.Code + " - " + StatusCode.Name + "</title></head><body><h1>Error " + StatusCode.Code + " - " + StatusCode.Name + "</h1>" + Reasons + "</body></html>"; #endregion #region TEXT_UTF8 // Error 400 - Bad Request // The first paramter is not a valid number! else if (ContentType == HTTPContentType.TEXT_UTF8 || ContentType == HTTPContentType.ALL) Content = (Reasons == null) ? "Error " + StatusCode.Code + " - " + StatusCode.Name : "Error " + StatusCode.Code + " - " + StatusCode.Name + Environment.NewLine + Reasons; #endregion #region XML_UTF8 // <?xml version="1.0" encoding="UTF-8"?> // <error> // <code>400</code> // <message>Bad Request</message> // <reason>The first paramter is not a valid number!</message> // </error> else if (ContentType == HTTPContentType.XML_UTF8) Content = (Reasons == null) ? "<?xml version=\"1.0\" encoding=\"UTF-8\"?><error><code>" + StatusCode.Code + "</code><message>" + StatusCode.Name + "</message></error></xml>" : "<?xml version=\"1.0\" encoding=\"UTF-8\"?><error><code>" + StatusCode.Code + "</code><message>" + StatusCode.Name + "</message><reasons>" + Reasons + "</reasons></error></xml>"; #endregion #region GEXF+XML // <?xml version="1.0" encoding="UTF-8"?> // <gexf xmlns=\"http://www.gexf.net/1.2draft\" version="1.2"> // <meta lastmodifieddate="2009-03-20"> // <creator>Vanaheimr Walkyr</creator> // <description>HTTP Error</description> // </meta> // <graph mode="static" defaultedgetype="directed"> // <attributes class="edge"> // <attribute id="0" title="Reasons" type="string"/> // </attributes> // <nodes> // <node id="Request" label="Request" /> // <node id="Error" label="Error 400 - Bad Request" /> // </nodes> // <edges> // <edge id="0" source="Request" target="Error"> // <attvalues> // <attvalue for="0" value="The first paramter is not a valid number!"/> // </attvalues> // <edge> // </edges> // </graph> // </gexf> // <reason></message> else if (ContentType == HTTPContentType.GEXF_UTF8) Content = (Reasons == null) ? "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<gexf xmlns=\"http://www.gexf.net/1.2draft\" version=\"1.2\">" + "<meta lastmodifieddate=\"2009-03-20\"><creator>Vanaheimr Walkyr</creator><description>HTTP Error</description></meta>" + "<graph mode=\"static\" defaultedgetype=\"directed\">" + "<nodes>" + "<node id=\"Request\" label=\"Request\" />" + "<node id=\"Error\" label=\"Error " + StatusCode.Code + " - " + StatusCode.Name + "\" />" + "</nodes><edges>" + "<edge id=\"0\" source=\"Request\" target=\"Error\" />" + "</edges></graph></gexf>" : "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<gexf xmlns=\"http://www.gexf.net/1.2draft\" version=\"1.2\">" + "<meta lastmodifieddate=\"2009-03-20\"><creator>Vanaheimr Walkyr</creator><description>HTTP Error</description></meta>" + "<graph mode=\"static\" defaultedgetype=\"directed\">" + "<attributes class=\"edge\">" + " <attribute id=\"0\" title=\"Reasons\" type=\"string\" />" + "</attributes> " + "<nodes>" + "<node id=\"Request\" label=\"Request\" />" + "<node id=\"Error\" label=\"Error " + StatusCode.Code + " - " + StatusCode.Name + "\" />" + "</nodes><edges>" + "<edge id=\"0\" source=\"Request\" target=\"Error\">" + "<attvalues>" + "<attvalue for=\"0\" value=\"" + Reasons + "\" />" + "</attvalues>" + "<edge>" + "</edges></graph></gexf>"; #endregion var x = new HTTPResponseBuilder(HTTPRequest) { HTTPStatusCode = StatusCode, CacheControl = "no-cache", Connection = "close", Content = Content.ToUTF8Bytes() }; return x; }
public static Boolean TryParseJArrayRequestBody(this HTTPRequest Request, out JArray JSON, out HTTPResponse HTTPResponse, Boolean AllowEmptyHTTPBody = false, String JSONLDContext = null) { #region AllowEmptyHTTPBody JSON = null; HTTPResponse = null; if (Request.ContentLength == 0 && AllowEmptyHTTPBody) { HTTPResponse = new HTTPResponseBuilder(Request) { HTTPStatusCode = HTTPStatusCode.OK, }; return(false); } #endregion #region Get text body var RequestBodyString = Request.GetRequestBodyAsUTF8String(HTTPContentType.JSON_UTF8, AllowEmptyHTTPBody); if (RequestBodyString.HasErrors) { HTTPResponse = RequestBodyString.Error; return(false); } #endregion #region Try to parse the JSON try { JSON = JArray.Parse(RequestBodyString.Data); } catch (Exception e) { HTTPResponse = new HTTPResponseBuilder(Request) { HTTPStatusCode = HTTPStatusCode.BadRequest, ContentType = HTTPContentType.JSON_UTF8, Content = JSONObject.Create( JSONLDContext.IsNotNullOrEmpty() ? new JProperty("context", JSONLDContext) : null, new JProperty("description", "Invalid JSON request body!"), new JProperty("hint", e.Message) ).ToUTF8Bytes() }; return(false); } return(true); #endregion }
/// <summary> /// Execute the given HTTP request and return its result. /// </summary> /// <param name="Request">A HTTP request.</param> /// <param name="RequestLogDelegate">A delegate for logging the HTTP request.</param> /// <param name="ResponseLogDelegate">A delegate for logging the HTTP request/response.</param> /// <param name="Timeout">An optional timeout.</param> /// <param name="CancellationToken">A cancellation token.</param> public async Task<HTTPResponse> Execute(HTTPRequest Request, ClientRequestLogHandler RequestLogDelegate = null, ClientResponseLogHandler ResponseLogDelegate = null, TimeSpan? Timeout = null, CancellationToken? CancellationToken = null) { #region Call the optional HTTP request log delegate try { RequestLogDelegate?.Invoke(DateTime.Now, this, Request); } catch (Exception e) { e.Log(nameof(HTTPClient) + "." + nameof(RequestLogDelegate)); } #endregion var task = Task<HTTPResponse>.Factory.StartNew(() => { HTTPResponse Response = null; try { if (Environment.MachineName.Contains("QUAD2QUANTOR") && Request.URI.Contains("eRoaming")) throw new Exception("Catch me if you can!"); Thread.CurrentThread.Priority = ThreadPriority.BelowNormal; #region Data var HTTPHeaderBytes = new Byte[0]; var sw = new Stopwatch(); if (!Timeout.HasValue) Timeout = TimeSpan.FromSeconds(60); #endregion #region Create TCP connection (possibly also do DNS lookups) if (TCPClient == null) { System.Net.IPEndPoint _FinalIPEndPoint = null; IIPAddress _ResolvedRemoteIPAddress = null; if (RemoteIPAddress == null) { if (Hostname.Trim() == "127.0.0.1") _ResolvedRemoteIPAddress = IPv4Address.Localhost; else { var RegExpr = new Regex(@"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b"); if (RegExpr.IsMatch(Hostname)) _ResolvedRemoteIPAddress = IPv4Address.Parse(Hostname); } #region DNS lookup... if (_ResolvedRemoteIPAddress == null) { try { var IPv4AddressTask = DNSClient. Query<A>(Hostname). ContinueWith(QueryTask => QueryTask.Result. Select(ARecord => ARecord.IPv4Address). FirstOrDefault()); IPv4AddressTask.Wait(); _ResolvedRemoteIPAddress = IPv4AddressTask.Result; } catch (Exception e) { Debug.WriteLine("[" + DateTime.Now + "] " + e.Message); } } #endregion } else _ResolvedRemoteIPAddress = RemoteIPAddress; _FinalIPEndPoint = new System.Net.IPEndPoint(new System.Net.IPAddress(_ResolvedRemoteIPAddress.GetBytes()), RemotePort.ToInt32()); sw.Start(); TCPClient = new TcpClient(); TCPClient.Connect(_FinalIPEndPoint); TCPClient.ReceiveTimeout = (Int32) Timeout.Value.TotalMilliseconds; } #endregion #region Create (Crypto-)Stream TCPStream = TCPClient.GetStream(); TCPStream.ReadTimeout = (Int32)Timeout.Value.TotalMilliseconds; TLSStream = RemoteCertificateValidator != null ? new SslStream(TCPStream, false, RemoteCertificateValidator) // ClientCertificateSelector, //EncryptionPolicy.RequireEncryption) : null; if (TLSStream != null) TLSStream.ReadTimeout = (Int32)Timeout.Value.TotalMilliseconds; HTTPStream = null; if (RemoteCertificateValidator != null) { HTTPStream = TLSStream; TLSStream.AuthenticateAsClient(Hostname);//, new X509CertificateCollection(new X509Certificate[] { ClientCert }), SslProtocols.Default, false); } else HTTPStream = TCPStream; HTTPStream.ReadTimeout = (Int32)Timeout.Value.TotalMilliseconds; #endregion #region Send Request HTTPStream.Write(String.Concat(Request.EntireRequestHeader, Environment.NewLine, Environment.NewLine). ToUTF8Bytes()); var RequestBodyLength = Request.HTTPBody == null ? Request.ContentLength.HasValue ? (Int32) Request.ContentLength.Value : 0 : Request.ContentLength.HasValue ? Math.Min((Int32) Request.ContentLength.Value, Request.HTTPBody.Length) : Request.HTTPBody.Length; if (RequestBodyLength > 0) HTTPStream.Write(Request.HTTPBody, 0, RequestBodyLength); var _MemoryStream = new MemoryStream(); var _Buffer = new Byte[10485760]; // 10 MBytes, a smaller value leads to read errors! #endregion #region Wait timeout for the server to react! //Debug.WriteLine("[" + DateTime.Now + "] HTTPClient timeout: " + Timeout.Value.ToString()); while (!TCPStream.DataAvailable) { if (sw.ElapsedMilliseconds >= Timeout.Value.TotalMilliseconds) { TCPClient.Close(); throw new Exception("[" + DateTime.Now + "] Could not read from the TCP stream for " + sw.ElapsedMilliseconds + "ms!"); } Thread.Sleep(1); } //Debug.WriteLine("[" + DateTime.Now + "] HTTPClient (" + TCPClient.Client.LocalEndPoint.ToString() + " -> " + RemoteSocket.ToString() + ") got first response after " + sw.ElapsedMilliseconds + "ms!"); #endregion #region Read the entire HTTP header, and maybe some of the HTTP body var CurrentDataLength = 0; do { #region When data available, write it to the buffer... while (TCPStream.DataAvailable) { CurrentDataLength = HTTPStream.Read(_Buffer, 0, _Buffer.Length); if (CurrentDataLength > -1) { _MemoryStream.Write(_Buffer, 0, CurrentDataLength); // Debug.WriteLine("[" + DateTime.Now + "] Read " + CurrentDataLength + " bytes from HTTP connection (" + TCPClient.Client.LocalEndPoint.ToString() + " -> " + RemoteSocket.ToString() + ") (" + sw.ElapsedMilliseconds + "ms)!"); } } #endregion #region Check if the entire HTTP header was already read into the buffer if (_MemoryStream.Length > 4) { var MemoryCopy = _MemoryStream.ToArray(); for (var pos = 3; pos < MemoryCopy.Length; pos++) { if (MemoryCopy[pos ] == 0x0a && MemoryCopy[pos - 1] == 0x0d && MemoryCopy[pos - 2] == 0x0a && MemoryCopy[pos - 3] == 0x0d) { Array.Resize(ref HTTPHeaderBytes, pos - 3); Array.Copy(MemoryCopy, 0, HTTPHeaderBytes, 0, pos - 3); break; } } //if (HTTPHeaderBytes.Length > 0) // Debug.WriteLine("[" + DateTime.Now + "] End of (" + TCPClient.Client.LocalEndPoint.ToString() + " -> " + RemoteSocket.ToString() + ") HTTP header at " + HTTPHeaderBytes.Length + " bytes (" + sw.ElapsedMilliseconds + "ms)!"); } #endregion Thread.Sleep(1); } // Note: Delayed parts of the HTTP body may not be read into the buffer // => Must be read later! while (TCPStream.DataAvailable || ((sw.ElapsedMilliseconds < HTTPStream.ReadTimeout) && HTTPHeaderBytes.Length == 0)); //Debug.WriteLine("[" + DateTime.Now + "] Finally read " + _MemoryStream.Length + " bytes of HTTP client (" + TCPClient.Client.LocalEndPoint.ToString() + " -> " + RemoteSocket.ToString() + ") data (" + sw.ElapsedMilliseconds + "ms)!"); #endregion #region Copy HTTP header data and create HTTP response if (HTTPHeaderBytes.Length == 0) throw new ApplicationException(DateTime.Now + " Could not find the end of the HTTP protocol header!"); Response = HTTPResponse.Parse(HTTPHeaderBytes.ToUTF8String(), Request); #endregion #region Read 'Content-Length' bytes... // Copy only the number of bytes given within // the HTTP header element 'Content-Length'! if (Response.ContentLength.HasValue && Response.ContentLength.Value > 0) { _MemoryStream.Seek(HTTPHeaderBytes.Length + 4, SeekOrigin.Begin); var _Read = _MemoryStream.Read(_Buffer, 0, _Buffer.Length); var _StillToRead = (Int32)Response.ContentLength.Value - _Read; Response.HTTPBodyStream.Write(_Buffer, 0, _Read); var _CurrentBufferSize = 0; do { while (TCPStream.DataAvailable && _StillToRead > 0) { _CurrentBufferSize = Math.Min(_Buffer.Length, (Int32)_StillToRead); _Read = HTTPStream.Read(_Buffer, 0, _CurrentBufferSize); Response.HTTPBodyStream.Write(_Buffer, 0, _Read); _StillToRead -= _Read; } if (_StillToRead <= 0) break; Thread.Sleep(1); } while (sw.ElapsedMilliseconds < HTTPStream.ReadTimeout); Response.ContentStreamToArray(); } #endregion #region ...or read till timeout (e.g. for chunked transport)! else { try { _MemoryStream.Seek(HTTPHeaderBytes.Length + 4, SeekOrigin.Begin); Response.NewContentStream(); Response.HTTPBodyStream.Write(_Buffer, 0, _MemoryStream.Read(_Buffer, 0, _Buffer.Length)); var Retries = 0; while (Retries < 10) { while (TCPStream.DataAvailable) { Response.HTTPBodyStream.Write(_Buffer, 0, HTTPStream.Read(_Buffer, 0, _Buffer.Length)); Retries = 0; } Thread.Sleep(10); Retries++; } if (Response.TransferEncoding == "chunked") { //Debug.WriteLine(DateTime.Now + " Chunked encoding detected"); var TEContent = ((MemoryStream)Response.HTTPBodyStream).ToArray(); var TEString = TEContent.ToUTF8String(); var ReadBlockLength = true; var TEMemStram = new MemoryStream(); var LastPos = 0; var i = 0; do { if (i > 2 && ReadBlockLength && TEContent[i - 1] == '\n' && TEContent[i - 2] == '\r') { var len = TEContent.ReadTEBlockLength(LastPos, i - LastPos - 2); //Debug.WriteLine(DateTime.Now + " Chunked encoded block of length " + len + " bytes detected"); if (len == 0) break; if (i + len <= TEContent.Length) { TEMemStram.Write(TEContent, i, len); i = i + len; if (TEContent[i] == 0x0d) i++; if (i < TEContent.Length - 1) { if (TEContent[i] == 0x0a) i++; } else { } LastPos = i; ReadBlockLength = false; } else { // Reaching this point seems to be an endless loop! break; } } else { ReadBlockLength = true; i++; } } while (i < TEContent.Length); Response.ContentStreamToArray(TEMemStram); } else Response.ContentStreamToArray(); } catch (Exception e) { Debug.WriteLine(DateTime.Now + " " + e.Message); } } #endregion #region Close connection if requested! if (Response.Connection == null || Response.Connection == "close") { TCPClient.Close(); HTTPStream = null; TCPClient = null; } #endregion } catch (Exception e) { #region Create a HTTP response for the exception... while (e.InnerException != null) e = e.InnerException; Response = new HTTPResponseBuilder(Request, HTTPStatusCode.BadRequest) { ContentType = HTTPContentType.JSON_UTF8, Content = JSONObject.Create(new JProperty("Message", e.Message), new JProperty("StackTrace", e.StackTrace)). ToUTF8Bytes() }; #endregion } #region Call the optional HTTP response log delegate try { ResponseLogDelegate?.Invoke(DateTime.Now, this, Request, Response); } catch (Exception e2) { e2.Log(nameof(HTTPClient) + "." + nameof(ResponseLogDelegate)); } #endregion return Response; }, TaskCreationOptions.AttachedToParent); return await task; }
/// <summary> /// Return a HTTP error response using the best-matching content type. /// </summary> /// <param name="HTTPRequest">The HTTP request.</param> /// <param name="StatusCode">A HTTP status code.</param> /// <param name="Reasons">Optional application side reasons for this error.</param> public static HTTPResponse HTTPErrorResponse_old(HTTPRequest HTTPRequest, HTTPStatusCode StatusCode, String Reasons = null) { #region Initial checks if (StatusCode == null) { return(HTTPErrorResponse_old(HTTPRequest, HTTPStatusCode.InternalServerError, "Calling the HTTPError lead to an error!")); } var Content = String.Empty; var ContentType = HTTPRequest.Accept.BestMatchingContentType(HTTPContentType.JSON_UTF8, HTTPContentType.HTML_UTF8, HTTPContentType.TEXT_UTF8, HTTPContentType.XML_UTF8); #endregion #region JSON_UTF8 // { // "error": { // "code" : 400 // "message" : "Bad Request" // "reason" : "The first paramter is not a valid number!" // } // } if (ContentType == HTTPContentType.JSON_UTF8) { Content = (Reasons == null) ? "{ \"error\": { \"code\" : " + StatusCode.Code + ", \"message\" : \"" + StatusCode.Name + "\" } }" : "{ \"error\": { \"code\" : " + StatusCode.Code + ", \"message\" : \"" + StatusCode.Name + "\", \"reasons\" : \"" + Reasons + "\" } }"; } #endregion #region HTML_UTF8 //<!doctype html> //<html> // <head> // <meta charset="UTF-8"> // <title>Error 400 - Bad Request</title> // </head> // <body> // <h1>Error 400 - Bad Request</h1> // The first paramter is not a valid number! // </body> //</html> else if (ContentType == HTTPContentType.HTML_UTF8) { Content = (Reasons == null) ? "<!doctype html><html><head><meta charset=\"UTF-8\"><title>Error " + StatusCode.Code + " - " + StatusCode.Name + "</title></head><body><h1>Error " + StatusCode.Code + " - " + StatusCode.Name + "</h1></body></html>" : "<!doctype html><html><head><meta charset=\"UTF-8\"><title>Error " + StatusCode.Code + " - " + StatusCode.Name + "</title></head><body><h1>Error " + StatusCode.Code + " - " + StatusCode.Name + "</h1>" + Reasons + "</body></html>"; } #endregion #region TEXT_UTF8 // Error 400 - Bad Request // The first paramter is not a valid number! else if (ContentType == HTTPContentType.TEXT_UTF8 || ContentType == HTTPContentType.ALL) { Content = (Reasons == null) ? "Error " + StatusCode.Code + " - " + StatusCode.Name : "Error " + StatusCode.Code + " - " + StatusCode.Name + Environment.NewLine + Reasons; } #endregion #region XML_UTF8 // <?xml version="1.0" encoding="UTF-8"?> // <error> // <code>400</code> // <message>Bad Request</message> // <reason>The first paramter is not a valid number!</message> // </error> else if (ContentType == HTTPContentType.XML_UTF8) { Content = (Reasons == null) ? "<?xml version=\"1.0\" encoding=\"UTF-8\"?><error><code>" + StatusCode.Code + "</code><message>" + StatusCode.Name + "</message></error></xml>" : "<?xml version=\"1.0\" encoding=\"UTF-8\"?><error><code>" + StatusCode.Code + "</code><message>" + StatusCode.Name + "</message><reasons>" + Reasons + "</reasons></error></xml>"; } #endregion #region GEXF+XML // <?xml version="1.0" encoding="UTF-8"?> // <gexf xmlns=\"http://www.gexf.net/1.2draft\" version="1.2"> // <meta lastmodifieddate="2009-03-20"> // <creator>Vanaheimr Walkyr</creator> // <description>HTTP Error</description> // </meta> // <graph mode="static" defaultedgetype="directed"> // <attributes class="edge"> // <attribute id="0" title="Reasons" type="string"/> // </attributes> // <nodes> // <node id="Request" label="Request" /> // <node id="Error" label="Error 400 - Bad Request" /> // </nodes> // <edges> // <edge id="0" source="Request" target="Error"> // <attvalues> // <attvalue for="0" value="The first paramter is not a valid number!"/> // </attvalues> // <edge> // </edges> // </graph> // </gexf> // <reason></message> else if (ContentType == HTTPContentType.GEXF_UTF8) { Content = (Reasons == null) ? "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<gexf xmlns=\"http://www.gexf.net/1.2draft\" version=\"1.2\">" + "<meta lastmodifieddate=\"2009-03-20\"><creator>Vanaheimr Walkyr</creator><description>HTTP Error</description></meta>" + "<graph mode=\"static\" defaultedgetype=\"directed\">" + "<nodes>" + "<node id=\"Request\" label=\"Request\" />" + "<node id=\"Error\" label=\"Error " + StatusCode.Code + " - " + StatusCode.Name + "\" />" + "</nodes><edges>" + "<edge id=\"0\" source=\"Request\" target=\"Error\" />" + "</edges></graph></gexf>" : "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<gexf xmlns=\"http://www.gexf.net/1.2draft\" version=\"1.2\">" + "<meta lastmodifieddate=\"2009-03-20\"><creator>Vanaheimr Walkyr</creator><description>HTTP Error</description></meta>" + "<graph mode=\"static\" defaultedgetype=\"directed\">" + "<attributes class=\"edge\">" + " <attribute id=\"0\" title=\"Reasons\" type=\"string\" />" + "</attributes> " + "<nodes>" + "<node id=\"Request\" label=\"Request\" />" + "<node id=\"Error\" label=\"Error " + StatusCode.Code + " - " + StatusCode.Name + "\" />" + "</nodes><edges>" + "<edge id=\"0\" source=\"Request\" target=\"Error\">" + "<attvalues>" + "<attvalue for=\"0\" value=\"" + Reasons + "\" />" + "</attvalues>" + "<edge>" + "</edges></graph></gexf>"; } #endregion var x = new HTTPResponseBuilder(HTTPRequest) { HTTPStatusCode = StatusCode, CacheControl = "no-cache", Connection = "close", Content = Content.ToUTF8Bytes() }; return(x); }