/// <summary> /// Send over unix domain sockets /// </summary> /// <param name="udsPath"></param> /// <param name="request"></param> /// <param name="ct"></param> /// <returns></returns> private async Task <HttpResponseMessage> SendOverUnixDomainSocketAsync(string udsPath, HttpRequestMessage request, CancellationToken ct) { if (request == null) { throw new ArgumentNullException(nameof(request)); } if (string.IsNullOrEmpty(udsPath)) { throw new ArgumentNullException(nameof(udsPath)); } using (var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified)) { await socket.ConnectAsync(new UdsEndPoint(udsPath)).ConfigureAwait(false); using (var stream = new HttpLineReader(new NetworkStream(socket, true))) { var requestBytes = GetRequestBuffer(request); await stream.WriteAsync(requestBytes, 0, requestBytes.Length, ct) .ConfigureAwait(false); if (request.Content != null) { await request.Content.CopyToAsync(stream).ConfigureAwait(false); } return(await ReadResponseAsync(stream, ct).ConfigureAwait(false)); } } }
private void NextChunk() { var chunkLengthHex = HttpLineReader.ReadLine(RawStream); if (String.IsNullOrEmpty(chunkLengthHex)) { CurrentChunkLength = 0; CurrentChunkRemaining = 0; } else { CurrentChunkLength = Convert.ToInt64(chunkLengthHex, 16); CurrentChunkRemaining = CurrentChunkLength; } }
static string[] ReadAllLines(string asciiInput) { var inputBytes = Encoding.ASCII.GetBytes(asciiInput); using (var memStream = new MemoryStream(inputBytes)) { memStream.Seek(0, SeekOrigin.Begin); var lines = new List <string>(); string line = null; while ((line = HttpLineReader.ReadLine(memStream)) != null) { lines.Add(line); } return(lines.ToArray()); } }
public override int Read(byte[] buffer, int offset, int length) { if (EndOfDataReached) { return(0); } int totalRead = 0; while (totalRead < length) { if (CurrentChunkRemaining == 0) { if (CurrentChunkLength > 0) { // Read the empty line that follows the previous chunk HttpLineReader.ReadLine(RawStream); } NextChunk(); // Chunk length zero means end of data. if (CurrentChunkLength == 0) { Close(); EndOfDataReached = true; break; } } int maxLength = (int)Math.Min(length - totalRead, CurrentChunkRemaining); int actualLength = RawStream.Read(buffer, offset, maxLength); totalRead += actualLength; offset += actualLength; CurrentChunkRemaining -= actualLength; if (actualLength == 0) { break; } } return(totalRead); }
public static async ValueTask ProcessWorkItemAsync(Socket tcpClient) { Interlocked.Increment(ref _usersCount); Interlocked.Increment(ref _busyThreads); var finalized = false; try { var stream = Ssl ? await AuthenticateSsl(tcpClient) : new NetworkStream(tcpClient); var requestData = await HttpLineReader.ReadLineSizedBuffered(stream, 2048); if (requestData == null || requestData.Length < 10) { return; } var request = HttpRequestParser.ParseRequest(requestData); if (request == null) { return; } using var holder = new HttpClientHolder(stream, tcpClient, (HttpInitialRequest)request); finalized = true; await HttpClientProcessor.ProcessClient(holder, (HttpInitialRequest)request); } catch (Exception e) { ILogManager.Log("Http work pool error.", "Client.Work.Pool", LogType.Error, true, true, e); } finally { if (!finalized) { HttpClientHolder.Close(tcpClient); } Interlocked.Decrement(ref _busyThreads); } }
static async Task<int> GetResponseAsync(StreamSocketStream nstream, WebConnectionData data, ServicePoint sPoint) { var isContinue = false; var emptyFirstLine = false; using (var lineReader = new HttpLineReader(nstream)) { do { if (data.ReadState == ReadState.Aborted) return -1; if (data.ReadState == ReadState.None) { var line = await lineReader.ReadLineAsync(CancellationToken.None).ConfigureAwait(false); if (null == line) { data.ReadState = ReadState.Aborted; return 0; } if (string.IsNullOrEmpty(line)) { emptyFirstLine = true; continue; } emptyFirstLine = false; data.ReadState = ReadState.Status; var parts = line.Split(' '); if (parts.Length < 2) return -1; if (string.Compare(parts[0], "HTTP/1.1", StringComparison.OrdinalIgnoreCase) == 0) { data.Version = HttpVersion.Version11; sPoint.SetVersion(HttpVersion.Version11); } else { data.Version = HttpVersion.Version10; sPoint.SetVersion(HttpVersion.Version10); } data.StatusCode = (int)UInt32.Parse(parts[1]); if (parts.Length >= 3) data.StatusDescription = string.Join(" ", parts, 2, parts.Length - 2); else data.StatusDescription = ""; } emptyFirstLine = false; if (data.ReadState == ReadState.Status) { data.ReadState = ReadState.Headers; data.Headers = new WebHeaderCollection(); var headers = new List<string>(); var finished = false; while (!finished) { var line = await lineReader.ReadLineAsync(CancellationToken.None).ConfigureAwait(false); if (null == line) break; if (string.IsNullOrEmpty(line)) { // Empty line: end of headers finished = true; continue; } if (line.Length > 0 && (line[0] == ' ' || line[0] == '\t')) { var count = headers.Count - 1; if (count < 0) break; var prev = headers[count] + line; headers[count] = prev; } else headers.Add(line); } if (!finished) return 0; lineReader.SyncStream(); foreach (var s in headers) data.Headers.SetInternal(s); if (data.StatusCode == (int)HttpStatusCode.Continue) { sPoint.SendContinue = true; if (data.Request.ExpectContinue) { data.Request.DoContinueDelegate(data.StatusCode, data.Headers); // Prevent double calls when getting the // headers in several packets. data.Request.ExpectContinue = false; } data.ReadState = ReadState.None; isContinue = true; } else { data.ReadState = ReadState.Content; return 1; } } } while (emptyFirstLine || isContinue); } return -1; }
async Task<Tuple<int, WebHeaderCollection>> ReadHeadersAsync(StreamSocketStream stream) { var status = 200; //var ms = new MemoryStream(); var gotStatus = false; using (var lineReader = new HttpLineReader(stream)) { while (true) { //var n = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); //if (n == 0) //{ // HandleError(WebExceptionStatus.ServerProtocolViolation, null, "ReadHeaders"); // return null; //} //ms.Write(buffer, 0, n); //var start = 0; var headers = new WebHeaderCollection(); for (; ; ) { var str = await lineReader.ReadLineAsync(CancellationToken.None).ConfigureAwait(false); if (str == null) { var contentLen = 0L; try { if (!long.TryParse(headers["Content-Length"], out contentLen)) contentLen = 0; } catch { contentLen = 0; } lineReader.SyncStream(); //if (false) //ms.Length - start - contentLen > 0) //{ // // we've read more data than the response header and contents, // // give back extra data to the caller // //retBuffer = new byte[ms.Length - start - contentLen]; // //Buffer.BlockCopy(ms.GetBuffer(), (int) (start + contentLen), retBuffer, 0, retBuffer.Length); //} if (contentLen > 0) { // haven't read in some or all of the contents for the response, do so now await FlushContentsAsync(stream, contentLen).ConfigureAwait(false); } return Tuple.Create(status, headers); } if (gotStatus) { headers.Add(str); continue; } var spaceidx = str.IndexOf(' '); if (spaceidx == -1) { HandleError(WebExceptionStatus.ServerProtocolViolation, null, "ReadHeaders2"); return null; } status = (int)UInt32.Parse(str.Substring(spaceidx + 1, 3)); gotStatus = true; } } } }
/// <summary> /// Deserialize response /// </summary> /// <param name="bufferedStream"></param> /// <param name="ct"></param> /// <returns></returns> private async Task <HttpResponseMessage> ReadResponseAsync( HttpLineReader bufferedStream, CancellationToken ct) { var response = new HttpResponseMessage(); var statusLine = await bufferedStream.ReadLineAsync(ct) .ConfigureAwait(false); if (string.IsNullOrWhiteSpace(statusLine)) { throw new HttpRequestException("Response is empty."); } var statusParts = statusLine.Split(new[] { kSpace }, 3); if (statusParts.Length < 3) { throw new HttpRequestException("Status line is not valid."); } var httpVersion = statusParts[0].Split(new[] { kProtoVersionSep }, 2); if (httpVersion.Length < 2 || !Version.TryParse(httpVersion[1], out var version)) { throw new HttpRequestException( $"Version is not valid {statusParts[0]}."); } response.Version = version; if (!Enum.TryParse(statusParts[1], out HttpStatusCode statusCode)) { throw new HttpRequestException( $"StatusCode is not valid {statusParts[1]}."); } response.StatusCode = statusCode; response.ReasonPhrase = statusParts[2]; // parse headers var headers = new List <string>(); var line = await bufferedStream.ReadLineAsync(ct) .ConfigureAwait(false); while (!string.IsNullOrWhiteSpace(line)) { headers.Add(line); line = await bufferedStream.ReadLineAsync(ct) .ConfigureAwait(false); } response.Content = new StreamContent(bufferedStream); foreach (var header in headers) { if (string.IsNullOrWhiteSpace(header)) { // headers end break; } var headerSeparatorPosition = header.IndexOf(kHeaderSeparator); if (headerSeparatorPosition <= 0) { throw new HttpRequestException($"Header is invalid {header}."); } var name = header.Substring(0, headerSeparatorPosition).Trim(); var value = header.Substring(headerSeparatorPosition + 1).Trim(); var wasAdded = response.Headers.TryAddWithoutValidation(name, value); if (!wasAdded) { if (name.EqualsIgnoreCase(kContentLength)) { if (!long.TryParse(value, out var length)) { throw new HttpRequestException( $"Header value is invalid for {name}."); } await response.Content.LoadIntoBufferAsync(length) .ConfigureAwait(false); } response.Content.Headers.TryAddWithoutValidation(name, value); } } return(response); }