/// <summary> /// Create a new http request header based on the given string representation. /// </summary> /// <param name="RemoteSocket">The remote TCP/IP socket.</param> /// <param name="LocalSocket">The local TCP/IP socket.</param> /// <param name="HTTPServer">The HTTP server of the request.</param> /// <param name="HTTPHeader">A valid string representation of a http request header.</param> /// <param name="HTTPBody">The HTTP body as an array of bytes.</param> /// <param name="HTTPBodyStream">The HTTP body as an stream of bytes.</param> /// <param name="CancellationToken">A token to cancel the HTTP request processing.</param> /// <param name="EventTrackingId">An unique event tracking identification for correlating this request with other events.</param> private HTTPRequest(IPSocket RemoteSocket, IPSocket LocalSocket, HTTPServer HTTPServer, String HTTPHeader, Byte[] HTTPBody = null, Stream HTTPBodyStream = null, CancellationToken?CancellationToken = null, EventTracking_Id EventTrackingId = null) : base(RemoteSocket, LocalSocket, HTTPHeader, HTTPBody, HTTPBodyStream, CancellationToken, EventTrackingId) { this._HTTPServer = HTTPServer; #region Parse HTTPMethod (first line of the http request) var _HTTPMethodHeader = FirstPDULine.Split(_SpaceSeparator, StringSplitOptions.RemoveEmptyEntries); // e.g: PROPFIND /file/file Name HTTP/1.1 if (_HTTPMethodHeader.Length != 3) { throw new Exception("Bad request"); } // Parse HTTP method // Propably not usefull to define here, as we can not send a response having an "Allow-header" here! this._HTTPMethod = (HTTPMethod.TryParseString(_HTTPMethodHeader[0], out _HTTPMethod)) ? _HTTPMethod : HTTPMethod.Create(_HTTPMethodHeader[0]); #endregion #region Parse URL and QueryString (first line of the http request) var RawUrl = _HTTPMethodHeader[1]; var _ParsedURL = RawUrl.Split(_URLSeparator, 2, StringSplitOptions.None); this.URI = HttpUtility.UrlDecode(_ParsedURL[0]); if (URI.StartsWith("http", StringComparison.Ordinal) || URI.StartsWith("https", StringComparison.Ordinal)) { URI = URI.Substring(URI.IndexOf("://", StringComparison.Ordinal) + 3); URI = URI.Substring(URI.IndexOf("/", StringComparison.Ordinal) + 1); } if (URI == "" || URI == null) { URI = "/"; } // Parse QueryString after '?' if (RawUrl.IndexOf('?') > -1 && _ParsedURL[1].IsNeitherNullNorEmpty()) { this._QueryString = QueryString.Parse(_ParsedURL[1]); } else { this._QueryString = QueryString.Empty; } #endregion #region Parse protocol name and -version (first line of the http request) var _ProtocolArray = _HTTPMethodHeader[2].Split(_SlashSeparator, 2, StringSplitOptions.RemoveEmptyEntries); this._ProtocolName = _ProtocolArray[0].ToUpper(); if (ProtocolName.ToUpper() != "HTTP") { throw new Exception("Bad request"); } HTTPVersion _HTTPVersion = null; if (HTTPVersion.TryParseVersionString(_ProtocolArray[1], out _HTTPVersion)) { this._ProtocolVersion = _HTTPVersion; } if (ProtocolVersion != HTTPVersion.HTTP_1_0 && ProtocolVersion != HTTPVersion.HTTP_1_1) { throw new Exception("HTTP version not supported"); } #endregion #region Check Host header // rfc 2616 - Section 19.6.1.1 // A client that sends an HTTP/1.1 request MUST send a Host header. // rfc 2616 - Section 14.23 // All Internet-based HTTP/1.1 servers MUST respond with a 400 (Bad Request) // status code to any HTTP/1.1 request message which lacks a Host header field. // rfc 2616 - Section 5.2 The Resource Identified by a Request // 1. If Request-URI is an absoluteURI, the host is part of the Request-URI. // Any Host header field value in the request MUST be ignored. // 2. If the Request-URI is not an absoluteURI, and the request includes a // Host header field, the host is determined by the Host header field value. // 3. If the host as determined by rule 1 or 2 is not a valid host on the server, // the response MUST be a 400 (Bad Request) error message. (Not valid for proxies?!) if (!_HeaderFields.ContainsKey(HTTPHeaderField.Host.Name)) { throw new Exception("The HTTP PDU does not have a HOST header!"); } // rfc 2616 - 3.2.2 // If the port is empty or not given, port 80 is assumed. var HostHeader = _HeaderFields[HTTPHeaderField.Host.Name].ToString(). Split(_ColonSeparator, StringSplitOptions.RemoveEmptyEntries). Select(v => v.Trim()). ToArray(); UInt16 HostPort = 80; if (HostHeader.Length == 1) { _HeaderFields[HTTPHeaderField.Host.Name] = _HeaderFields[HTTPHeaderField.Host.Name].ToString();// + ":80"; ":80" will cause side effects! } else if ((HostHeader.Length == 2 && !UInt16.TryParse(HostHeader[1], out HostPort)) || HostHeader.Length > 2) { throw new Exception("Bad request"); } #endregion }
/// <summary> /// Set the protocol version. /// </summary> /// <param name="ProtocolVersion">The protocol version.</param> public HTTPRequestBuilder SetProtocolVersion(HTTPVersion ProtocolVersion) { this.ProtocolVersion = ProtocolVersion; return(this); }