private HttpResponse ReadResponse(Stream responseStream) { var headers = new HttpHeaders(); char currentChar; int streamPosition = 0; // https://tools.ietf.org/html/rfc2616#section-4.2 // HTTP/1.1 200 OK // HTTP/1.1 XXX MESSAGE const int statusCodeStart = 9; const int statusCodeEnd = 12; const int startOfReasonPhrase = 13; // TODO: Get this from StringBuilderCache after we determine safe maximum capacity var stringBuilder = new StringBuilder(); var chArray = new byte[1]; void GoNextChar() { streamPosition++; chArray[0] = (byte)responseStream.ReadByte(); currentChar = Encoding.ASCII.GetChars(chArray)[0]; } bool IsNewLine() { if (currentChar.Equals(DatadogHttpValues.CarriageReturn)) { // end of headers if (DatadogHttpValues.CrLfLength > 1) { // Skip the newline indicator GoNextChar(); } return(true); } return(false); } // Skip to status code while (streamPosition < statusCodeStart) { GoNextChar(); } // Read status code while (streamPosition < statusCodeEnd) { GoNextChar(); stringBuilder.Append(currentChar); } var potentialStatusCode = stringBuilder.ToString(); stringBuilder.Clear(); if (!int.TryParse(potentialStatusCode, out var statusCode)) { throw new DatadogHttpRequestException("Invalid response, can't parse status code. Line was:" + potentialStatusCode); } // Skip to reason while (streamPosition < startOfReasonPhrase) { GoNextChar(); } // Read reason do { GoNextChar(); if (IsNewLine()) { break; } stringBuilder.Append(currentChar); }while (true); var reasonPhrase = stringBuilder.ToString(); stringBuilder.Clear(); // Read headers do { GoNextChar(); // Check for end of headers if (IsNewLine()) { // Empty line, content starts next break; } // Read key do { if (currentChar.Equals(':')) { // Value portion starts break; } stringBuilder.Append(currentChar); GoNextChar(); }while (true); var name = stringBuilder.ToString().Trim(); stringBuilder.Clear(); // Read value do { GoNextChar(); if (IsNewLine()) { // Next header pair starts break; } stringBuilder.Append(currentChar); }while (true); var value = stringBuilder.ToString().Trim(); stringBuilder.Clear(); headers.Add(name, value); }while (true); var length = long.TryParse(headers.GetValue(ContentLengthHeaderKey), out var headerValue) ? headerValue : (long?)null; return(new HttpResponse(statusCode, reasonPhrase, headers, new StreamContent(responseStream, length))); }