/// <summary> /// contructor processes the HTTP response data /// </summary> /// <param name="messageHandler">external message handler</param> /// <param name="supportsGZip">are we supporting GZip compression</param> /// <param name="input"></param> /// <param name="log"></param> public ProxyResponseMessage(IExternalMessageHandler messageHandler, bool supportsGZip, Stream input, LogRequest log) : base(messageHandler, supportsGZip, input, log, false) { if (FirstHeaderLine != null) { // parse the status result for the response string[] parts = FirstHeaderLine.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length > 1) { log.ScStatus = parts[1]; log.ScSubstatus = "0"; messageHandler.ProcessHeaderLineResponse(log); int status; if ( int.TryParse(log.ScStatus, out status) == false && log.ScStatus.StartsWith("html", StringComparison.InvariantCultureIgnoreCase) ) log.ScStatus = "200"; } else { // default to a 200 "Success" status log.ScStatus = "200"; log.ScSubstatus = "0"; } } }
/// <summary> /// contructor processes the HTTP request data /// </summary> /// <param name="messageHandler">external message handler</param> /// <param name="supportsGZip">are we supporting GZip compression</param> /// <param name="input"></param> /// <param name="log"></param> public ProxyRequestMessage(IExternalMessageHandler messageHandler, bool supportsGZip, Stream input, LogRequest log) : base(messageHandler, supportsGZip, input, log, true) { if (FirstHeaderLine != null) { // parse the first line to get header information string[] parts = FirstHeaderLine.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length > 0) { // method is the first token log.CsMethod = parts[0]; if (parts.Length > 1) { // parse the query string int index = parts[1].IndexOf('?'); if (index == -1) log.CsUriStem = parts[1]; else { log.CsUriStem = parts[1].Substring(0, index); log.CsUriQuery = parts[1].Substring(index + 1); } messageHandler.ProcessHeaderLineRequest(log); // get the HTTP version if available if (parts.Length > 2) log.CsVersion = parts[2]; } } if (Authorization != null) { // get header authorization infromation int index = Authorization.IndexOf(_basicAuthorization); if (index == 0) { // if basic authentication, get un/domain log.CsUsername = ProcessUserNameAndPassword( Authorization.Substring(index + _basicAuthorization.Length), true, log.CsUsername); } } } // must happen before settings code code below as it depends on username UserName = log.CsUsername; messageHandler.ProcessRequest(this, UserName); }
/// <summary> /// socket input from client or server to process /// </summary> /// <param name="messageHandler">external message handler</param> /// <param name="supportsGZip">are we supporting GZip compression</param> /// <param name="input">the client for server HTTP stream</param> /// <param name="log">request log structure</param> /// <param name="checkPreHttp">is this the request and a pre http 1.1 request</param> protected ProxyMessage(IExternalMessageHandler messageHandler, bool supportsGZip, Stream input, LogRequest log, bool checkPreHttp) { _messageHandler = messageHandler; _supportsGZip = supportsGZip; _rawRead = new byte[BufferSize]; _header = new List<byte>(BufferSize); _content = new List<byte>(BufferSize); int bytes = 0; bool headerDone = false; bool contentDone = false; int contentLength = 0; // loop until we have read al the input (no bytes returned, header end character or content length reached) do { bytes = input.Read(_rawRead, 0, BufferSize); if (bytes != 0) { if (headerDone == false) { // add all bytes read to the header _header.AddRange(_rawRead.Take(bytes)); // parse the header information HeaderPositions match = ParseHeader(); // if we read the entire HTTP header process it if (match.HeaderEnd != -1) { // find the end of the list line _firstHeaderLineEnd = match.FirstLineEnd; // add any content we may have read into the content buffer based on the header end characters _content.AddRange(_header.Skip(match.HeaderEnd)); // trim the header of any content information _header.RemoveRange(match.HeaderEnd, _header.Count - match.HeaderEnd); headerDone = true; // if the header did not contain a content length tag, content is done if (match.ContentLength == -1) contentDone = true; else { // get the "real" content length from the header int pos = match.ContentLength; while (_header[pos] != '\r') { char c = (char)_header[pos]; if (char.IsNumber(c)) contentLength = ((contentLength * 10) + (c - '0')); ++pos; } // see if we have alread read in all the content if (contentLength == 0 || _content.Count == contentLength) contentDone = true; } // get misc. header values _contentType = ParseHeaderValue(match.ContentType); _contentEncoding = ParseHeaderValue(match.ContentEncoding); _cacheControl = ParseHeaderValue(match.CacheControl); string transferEncoding = ParseHeaderValue(match.TransferEncoding); if (transferEncoding != null && transferEncoding.IndexOf(_transferEncodingChunkedToken, StringComparison.InvariantCultureIgnoreCase) != -1) { _transferEncodingChunked = true; contentDone = ReadChunkedContent(); } if (match.Host != -1) Host = ParseHeaderValue(match.Host, ':'); // have logging values if (match.UserAgent != -1) UserAgent = log.CsUserAgent = ParseHeaderValue(match.UserAgent); if (match.Authorization != -1) Authorization = ParseHeaderValue(match.Authorization); } else if ( match.FirstLineEnd != -1 && checkPreHttp ) { // check pre http 1.1 headers string []parts = Encoding.UTF8.GetString(_header.ToArray()).Split( new char[] { ' ', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries ); if (parts.Length == 2 && string.Compare(parts[0], "GET", true) == 0) { headerDone = true; contentDone = true; } } } else { // if the header is complete, read the content (if specified in Content-Length) _content.AddRange(_rawRead.Take(bytes)); if (_transferEncodingChunked) contentDone = ReadChunkedContent(); else contentDone = (_content.Count == contentLength); } } } while (bytes != 0 && (headerDone == false || contentDone == false)); if (_transferEncodingChunked) DeChunkData(); LogHeaderContent(); }