private ProxyToken HandleOtherRequest(HttpRequestHeader header, DataAdapterToStream stm, TcpClientDataAdapter tcpAdapter) { string host = null; foreach (KeyDataPair<string> pair in header.Headers) { if (pair.Name.Equals("host", StringComparison.OrdinalIgnoreCase)) { host = pair.Value; } } Uri url = GetUri(host, tcpAdapter); if (url != null) { // Use generic token so filters don't get used IpProxyToken ret = new IpProxyToken(null, url.Host, url.Port, IpProxyToken.IpClientType.Tcp, false); if(_config.SslConfig.Enabled) { ret.Layers = new INetworkLayer[1]; ret.Layers[0] = new SslNetworkLayer(new SslNetworkLayerConfig(false, true) { Enabled = true }); } ret.State.Add("url", url); ret.State.Add("stm", stm); ret.State.Add("header", header); return ret; } else { _logger.LogError(CANAPE.Net.Properties.Resources.HttpProxyServer_InvalidUrl, header.Path); ReturnResponse(null, 400, "Bad Request", header.Method, header.Version, stm); return null; } }
private void ReturnResponse(HttpRequestHeader request, int responseCode, string message, string method, HttpVersion version, DataAdapterToStream stm) { ReturnResponse(request, responseCode, message, method, version, new KeyDataPair<string>[0], stm); }
internal HttpRequestDataChunk(HttpRequestHeader header) : base(header.Headers, header.Version) { Method = header.Method; Path = header.Path; }
private void FlushRequest(HttpRequestHeader request) { if (!request.IsConnect) { HttpParserConfig config = new HttpParserConfig(); config.StreamBody = true; IEnumerator<HttpRequestDataChunk> e = request.ReadChunks(config).GetEnumerator(); while (e.MoveNext()) { } } }
/// <summary> /// /// </summary> /// <param name="request"></param> /// <param name="response"></param> /// <returns></returns> public bool IsMatch(HttpRequestHeader request, HttpResponseHeader response) { if (IsMatch(request)) { foreach (KeyDataPair<string> pair in response.Headers) { if(pair.Name.Equals("Content-Type", StringComparison.OrdinalIgnoreCase)) { return ContentTypeMatch.IsMatch(pair.Value); } } } return false; }
private HttpParserConfig CreateConfig(HttpRequestHeader header) { HttpParserConfig config = new HttpParserConfig(); HttpLayerConfigEntry entry = _layer._config.GetEntry(header); config.StreamBody = entry.RequestStreamBody; config.StreamChunkSize = _layer._config.RequestStreamChunkSize; config.StrictParsing = _layer._config.RequestStrictParsing; if (_layer._config.BufferedRequestMaxLength != 0 && (header.ContentLength > _layer._config.BufferedRequestMaxLength)) { config.StreamBody = true; } return config; }
public HttpProxyServerAdapter(FullHttpProxyServer server, DataAdapterToStream stm, HttpRequestHeader initialRequest, Logger logger) { _server = server; _stm = stm; _writer = new DataWriter(_stm); _request = initialRequest; ProcessProxyRequestHeaders(_request); _config = new HttpParserConfig(); _config.StreamBody = true; _logger = logger; _requestQueue = new Queue<HttpRequestHeader>(); _requestQueue.Enqueue(_request); Description = stm.Description; }
public override DataFrame Read() { try { if (_request == null) { _request = HttpParser.ReadRequestHeader(new DataReader(_stm), false, _logger); } if (_chunks == null) { _chunks = _request.ReadChunks(_config).GetEnumerator(); // If we can't move to the first chunk (headers) there is a serious issue if (!_chunks.MoveNext()) { throw new EndOfStreamException(); } } HttpRequestDataChunk chunk = _chunks.Current; if (!_chunks.MoveNext()) { _request = null; _chunks = null; } MemoryStream stm = new MemoryStream(); DataWriter writer = new DataWriter(stm); chunk.WriteChunk(writer); return new DataFrame(stm.ToArray()); } catch (EndOfStreamException) { return null; } }
private bool MustCloseConnection(HttpRequestHeader request) { return request.Version.IsVersion10 || request.Version.IsVersionUnknown || _config.Version10Proxy || request.Headers.HasHeader("Connection", "close") || request.Headers.HasHeader("Proxy-Connection", "close"); }
private bool ProcessProxyAuth(HttpRequestHeader request) { bool ret = false; if (_config.RequireAuth) { if (request.Headers.HasHeader("Proxy-Authorization")) { string[] values = request.Headers.GetHeaderValues("Proxy-Authorization").First().Split(new char[] { ' ' }, 2); if (values.Length == 2) { if (values[0].Equals("Basic", StringComparison.OrdinalIgnoreCase)) { try { string data = BinaryEncoding.Instance.GetString(Convert.FromBase64String(values[1])); string[] vs = data.Split(new char[] { ':' }, 2); if ((vs.Length == 0) || (String.IsNullOrWhiteSpace(vs[0]))) { _logger.LogError(Properties.Resources.FullHttpProxyServer_InvalidUsernamePasswordString); } else { // Username case-insensitive, password case sensitive ret = vs[0].Equals(_config.ProxyUsername, StringComparison.OrdinalIgnoreCase) && _config.ProxyPassword.Equals(vs.Length > 1 ? vs[1] : String.Empty); } } catch (FormatException) { _logger.LogError(Properties.Resources.FullHttpProxyServer_InvalidBase64Auth); } } else { _logger.LogError(Properties.Resources.FullHttpProxyServer_OnlySupportBasicAuth); } } else { _logger.LogError(Properties.Resources.FullHttpProxyServer_InvalidAuthLine); } } } else { ret = true; } return ret; }
private bool HandleProxyAuthentication(DataReader reader, DataAdapterToStream stm, ref HttpRequestHeader request) { if (_config.RequireAuth) { bool auth = ProcessProxyAuth(request); if (!auth) { ReturnResponse(request, 407, "Proxy Authentication Required", request.Method, request.Version, new KeyDataPair<string>[] { new KeyDataPair<string>("Proxy-Authenticate", String.Format("Basic realm=\"{0}\"", _config.AuthRealm ?? "canape.local")) }, stm); if (!MustCloseConnection(request)) { // If version 1.1 server we can assume connection will probably stay up so re-read request // Only give it one chance to get it right though request = HttpParser.ReadRequestHeader(reader, false, _logger); auth = ProcessProxyAuth(request); } } return auth; } else { return true; } }
private ProxyToken HandleOtherRequest(HttpRequestHeader header, DataAdapterToStream stm, ProxyNetworkService service) { Uri url; if (Uri.TryCreate(header.Path, UriKind.Absolute, out url)) { // Use generic token so filters don't get used ProxyToken ret = new ProxyToken(); ret.State.Add("url", url); ret.State.Add("stm", stm); ret.State.Add("header", header); ret.Client = new HttpProxyDummyClient(this, service); ret.Graph = _factory; return ret; } else { _logger.LogError(CANAPE.Net.Properties.Resources.HttpProxyServer_InvalidUrl, header.Path); // TODO: Put in some decent error codes ReturnResponse(null, 400, "Bad Request", header.Method, header.Version, stm); return null; } }
private IpProxyToken HandleConnect(HttpRequestHeader header, DataAdapterToStream stm) { string hostName = null; int port = 80; string[] connectHeader = header.Path.Split(':'); IpProxyToken ret = null; if (connectHeader.Length > 0) { hostName = connectHeader[0]; if (connectHeader.Length > 1) { if (!int.TryParse(connectHeader[1], out port)) { _logger.LogError(CANAPE.Net.Properties.Resources.HttpProxyServer_InvalidConnect, connectHeader[1]); port = 0; } } if (port > 0) { ret = new IpProxyToken(null, hostName, port, IpProxyToken.IpClientType.Tcp, false); ret.State.Add("stm", stm); ret.State.Add("header", header); } else { ReturnResponse(null, 400, "Bad Request", header.Method, header.Version, stm); } } return ret; }
private void ReturnResponse(HttpRequestHeader request, int responseCode, string message, string method, HttpVersion version, IEnumerable<KeyDataPair<string>> sendHeaders, DataAdapterToStream stm) { if (request != null) { FlushRequest(request); } HttpResponseDataChunk response = new HttpResponseDataChunk(); if (_config.Version10Proxy && !version.IsVersionUnknown) { response.Version = HttpVersion.Version10; } else { response.Version = version; } response.ResponseCode = responseCode; response.Message = message; response.FinalChunk = true; response.Body = new byte[0]; List<KeyDataPair<string>> headers = new List<KeyDataPair<string>>(sendHeaders); headers.Add(new KeyDataPair<string>("X-Proxy-Server", "CANAPE")); if (response.Body.Length > 0) { headers.Add(new KeyDataPair<string>("Content-Type", "text/html")); } response.Headers = headers.ToArray(); if (method.Equals("HEAD", StringComparison.OrdinalIgnoreCase)) { response.HeadResponse = true; } else if (method.Equals("CONNECT", StringComparison.OrdinalIgnoreCase)) { response.ConnectResponse = true; } response.WriteChunk(new DataWriter(stm)); }
public override DataFrame Read() { try { if(_request == null) { _request = HttpParser.ReadRequestHeader(new DataReader(_stm), false, _logger); lock (_requestQueue) { _requestQueue.Enqueue(_request); } ProcessProxyRequestHeaders(_request); } if (_chunks == null) { _chunks = _request.ReadChunks(_config).GetEnumerator(); // If we can't move to the first chunk (headers) there is a serious issue if (!_chunks.MoveNext()) { throw new EndOfStreamException(); } } HttpRequestDataChunk chunk = _chunks.Current; if (!_chunks.MoveNext()) { _request = null; _chunks = null; } DataKey root = new DataKey("Root"); root.AddValue(new DynamicDataValue(DATA_NAME, chunk)); return new DataFrame(root); } catch (EndOfStreamException) { return null; } }
public HttpProxyServerAdapter(DataAdapterToStream stm, HttpRequestHeader initialRequest, Logger logger) { _stm = stm; _writer = new DataWriter(_stm); _request = initialRequest; _config = new HttpParserConfig(); _config.StreamBody = true; _logger = logger; Description = stm.Description; }
private void ProcessProxyRequestHeaders(HttpRequestHeader request) { int i = 0; // If we have a request for a client version which will close then ensure the job is done if (request.Version.IsVersionUnknown || request.Version.IsVersion10 || _server._config.Version10Proxy) { _closeConnection = true; } while(i < request.Headers.Count) { KeyDataPair<string> pair = request.Headers[i]; // Just remove, we already have handled this if (pair.Name.Equals("Proxy-Authorization", StringComparison.OrdinalIgnoreCase)) { request.Headers.RemoveAt(i); } else if (pair.Name.Equals("Connection", StringComparison.OrdinalIgnoreCase) || pair.Name.Equals("Proxy-Connection", StringComparison.OrdinalIgnoreCase)) { // If sender wants the connection close then signal it for next response if (pair.Value.Equals("close", StringComparison.OrdinalIgnoreCase)) { _closeConnection = true; } request.Headers.RemoveAt(i); } else { ++i; } } }
/// <summary> /// Does this entry match the request /// </summary> /// <param name="request">The request</param> /// <returns>True if it matches</returns> public bool IsMatch(HttpRequestHeader request) { bool ret = true; if (request != null) { if (!PathMatch.IsMatch(request.Path)) { ret = false; } if (MethodMatch.IsMatch(request.Method)) { ret = false; } } return ret; }
/// <summary> /// /// </summary> /// <param name="request"></param> /// <returns></returns> public HttpLayerConfigEntry GetEntry(HttpRequestHeader request) { return GetEntry(e => e.IsMatch(request)); }
public override DataFrame Read() { DataFrame frame = null; try { if (_chunks == null || !_chunks.MoveNext()) { char firstChar = _reader.ReadChar(); // Check whether we need to upgrade the connection to raw data, could even at this point actually implement // TLS upgrade (and put back the HTTP parser on top?) if (_isTransparent) { // If transparent send the first chunk along and don't increment enumerator _chunks = BaseHttpDataAdapter.ReadFrames(new DataFrame(new byte[] { (byte)firstChar }), _reader).GetEnumerator(); } else { _currentHeader = HttpParser.ReadRequestHeader(_reader, _layer._config.RequestStrictParsing, _logger, new char[] { firstChar }); if (_currentHeader.Version.IsVersion11 && _layer._config.Handle100Continue) { bool sendResponse = false; int i = 0; while(i < _currentHeader.Headers.Count) { KeyDataPair<string> header = _currentHeader.Headers[i]; // Remove expect headers if (header.Name.Equals("Expect", StringComparison.OrdinalIgnoreCase) && header.Value.Equals("100-continue", StringComparison.OrdinalIgnoreCase)) { _currentHeader.Headers.RemoveAt(i); sendResponse = true; } else { i++; } } if (sendResponse) { _adapter.Write(new DataFrame("HTTP/1.1 100 Continue\r\n\r\n")); } } _chunks = _currentHeader.ReadFrames(CreateConfig(_currentHeader)).GetEnumerator(); } // Increment to next chunk if (!_chunks.MoveNext()) { throw new EndOfStreamException(); } } frame = _chunks.Current; } catch(EndOfStreamException) { frame = null; } return frame; }
/// <summary> /// /// </summary> /// <param name="request"></param> /// <param name="response"></param> /// <returns></returns> public HttpLayerConfigEntry GetEntry(HttpRequestHeader request, HttpResponseHeader response) { return GetEntry(e => e.IsMatch(request, response)); }
private HttpParserConfig CreateConfig(HttpResponseHeader response, HttpRequestHeader request) { HttpParserConfig config = new HttpParserConfig(); HttpLayerConfigEntry entry = _layer._config.GetEntry(request, response); config.ConvertToChunked = entry.ConvertToChunked; config.StreamBody = entry.ResponseStreamBody; config.StreamChunkSize = _layer._config.ResponseStreamChunkSize; config.StrictParsing = _layer._config.ResponseStrictParsing; if (_layer._config.BufferedResponseMaxLength != 0 && (response.ContentLength > _layer._config.BufferedResponseMaxLength)) { config.StreamBody = true; } return config; }