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; } }
public void OpenTest() { var webServer = new WebServer("http://mss.alkotorg.com"); string username = "******"; string password = "******"; var target = new WebConnection(webServer, username, password); target.Open(); }
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); }
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."); }
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); }
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; } }
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"); } }
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); }
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); }
void Debug(string message) { WebConnection.Debug($"SPS({ID}): {message}"); }
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); }
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); }
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); }
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); } }
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); }
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; } }
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); }
void Debug(string message, params object[] args) { WebConnection.Debug($"SPS({ID}): {string.Format (message, args)}"); }
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; } }
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); }
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; } }
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; }
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); }
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); }
public ConnectionState(WebConnectionGroup group) { Group = group; idleSince = DateTime.UtcNow; Connection = new WebConnection(this, group.sPoint); }
public ConnectionState (WebConnectionGroup group) { Group = group; idleSince = DateTime.UtcNow; Connection = new WebConnection (this, group.sPoint); }
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); } }
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; }
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 (); } }
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; } } }
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; }
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); }