/// <summary> /// Parses a HTTP header by reading the input stream /// </summary> /// <returns>An awaitable task.</returns> /// <param name="reader">The stream to read from.</param> /// <param name="config">The server configuration.</param> /// <param name="idletime">The maximum idle time.</param> /// <param name="timeouttask">A task that signals request timeout.</param> /// <param name="stoptask">A task that signals server stop.</param> internal async Task Parse(BufferedStreamReader reader, ServerConfig config, TimeSpan idletime, Task timeouttask, Task stoptask) { await reader.ReadHeaders( config.MaxRequestLineSize, config.MaxRequestHeaderSize, idletime, HandleLine, timeouttask, stoptask ); if (this.ContentLength > config.MaxPostSize) { throw new HttpException(HttpStatusCode.PayloadTooLarge); } // Disable HTTP/1.0 unless explictly allowed if (!config.AllowLegacyHttp && this.HttpVersion == HTTP_VERSION_1_0) { throw new HttpException(HttpStatusCode.HTTPVersionNotSupported); } // Enforce HTTP/1.1 requiring a header if (this.HttpVersion != HTTP_VERSION_1_0 && string.IsNullOrWhiteSpace(this.Headers["Host"])) { throw new HttpException(HttpStatusCode.BadRequest, "Host header missing"); } if (config.AllowHttpMethodOverride) { string newmethod; this.Headers.TryGetValue("X-HTTP-Method-Override", out newmethod); if (!string.IsNullOrWhiteSpace(newmethod)) { this.Method = newmethod; } } if (!string.IsNullOrWhiteSpace(config.AllowedSourceIPHeaderValue)) { string realip; this.Headers.TryGetValue(config.AllowedSourceIPHeaderValue, out realip); if (!string.IsNullOrWhiteSpace(realip)) { this.RemoteEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Parse(realip), ((System.Net.IPEndPoint) this.RemoteEndPoint).Port); } } await ParseFormData(reader, config, idletime, timeouttask, stoptask); }
/// <summary> /// Parses a HTTP header by reading the input stream /// </summary> /// <returns>An awaitable task.</returns> /// <param name="reader">The stream to read from.</param> /// <param name="config">The server configuration.</param> /// <param name="idletime">The maximum idle time.</param> /// <param name="timeouttask">A task that signals request timeout.</param> /// <param name="stoptask">A task that signals server stop.</param> internal async Task Parse(BufferedStreamReader reader, ServerConfig config, TimeSpan idletime, Task timeouttask, Task stoptask) { await reader.ReadHeaders( config.MaxRequestLineSize, config.MaxRequestHeaderSize, idletime, HandleLine, timeouttask, stoptask ); if (this.ContentLength > config.MaxPostSize) { throw new HttpException(HttpStatusCode.PayloadTooLarge); } if (config.AllowHttpMethodOverride) { string newmethod; this.Headers.TryGetValue("X-HTTP-Method-Override", out newmethod); if (!string.IsNullOrWhiteSpace(newmethod)) { this.Method = newmethod; } } if (!string.IsNullOrWhiteSpace(config.AllowedSourceIPHeaderValue)) { string realip; this.Headers.TryGetValue(config.AllowedSourceIPHeaderValue, out realip); if (!string.IsNullOrWhiteSpace(realip)) { this.RemoteEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Parse(realip), ((System.Net.IPEndPoint) this.RemoteEndPoint).Port); } } await ParseFormData(reader, config, idletime, timeouttask, stoptask); }
private async Task ParseMultiPart(Func <IDictionary <string, string>, Stream, Task> itemparser, BufferedStreamReader reader, ServerConfig config, TimeSpan idletime, Task timeouttask, Task stoptask) { if ((this.ContentType ?? "").StartsWith("multipart/form-data", StringComparison.OrdinalIgnoreCase)) { if (this.ContentLength > config.MaxPostSize) { throw new HttpException(HttpStatusCode.PayloadTooLarge); } var startpos = reader.Position; var trail = new byte[2]; var parts = this.ContentType.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); var bndpart = parts.FirstOrDefault(x => x.Trim().StartsWith("boundary", StringComparison.OrdinalIgnoreCase)) ?? string.Empty; var boundary = bndpart.Split(new char[] { '=' }, 2, StringSplitOptions.RemoveEmptyEntries).LastOrDefault(); if (string.IsNullOrWhiteSpace(boundary)) { throw new HttpException(HttpStatusCode.BadRequest); } // Since we have read the headers, we have consumed the initial CRLF // so we adjust the initial boundary reading to skip the CRLF var itemboundary = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary); var tmp = await reader.RepeatReadAsync(itemboundary.Length - 2, idletime, timeouttask, stoptask); if (!Enumerable.SequenceEqual(itemboundary.Skip(2), tmp)) { throw new HttpException(HttpStatusCode.BadRequest); } await reader.RepeatReadAsync(trail, 0, 2, idletime, timeouttask, stoptask); if (trail[0] != '\r' || trail[1] != '\n') { throw new HttpException(HttpStatusCode.BadRequest); } do { var headers = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase).WithDefaultValue(null); await reader.ReadHeaders( config.MaxRequestLineSize, config.MaxRequestHeaderSize, idletime, line => { var components = line.Split(new char[] { ':' }, 2); if (components.Length != 2 || string.IsNullOrWhiteSpace(components[0])) { throw new HttpException(HttpStatusCode.BadRequest); } headers[components[0].Trim()] = (components[1] ?? string.Empty).Trim(); }, timeouttask, stoptask ); await itemparser(headers, reader.GetDelimitedSubStream(itemboundary, idletime, timeouttask, stoptask)); await reader.RepeatReadAsync(trail, 0, 2, idletime, timeouttask, stoptask); }while (trail[0] == '\r' && trail[1] == '\n'); if (trail[0] != '-' || trail[1] != '-') { throw new HttpException(HttpStatusCode.BadRequest); } await reader.RepeatReadAsync(trail, 0, 2, idletime, timeouttask, stoptask); if (trail[0] != '\r' || trail[1] != '\n') { throw new HttpException(HttpStatusCode.BadRequest); } if (this.ContentLength > 0 && this.ContentLength != (reader.Position - startpos)) { throw new HttpException(HttpStatusCode.BadRequest); } } }