DisposeAndGetRemainingBytes() публичный Метод

public DisposeAndGetRemainingBytes ( ) : ArraySegment
Результат ArraySegment
Пример #1
0
        public void DisposeAndGetRemainingBytes()
        {
            WriteTestData("abcd\r\nefgh\0ijkl");
            RewindStream();

            var fLine = Reader.ReadLine();

            fLine.GetCompletionEvent().Wait();

            Assert.AreEqual("abcd", fLine.Result);

            var remainingBytes = Reader.DisposeAndGetRemainingBytes();

            Assert.AreEqual("efgh\0ijkl", Encoding.ASCII.GetString(remainingBytes.Array, remainingBytes.Offset, remainingBytes.Count));
        }
Пример #2
0
        private IEnumerator<object> RequestTask(ListenerContext context, SocketDataAdapter adapter)
        {
            var startedWhen = DateTime.UtcNow;
            bool successful = false;

            try {
                const int headerBufferSize = 1024 * 32;
                const int bodyBufferSize = 1024 * 128;
                const double requestLineTimeout = 5;

                // RFC2616:
                // Words of *TEXT MAY contain characters from character sets other than ISO-8859-1 [22]
                //  only when encoded according to the rules of RFC 2047 [14].
                Encoding headerEncoding;
                try {
                    headerEncoding = Encoding.GetEncoding("ISO-8859-1");
                } catch {
                    headerEncoding = Encoding.ASCII;
                }

                Request request;
                RequestBody body;
                HeaderCollection headers;
                long bodyBytesRead = 0;
                long? expectedBodyLength = null;

                var reader = new AsyncTextReader(adapter, headerEncoding, headerBufferSize, false);
                string requestLineText;

                while (true) {
                    var fRequestLine = reader.ReadLine();
                    var fRequestOrTimeout = Scheduler.Start(new WaitWithTimeout(fRequestLine, requestLineTimeout));

                    yield return fRequestOrTimeout;

                    if (fRequestOrTimeout.Failed) {
                        if (!(fRequestOrTimeout.Error is TimeoutException))
                            OnRequestError(fRequestOrTimeout.Error);

                        yield break;
                    }

                    if (fRequestLine.Failed) {
                        if (!(fRequestLine.Error is SocketDisconnectedException))
                            OnRequestError(fRequestLine.Error);

                        yield break;
                    }

                    requestLineText = fRequestLine.Result;

                    // RFC2616:
                    // In the interest of robustness, servers SHOULD ignore any empty line(s) received where a
                    //  Request-Line is expected. In other words, if the server is reading the protocol stream
                    //   at the beginning of a message and receives a CRLF first, it should ignore the CRLF.
                    if ((requestLineText != null) && (requestLineText.Trim().Length == 0))
                        continue;

                    break;
                }

                var requestLineParsed = DateTime.UtcNow;

                headers = new HeaderCollection();
                while (true) {
                    var fHeaderLine = reader.ReadLine();
                    yield return fHeaderLine;

                    if (String.IsNullOrWhiteSpace(fHeaderLine.Result))
                        break;

                    headers.Add(new Header(fHeaderLine.Result));
                }

                var headersParsed = DateTime.UtcNow;

                var expectHeader = (headers.GetValue("Expect") ?? "").ToLowerInvariant();
                var expectsContinue = expectHeader.Contains("100-continue");

                string hostName;
                if (headers.Contains("Host")) {
                    hostName = String.Format("http://{0}", headers["Host"].Value);
                } else {
                    var lep = (IPEndPoint)adapter.Socket.LocalEndPoint;
                    hostName = String.Format("http://{0}:{1}", lep.Address, lep.Port);
                }

                var requestLine = new RequestLine(hostName, requestLineText);

                var remainingBytes = reader.DisposeAndGetRemainingBytes();
                bodyBytesRead += remainingBytes.Count;

                var connectionHeader = (headers.GetValue("Connection") ?? "").ToLowerInvariant();
                var shouldKeepAlive =
                    ((requestLine.Version == "1.1") || connectionHeader.Contains("keep-alive")) &&
                    !connectionHeader.Contains("close");

                if (headers.Contains("Content-Length"))
                    expectedBodyLength = long.Parse(headers["Content-Length"].Value);

                body = new RequestBody(remainingBytes, expectedBodyLength);

                if (expectsContinue)
                    yield return adapter.Write(Continue100, 0, Continue100.Length);

                request = new Request(
                    this, adapter, shouldKeepAlive,
                    requestLine, headers, body
                );

                IncomingRequests.Enqueue(request);

                var requestEnqueued = DateTime.UtcNow;
                DateTime? requestBodyRead = null;

                // FIXME: I think it's technically accepted to send a body without a content-length, but
                //  it seems to be impossible to make that work right.
                if (expectedBodyLength.HasValue) {
                    using (var bodyBuffer = BufferPool<byte>.Allocate(bodyBufferSize))
                    while (bodyBytesRead < expectedBodyLength.Value) {
                        long bytesToRead = Math.Min(expectedBodyLength.Value - bodyBytesRead, bodyBufferSize);

                        if (bytesToRead <= 0)
                            break;

                        var fBytesRead = adapter.Read(bodyBuffer.Data, 0, (int)bytesToRead);
                        yield return fBytesRead;

                        if (fBytesRead.Failed) {
                            if (fBytesRead.Error is SocketDisconnectedException)
                                break;

                            body.Failed(fBytesRead.Error);
                            OnRequestError(fBytesRead.Error);
                            yield break;
                        }

                        var bytesRead = fBytesRead.Result;

                        bodyBytesRead += bytesRead;
                        body.Append(bodyBuffer.Data, 0, bytesRead);
                    }

                    requestBodyRead = DateTime.UtcNow;
                }

                body.Finish();
                successful = true;

                request.Timing = new Request.TimingData {
                    Line = (requestLineParsed - startedWhen),
                    Headers = (headersParsed - requestLineParsed),
                    Queue = (requestEnqueued - headersParsed),
                    Body = (requestBodyRead - requestEnqueued)
                };
            } finally {
                if (!successful)
                    adapter.Dispose();
            }
        }