/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public void Pass(ProxyResponse response) { response.pass_ = true; if (response.completable_ && !response.skipRemainingHandlers_ && (PostResponse != null)) { PostResponse(response.request_, response); } if (response.pass_) { if (response.completable_ && (response.outbound_ != null)) { response.outbound_.Complete(response); } response.request_.encoding_ = null; response.request_.inbound_ = null; response.encoding_ = null; response.outbound_ = null; } else { Drop(response); } }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// internal void OnResponse(ProxyResponse response) { if ((response.request_ != null) && (response.request_.Header != null)) { notifyQueueMutex_.WaitOne(); notifyQueue_.Enqueue(response); threadNotifyEvent_.Set(); notifyQueueMutex_.ReleaseMutex(); } }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// internal void Complete(ProxyResponse response) { if (response.Completable && (response.header_ != null)) { string header = response.header_; string contents = response.contents_; byte[] headerBytes = null; byte[] contentsBytes = new byte[0]; if (contents != null) { contentsBytes = response.encoding_.GetBytes(contents); header += "\r\nContent-Length: " + Convert.ToString(contentsBytes.Length) + "\r\n\r\n"; headerBytes = wwwProxy_.defaultEncoding_.GetBytes(header); } wwwProxy_.log_.Write("Outbound.Complete()", header + ((contents != null) ? contents : "")); byte[] responseBytes = new byte[headerBytes.Length + contentsBytes.Length]; Array.Copy(headerBytes, 0, responseBytes, 0, headerBytes.Length); Array.Copy(contentsBytes, 0, responseBytes, headerBytes.Length, contentsBytes.Length); inbound_.StopKeepAliveTimer(); try { inbound_.Send(responseBytes, 0, responseBytes.Length); } catch (IOException) { } catch (ObjectDisposedException) { } catch (SocketException) { } } if (responseCloseInbound_) { inbound_.Close(); } if (completableResponse_) { completableResponse_ = false; responseCloseInbound_ = false; } response_ = null; }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public void Drop(ProxyResponse response) { response.pass_ = false; response.skipRemainingHandlers_ = true; if (response.outbound_ != null) { if (response.outbound_.inbound_ != null) { response.outbound_.inbound_.Close(); } response.outbound_.Close(); } response.request_.encoding_ = null; response.request_.inbound_ = null; response.encoding_ = null; response.outbound_ = null; }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static void WwwProxy_Response(IPEndPoint ipEndPoint, WwwProxy.ProxyRequest request, WwwProxy.ProxyResponse response) { try { pythonMutex_.WaitOne(); object[] args = new object[2]; args[0] = request; args[1] = response; object rtnValue = Ops.Invoke(wwwPyFilterClassObject_, SymbolTable.StringToId("response_filter"), args); if (rtnValue is bool) { if (!response.Completable || (bool)rtnValue) { wwwProxy_.Pass(response); } else { wwwProxy_.Drop(response); } } else { Console.WriteLine("WwwProxy_Response Warning: response_filter returned non-bool"); wwwProxy_.Pass(response); } } catch (Exception e) { Console.WriteLine("Error: {0}", e.Message); Console.WriteLine(); Console.WriteLine(e.StackTrace); } finally { pythonMutex_.ReleaseMutex(); } }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private void RunNotifier() { WaitHandle[] waitHandles = new WaitHandle[2]; waitHandles[0] = threadExitEvent_; waitHandles[1] = threadNotifyEvent_; while (!threadExitEvent_.WaitOne(0, false)) { object notifyObject = null; if (WaitHandle.WaitAny(waitHandles, Timeout.Infinite, false) == 0) { break; } notifyQueueMutex_.WaitOne(); if (notifyQueue_.Count > 0) { notifyObject = notifyQueue_.Dequeue(); } else { threadNotifyEvent_.Reset(); } notifyQueueMutex_.ReleaseMutex(); if (notifyObject != null) { if (notifyObject is ProxyRequest) { ProxyRequest notifyRequest = (ProxyRequest)notifyObject; notifyRequest.pass_ = true; notifyRequest.skipRemainingHandlers_ = false; if (PreRequest != null) { PreRequest(notifyRequest); } if (!notifyRequest.skipRemainingHandlers_ && (Request != null)) { Request(notifyRequest); } else if (notifyRequest.pass_) { Pass(notifyRequest); } else { Drop(notifyRequest); } } else if (notifyObject is ProxyResponse) { ProxyResponse notifyResponse = (ProxyResponse)notifyObject; notifyResponse.pass_ = true; notifyResponse.skipRemainingHandlers_ = notifyResponse.request_.skipRemainingHandlers_; if (notifyResponse.completable_ && !notifyResponse.skipRemainingHandlers_ && (PreResponse != null)) { PreResponse(notifyResponse.request_, notifyResponse); } if (!notifyResponse.skipRemainingHandlers_ && (Response != null)) { Response(notifyResponse.request_, notifyResponse); } else if (notifyResponse.pass_) { Pass(notifyResponse); } else { Drop(notifyResponse); } } } } }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private void RunSocket() { byte[] receiveBuffer = new byte[4096]; int receiveBufferCount = 0; ushort outboundConnectionAttempt = 0; while (!outboundThreadExitEvent_.WaitOne(0, false)) { try { if (outboundSocket_ == null) { if (++outboundConnectionAttempt <= 5) { try { outboundSocket_ = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); outboundSocket_.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, new LingerOption(true, 1)); outboundSocket_.Connect(outboundIpEndPoint_); } catch (Exception) { break; } if (outboundSocket_.Connected) { outboundConnectionAttempt = 0xFFFF; } else { Thread.Sleep(1000); } } else { wwwProxy_.OnError(inbound_, request_, null, "Connection Failed [" + outboundIpEndPoint_.Address.ToString() + ":" + outboundIpEndPoint_.Port + "]"); break; } } else { if ((receiveBuffer.Length - receiveBufferCount) < 4096) { int newReceiveBufferLength = receiveBuffer.Length; while ((newReceiveBufferLength - receiveBufferCount) < 4096) { newReceiveBufferLength *= 2; } byte[] newReceiveBuffer = new byte[newReceiveBufferLength]; Array.Copy(receiveBuffer, 0, newReceiveBuffer, 0, receiveBuffer.Length); receiveBuffer = newReceiveBuffer; } if (ssl_) { if (useRemoteProxy_ && !sslProxyNegotiationSent_) { string sslProxyNegotiation = "CONNECT " + host_ + ":" + port_ + " HTTP/1.0\r\n\r\n"; byte[] sslProxyNegotationBytes = wwwProxy_.defaultEncoding_.GetBytes(sslProxyNegotiation); outboundSocket_.Send(sslProxyNegotationBytes, 0, sslProxyNegotationBytes.Length, SocketFlags.None); sslProxyNegotiationSent_ = true; while ((receiveBuffer.Length - receiveBufferCount) > 0) { int bytesReceived = outboundSocket_.Receive(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None); receiveBufferCount += bytesReceived; bool bHeaderEnd = false; for (int i = 0; i < receiveBufferCount - 3; ++i) { if ((receiveBuffer[i] == '\r') && (receiveBuffer[i + 1] == '\n') && (receiveBuffer[i + 2] == '\r') && (receiveBuffer[i + 3] == '\n')) { bHeaderEnd = true; receiveBufferCount -= (i + 4); break; } } if (bHeaderEnd) { break; } } if (receiveBufferCount == receiveBuffer.Length) { break; } } if ((sslNetworkStream_ == null) || (sslStream_ == null)) { sslNetworkStream_ = new NetworkStream(outboundSocket_); sslStream_ = new SslStream(sslNetworkStream_, false, new RemoteCertificateValidationCallback(OnRemoteCertificateValidation)); sslStream_.AuthenticateAsClient(outboundIpEndPoint_.Address.ToString(), wwwProxy_.clientCertificates_, SslProtocols.Default, false); } } if (outboundSocket_.Connected) { if ((request_ != null) && !request_.sent_) { Send(request_); } int bytesReceived = Receive(receiveBuffer, receiveBufferCount, receiveBuffer.Length - receiveBufferCount); receiveBufferCount += bytesReceived; if (receiveBufferCount > 0) { while (receiveBufferCount > 0) { int bytesParsed = 0; if ((bytesRequired_ == 0) || ((bytesRequired_ -= bytesReceived) <= 0)) { bytesRequired_ = 0; if (processResponse_) { bytesParsed = OnResponse(receiveBuffer, receiveBufferCount, (bytesReceived == 0)); } else { inbound_.Send(receiveBuffer, 0, receiveBufferCount); bytesParsed = bytesReceived; } } if (bytesParsed > 0) { for (int i = 0; i < receiveBuffer.Length - bytesParsed; ++i) { receiveBuffer[i] = receiveBuffer[bytesParsed + i]; } receiveBufferCount -= bytesParsed; } else { break; } } if (bytesReceived == 0) { break; } } else { break; } } else { break; } } } catch (Exception e) { wwwProxy_.OnError(inbound_, null, e, e.Message); } } if (outboundSocket_ != null) { if (outboundSocket_.Connected) { outboundSocket_.Shutdown(SocketShutdown.Both); outboundSocket_.Disconnect(false); } outboundSocket_.Close(); } if (outboundThreadExitEvent_ != null) { outboundThreadExitEvent_.Close(); } if (outboundSocketReceiveEvent_ != null) { outboundSocketReceiveEvent_.Close(); } if (sslNetworkStreamReceiveEvent_ != null) { sslNetworkStreamReceiveEvent_.Close(); } if (sslNetworkStream_ != null) { sslNetworkStream_.Close(); } if (sslStream_ != null) { sslStream_.Close(); } inbound_.OnDisconnect(this); if (!completableResponse_) { response_ = null; if (responseCloseInbound_) { inbound_.Close(); } } if (outboundThread_ != null) { outboundThread_ = null; } }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private int OnResponse(byte[] receiveBuffer, int bytesReceived, bool bConnectionClosed) { string proxyResponse = wwwProxy_.defaultEncoding_.GetString(receiveBuffer, 0, bytesReceived); int processedResponseBytes = 0; wwwProxy_.log_.Write("Outbound.OnResponse()", proxyResponse); string header = null; string contents = null; byte[] contentsBytes = null; string defaultCharset = "iso-8859-1"; string charset = defaultCharset; Match httpResponseMatch = Regex.Match(proxyResponse, "^HTTP/\\d\\.\\d\\s+(\\d+)\\s+", RegexOptions.IgnoreCase); if (httpResponseMatch.Success) { ushort httpResponseCode = Convert.ToUInt16(httpResponseMatch.Groups[1].Value); if ((httpResponseCode >= 100) && (httpResponseCode <= 199)) { inbound_.StopKeepAliveTimer(); inbound_.Send(receiveBuffer, 0, bytesReceived); processedResponseBytes = bytesReceived; } else { int contentsIndex = 0; for (int i = 0; i < (proxyResponse.Length - 3); ++i) { if ((receiveBuffer[i] == '\r') && (receiveBuffer[i + 1] == '\n') && (receiveBuffer[i + 2] == '\r') && (receiveBuffer[i + 3] == '\n')) { contentsIndex = i + 4; header = wwwProxy_.defaultEncoding_.GetString(receiveBuffer, 0, i); contentsBytes = new byte[bytesReceived - (contentsIndex)]; Array.Copy(receiveBuffer, contentsIndex, contentsBytes, 0, bytesReceived - (contentsIndex)); break; } } if (header != null) { Match connectionCloseMatch = Regex.Match(header, "^(Proxy-)*(Connection)+:\\s+close", RegexOptions.IgnoreCase | RegexOptions.Multiline); Match contentEncodingTypeMatch = Regex.Match(header, "^Content-Type:\\s+\\S+?\\s*;\\s*charset=(\\S+)?", RegexOptions.IgnoreCase | RegexOptions.Multiline); Match contentLengthMatch = Regex.Match(header, "^Content-Length:\\s+(\\d+)[\r\n]*", RegexOptions.IgnoreCase | RegexOptions.Multiline); Match contentTextTypeMatch = Regex.Match(header, "^Content-Type:\\s+text|application/x-javascript", RegexOptions.IgnoreCase | RegexOptions.Multiline); Match transferEncodingMatch = Regex.Match(header, "^Transfer-Encoding:\\s+chunked\\s*[\r\n]*", RegexOptions.IgnoreCase | RegexOptions.Multiline); if (contentEncodingTypeMatch.Success) { charset = contentEncodingTypeMatch.Groups[1].Value.ToLower(); } Encoding responseEncoding = null; try { responseEncoding = Encoding.GetEncoding(charset); } catch (ArgumentException) { responseEncoding = wwwProxy_.defaultEncoding_; } if (connectionCloseMatch.Success) { responseCloseInbound_ = true; } completableResponse_ = contentTextTypeMatch.Success || (httpResponseCode >= 300); if (!completableResponse_) { inbound_.StopKeepAliveTimer(); inbound_.Send(receiveBuffer, 0, bytesReceived); processedResponseBytes = bytesReceived; } else { if (contentLengthMatch.Success) { int contentsLength = Convert.ToInt32(contentLengthMatch.Groups[1].Value); if (contentsBytes.Length >= contentsLength) { header = Regex.Replace(header, "^Content-Length:\\s+(\\d+)[ \t]*[\r\n]*", "", RegexOptions.IgnoreCase | RegexOptions.Multiline); header = header.TrimEnd(" \t\r\n".ToCharArray()); contents = responseEncoding.GetString(contentsBytes, 0, contentsBytes.Length); processedResponseBytes = contentsIndex + contentsLength; } else { bytesRequired_ = contentsLength - contentsBytes.Length; } } else if (transferEncodingMatch.Success) { int deChunkingIndex = 0; byte[] chunkedContents = new byte[contentsBytes.Length]; Array.Copy(contentsBytes, chunkedContents, contentsBytes.Length); string deChunkedContents = ""; while (true) { int chunkLengthEnd = -1; for (int i = deChunkingIndex; i < chunkedContents.Length; ++i) { if ((chunkedContents[i] == '\r') && (chunkedContents[i + 1] == '\n')) { chunkLengthEnd = i; break; } } if (chunkLengthEnd != -1) { int chunkLength = Convert.ToInt32(responseEncoding.GetString(chunkedContents, deChunkingIndex, chunkLengthEnd - deChunkingIndex).Trim(), 16); deChunkingIndex = chunkLengthEnd + 2; if (chunkLength != 0) { if (chunkedContents.Length >= (deChunkingIndex + chunkLength)) { deChunkedContents += responseEncoding.GetString(chunkedContents, deChunkingIndex, chunkLength); } else { bytesRequired_ = (deChunkingIndex + chunkLength) - chunkedContents.Length; deChunkedContents = null; } } deChunkingIndex += chunkLength; while ((deChunkingIndex < chunkedContents.Length) && ((chunkedContents[deChunkingIndex] == '\r') || (chunkedContents[deChunkingIndex] == '\n'))) { deChunkingIndex++; } if (chunkLength == 0) { break; } } else { deChunkedContents = null; break; } } if (deChunkedContents != null) { header = Regex.Replace(header, "^Transfer-Encoding:\\s+chunked(.*?)[ \t]*[\r\n]*", "", RegexOptions.IgnoreCase | RegexOptions.Multiline); header = header.TrimEnd(" \t\r\n".ToCharArray()); contents = deChunkedContents; processedResponseBytes = contentsIndex + deChunkingIndex; } } else { if (((connectionCloseMatch.Success) && (bConnectionClosed)) || (bConnectionClosed) || (httpResponseCode == 204) || (httpResponseCode == 304)) // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html { contents = responseEncoding.GetString(contentsBytes, 0, contentsBytes.Length); processedResponseBytes = bytesReceived; } } } if (processedResponseBytes != 0) { if (completableResponse_) { header = Regex.Replace(header, "^Proxy-Connection:\\s+(.*)?[ \t]*[\r\n]*", "", RegexOptions.IgnoreCase | RegexOptions.Multiline); header = header.TrimEnd(" \t\r\n".ToCharArray()); } if ((httpResponseCode == 401) || (httpResponseCode == 407)) { if (wwwProxy_.ntlmEnabled_) { Match urlMatch = Regex.Match(request_.completedHeader_, "([A-Z]+)\\s+(.*?)\\s+HTTP/\\d.\\d\r$", RegexOptions.IgnoreCase | RegexOptions.Multiline); if (urlMatch.Success) { try { wwwProxy_.ntlmListMutex_.WaitOne(); string ntlmSite = host_ + ":" + port_; string ntlmPath = urlMatch.Groups[2].Value; Match wwwAuthenticateBasicMatch = Regex.Match(header, "^(WWW|Proxy)-Authenticate:\\s+Basic(.*)?[ \t]*[\r\n]*", RegexOptions.IgnoreCase | RegexOptions.Multiline); if (wwwAuthenticateBasicMatch.Success) { List <INtlm> toRemove = new List <INtlm>(); foreach (INtlm w in wwwProxy_.ntlmList_) { if (w.Site == ntlmSite) { toRemove.Add(w); } } foreach (INtlm w in toRemove) { wwwProxy_.ntlmList_.Remove(w); } } INtlm wwwProxyNtlm = null; foreach (INtlm w in wwwProxy_.ntlmList_) { if ((w.Site == ntlmSite) && (w.Path == ntlmPath)) { wwwProxyNtlm = w; break; } } Match wwwAuthenticateNegotiateMatch = Regex.Match(header, "^(WWW|Proxy)-Authenticate:\\s+Negotiate[ \t]*[\r\n]*", RegexOptions.IgnoreCase | RegexOptions.Multiline); Match wwwAuthenticateNTLMMatch = Regex.Match(header, "^(WWW|Proxy)-Authenticate:\\s+NTLM[\r\n]*", RegexOptions.IgnoreCase | RegexOptions.Multiline); Match wwwAuthenticateNTLMResponseMatch = Regex.Match(header, "^(WWW|Proxy)-Authenticate:\\s+NTLM\\s+([A-Za-z0-9+/=]*)[ \t]*[\r\n]*", RegexOptions.IgnoreCase | RegexOptions.Multiline); if (wwwAuthenticateNegotiateMatch.Success && wwwAuthenticateNTLMMatch.Success) { string authType = wwwAuthenticateNegotiateMatch.Groups[1].Value; header = Regex.Replace(header, "^(WWW|Proxy)-Authenticate:\\s+Negotiate[ \t]*[\r\n]*", "", RegexOptions.IgnoreCase | RegexOptions.Multiline); header = Regex.Replace(header, "(^(WWW|Proxy)-Authenticate:\\s+)NTLM[ \t]*([\r\n]*)", "${1}Basic Realm=\"WwwProxy NTLM (" + authType + ")\"${3}", RegexOptions.IgnoreCase | RegexOptions.Multiline); header = header.TrimEnd(" \t\r\n".ToCharArray()); if (wwwProxyNtlm == null) { wwwProxyNtlm = wwwProxy_.ntlmFactory_.CreateInstance(); if (wwwProxyNtlm != null) { wwwProxyNtlm.Site = ntlmSite; wwwProxyNtlm.Path = ntlmPath; wwwProxyNtlm.Type = authType; wwwProxy_.ntlmList_.Add(wwwProxyNtlm); } } else { wwwProxyNtlm.Reset(); } } else if (wwwAuthenticateNTLMResponseMatch.Success) { string replacementAuth = "${1}" + wwwProxyNtlm.Continue(wwwAuthenticateNTLMResponseMatch.Groups[2].Value) + "${3}"; request_.completedHeader_ = Regex.Replace(request_.completedHeader_, "^((Proxy-)*Authorization:\\s+NTLM\\s+)[a-zA-Z0-9=]+[ \t]*([\r\n]*)", replacementAuth, RegexOptions.IgnoreCase | RegexOptions.Multiline); Send(request_); header = null; } } finally { wwwProxy_.ntlmListMutex_.ReleaseMutex(); } } } } if (header != null) { response_ = new ProxyResponse(); response_.encoding_ = responseEncoding; response_.outbound_ = this; response_.request_ = request_; response_.completable_ = completableResponse_; response_.ssl_ = ssl_; response_.header_ = header; response_.contents_ = contents; wwwProxy_.OnResponse(response_); } } } } } else { inbound_.StopKeepAliveTimer(); inbound_.Send(receiveBuffer, 0, bytesReceived); processedResponseBytes = bytesReceived; bytesRequired_ = 0; processResponse_ = false; } return(processedResponseBytes); }