Пример #1
0
        /// <summary>
        /// Parses url encoded form data
        /// </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 ParseFormData(BufferedStreamReader reader, ServerConfig config, TimeSpan idletime, Task timeouttask, Task stoptask)
        {
            if (this.IsContentType("application/x-www-form-urlencoded"))
            {
                if (this.ContentLength != 0)
                {
                    if (this.ContentLength > config.MaxUrlEncodedFormSize)
                    {
                        throw new HttpException(HttpStatusCode.PayloadTooLarge);
                    }

                    var enc = this.GetEncodingForContentType();
                    ParseQueryString(
                        enc.GetString(
                            this.ContentLength > 0
                            ? await reader.RepeatReadAsync(this.ContentLength, idletime, timeouttask, stoptask)
                            : await reader.ReadUntilCrlfAsync(config.MaxRequestLineSize, config.MaxUrlEncodedFormSize, idletime, timeouttask, stoptask)
                            ), this.Form);
                }

                this.Body = new LimitedBodyStream(reader, 0, idletime, timeouttask, stoptask);
            }
            else if (RequestUtility.IsMultipartRequest(this.ContentType) && this.ContentLength > 0 && this.ContentLength < config.MaxUrlEncodedFormSize && config.AutoParseMultipartFormData)
            {
                await ParseMultiPart(
                    async (headers, stream) =>
                {
                    var dispositionItems = RequestUtility.SplitHeaderLine(headers["Content-Disposition"]);
                    if (!string.Equals(dispositionItems.FirstOrDefault().Key, "form-data", StringComparison.OrdinalIgnoreCase))
                    {
                        throw new HttpException(HttpStatusCode.BadRequest);
                    }

                    var name = RequestUtility.GetHeaderComponent(headers["Content-Disposition"], "name");
                    if (string.IsNullOrWhiteSpace("name"))
                    {
                        throw new HttpException(HttpStatusCode.BadRequest);
                    }

                    var filename = RequestUtility.GetHeaderComponent(headers["Content-Disposition"], "filename");
                    var charset  = RequestUtility.GetHeaderComponent(headers["Content-Type"], "charset") ?? "ascii";

                    if (string.IsNullOrWhiteSpace(filename))
                    {
                        using (var sr = new StreamReader(stream, RequestUtility.GetEncodingForCharset(charset)))
                        {
                            var rtask = sr.ReadToEndAsync();
                            var rt    = await Task.WhenAny(timeouttask, stoptask, rtask);
                            if (rt != rtask)
                            {
                                if (rt == stoptask)
                                {
                                    throw new TaskCanceledException();
                                }
                                else
                                {
                                    throw new HttpException(HttpStatusCode.RequestTimeout);
                                }
                            }

                            this.Form[name] = rtask.Result;
                        }
                    }
                    else
                    {
                        var me = new MultipartItem(headers)
                        {
                            Name     = name,
                            Filename = filename,
                            Data     = new MemoryStream()
                        };

                        Task rtask;
                        Task rt;

                        using (var cs = new CancellationTokenSource(idletime))
                        {
                            rtask = stream.CopyToAsync(me.Data, 8 * 1024, cs.Token);
                            rt    = await Task.WhenAny(timeouttask, stoptask, rtask);
                        }

                        if (rt != rtask)
                        {
                            if (rt == stoptask)
                            {
                                throw new TaskCanceledException();
                            }
                            else
                            {
                                throw new HttpException(HttpStatusCode.RequestTimeout);
                            }
                        }

                        rtask.GetAwaiter().GetResult();
                        me.Data.Position = 0;

                        this.Files.Add(me);
                    }
                },
                    reader,
                    config,
                    idletime,
                    timeouttask,
                    stoptask
                    );

                this.Body = new LimitedBodyStream(reader, 0, idletime, timeouttask, stoptask);
            }
            else
            {
                this.Body = new LimitedBodyStream(reader, this.ContentLength, idletime, timeouttask, stoptask);
            }
        }
Пример #2
0
        /// <summary>
        /// Parses the stream items, if sent as multipart encoded
        /// </summary>
        /// <param name="itemparser">The parser method</param>
        /// <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>
        /// <returns>An awaitable task</returns>
        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);
                }
            }
        }