summaryrefslogtreecommitdiff
path: root/inc/HTTPClient.php
diff options
context:
space:
mode:
authorAndreas Gohr <andi@splitbrain.org>2012-07-28 14:55:45 +0200
committerAndreas Gohr <andi@splitbrain.org>2012-07-28 14:55:45 +0200
commit1ea7a6bada66fc9b7a45f61b4892e4ea23196d89 (patch)
tree563cd2f49e112af43dbb8b4f7b31f7285ed4fe36 /inc/HTTPClient.php
parentae22dee70061990f256be2671c0f585a572ce712 (diff)
downloadrpg-1ea7a6bada66fc9b7a45f61b4892e4ea23196d89.tar.gz
rpg-1ea7a6bada66fc9b7a45f61b4892e4ea23196d89.tar.bz2
support CONNECT for tunneling SSL via HTTP proxies FS#2431
The included test cases currently expect a squid at localhost:3128
Diffstat (limited to 'inc/HTTPClient.php')
-rw-r--r--inc/HTTPClient.php66
1 files changed, 61 insertions, 5 deletions
diff --git a/inc/HTTPClient.php b/inc/HTTPClient.php
index a25846c31..8d2c10be1 100644
--- a/inc/HTTPClient.php
+++ b/inc/HTTPClient.php
@@ -254,11 +254,7 @@ class HTTPClient {
if(!empty($uri['port'])) $headers['Host'].= ':'.$uri['port'];
$headers['User-Agent'] = $this->agent;
$headers['Referer'] = $this->referer;
- if ($this->keep_alive) {
- $headers['Connection'] = 'Keep-Alive';
- } else {
- $headers['Connection'] = 'Close';
- }
+
if($method == 'POST'){
if(is_array($data)){
if($headers['Content-Type'] == 'multipart/form-data'){
@@ -299,6 +295,14 @@ class HTTPClient {
return false;
}
+ // try establish a CONNECT tunnel for SSL
+ if($this->_ssltunnel($socket, $request_url)){
+ // no keep alive for tunnels
+ $this->keep_alive = false;
+ // tunnel is authed already
+ if(isset($headers['Proxy-Authentication'])) unset($headers['Proxy-Authentication']);
+ }
+
// keep alive?
if ($this->keep_alive) {
self::$connections[$connectionId] = $socket;
@@ -307,6 +311,15 @@ class HTTPClient {
}
}
+ if ($this->keep_alive && !$this->proxy_host) {
+ // RFC 2068, section 19.7.1: A client MUST NOT send the Keep-Alive
+ // connection token to a proxy server. We still do keep the connection the
+ // proxy alive (well except for CONNECT tunnels)
+ $headers['Connection'] = 'Keep-Alive';
+ } else {
+ $headers['Connection'] = 'Close';
+ }
+
try {
//set non-blocking
stream_set_blocking($socket, false);
@@ -485,6 +498,49 @@ class HTTPClient {
}
/**
+ * Tries to establish a CONNECT tunnel via Proxy
+ *
+ * Protocol, Servername and Port will be stripped from the request URL when a successful CONNECT happened
+ *
+ * @param ressource &$socket
+ * @param string &$requesturl
+ * @return bool true if a tunnel was established
+ */
+ function _ssltunnel(&$socket, &$requesturl){
+ if(!$this->proxy_host) return false;
+ $requestinfo = parse_url($requesturl);
+ if($requestinfo['scheme'] != 'https') return false;
+ if(!$requestinfo['port']) $requestinfo['port'] = 443;
+
+ // build request
+ $request = "CONNECT {$requestinfo['host']}:{$requestinfo['port']} HTTP/1.0".HTTP_NL;
+ $request .= "Host: {$requestinfo['host']}".HTTP_NL;
+ if($this->proxy_user) {
+ 'Proxy-Authorization Basic '.base64_encode($this->proxy_user.':'.$this->proxy_pass).HTTP_NL;
+ }
+ $request .= HTTP_NL;
+
+ $this->_debug('SSL Tunnel CONNECT',$request);
+ $this->_sendData($socket, $request, 'SSL Tunnel CONNECT');
+
+ // read headers from socket
+ $r_headers = '';
+ do{
+ $r_line = $this->_readLine($socket, 'headers');
+ $r_headers .= $r_line;
+ }while($r_line != "\r\n" && $r_line != "\n");
+
+ $this->_debug('SSL Tunnel Response',$r_headers);
+ if(preg_match('/^HTTP\/1\.0 200/i',$r_headers)){
+ if (stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_SSLv3_CLIENT)) {
+ $requesturl = $requestinfo['path'];
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Safely write data to a socket
*
* @param handle $socket An open socket handle