/// <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); }
void IExternalMessageHandler.ProcessHeaderLineResponse(LogRequest log) { }
bool IExternalMessageHandler.OverrideResponseFromRequest(LogRequest log, string userName, string userAgent) { return false; }
/// <summary> /// IIS like logging factility /// </summary> /// <param name="proxyIP">The IP of this proxy server</param> /// <param name="request">request specific information</param> void ILogger.LogRequest(string proxyIP, LogRequest request) { if (BabaluConfigurationFactory.Instance.LogRequests) { try { StringBuilder output = new StringBuilder(256); foreach (string field in _fields) { string value = null; switch (field) { case _fieldDate: value = DateTime.Now.ToString("yyyy-MM-dd"); break; case _fieldTime: value = DateTime.Now.ToString("HH:mm:ss"); break; case _fieldServerSitename: value = _siteName; break; case _fieldServerComputername: value = _computerName; break; case _fieldServerIp: value = proxyIP; break; case _fieldCsMethod: value = request.CsMethod; break; case _fieldCsUriStem: value = request.CsUriStem; break; case _fieldCsUriQuery: value = request.CsUriQuery; break; case _fieldServerPort: value = request.ServerPort; break; case _fieldCsUsername: value = request.CsUsername; break; case _fieldClientIp: value = request.ClientIp; break; case _fieldCsVersion: value = request.CsVersion; break; case _fieldCsUserAgent: value = request.CsUserAgent; break; case _fieldScStatus: value = request.ScStatus; break; case _fieldScSubstatus: value = request.ScSubstatus; break; case _fieldDeviceType: value = request.ExternalInfo; break; case _fieldBabaluStatus: value = request.BabaluStatus; break; } if (string.IsNullOrEmpty(value)) value = "-"; output.AppendFormat("{0} ", value.Replace(" ", "")); } _resultsLogQueue.Enqueue(output.ToString()); } catch (Exception excp) { // eat any exception as we do not want to do any harm when logging _me.LogException(excp, "Writting to Request log"); } } }
/// <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(); }
/// <summary> /// log this request /// </summary> /// <param name="proxyIP"></param> /// <param name="request"></param> public static void LogRequest(string proxyIP, LogRequest request) { if (_logger != null) _logger.LogRequest(proxyIP, request); }
/// <summary> /// thread method to handle http request /// </summary> /// <param name="stateInfo">the TcpClient from the listener</param> private void HandleAsyncConnection(object stateInfo) { BabaluCounters.DecrementPendingThread(); // initialize log information class LogRequest log = new LogRequest(); Guid? activity = null; try { // increment the gateway call count activity = BabaluCounters.IncrementAllRequest(); using (TcpClient realClient = stateInfo as TcpClient) { // get client information for logging IPEndPoint localIp = realClient.Client.LocalEndPoint as IPEndPoint; if (localIp != null) log.ServerPort = localIp.Port.ToString(); IPEndPoint remoteIp = realClient.Client.RemoteEndPoint as IPEndPoint; if (remoteIp != null) log.ClientIp = remoteIp.Address.ToString(); // get client stream using (NetworkStream realClientStream = realClient.GetStream()) { // get specific implementation of client stream using (Stream realClientStreamImpl = GetRealClientStream(realClientStream)) { // process the client stream IExternalMessageHandler messageHandler = ExtensionConfig.BabaluExtension.MessageHandler(_proxiedServer.ServerType); ProxyRequestMessage request = new ProxyRequestMessage(messageHandler, _proxiedServer.SupportGZip, realClientStreamImpl, log); if (messageHandler.OverrideResponseFromRequest(log, request.UserName, request.UserAgent)) { realClientStreamImpl.Write(messageHandler.ResponseBuffer, 0, messageHandler.ResponseBuffer.Length); log.ScStatus = messageHandler.ResponseCode; log.ScSubstatus = "0"; } else if (request.HasData && _proxiedServer.ProxiedServers.ContainsKey(request.Host.ToLower())) { Tuple<string, int, bool> proxied = _proxiedServer.ProxiedServers[request.Host.ToLower()]; string proxiedServer = proxied.Item1; int proxiedPort = proxied.Item2; bool proxiedSsl = proxied.Item3; // see if this request is cached on the server byte[] buffer = (_proxiedServer.CacheContent ? RequestCache.GetCache(request.Host, request.RequestUrl) : null); if (buffer != null) { // write out cache result, no need to ask proxied server for data realClientStreamImpl.Write(buffer, 0, buffer.Length); log.ScStatus = "200"; log.ScSubstatus = "0"; LogFactory.LogDebug("Cache hit {0}", request.RequestUrl); log.BabaluStatus = "Cache"; } else { // create a connection to the proxied server and pass client request to that server using (TcpClient proxyClient = new TcpClient(proxiedServer, proxiedPort)) { // change all ip/dns information from proxy server to proxied server byte[] data = request.Tranform(request.Host, proxiedServer); // get proxied client stream using (NetworkStream proxyClientStream = proxyClient.GetStream()) { // get specific implementation of proxied client stream using (Stream proxyClientImpl = GetProxyClientStream(proxyClientStream, proxiedServer, proxiedSsl)) { // Send the message to the connected proxied server proxyClientImpl.Write(data, 0, data.Length); // read the response from the proxied server ProxyResponseMessage response = new ProxyResponseMessage(messageHandler, _proxiedServer.SupportGZip, proxyClientImpl, log); if (response.HasData) { if ( messageHandler.OverrideResponseFromResponse(response, request.UserName)) { realClientStreamImpl.Write(messageHandler.ResponseBuffer, 0, messageHandler.ResponseBuffer.Length); log.ScStatus = messageHandler.ResponseCode; log.ScSubstatus = "0"; LogFactory.LogInformation("Response Overridden from Response: {0} User: {1}", log.ScStatus, request.UserName); } else { // change all ip/dns information from proxied server to proxy server - if provisional and it is a sync command special tranform processing buffer = response.Tranform(proxiedServer, request.Host); // write response back to the original client realClientStreamImpl.Write(buffer, 0, buffer.Length); // add request to server cache if possible if (_proxiedServer.CacheContent) response.ProcessCacheItem(request, buffer); } } else LogFactory.LogDebug("response has no data"); ProxyMessage.RawLog( request, response ); } } } } } else LogFactory.LogDebug("request has no data"); } } } } catch (Exception excp) { LogFactory.LogException(excp, "Processing to Request: {0}", log); log.ScSubstatus = "-1"; BabaluCounters.IncrementException(); } finally { LogFactory.LogRequest(_proxiedServer.ProxyIP, log); BabaluCounters.DecrementAllRequest(activity); } }