예제 #1
1
		public WebConnectionStream (WebConnection cnc, WebConnectionData data)
		{          
			if (data == null)
				throw new InvalidOperationException ("data was not initialized");
			if (data.Headers == null)
				throw new InvalidOperationException ("data.Headers was not initialized");
			if (data.request == null)
				throw new InvalidOperationException ("data.request was not initialized");
			isRead = true;
			cb_wrapper = new AsyncCallback (ReadCallbackWrapper);
			pending = new ManualResetEvent (true);
			this.request = data.request;
			read_timeout = request.ReadWriteTimeout;
			write_timeout = read_timeout;
			this.cnc = cnc;
			string contentType = data.Headers ["Transfer-Encoding"];
			bool chunkedRead = (contentType != null && contentType.IndexOf ("chunked", StringComparison.OrdinalIgnoreCase) != -1);
			string clength = data.Headers ["Content-Length"];
			if (!chunkedRead && clength != null && clength != "") {
				try {
					contentLength = Int32.Parse (clength);
					if (contentLength == 0 && !IsNtlmAuth ()) {
						ReadAll ();
					}
				} catch {
					contentLength = Int64.MaxValue;
				}
			} else {
				contentLength = Int64.MaxValue;
			}

			// Negative numbers?
			if (!Int32.TryParse (clength, out stream_length))
				stream_length = -1;
		}
		AsyncCallback cb_wrapper; // Calls to ReadCallbackWrapper or WriteCallbacWrapper

		public WebConnectionStream (WebConnection cnc)
		{
			isRead = true;
			cb_wrapper = new AsyncCallback (ReadCallbackWrapper);
			pending = new ManualResetEvent (true);
			this.request = cnc.Data.request;
			read_timeout = request.ReadWriteTimeout;
			write_timeout = read_timeout;
			this.cnc = cnc;
			string contentType = cnc.Data.Headers ["Transfer-Encoding"];
			bool chunkedRead = (contentType != null && contentType.IndexOf ("chunked", StringComparison.OrdinalIgnoreCase) != -1);
			string clength = cnc.Data.Headers ["Content-Length"];
			if (!chunkedRead && clength != null && clength != "") {
				try {
					contentLength = Int32.Parse (clength);
					if (contentLength == 0 && !IsNtlmAuth ()) {
						ReadAll ();
					}
				} catch {
					contentLength = Int32.MaxValue;
				}
			} else {
				contentLength = Int32.MaxValue;
			}
		}
예제 #3
0
 public void OpenTest()
 {
     var webServer = new WebServer("http://mss.alkotorg.com");
     string username = "******";
     string password = "******";
     var target = new WebConnection(webServer, username, password);
     target.Open();
 }
예제 #4
0
 public void ServerTimeTest()
 {
     WebServer webServer = new WebServer("http://mss.alkotorg.com");
     string username = "******";
     string password = "******";
     WebConnection target = new WebConnection(webServer, username, password);
     target.Open();
     DateTime actual = target.ServerTime();
     Console.WriteLine("Server time - \"{0}\"", actual);
     Assert.IsNotNull(actual);
 }
예제 #5
0
 public void PostTest()
 {
     WebServer webServer = new WebServer("http://mss.alkotorg.com");
     string username = "******";
     string password = "******";
     WebConnection target = new WebConnection(webServer, username, password); // TODO: Initialize to an appropriate value
     HttpWebRequest httpWebRequest = null; // TODO: Initialize to an appropriate value
     string expected = string.Empty; // TODO: Initialize to an appropriate value
     string actual;
     actual = target.Post(httpWebRequest);
     Assert.AreEqual(expected, actual);
     Assert.Inconclusive("Verify the correctness of this test method.");
 }
예제 #6
0
 public void GetTest()
 {
     WebServer webServer = new WebServer("http://mss.alkotorg.com");
     string username = "******";
     string password = "******";
     WebConnection target = new WebConnection(webServer, username, password);
     HttpWebRequest httpWebRequest = RequestFactory.CreateGetRequest(target, @"users/sign_in");
     string expected = RequestDispatcher.Dispatch(target, httpWebRequest);
     Console.WriteLine("Response - \"{0}\"", expected);
     Console.WriteLine("CSRF token - \"{0}\"", target.CsrfTokenContainer.CsrfToken);
     Console.WriteLine("Cookies - \"{0}\"", target.CookieContainer.Cookie);
     Assert.AreNotEqual(string.Empty, target.CsrfTokenContainer.CsrfToken);
 }
예제 #7
0
		public WebConnectionStream (WebConnection cnc)
		{
			isRead = true;
			pending = new ManualResetEvent (true);
			this.request = cnc.Data.request;
			read_timeout = request.ReadWriteTimeout;
			write_timeout = read_timeout;
			this.cnc = cnc;
			string contentType = cnc.Data.Headers ["Transfer-Encoding"];
			bool chunkedRead = (contentType != null && contentType.ToLower ().IndexOf ("chunked") != -1);
			string clength = cnc.Data.Headers ["Content-Length"];
			if (!chunkedRead && clength != null && clength != "") {
				try {
					contentLength = Int32.Parse (clength);
					if (contentLength == 0 && !IsNtlmAuth ()) {
						ReadAll ();
					}
				} catch {
					contentLength = Int32.MaxValue;
				}
			} else {
				contentLength = Int32.MaxValue;
			}
		}
예제 #8
0
		public WebConnectionStream (WebConnection cnc, HttpWebRequest request)
		{
			read_timeout = request.ReadWriteTimeout;
			write_timeout = read_timeout;
			isRead = false;
			cb_wrapper = new AsyncCallback (WriteCallbackWrapper);
			this.cnc = cnc;
			this.request = request;
			allowBuffering = request.InternalAllowBuffering;
			sendChunked = request.SendChunked;
			if (sendChunked)
				pending = new ManualResetEvent (true);
			else if (allowBuffering)
				writeBuffer = new MemoryStream ();
		}
        async Task Initialize(BufferOffsetSize buffer, CancellationToken cancellationToken)
        {
            WebConnection.Debug($"{ME} INIT: status={(int)StatusCode} bos={buffer.Offset}/{buffer.Size}");

            string contentType = Headers["Transfer-Encoding"];
            bool   chunkedRead = (contentType != null && contentType.IndexOf("chunked", StringComparison.OrdinalIgnoreCase) != -1);
            string clength     = Headers["Content-Length"];

            if (!chunkedRead && !string.IsNullOrEmpty(clength))
            {
                if (!long.TryParse(clength, out contentLength))
                {
                    contentLength = Int64.MaxValue;
                }
            }
            else
            {
                contentLength = Int64.MaxValue;
            }

            if (Version == HttpVersion.Version11 && RequestStream.KeepAlive)
            {
                KeepAlive = true;
                var cncHeader = Headers[ServicePoint.UsesProxy ? "Proxy-Connection" : "Connection"];
                if (cncHeader != null)
                {
                    cncHeader = cncHeader.ToLower();
                    KeepAlive = cncHeader.IndexOf("keep-alive", StringComparison.Ordinal) != -1;
                    if (cncHeader.IndexOf("close", StringComparison.Ordinal) != -1)
                    {
                        KeepAlive = false;
                    }
                }
            }

            // Negative numbers?
            if (!Int32.TryParse(clength, out stream_length))
            {
                stream_length = -1;
            }

            string me        = "WebResponseStream.Initialize()";
            string tencoding = null;

            if (ExpectContent)
            {
                tencoding = Headers["Transfer-Encoding"];
            }

            ChunkedRead = (tencoding != null && tencoding.IndexOf("chunked", StringComparison.OrdinalIgnoreCase) != -1);
            if (!ChunkedRead)
            {
                readBuffer = buffer;
                try {
                    if (contentLength > 0 && readBuffer.Size >= contentLength)
                    {
                        if (!IsNtlmAuth())
                        {
                            await ReadAllAsync(false, cancellationToken).ConfigureAwait(false);
                        }
                    }
                } catch (Exception e) {
                    throw GetReadException(WebExceptionStatus.ReceiveFailure, e, me);
                }
            }
            else if (ChunkStream == null)
            {
                try {
                    ChunkStream = new MonoChunkStream(buffer.Buffer, buffer.Offset, buffer.Offset + buffer.Size, Headers);
                } catch (Exception e) {
                    throw GetReadException(WebExceptionStatus.ServerProtocolViolation, e, me);
                }
            }
            else
            {
                ChunkStream.ResetBuffer();
                try {
                    ChunkStream.Write(buffer.Buffer, buffer.Offset, buffer.Size);
                } catch (Exception e) {
                    throw GetReadException(WebExceptionStatus.ServerProtocolViolation, e, me);
                }
            }

            WebConnection.Debug($"{ME} INIT #1: - {ExpectContent} {closed} {nextReadCalled}");

            if (!ExpectContent)
            {
                if (!closed && !nextReadCalled)
                {
                    if (contentLength == Int64.MaxValue)
                    {
                        contentLength = 0;
                    }
                    nextReadCalled = true;
                }
                Operation.Finish(true);
            }
        }
        internal async Task InitReadAsync(CancellationToken cancellationToken)
        {
            WebConnection.Debug($"{ME} INIT READ ASYNC");

            var buffer   = new BufferOffsetSize(new byte[4096], false);
            var state    = ReadState.None;
            int position = 0;

            while (true)
            {
                Operation.ThrowIfClosedOrDisposed(cancellationToken);

                WebConnection.Debug($"{ME} INIT READ ASYNC LOOP: {state} {position} - {buffer.Offset}/{buffer.Size}");

                var nread = await InnerStream.ReadAsync(
                    buffer.Buffer, buffer.Offset, buffer.Size, cancellationToken).ConfigureAwait(false);

                WebConnection.Debug($"{ME} INIT READ ASYNC LOOP #1: {state} {position} - {buffer.Offset}/{buffer.Size} - {nread}");

                if (nread == 0)
                {
                    throw GetReadException(WebExceptionStatus.ReceiveFailure, null, "ReadDoneAsync2");
                }

                if (nread < 0)
                {
                    throw GetReadException(WebExceptionStatus.ServerProtocolViolation, null, "ReadDoneAsync3");
                }

                buffer.Offset += nread;
                buffer.Size   -= nread;

                if (state == ReadState.None)
                {
                    try {
                        var oldPos = position;
                        if (!GetResponse(buffer, ref position, ref state))
                        {
                            position = oldPos;
                        }
                    } catch (Exception e) {
                        WebConnection.Debug($"{ME} INIT READ ASYNC FAILED: {e.Message}\n{e}");
                        throw GetReadException(WebExceptionStatus.ServerProtocolViolation, e, "ReadDoneAsync4");
                    }
                }

                if (state == ReadState.Aborted)
                {
                    throw GetReadException(WebExceptionStatus.RequestCanceled, null, "ReadDoneAsync5");
                }

                if (state == ReadState.Content)
                {
                    buffer.Size   = buffer.Offset - position;
                    buffer.Offset = position;
                    break;
                }

                int est = nread * 2;
                if (est > buffer.Size)
                {
                    var newBuffer = new byte [buffer.Buffer.Length + est];
                    Buffer.BlockCopy(buffer.Buffer, 0, newBuffer, 0, buffer.Offset);
                    buffer = new BufferOffsetSize(newBuffer, buffer.Offset, newBuffer.Length - buffer.Offset, false);
                }
                state    = ReadState.None;
                position = 0;
            }

            WebConnection.Debug($"{ME} INIT READ ASYNC LOOP DONE: {buffer.Offset} {buffer.Size}");

            try {
                Operation.ThrowIfDisposed(cancellationToken);
                await Initialize(buffer, cancellationToken).ConfigureAwait(false);
            } catch (Exception e) {
                throw GetReadException(WebExceptionStatus.ReceiveFailure, e, "ReadDoneAsync6");
            }
        }
예제 #11
0
        internal bool WriteRequestAsync(SimpleAsyncResult result)
        {
            if (requestWritten)
            {
                return(false);
            }

            requestWritten = true;
            if (sendChunked || !allowBuffering || writeBuffer == null)
            {
                return(false);
            }

            // Keep the call for a potential side-effect of GetBuffer
            var bytes  = writeBuffer.GetBuffer();
            var length = (int)writeBuffer.Length;

            if (request.ContentLength != -1 && request.ContentLength < length)
            {
                nextReadCalled = true;
                cnc.Close(true);
                throw new WebException("Specified Content-Length is less than the number of bytes to write", null,
                                       WebExceptionStatus.ServerProtocolViolation, null);
            }

            SetHeadersAsync(true, inner => {
                if (inner.GotException)
                {
                    result.SetCompleted(inner.CompletedSynchronously, inner.Exception);
                    return;
                }

                if (cnc.Data.StatusCode != 0 && cnc.Data.StatusCode != 100)
                {
                    result.SetCompleted(inner.CompletedSynchronously);
                    return;
                }

                if (!initRead)
                {
                    initRead = true;
                    WebConnection.InitRead(cnc);
                }

                if (length == 0)
                {
                    complete_request_written = true;
                    result.SetCompleted(inner.CompletedSynchronously);
                    return;
                }

                cnc.BeginWrite(request, bytes, 0, length, r => {
                    try {
                        complete_request_written = cnc.EndWrite(request, false, r);
                        result.SetCompleted(false);
                    } catch (Exception exc) {
                        result.SetCompleted(false, exc);
                    }
                }, null);
            });

            return(true);
        }
        public override async Task <int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
        {
            WebConnection.Debug($"{ME} READ ASYNC");

            cancellationToken.ThrowIfCancellationRequested();

            if (buffer == null)
            {
                throw new ArgumentNullException(nameof(buffer));
            }

            int length = buffer.Length;

            if (offset < 0 || length < offset)
            {
                throw new ArgumentOutOfRangeException(nameof(offset));
            }
            if (count < 0 || (length - offset) < count)
            {
                throw new ArgumentOutOfRangeException(nameof(count));
            }

            if (Interlocked.CompareExchange(ref nestedRead, 1, 0) != 0)
            {
                throw new InvalidOperationException("Invalid nested call.");
            }

            var completion = new WebCompletionSource();

            while (!cancellationToken.IsCancellationRequested)
            {
                /*
                 * 'currentRead' is set by ReadAllAsync().
                 */
                var oldCompletion = Interlocked.CompareExchange(ref pendingRead, completion, null);
                WebConnection.Debug($"{ME} READ ASYNC #1: {oldCompletion != null}");
                if (oldCompletion == null)
                {
                    break;
                }
                await oldCompletion.WaitForCompletion().ConfigureAwait(false);
            }

            WebConnection.Debug($"{ME} READ ASYNC #2: {totalRead} {contentLength}");

            int       oldBytes = 0, nbytes = 0;
            Exception throwMe = null;

            try {
                // FIXME: NetworkStream.ReadAsync() does not support cancellation.
                (oldBytes, nbytes) = await HttpWebRequest.RunWithTimeout(
                    ct => ProcessRead(buffer, offset, count, ct),
                    ReadTimeout, () => {
                    Operation.Abort();
                    InnerStream.Dispose();
                }, () => Operation.Aborted, cancellationToken).ConfigureAwait(false);
            } catch (Exception e) {
                throwMe = GetReadException(WebExceptionStatus.ReceiveFailure, e, "ReadAsync");
            }

            WebConnection.Debug($"{ME} READ ASYNC #3: {totalRead} {contentLength} - {oldBytes} {nbytes} {throwMe?.Message}");

            if (throwMe != null)
            {
                lock (locker) {
                    completion.TrySetException(throwMe);
                    pendingRead = null;
                    nestedRead  = 0;
                }

                closed = true;
                Operation.Finish(false, throwMe);
                throw throwMe;
            }

            lock (locker) {
                pendingRead.TrySetCompleted();
                pendingRead = null;
                nestedRead  = 0;
            }

            if (totalRead >= contentLength && !nextReadCalled)
            {
                WebConnection.Debug($"{ME} READ ASYNC - READ COMPLETE: {oldBytes} {nbytes} - {totalRead} {contentLength} {nextReadCalled}");
                if (!nextReadCalled)
                {
                    nextReadCalled = true;
                    Operation.Finish(true);
                }
            }

            return(oldBytes + nbytes);
        }
예제 #13
0
        private int GetResponse(byte[] buffer, int max)
        {
            int    num   = 0;
            string text  = null;
            bool   flag  = false;
            bool   flag2 = false;

            for (;;)
            {
                if (this.readState != ReadState.None)
                {
                    goto IL_114;
                }
                if (!WebConnection.ReadLine(buffer, ref num, max, ref text))
                {
                    break;
                }
                if (text == null)
                {
                    flag2 = true;
                }
                else
                {
                    flag2          = false;
                    this.readState = ReadState.Status;
                    string[] array = text.Split(new char[]
                    {
                        ' '
                    });
                    if (array.Length < 2)
                    {
                        return(-1);
                    }
                    if (string.Compare(array[0], "HTTP/1.1", true) == 0)
                    {
                        this.Data.Version = HttpVersion.Version11;
                        this.sPoint.SetVersion(HttpVersion.Version11);
                    }
                    else
                    {
                        this.Data.Version = HttpVersion.Version10;
                        this.sPoint.SetVersion(HttpVersion.Version10);
                    }
                    this.Data.StatusCode = (int)uint.Parse(array[1]);
                    if (array.Length >= 3)
                    {
                        this.Data.StatusDescription = string.Join(" ", array, 2, array.Length - 2);
                    }
                    else
                    {
                        this.Data.StatusDescription = string.Empty;
                    }
                    if (num >= max)
                    {
                        return(num);
                    }
                    goto IL_114;
                }
IL_2CA:
                if (!flag2 && !flag)
                {
                    return(-1);
                }
                continue;
IL_114:
                flag2 = false;
                if (this.readState != ReadState.Status)
                {
                    goto IL_2CA;
                }
                this.readState    = ReadState.Headers;
                this.Data.Headers = new WebHeaderCollection();
                ArrayList arrayList = new ArrayList();
                bool      flag3     = false;
                while (!flag3)
                {
                    if (!WebConnection.ReadLine(buffer, ref num, max, ref text))
                    {
                        break;
                    }
                    if (text == null)
                    {
                        flag3 = true;
                    }
                    else if (text.Length > 0 && (text[0] == ' ' || text[0] == '\t'))
                    {
                        int num2 = arrayList.Count - 1;
                        if (num2 < 0)
                        {
                            break;
                        }
                        string value = (string)arrayList[num2] + text;
                        arrayList[num2] = value;
                    }
                    else
                    {
                        arrayList.Add(text);
                    }
                }
                if (!flag3)
                {
                    return(-1);
                }
                foreach (object obj in arrayList)
                {
                    string @internal = (string)obj;
                    this.Data.Headers.SetInternal(@internal);
                }
                if (this.Data.StatusCode != 100)
                {
                    goto IL_2C1;
                }
                this.sPoint.SendContinue = true;
                if (num >= max)
                {
                    return(num);
                }
                if (this.Data.request.ExpectContinue)
                {
                    this.Data.request.DoContinueDelegate(this.Data.StatusCode, this.Data.Headers);
                    this.Data.request.ExpectContinue = false;
                }
                this.readState = ReadState.None;
                flag           = true;
                goto IL_2CA;
            }
            return(-1);

IL_2C1:
            this.readState = ReadState.Content;
            return(num);
        }
예제 #14
0
 void Debug(string message)
 {
     WebConnection.Debug($"SPS({ID}): {message}");
 }
예제 #15
0
        public override async Task <int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
        {
            WebConnection.Debug($"{ME} READ ASYNC");

            cancellationToken.ThrowIfCancellationRequested();

            if (buffer == null)
            {
                throw new ArgumentNullException(nameof(buffer));
            }

            int length = buffer.Length;

            if (offset < 0 || length < offset)
            {
                throw new ArgumentOutOfRangeException(nameof(offset));
            }
            if (count < 0 || (length - offset) < count)
            {
                throw new ArgumentOutOfRangeException(nameof(count));
            }

            if (Interlocked.CompareExchange(ref nestedRead, 1, 0) != 0)
            {
                throw new InvalidOperationException("Invalid nested call.");
            }

            var completion = new WebCompletionSource();

            while (!cancellationToken.IsCancellationRequested)
            {
                /*
                 * 'currentRead' is set by ReadAllAsync().
                 */
                var oldCompletion = Interlocked.CompareExchange(ref pendingRead, completion, null);
                WebConnection.Debug($"{ME} READ ASYNC #1: {oldCompletion != null}");
                if (oldCompletion == null)
                {
                    break;
                }
                await oldCompletion.WaitForCompletion().ConfigureAwait(false);
            }

            WebConnection.Debug($"{ME} READ ASYNC #2");

            int       nbytes  = 0;
            Exception throwMe = null;

            try {
                nbytes = await ProcessRead(buffer, offset, count, cancellationToken).ConfigureAwait(false);
            } catch (Exception e) {
                throwMe = GetReadException(WebExceptionStatus.ReceiveFailure, e, "ReadAsync");
            }

            WebConnection.Debug($"{ME} READ ASYNC #3: {nbytes} {throwMe?.Message}");

            if (throwMe != null)
            {
                lock (locker) {
                    completion.TrySetException(throwMe);
                    pendingRead = null;
                    nestedRead  = 0;
                }

                closed = true;
                Operation.Finish(false, throwMe);
                throw throwMe;
            }

            lock (locker) {
                completion.TrySetCompleted();
                pendingRead = null;
                nestedRead  = 0;
            }

            if (nbytes <= 0 && !read_eof)
            {
                read_eof = true;

                if (!nextReadCalled)
                {
                    WebConnection.Debug($"{ME} READ ASYNC - READ COMPLETE: {nbytes} - {nextReadCalled}");
                    if (!nextReadCalled)
                    {
                        nextReadCalled = true;
                        Operation.Finish(true);
                    }
                }
            }

            return(nbytes);
        }
예제 #16
0
        private static void ReadDone(IAsyncResult result)
        {
            WebConnection     webConnection = (WebConnection)result.AsyncState;
            WebConnectionData data          = webConnection.Data;
            Stream            stream        = webConnection.nstream;

            if (stream == null)
            {
                webConnection.Close(true);
                return;
            }
            int num = -1;

            try
            {
                num = stream.EndRead(result);
            }
            catch (Exception e)
            {
                webConnection.HandleError(WebExceptionStatus.ReceiveFailure, e, "ReadDone1");
                return;
            }
            if (num == 0)
            {
                webConnection.HandleError(WebExceptionStatus.ReceiveFailure, null, "ReadDone2");
                return;
            }
            if (num < 0)
            {
                webConnection.HandleError(WebExceptionStatus.ServerProtocolViolation, null, "ReadDone3");
                return;
            }
            int num2 = -1;

            num += webConnection.position;
            if (webConnection.readState == ReadState.None)
            {
                Exception ex = null;
                try
                {
                    num2 = webConnection.GetResponse(webConnection.buffer, num);
                }
                catch (Exception ex2)
                {
                    ex = ex2;
                }
                if (ex != null)
                {
                    webConnection.HandleError(WebExceptionStatus.ServerProtocolViolation, ex, "ReadDone4");
                    return;
                }
            }
            if (webConnection.readState != ReadState.Content)
            {
                int    num3 = num * 2;
                int    num4 = (num3 >= webConnection.buffer.Length) ? num3 : webConnection.buffer.Length;
                byte[] dst  = new byte[num4];
                Buffer.BlockCopy(webConnection.buffer, 0, dst, 0, num);
                webConnection.buffer    = dst;
                webConnection.position  = num;
                webConnection.readState = ReadState.None;
                WebConnection.InitRead(webConnection);
                return;
            }
            webConnection.position = 0;
            WebConnectionStream webConnectionStream = new WebConnectionStream(webConnection);
            string text = data.Headers["Transfer-Encoding"];

            webConnection.chunkedRead = (text != null && text.ToLower().IndexOf("chunked") != -1);
            if (!webConnection.chunkedRead)
            {
                webConnectionStream.ReadBuffer       = webConnection.buffer;
                webConnectionStream.ReadBufferOffset = num2;
                webConnectionStream.ReadBufferSize   = num;
                webConnectionStream.CheckResponseInBuffer();
            }
            else if (webConnection.chunkStream == null)
            {
                try
                {
                    webConnection.chunkStream = new ChunkStream(webConnection.buffer, num2, num, data.Headers);
                }
                catch (Exception e2)
                {
                    webConnection.HandleError(WebExceptionStatus.ServerProtocolViolation, e2, "ReadDone5");
                    return;
                }
            }
            else
            {
                webConnection.chunkStream.ResetBuffer();
                try
                {
                    webConnection.chunkStream.Write(webConnection.buffer, num2, num);
                }
                catch (Exception e3)
                {
                    webConnection.HandleError(WebExceptionStatus.ServerProtocolViolation, e3, "ReadDone6");
                    return;
                }
            }
            data.stream = webConnectionStream;
            if (!WebConnection.ExpectContent(data.StatusCode) || data.request.Method == "HEAD")
            {
                webConnectionStream.ForceCompletion();
            }
            data.request.SetResponseData(data);
        }
예제 #17
0
        internal async Task ReadAllAsync(bool resending, CancellationToken cancellationToken)
        {
            WebConnection.Debug($"{ME} READ ALL ASYNC: resending={resending} eof={read_eof} " +
                                "nextReadCalled={nextReadCalled}");
            if (read_eof || bufferedEntireContent || nextReadCalled)
            {
                if (!nextReadCalled)
                {
                    nextReadCalled = true;
                    Operation.Finish(true);
                }
                return;
            }

            var completion = new WebCompletionSource();
            var timeoutCts = new CancellationTokenSource();

            try {
                var timeoutTask = Task.Delay(ReadTimeout, timeoutCts.Token);
                while (true)
                {
                    /*
                     * 'currentRead' is set by ReadAsync().
                     */
                    cancellationToken.ThrowIfCancellationRequested();
                    var oldCompletion = Interlocked.CompareExchange(ref pendingRead, completion, null);
                    if (oldCompletion == null)
                    {
                        break;
                    }

                    // ReadAsync() is in progress.
                    var oldReadTask = oldCompletion.WaitForCompletion();
                    var anyTask     = await Task.WhenAny(oldReadTask, timeoutTask).ConfigureAwait(false);

                    if (anyTask == timeoutTask)
                    {
                        throw new WebException("The operation has timed out.", WebExceptionStatus.Timeout);
                    }
                }
            } finally {
                timeoutCts.Cancel();
                timeoutCts.Dispose();
            }

            WebConnection.Debug($"{ME} READ ALL ASYNC #1");

            try {
                cancellationToken.ThrowIfCancellationRequested();

                /*
                 * We may have awaited on the 'readTcs', so check
                 * for eof again as ReadAsync() may have set it.
                 */
                if (read_eof || bufferedEntireContent)
                {
                    return;
                }

                /*
                 * Simplify: if we're resending on a new connection,
                 * then we can simply close the connection here.
                 */
                if (resending && !KeepAlive)
                {
                    Close();
                    return;
                }

                var buffer = await ReadAllAsyncInner(cancellationToken).ConfigureAwait(false);

                var bos = new BufferOffsetSize(buffer, 0, buffer.Length, false);
                innerStream = new BufferedReadStream(Operation, null, bos);

                nextReadCalled = true;
                completion.TrySetCompleted();
            } catch (Exception ex) {
                WebConnection.Debug($"{ME} READ ALL ASYNC EX: {ex.Message}");
                completion.TrySetException(ex);
                throw;
            } finally {
                WebConnection.Debug($"{ME} READ ALL ASYNC #2");
                pendingRead = null;
            }

            Operation.Finish(true);
        }
예제 #18
0
        void Initialize(BufferOffsetSize buffer)
        {
            WebConnection.Debug($"{ME} INIT: status={(int)StatusCode} bos={buffer.Offset}/{buffer.Size}");

            long   contentLength;
            string contentType = Headers["Transfer-Encoding"];
            bool   chunkedRead = (contentType != null && contentType.IndexOf("chunked", StringComparison.OrdinalIgnoreCase) != -1);
            string clength     = Headers["Content-Length"];

            if (!chunkedRead && !string.IsNullOrEmpty(clength))
            {
                if (!long.TryParse(clength, out contentLength))
                {
                    contentLength = Int64.MaxValue;
                }
            }
            else
            {
                contentLength = Int64.MaxValue;
            }

            string tencoding = null;

            if (ExpectContent)
            {
                tencoding = Headers["Transfer-Encoding"];
            }

            ChunkedRead = (tencoding != null && tencoding.IndexOf("chunked", StringComparison.OrdinalIgnoreCase) != -1);

            if (Version == HttpVersion.Version11 && RequestStream.KeepAlive)
            {
                KeepAlive = true;
                var cncHeader = Headers[ServicePoint.UsesProxy ? "Proxy-Connection" : "Connection"];
                if (cncHeader != null)
                {
                    cncHeader = cncHeader.ToLower();
                    KeepAlive = cncHeader.IndexOf("keep-alive", StringComparison.Ordinal) != -1;
                    if (cncHeader.IndexOf("close", StringComparison.Ordinal) != -1)
                    {
                        KeepAlive = false;
                    }
                }

                if (!ChunkedRead && contentLength == Int64.MaxValue)
                {
                    /*
                     * This is a violation of the HTTP Spec - the server neither send a
                     * "Content-Length:" nor a "Transfer-Encoding: chunked" header.
                     * The only way to recover from this is to keep reading until the
                     * remote closes the connection, so we can't reuse it.
                     */
                    KeepAlive = false;
                }
            }

            /*
             * Inner layer:
             * We may have read a few extra bytes while parsing the headers, these will be
             * passed to us in the @buffer parameter and we need to read these before
             * reading from the `InnerStream`.
             */
            Stream networkStream;

            if (!ExpectContent || (!ChunkedRead && buffer.Size >= contentLength))
            {
                bufferedEntireContent = true;
                innerStream           = new BufferedReadStream(Operation, null, buffer);
                networkStream         = innerStream;
            }
            else if (buffer.Size > 0)
            {
                networkStream = new BufferedReadStream(Operation, RequestStream.InnerStream, buffer);
            }
            else
            {
                networkStream = RequestStream.InnerStream;
            }

            /*
             * Intermediate layer:
             * - Wrap with MonoChunkStream when using chunked encoding.
             * - Otherwise, we should have a Content-Length, wrap with
             *   FixedSizeReadStream to read exactly that many bytes.
             */
            if (ChunkedRead)
            {
                innerStream = new MonoChunkStream(Operation, networkStream, Headers);
            }
            else if (bufferedEntireContent)
            {
                // 'innerStream' has already been set above.
            }
            else if (contentLength != Int64.MaxValue)
            {
                innerStream = new FixedSizeReadStream(Operation, networkStream, contentLength);
            }
            else
            {
                // Violation of the HTTP Spec - neither chunked nor length.
                innerStream = new BufferedReadStream(Operation, networkStream, null);
            }

            /*
             * Outer layer:
             * - Decode gzip/deflate if requested.
             */
            string content_encoding = Headers["Content-Encoding"];

            if (content_encoding == "gzip" && (Request.AutomaticDecompression & DecompressionMethods.GZip) != 0)
            {
                innerStream = ContentDecodeStream.Create(Operation, innerStream, ContentDecodeStream.Mode.GZip);
                Headers.Remove(HttpRequestHeader.ContentEncoding);
            }
            else if (content_encoding == "deflate" && (Request.AutomaticDecompression & DecompressionMethods.Deflate) != 0)
            {
                innerStream = ContentDecodeStream.Create(Operation, innerStream, ContentDecodeStream.Mode.Deflate);
                Headers.Remove(HttpRequestHeader.ContentEncoding);
            }

            WebConnection.Debug($"{ME} INIT #1: - {ExpectContent} {closed} {nextReadCalled}");

            if (!ExpectContent)
            {
                nextReadCalled = true;
                Operation.Finish(true);
            }
        }
예제 #19
0
        static void ReadDone(IAsyncResult result)
        {
            WebConnection     cnc  = (WebConnection)result.AsyncState;
            WebConnectionData data = cnc.Data;
            Stream            ns   = cnc.nstream;

            if (ns == null)
            {
                cnc.Close(true);
                return;
            }

            int nread = -1;

            try {
                nread = ns.EndRead(result);
            } catch (Exception e) {
                cnc.HandleError(WebExceptionStatus.ReceiveFailure, e, "ReadDone1");
                return;
            }

            if (nread == 0)
            {
                cnc.HandleError(WebExceptionStatus.ReceiveFailure, null, "ReadDone2");
                return;
            }

            if (nread < 0)
            {
                cnc.HandleError(WebExceptionStatus.ServerProtocolViolation, null, "ReadDone3");
                return;
            }

            int pos = -1;

            nread += cnc.position;
            if (cnc.readState == ReadState.None)
            {
                Exception exc = null;
                try {
                    pos = cnc.GetResponse(cnc.buffer, nread);
                } catch (Exception e) {
                    exc = e;
                }

                if (exc != null)
                {
                    cnc.HandleError(WebExceptionStatus.ServerProtocolViolation, exc, "ReadDone4");
                    return;
                }
            }

            if (cnc.readState != ReadState.Content)
            {
                int     est       = nread * 2;
                int     max       = (est < cnc.buffer.Length) ? cnc.buffer.Length : est;
                byte [] newBuffer = new byte [max];
                Buffer.BlockCopy(cnc.buffer, 0, newBuffer, 0, nread);
                cnc.buffer    = newBuffer;
                cnc.position  = nread;
                cnc.readState = ReadState.None;
                InitRead(cnc);
                return;
            }

            cnc.position = 0;

            WebConnectionStream stream = new WebConnectionStream(cnc);

            string contentType = data.Headers ["Transfer-Encoding"];

            cnc.chunkedRead = (contentType != null && contentType.ToLower().IndexOf("chunked") != -1);
            if (!cnc.chunkedRead)
            {
                stream.ReadBuffer       = cnc.buffer;
                stream.ReadBufferOffset = pos;
                stream.ReadBufferSize   = nread;
                stream.CheckResponseInBuffer();
            }
            else if (cnc.chunkStream == null)
            {
                try {
                    cnc.chunkStream = new ChunkStream(cnc.buffer, pos, nread, data.Headers);
                } catch (Exception e) {
                    cnc.HandleError(WebExceptionStatus.ServerProtocolViolation, e, "ReadDone5");
                    return;
                }
            }
            else
            {
                cnc.chunkStream.ResetBuffer();
                try {
                    cnc.chunkStream.Write(cnc.buffer, pos, nread);
                } catch (Exception e) {
                    cnc.HandleError(WebExceptionStatus.ServerProtocolViolation, e, "ReadDone6");
                    return;
                }
            }

            data.stream = stream;

            if (!ExpectContent(data.StatusCode) || data.request.Method == "HEAD")
            {
                stream.ForceCompletion();
            }

            data.request.SetResponseData(data);
        }
예제 #20
0
        internal void WriteRequest()
        {
            if (requestWritten)
            {
                return;
            }

            requestWritten = true;
            if (sendChunked)
            {
                return;
            }

            if (!allowBuffering || writeBuffer == null)
            {
                return;
            }

            byte [] bytes  = writeBuffer.GetBuffer();
            int     length = (int)writeBuffer.Length;

            if (request.ContentLength != -1 && request.ContentLength < length)
            {
                nextReadCalled = true;
                cnc.Close(true);
                throw new WebException("Specified Content-Length is less than the number of bytes to write", null,
                                       WebExceptionStatus.ServerProtocolViolation, null);
            }

            if (!headersSent)
            {
                string method         = request.Method;
                bool   no_writestream = (method == "GET" || method == "CONNECT" || method == "HEAD" ||
                                         method == "TRACE");
                if (!no_writestream)
                {
                    request.InternalContentLength = length;
                }
                request.SendRequestHeaders(true);
            }
            WriteHeaders();
            if (cnc.Data.StatusCode != 0 && cnc.Data.StatusCode != 100)
            {
                return;
            }

            IAsyncResult result = null;

            if (length > 0)
            {
                result = cnc.BeginWrite(request, bytes, 0, length, null, null);
            }

            if (!initRead)
            {
                initRead = true;
                WebConnection.InitRead(cnc);
            }

            if (length > 0)
            {
                complete_request_written = cnc.EndWrite(request, result);
            }
            else
            {
                complete_request_written = true;
            }
        }
예제 #21
0
        bool SetHeadersAsync(SimpleAsyncResult result, bool setInternalLength)
        {
            if (headersSent)
            {
                return(false);
            }

            bool webdav      = false;
            bool writestream = false;

            switch (request.Method)
            {
            case "PROPFIND":
            case "PROPPATCH":
            case "MKCOL":
            case "COPY":
            case "MOVE":
            case "LOCK":
            case "UNLOCK":
                webdav = true;
                break;

            case "POST":
            case "PUT":
                writestream = true;
                break;
            }

            if (setInternalLength && writestream && writeBuffer != null)
            {
                request.InternalContentLength = writeBuffer.Length;
            }

            if (!(sendChunked || request.ContentLength > -1 || !writestream || webdav))
            {
                return(false);
            }

            headersSent = true;
            headers     = request.GetRequestHeaders();

            var innerResult = cnc.BeginWrite(request, headers, 0, headers.Length, r => {
                try {
                    cnc.EndWrite(request, true, r);
                    if (!initRead)
                    {
                        initRead = true;
                        WebConnection.InitRead(cnc);
                    }
                    var cl = request.ContentLength;
                    if (!sendChunked && cl == 0)
                    {
                        requestWritten = true;
                    }
                    result.SetCompleted(false);
                } catch (WebException e) {
                    result.SetCompleted(false, e);
                } catch (Exception e) {
                    result.SetCompleted(false, new WebException("Error writing headers", e, WebExceptionStatus.SendFailure));
                }
            }, null);

            return(innerResult != null);
        }
예제 #22
0
 void Debug(string message, params object[] args)
 {
     WebConnection.Debug($"SPS({ID}): {string.Format (message, args)}");
 }
예제 #23
0
        public override async Task WriteAsync(byte[] buffer, int offset, int size, CancellationToken cancellationToken)
        {
            WebConnection.Debug($"{ME} WRITE ASYNC: {buffer.Length}/{offset}/{size}");

            Operation.ThrowIfClosedOrDisposed(cancellationToken);

            if (Operation.WriteBuffer != null)
            {
                throw new InvalidOperationException();
            }

            if (buffer == null)
            {
                throw new ArgumentNullException(nameof(buffer));
            }

            int length = buffer.Length;

            if (offset < 0 || length < offset)
            {
                throw new ArgumentOutOfRangeException(nameof(offset));
            }
            if (size < 0 || (length - offset) < size)
            {
                throw new ArgumentOutOfRangeException(nameof(size));
            }

            var myWriteTcs = new TaskCompletionSource <int> ();

            if (Interlocked.CompareExchange(ref pendingWrite, myWriteTcs, null) != null)
            {
                throw new InvalidOperationException(SR.GetString(SR.net_repcall));
            }

            try {
                await ProcessWrite(buffer, offset, size, cancellationToken).ConfigureAwait(false);

                WebConnection.Debug($"{ME} WRITE ASYNC #1: {allowBuffering} {sendChunked} {Request.ContentLength} {totalWritten}");

                if (Request.ContentLength > 0 && totalWritten == Request.ContentLength)
                {
                    await FinishWriting(cancellationToken);
                }

                pendingWrite = null;
                myWriteTcs.TrySetResult(0);
            } catch (Exception ex) {
                KillBuffer();
                closed = true;

                WebConnection.Debug($"{ME} WRITE ASYNC EX: {ex.Message}");

                if (ex is SocketException)
                {
                    ex = new IOException("Error writing request", ex);
                }

                Operation.CompleteRequestWritten(this, ex);

                pendingWrite = null;
                myWriteTcs.TrySetException(ex);
                throw;
            }
        }
예제 #24
0
        static void ReadDone(IAsyncResult result)
        {
            WebConnection     cnc  = (WebConnection)result.AsyncState;
            WebConnectionData data = cnc.Data;
            Stream            ns   = cnc.nstream;

            if (ns == null)
            {
                cnc.Close(true);
                return;
            }

            int nread = -1;

            try {
                nread = ns.EndRead(result);
            } catch (ObjectDisposedException) {
                return;
            } catch (Exception e) {
                if (e.InnerException is ObjectDisposedException)
                {
                    return;
                }

                cnc.HandleError(WebExceptionStatus.ReceiveFailure, e, "ReadDone1");
                return;
            }

            if (nread == 0)
            {
                cnc.HandleError(WebExceptionStatus.ReceiveFailure, null, "ReadDone2");
                return;
            }

            if (nread < 0)
            {
                cnc.HandleError(WebExceptionStatus.ServerProtocolViolation, null, "ReadDone3");
                return;
            }

            int pos = -1;

            nread += cnc.position;
            if (data.ReadState == ReadState.None)
            {
                Exception exc = null;
                try {
                    pos = GetResponse(data, cnc.sPoint, cnc.buffer, nread);
                } catch (Exception e) {
                    exc = e;
                }

                if (exc != null || pos == -1)
                {
                    cnc.HandleError(WebExceptionStatus.ServerProtocolViolation, exc, "ReadDone4");
                    return;
                }
            }

            if (data.ReadState == ReadState.Aborted)
            {
                cnc.HandleError(WebExceptionStatus.RequestCanceled, null, "ReadDone");
                return;
            }

            if (data.ReadState != ReadState.Content)
            {
                int     est       = nread * 2;
                int     max       = (est < cnc.buffer.Length) ? cnc.buffer.Length : est;
                byte [] newBuffer = new byte [max];
                Buffer.BlockCopy(cnc.buffer, 0, newBuffer, 0, nread);
                cnc.buffer     = newBuffer;
                cnc.position   = nread;
                data.ReadState = ReadState.None;
                InitRead(cnc);
                return;
            }

            cnc.position = 0;

            WebConnectionStream stream = new WebConnectionStream(cnc, data);
            bool   expect_content      = ExpectContent(data.StatusCode, data.request.Method);
            string tencoding           = null;

            if (expect_content)
            {
                tencoding = data.Headers ["Transfer-Encoding"];
            }

            cnc.chunkedRead = (tencoding != null && tencoding.IndexOf("chunked", StringComparison.OrdinalIgnoreCase) != -1);
            if (!cnc.chunkedRead)
            {
                stream.ReadBuffer       = cnc.buffer;
                stream.ReadBufferOffset = pos;
                stream.ReadBufferSize   = nread;
                try {
                    stream.CheckResponseInBuffer();
                } catch (Exception e) {
                    cnc.HandleError(WebExceptionStatus.ReceiveFailure, e, "ReadDone7");
                }
            }
            else if (cnc.chunkStream == null)
            {
                try {
                    cnc.chunkStream = new ChunkStream(cnc.buffer, pos, nread, data.Headers);
                } catch (Exception e) {
                    cnc.HandleError(WebExceptionStatus.ServerProtocolViolation, e, "ReadDone5");
                    return;
                }
            }
            else
            {
                cnc.chunkStream.ResetBuffer();
                try {
                    cnc.chunkStream.Write(cnc.buffer, pos, nread);
                } catch (Exception e) {
                    cnc.HandleError(WebExceptionStatus.ServerProtocolViolation, e, "ReadDone6");
                    return;
                }
            }

            data.stream = stream;

            if (!expect_content)
            {
                stream.ForceCompletion();
            }

            data.request.SetResponseData(data);
        }
예제 #25
0
        internal void WriteRequest()
        {
            if (requestWritten)
            {
                return;
            }

            if (sendChunked)
            {
                request.SendRequestHeaders();
                requestWritten = true;
                return;
            }

            if (!allowBuffering || writeBuffer == null)
            {
                return;
            }

            byte [] bytes  = writeBuffer.GetBuffer();
            int     length = (int)writeBuffer.Length;

            if (request.ContentLength != -1 && request.ContentLength < length)
            {
                throw new WebException("Specified Content-Length is less than the number of bytes to write", null,
                                       WebExceptionStatus.ServerProtocolViolation, null);
            }

            request.InternalContentLength = length;
            request.SendRequestHeaders();
            requestWritten = true;
            if (!cnc.Write(headers, 0, headers.Length))
            {
                throw new WebException("Error writing request.", null, WebExceptionStatus.SendFailure, null);
            }

            headersSent = true;
            if (cnc.Data.StatusCode != 0 && cnc.Data.StatusCode != 100)
            {
                return;
            }

            IAsyncResult result = null;

            if (length > 0)
            {
                result = cnc.BeginWrite(bytes, 0, length, null, null);
            }

            if (!initRead)
            {
                initRead = true;
                WebConnection.InitRead(cnc);
            }

            if (length > 0)
            {
                complete_request_written = cnc.EndWrite(result);
            }
            else
            {
                complete_request_written = true;
            }
        }
예제 #26
0
        public override void Close()
        {
            if (GetResponseOnClose)
            {
                if (disposed)
                {
                    return;
                }
                disposed = true;
                var response = (HttpWebResponse)request.GetResponse();
                response.ReadAll();
                response.Close();
                return;
            }

            if (sendChunked)
            {
                if (disposed)
                {
                    return;
                }
                disposed = true;
                if (!pending.WaitOne(WriteTimeout))
                {
                    throw new WebException("The operation has timed out.", WebExceptionStatus.Timeout);
                }
                byte [] chunk   = Encoding.ASCII.GetBytes("0\r\n\r\n");
                string  err_msg = null;
                cnc.Write(request, chunk, 0, chunk.Length, ref err_msg);
                return;
            }

            if (isRead)
            {
                if (!nextReadCalled)
                {
                    CheckComplete();
                    // If we have not read all the contents
                    if (!nextReadCalled)
                    {
                        nextReadCalled = true;
                        cnc.Close(true);
                    }
                }
                return;
            }
            else if (!allowBuffering)
            {
                complete_request_written = true;
                if (!initRead)
                {
                    initRead = true;
                    WebConnection.InitRead(cnc);
                }
                return;
            }

            if (disposed || requestWritten)
            {
                return;
            }

            long length = request.ContentLength;

            if (!sendChunked && length != -1 && totalWritten != length)
            {
                IOException io = new IOException("Cannot close the stream until all bytes are written");
                nextReadCalled = true;
                cnc.Close(true);
                throw new WebException("Request was cancelled.", io, WebExceptionStatus.RequestCanceled);
            }

            // Commented out the next line to fix xamarin bug #1512
            //WriteRequest ();
            disposed = true;
        }
예제 #27
0
        internal void WriteRequest()
        {
            if (requestWritten)
            {
                return;
            }
            requestWritten = true;
            if (sendChunked || !allowBuffering || writeBuffer == null)
            {
                return;
            }
            byte[] buffer = writeBuffer.GetBuffer();
            int    num    = (int)writeBuffer.Length;

            if (request.ContentLength != -1 && request.ContentLength < num)
            {
                nextReadCalled = true;
                cnc.Close(sendNext: true);
                throw new WebException("Specified Content-Length is less than the number of bytes to write", null, WebExceptionStatus.ServerProtocolViolation, null);
            }
            if (!headersSent)
            {
                string method = request.Method;
                int    num2;
                switch (method)
                {
                default:
                    num2 = ((method == "DELETE") ? 1 : 0);
                    break;

                case "GET":
                case "CONNECT":
                case "HEAD":
                case "TRACE":
                    num2 = 1;
                    break;
                }
                if (num2 == 0)
                {
                    request.InternalContentLength = num;
                }
                request.SendRequestHeaders(propagate_error: true);
            }
            WriteHeaders();
            if (cnc.Data.StatusCode == 0 || cnc.Data.StatusCode == 100)
            {
                IAsyncResult result = null;
                if (num > 0)
                {
                    result = cnc.BeginWrite(request, buffer, 0, num, null, null);
                }
                if (!initRead)
                {
                    initRead = true;
                    WebConnection.InitRead(cnc);
                }
                if (num > 0)
                {
                    complete_request_written = cnc.EndWrite(request, result);
                }
                else
                {
                    complete_request_written = true;
                }
            }
        }
        async Task <(int, int)> ProcessRead(byte[] buffer, int offset, int size, CancellationToken cancellationToken)
        {
            WebConnection.Debug($"{ME} PROCESS READ: {totalRead} {contentLength}");

            cancellationToken.ThrowIfCancellationRequested();
            if (totalRead >= contentLength)
            {
                read_eof      = true;
                contentLength = totalRead;
                return(0, 0);
            }

            int oldBytes  = 0;
            int remaining = readBuffer?.Size ?? 0;

            if (remaining > 0)
            {
                int copy = (remaining > size) ? size : remaining;
                Buffer.BlockCopy(readBuffer.Buffer, readBuffer.Offset, buffer, offset, copy);
                readBuffer.Offset += copy;
                readBuffer.Size   -= copy;
                offset            += copy;
                size      -= copy;
                totalRead += copy;
                if (totalRead >= contentLength)
                {
                    contentLength = totalRead;
                    read_eof      = true;
                }
                if (size == 0 || totalRead >= contentLength)
                {
                    return(0, copy);
                }
                oldBytes = copy;
            }

            if (contentLength != Int64.MaxValue && contentLength - totalRead < size)
            {
                size = (int)(contentLength - totalRead);
            }

            WebConnection.Debug($"{ME} PROCESS READ #1: {oldBytes} {size} {read_eof}");

            if (read_eof)
            {
                contentLength = totalRead;
                return(oldBytes, 0);
            }

            var ret = await InnerReadAsync(buffer, offset, size, cancellationToken).ConfigureAwait(false);

            if (ret <= 0)
            {
                read_eof      = true;
                contentLength = totalRead;
                return(oldBytes, 0);
            }

            totalRead += ret;
            return(oldBytes, ret);
        }
예제 #29
0
		static void PrepareSharingNtlm (WebConnection cnc, HttpWebRequest request)
		{
			if (!cnc.NtlmAuthenticated)
				return;

			bool needs_reset = false;
			NetworkCredential cnc_cred = cnc.NtlmCredential;

			bool isProxy = (request.Proxy != null && !request.Proxy.IsBypassed (request.RequestUri));
			ICredentials req_icreds = (!isProxy) ? request.Credentials : request.Proxy.Credentials;
			NetworkCredential req_cred = (req_icreds != null) ? req_icreds.GetCredential (request.RequestUri, "NTLM") : null;

			if (cnc_cred == null || req_cred == null ||
				cnc_cred.Domain != req_cred.Domain || cnc_cred.UserName != req_cred.UserName ||
				cnc_cred.Password != req_cred.Password) {
				needs_reset = true;
			}

			if (!needs_reset) {
				bool req_sharing = request.UnsafeAuthenticatedConnectionSharing;
				bool cnc_sharing = cnc.UnsafeAuthenticatedConnectionSharing;
				needs_reset = (req_sharing == false || req_sharing != cnc_sharing);
			}
			if (needs_reset) {
				cnc.Close (false); // closes the authenticated connection
				cnc.ResetNtlm ();
			}
		}
        internal async Task ReadAllAsync(bool resending, CancellationToken cancellationToken)
        {
            WebConnection.Debug($"{ME} READ ALL ASYNC: resending={resending} eof={read_eof} total={totalRead} " +
                                "length={contentLength} nextReadCalled={nextReadCalled}");
            if (read_eof || totalRead >= contentLength || nextReadCalled)
            {
                if (!nextReadCalled)
                {
                    nextReadCalled = true;
                    Operation.Finish(true);
                }
                return;
            }

            var completion = new WebCompletionSource();
            var timeoutCts = new CancellationTokenSource();

            try {
                var timeoutTask = Task.Delay(ReadTimeout, timeoutCts.Token);
                while (true)
                {
                    /*
                     * 'currentRead' is set by ReadAsync().
                     */
                    cancellationToken.ThrowIfCancellationRequested();
                    var oldCompletion = Interlocked.CompareExchange(ref pendingRead, completion, null);
                    if (oldCompletion == null)
                    {
                        break;
                    }

                    // ReadAsync() is in progress.
                    var oldReadTask = oldCompletion.WaitForCompletion();
                    var anyTask     = await Task.WhenAny(oldReadTask, timeoutTask).ConfigureAwait(false);

                    if (anyTask == timeoutTask)
                    {
                        throw new WebException("The operation has timed out.", WebExceptionStatus.Timeout);
                    }
                }
            } finally {
                timeoutCts.Cancel();
                timeoutCts.Dispose();
            }

            WebConnection.Debug($"{ME} READ ALL ASYNC #1");

            cancellationToken.ThrowIfCancellationRequested();

            try {
                if (totalRead >= contentLength)
                {
                    return;
                }

                byte[] b = null;
                int    new_size;

                if (contentLength == Int64.MaxValue && !ChunkedRead)
                {
                    WebConnection.Debug($"{ME} READ ALL ASYNC - NEITHER LENGTH NOR CHUNKED");

                    /*
                     * This is a violation of the HTTP Spec - the server neither send a
                     * "Content-Length:" nor a "Transfer-Encoding: chunked" header.
                     *
                     * When we're redirecting or resending for NTLM, then we can simply close
                     * the connection here.
                     *
                     * However, if it's the final reply, then we need to try our best to read it.
                     */
                    if (resending)
                    {
                        Close();
                        return;
                    }
                    KeepAlive = false;
                }

                if (contentLength == Int64.MaxValue)
                {
                    MemoryStream     ms     = new MemoryStream();
                    BufferOffsetSize buffer = null;
                    if (readBuffer != null && readBuffer.Size > 0)
                    {
                        ms.Write(readBuffer.Buffer, readBuffer.Offset, readBuffer.Size);
                        readBuffer.Offset = 0;
                        readBuffer.Size   = readBuffer.Buffer.Length;
                        if (readBuffer.Buffer.Length >= 8192)
                        {
                            buffer = readBuffer;
                        }
                    }

                    if (buffer == null)
                    {
                        buffer = new BufferOffsetSize(new byte[8192], false);
                    }

                    int read;
                    while ((read = await InnerReadAsync(buffer.Buffer, buffer.Offset, buffer.Size, cancellationToken)) != 0)
                    {
                        ms.Write(buffer.Buffer, buffer.Offset, read);
                    }

                    new_size      = (int)ms.Length;
                    contentLength = new_size;
                    readBuffer    = new BufferOffsetSize(ms.GetBuffer(), 0, new_size, false);
                }
                else
                {
                    new_size = (int)(contentLength - totalRead);
                    b        = new byte[new_size];
                    int readSize = 0;
                    if (readBuffer != null && readBuffer.Size > 0)
                    {
                        readSize = readBuffer.Size;
                        if (readSize > new_size)
                        {
                            readSize = new_size;
                        }

                        Buffer.BlockCopy(readBuffer.Buffer, readBuffer.Offset, b, 0, readSize);
                    }

                    int remaining = new_size - readSize;
                    int r         = -1;
                    while (remaining > 0 && r != 0)
                    {
                        r = await InnerReadAsync(b, readSize, remaining, cancellationToken);

                        remaining -= r;
                        readSize  += r;
                    }
                }

                readBuffer     = new BufferOffsetSize(b, 0, new_size, false);
                totalRead      = 0;
                nextReadCalled = true;
                completion.TrySetCompleted();
            } catch (Exception ex) {
                WebConnection.Debug($"{ME} READ ALL ASYNC EX: {ex.Message}");
                completion.TrySetException(ex);
                throw;
            } finally {
                WebConnection.Debug($"{ME} READ ALL ASYNC #2");
                pendingRead = null;
            }

            Operation.Finish(true);
        }
예제 #31
0
 public ConnectionState(WebConnectionGroup group)
 {
     Group      = group;
     idleSince  = DateTime.UtcNow;
     Connection = new WebConnection(this, group.sPoint);
 }
예제 #32
0
			public ConnectionState (WebConnectionGroup group)
			{
				Group = group;
				idleSince = DateTime.UtcNow;
				Connection = new WebConnection (this, group.sPoint);
			}
예제 #33
0
        void Initialize(BufferOffsetSize buffer)
        {
            WebConnection.Debug($"{ME} INIT: status={(int)StatusCode} bos={buffer.Offset}/{buffer.Size}");

            string contentType = Headers["Transfer-Encoding"];
            bool   chunkedRead = (contentType != null && contentType.IndexOf("chunked", StringComparison.OrdinalIgnoreCase) != -1);
            string clength     = Headers["Content-Length"];

            if (!chunkedRead && !string.IsNullOrEmpty(clength))
            {
                if (!long.TryParse(clength, out contentLength))
                {
                    contentLength = Int64.MaxValue;
                }
            }
            else
            {
                contentLength = Int64.MaxValue;
            }

            if (Version == HttpVersion.Version11 && RequestStream.KeepAlive)
            {
                KeepAlive = true;
                var cncHeader = Headers[ServicePoint.UsesProxy ? "Proxy-Connection" : "Connection"];
                if (cncHeader != null)
                {
                    cncHeader = cncHeader.ToLower();
                    KeepAlive = cncHeader.IndexOf("keep-alive", StringComparison.Ordinal) != -1;
                    if (cncHeader.IndexOf("close", StringComparison.Ordinal) != -1)
                    {
                        KeepAlive = false;
                    }
                }
            }

            // Negative numbers?
            if (!Int32.TryParse(clength, out stream_length))
            {
                stream_length = -1;
            }

            string tencoding = null;

            if (ExpectContent)
            {
                tencoding = Headers["Transfer-Encoding"];
            }

            ChunkedRead = (tencoding != null && tencoding.IndexOf("chunked", StringComparison.OrdinalIgnoreCase) != -1);

            if (ChunkedRead)
            {
                innerStreamWrapper = innerChunkStream = new MonoChunkStream(
                    Operation, CreateStreamWrapper(buffer), Headers);
            }
            else if (!IsNtlmAuth() && contentLength > 0 && buffer.Size >= contentLength)
            {
                innerStreamWrapper = new BufferedReadStream(Operation, null, buffer);
            }
            else
            {
                innerStreamWrapper = CreateStreamWrapper(buffer);
            }

            string content_encoding = Headers["Content-Encoding"];

            if (content_encoding == "gzip" && (Request.AutomaticDecompression & DecompressionMethods.GZip) != 0)
            {
                innerStreamWrapper = new GZipStream(innerStreamWrapper, CompressionMode.Decompress);
                Headers.Remove(HttpRequestHeader.ContentEncoding);
            }
            else if (content_encoding == "deflate" && (Request.AutomaticDecompression & DecompressionMethods.Deflate) != 0)
            {
                innerStreamWrapper = new DeflateStream(innerStreamWrapper, CompressionMode.Decompress);
                Headers.Remove(HttpRequestHeader.ContentEncoding);
            }

            WebConnection.Debug($"{ME} INIT #1: - {ExpectContent} {closed} {nextReadCalled}");

            if (!ExpectContent)
            {
                if (!closed && !nextReadCalled)
                {
                    if (contentLength == Int64.MaxValue)
                    {
                        contentLength = 0;
                    }
                    nextReadCalled = true;
                }
                Operation.CompleteResponseRead(true);
            }
        }
예제 #34
0
		public async Task ConnectAsync (Uri uri, CancellationToken cancellationToken)
		{
			state = WebSocketState.Connecting;
			var httpUri = new UriBuilder (uri);
			if (uri.Scheme == "wss")
				httpUri.Scheme = "https";
			else
				httpUri.Scheme = "http";
			req = (HttpWebRequest)WebRequest.Create (httpUri.Uri);
			req.ReuseConnection = true;
			if (options.Cookies != null)
				req.CookieContainer = options.Cookies;

			if (options.CustomRequestHeaders.Count > 0) {
				foreach (var header in options.CustomRequestHeaders)
					req.Headers[header.Key] = header.Value;
			}

			var secKey = Convert.ToBase64String (Encoding.ASCII.GetBytes (Guid.NewGuid ().ToString ().Substring (0, 16)));
			string expectedAccept = Convert.ToBase64String (SHA1.Create ().ComputeHash (Encoding.ASCII.GetBytes (secKey + Magic)));

			req.Headers["Upgrade"] = "WebSocket";
			req.Headers["Sec-WebSocket-Version"] = VersionTag;
			req.Headers["Sec-WebSocket-Key"] = secKey;
			req.Headers["Sec-WebSocket-Origin"] = uri.Host;
			if (options.SubProtocols.Count > 0)
				req.Headers["Sec-WebSocket-Protocol"] = string.Join (",", options.SubProtocols);

			if (options.Credentials != null)
				req.Credentials = options.Credentials;
			if (options.ClientCertificates != null)
				req.ClientCertificates = options.ClientCertificates;
			if (options.Proxy != null)
				req.Proxy = options.Proxy;
			req.UseDefaultCredentials = options.UseDefaultCredentials;
			req.Connection = "Upgrade";

			HttpWebResponse resp = null;
			try {
				resp = (HttpWebResponse)(await req.GetResponseAsync ().ConfigureAwait (false));
			} catch (Exception e) {
				throw new WebSocketException (WebSocketError.Success, e);
			}

			connection = req.StoredConnection;
			underlyingSocket = connection.socket;

			if (resp.StatusCode != HttpStatusCode.SwitchingProtocols)
				throw new WebSocketException ("The server returned status code '" + (int)resp.StatusCode + "' when status code '101' was expected");
			if (!string.Equals (resp.Headers["Upgrade"], "WebSocket", StringComparison.OrdinalIgnoreCase)
				|| !string.Equals (resp.Headers["Connection"], "Upgrade", StringComparison.OrdinalIgnoreCase)
				|| !string.Equals (resp.Headers["Sec-WebSocket-Accept"], expectedAccept))
				throw new WebSocketException ("HTTP header error during handshake");
			if (resp.Headers["Sec-WebSocket-Protocol"] != null) {
				if (!options.SubProtocols.Contains (resp.Headers["Sec-WebSocket-Protocol"]))
					throw new WebSocketException (WebSocketError.UnsupportedProtocol);
				subProtocol = resp.Headers["Sec-WebSocket-Protocol"];
			}

			state = WebSocketState.Open;
		}
예제 #35
0
        bool GetResponse(BufferOffsetSize buffer, ref int pos, ref ReadState state)
        {
            string line           = null;
            bool   lineok         = false;
            bool   isContinue     = false;
            bool   emptyFirstLine = false;

            do
            {
                if (state == ReadState.Aborted)
                {
                    throw GetReadException(WebExceptionStatus.RequestCanceled, null, "GetResponse");
                }

                if (state == ReadState.None)
                {
                    lineok = WebConnection.ReadLine(buffer.Buffer, ref pos, buffer.Offset, ref line);
                    if (!lineok)
                    {
                        return(false);
                    }

                    if (line == null)
                    {
                        emptyFirstLine = true;
                        continue;
                    }
                    emptyFirstLine = false;
                    state          = ReadState.Status;

                    string[] parts = line.Split(' ');
                    if (parts.Length < 2)
                    {
                        throw GetReadException(WebExceptionStatus.ServerProtocolViolation, null, "GetResponse");
                    }

                    if (String.Compare(parts[0], "HTTP/1.1", true) == 0)
                    {
                        Version = HttpVersion.Version11;
                        ServicePoint.SetVersion(HttpVersion.Version11);
                    }
                    else
                    {
                        Version = HttpVersion.Version10;
                        ServicePoint.SetVersion(HttpVersion.Version10);
                    }

                    StatusCode = (HttpStatusCode)UInt32.Parse(parts[1]);
                    if (parts.Length >= 3)
                    {
                        StatusDescription = String.Join(" ", parts, 2, parts.Length - 2);
                    }
                    else
                    {
                        StatusDescription = string.Empty;
                    }

                    if (pos >= buffer.Size)
                    {
                        return(true);
                    }
                }

                emptyFirstLine = false;
                if (state == ReadState.Status)
                {
                    state   = ReadState.Headers;
                    Headers = new WebHeaderCollection();
                    var  headerList = new List <string> ();
                    bool finished   = false;
                    while (!finished)
                    {
                        if (WebConnection.ReadLine(buffer.Buffer, ref pos, buffer.Offset, ref line) == false)
                        {
                            break;
                        }

                        if (line == null)
                        {
                            // Empty line: end of headers
                            finished = true;
                            continue;
                        }

                        if (line.Length > 0 && (line[0] == ' ' || line[0] == '\t'))
                        {
                            int count = headerList.Count - 1;
                            if (count < 0)
                            {
                                break;
                            }

                            string prev = headerList[count] + line;
                            headerList[count] = prev;
                        }
                        else
                        {
                            headerList.Add(line);
                        }
                    }

                    if (!finished)
                    {
                        return(false);
                    }

                    // .NET uses ParseHeaders or ParseHeadersStrict which is much better
                    foreach (string s in headerList)
                    {
                        int pos_s = s.IndexOf(':');
                        if (pos_s == -1)
                        {
                            throw new ArgumentException("no colon found", "header");
                        }

                        var header = s.Substring(0, pos_s);
                        var value  = s.Substring(pos_s + 1).Trim();

                        if (WebHeaderCollection.AllowMultiValues(header))
                        {
                            Headers.AddInternal(header, value);
                        }
                        else
                        {
                            Headers.SetInternal(header, value);
                        }
                    }

                    if (StatusCode == HttpStatusCode.Continue)
                    {
                        ServicePoint.SendContinue = true;
                        if (pos >= buffer.Offset)
                        {
                            return(true);
                        }

                        if (Request.ExpectContinue)
                        {
                            Request.DoContinueDelegate((int)StatusCode, Headers);
                            // Prevent double calls when getting the
                            // headers in several packets.
                            Request.ExpectContinue = false;
                        }

                        state      = ReadState.None;
                        isContinue = true;
                    }
                    else
                    {
                        state = ReadState.Content;
                        return(true);
                    }
                }
            } while (emptyFirstLine || isContinue);

            throw GetReadException(WebExceptionStatus.ServerProtocolViolation, null, "GetResponse");
        }
		static void PrepareSharingNtlm (WebConnection cnc, HttpWebRequest request)
		{
			if (!cnc.NtlmAuthenticated)
				return;

			bool needs_reset = false;
			NetworkCredential cnc_cred = cnc.NtlmCredential;
			NetworkCredential req_cred = request.Credentials.GetCredential (request.RequestUri, "NTLM");
			if (cnc_cred == null || req_cred == null || cnc_cred.Domain != req_cred.Domain || cnc_cred.UserName != req_cred.UserName ||
				cnc_cred.Password != req_cred.Password) {
				needs_reset = true;
			}
#if NET_1_1
			if (!needs_reset) {
				bool req_sharing = request.UnsafeAuthenticatedConnectionSharing;
				bool cnc_sharing = cnc.UnsafeAuthenticatedConnectionSharing;
				needs_reset = (req_sharing == false || req_sharing != cnc_sharing);
			}
#endif
			if (needs_reset) {
				cnc.Close (false); // closes the authenticated connection
				cnc.ResetNtlm ();
			}
		}
예제 #37
0
        async Task <(WebHeaderCollection, byte[], int)> ReadHeaders(Stream stream, CancellationToken cancellationToken)
        {
            byte[] retBuffer = null;
            int    status    = 200;

            byte[]       buffer = new byte[1024];
            MemoryStream ms     = new MemoryStream();

            while (true)
            {
                cancellationToken.ThrowIfCancellationRequested();
                int n = await stream.ReadAsync(buffer, 0, 1024, cancellationToken).ConfigureAwait(false);

                if (n == 0)
                {
                    throw WebConnection.GetException(WebExceptionStatus.ServerProtocolViolation, null);
                }

                ms.Write(buffer, 0, n);
                int    start                = 0;
                string str                  = null;
                bool   gotStatus            = false;
                WebHeaderCollection headers = new WebHeaderCollection();
                while (WebConnection.ReadLine(ms.GetBuffer(), ref start, (int)ms.Length, ref str))
                {
                    if (str == null)
                    {
                        int contentLen;
                        var clengthHeader = headers["Content-Length"];
                        if (string.IsNullOrEmpty(clengthHeader) || !int.TryParse(clengthHeader, out contentLen))
                        {
                            contentLen = 0;
                        }

                        if (ms.Length - start - contentLen > 0)
                        {
                            // we've read more data than the response header and conents,
                            // give back extra data to the caller
                            retBuffer = new byte[ms.Length - start - contentLen];
                            Buffer.BlockCopy(ms.GetBuffer(), start + contentLen, retBuffer, 0, retBuffer.Length);
                        }
                        else
                        {
                            // haven't read in some or all of the contents for the response, do so now
                            FlushContents(stream, contentLen - (int)(ms.Length - start));
                        }

                        return(headers, retBuffer, status);
                    }

                    if (gotStatus)
                    {
                        headers.Add(str);
                        continue;
                    }

                    string[] parts = str.Split(' ');
                    if (parts.Length < 2)
                    {
                        throw WebConnection.GetException(WebExceptionStatus.ServerProtocolViolation, null);
                    }

                    if (String.Compare(parts[0], "HTTP/1.1", true) == 0)
                    {
                        ProxyVersion = HttpVersion.Version11;
                    }
                    else if (String.Compare(parts[0], "HTTP/1.0", true) == 0)
                    {
                        ProxyVersion = HttpVersion.Version10;
                    }
                    else
                    {
                        throw WebConnection.GetException(WebExceptionStatus.ServerProtocolViolation, null);
                    }

                    status = (int)UInt32.Parse(parts[1]);
                    if (parts.Length >= 3)
                    {
                        StatusDescription = String.Join(" ", parts, 2, parts.Length - 2);
                    }

                    gotStatus = true;
                }
            }
        }
예제 #38
0
		WebConnection CreateOrReuseConnection (HttpWebRequest request)
		{
			// lock is up there.
			WebConnection cnc;
			WeakReference cncRef;

			int count = connections.Count;
			for (int i = 0; i < count; i++) {
				WeakReference wr = connections [i] as WeakReference;
				cnc = wr.Target as WebConnection;
				if (cnc == null) {
					connections.RemoveAt (i);
					count--;
					i--;
					continue;
				}

				if (cnc.Busy)
					continue;

				PrepareSharingNtlm (cnc, request);
				return cnc;
			}

			if (sPoint.ConnectionLimit > count) {
				cnc = new WebConnection (this, sPoint);
				connections.Add (new WeakReference (cnc));
				return cnc;
			}

			if (rnd == null)
				rnd = new Random ();

			int idx = (count > 1) ? rnd.Next (0, count) : 0;
			cncRef = (WeakReference) connections [idx];
			cnc = cncRef.Target as WebConnection;
			if (cnc == null) {
				cnc = new WebConnection (this, sPoint);
				connections.RemoveAt (idx);
				connections.Add (new WeakReference (cnc));
			}
			return cnc;
		}
예제 #39
0
        public override async Task <int> ReadAsync(byte[] buffer, int offset, int size, CancellationToken cancellationToken)
        {
            WebConnection.Debug($"{ME} READ ASYNC");

            cancellationToken.ThrowIfCancellationRequested();

            if (buffer == null)
            {
                throw new ArgumentNullException(nameof(buffer));
            }

            int length = buffer.Length;

            if (offset < 0 || length < offset)
            {
                throw new ArgumentOutOfRangeException(nameof(offset));
            }
            if (size < 0 || (length - offset) < size)
            {
                throw new ArgumentOutOfRangeException(nameof(size));
            }

            if (Interlocked.CompareExchange(ref nestedRead, 1, 0) != 0)
            {
                throw new InvalidOperationException("Invalid nested call.");
            }

            var myReadTcs = new TaskCompletionSource <int> ();

            while (!cancellationToken.IsCancellationRequested)
            {
                /*
                 * 'readTcs' is set by ReadAllAsync().
                 */
                var oldReadTcs = Interlocked.CompareExchange(ref readTcs, myReadTcs, null);
                WebConnection.Debug($"{ME} READ ASYNC #1: {oldReadTcs != null}");
                if (oldReadTcs == null)
                {
                    break;
                }
                await oldReadTcs.Task.ConfigureAwait(false);
            }

            WebConnection.Debug($"{ME} READ ASYNC #2: {totalRead} {contentLength}");

            int       nbytes  = 0;
            Exception throwMe = null;

            try {
                // FIXME: NetworkStream.ReadAsync() does not support cancellation.
                nbytes = await HttpWebRequest.RunWithTimeout(
                    ct => ProcessRead(buffer, offset, size, ct),
                    ReadTimeout, () => {
                    Operation.Abort();
                    InnerStream.Dispose();
                }).ConfigureAwait(false);
            } catch (Exception e) {
                throwMe = GetReadException(WebExceptionStatus.ReceiveFailure, e, "ReadAsync");
            }

            WebConnection.Debug($"{ME} READ ASYNC #3: {totalRead} {contentLength} - {nbytes} {throwMe?.Message}");

            if (throwMe != null)
            {
                lock (locker) {
                    myReadTcs.TrySetException(throwMe);
                    readTcs    = null;
                    nestedRead = 0;
                }

                closed = true;
                Operation.CompleteResponseRead(false, throwMe);
                throw throwMe;
            }

            lock (locker) {
                readTcs.TrySetResult(nbytes);
                readTcs    = null;
                nestedRead = 0;
            }

            if (totalRead >= contentLength && !nextReadCalled)
            {
                WebConnection.Debug($"{ME} READ ASYNC - READ COMPLETE: {nbytes} - {totalRead} {contentLength} {nextReadCalled}");
                if (!nextReadCalled)
                {
                    nextReadCalled = true;
                    Operation.CompleteResponseRead(true);
                }
            }

            return(nbytes);
        }