A read-write HTTP response header.
Inheritance: AHTTPPDUBuilder
Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        private HTTPResponse(HTTPRequest Request,
                             TContent Content)

            : this(HTTPResponseBuilder.OK(Request), Content, false)

        {
        }
Ejemplo n.º 3
0
        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);
            }
        }
Ejemplo n.º 4
0
        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);
        }
Ejemplo n.º 5
0
        /// <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);
        }
Ejemplo n.º 6
0
        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);
        }
Ejemplo n.º 7
0
        /// <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);
        }
Ejemplo n.º 8
0
        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
        }
Ejemplo n.º 9
0
        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);
        }
Ejemplo n.º 10
0
        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);
        }
Ejemplo n.º 11
0
        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);
        }
Ejemplo n.º 12
0
        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);
        }
Ejemplo n.º 13
0
        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);
        }
Ejemplo n.º 14
0
        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);
        }
Ejemplo n.º 15
0
        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

        }
Ejemplo n.º 16
0
        /// <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);
        }
Ejemplo n.º 17
0
        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;

        }
Ejemplo n.º 18
0
        /// <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;
        }
Ejemplo n.º 19
0
        /// <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;
        }
Ejemplo n.º 20
0
        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);
        }
Ejemplo n.º 21
0
        /// <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;
        }
Ejemplo n.º 22
0
        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
        }
Ejemplo n.º 23
0
        /// <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;

        }
Ejemplo n.º 24
0
        /// <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);
        }