|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00027 require_once 'Zend/Uri/Http.php'; 00031 require_once 'Zend/Http/Client.php'; 00035 require_once 'Zend/Http/Client/Adapter/Socket.php'; 00036 00052 class Zend_Http_Client_Adapter_Proxy extends Zend_Http_Client_Adapter_Socket 00053 { 00059 protected $config = array( 00060 'ssltransport' => 'ssl', 00061 'sslcert' => null, 00062 'sslpassphrase' => null, 00063 'sslusecontext' => false, 00064 'proxy_host' => '', 00065 'proxy_port' => 8080, 00066 'proxy_user' => '', 00067 'proxy_pass' => '', 00068 'proxy_auth' => Zend_Http_Client::AUTH_BASIC, 00069 'persistent' => false 00070 ); 00071 00077 protected $negotiated = false; 00078 00089 public function connect($host, $port = 80, $secure = false) 00090 { 00091 // If no proxy is set, fall back to Socket adapter 00092 if (! $this->config['proxy_host']) { 00093 return parent::connect($host, $port, $secure); 00094 } 00095 00096 /* Url might require stream context even if proxy connection doesn't */ 00097 if ($secure) { 00098 $this->config['sslusecontext'] = true; 00099 } 00100 00101 // Connect (a non-secure connection) to the proxy server 00102 return parent::connect( 00103 $this->config['proxy_host'], 00104 $this->config['proxy_port'], 00105 false 00106 ); 00107 } 00108 00119 public function write($method, $uri, $http_ver = '1.1', $headers = array(), $body = '') 00120 { 00121 // If no proxy is set, fall back to default Socket adapter 00122 if (! $this->config['proxy_host']) return parent::write($method, $uri, $http_ver, $headers, $body); 00123 00124 // Make sure we're properly connected 00125 if (! $this->socket) { 00126 require_once 'Zend/Http/Client/Adapter/Exception.php'; 00127 throw new Zend_Http_Client_Adapter_Exception("Trying to write but we are not connected"); 00128 } 00129 00130 $host = $this->config['proxy_host']; 00131 $port = $this->config['proxy_port']; 00132 00133 if ($this->connected_to[0] != "tcp://$host" || $this->connected_to[1] != $port) { 00134 require_once 'Zend/Http/Client/Adapter/Exception.php'; 00135 throw new Zend_Http_Client_Adapter_Exception("Trying to write but we are connected to the wrong proxy server"); 00136 } 00137 00138 // Add Proxy-Authorization header 00139 if ($this->config['proxy_user'] && ! isset($headers['proxy-authorization'])) { 00140 $headers['proxy-authorization'] = Zend_Http_Client::encodeAuthHeader( 00141 $this->config['proxy_user'], $this->config['proxy_pass'], $this->config['proxy_auth'] 00142 ); 00143 } 00144 00145 // if we are proxying HTTPS, preform CONNECT handshake with the proxy 00146 if ($uri->getScheme() == 'https' && (! $this->negotiated)) { 00147 $this->connectHandshake($uri->getHost(), $uri->getPort(), $http_ver, $headers); 00148 $this->negotiated = true; 00149 } 00150 00151 // Save request method for later 00152 $this->method = $method; 00153 00154 // Build request headers 00155 if ($this->negotiated) { 00156 $path = $uri->getPath(); 00157 if ($uri->getQuery()) { 00158 $path .= '?' . $uri->getQuery(); 00159 } 00160 $request = "$method $path HTTP/$http_ver\r\n"; 00161 } else { 00162 $request = "$method $uri HTTP/$http_ver\r\n"; 00163 } 00164 00165 // Add all headers to the request string 00166 foreach ($headers as $k => $v) { 00167 if (is_string($k)) $v = "$k: $v"; 00168 $request .= "$v\r\n"; 00169 } 00170 00171 if(is_resource($body)) { 00172 $request .= "\r\n"; 00173 } else { 00174 // Add the request body 00175 $request .= "\r\n" . $body; 00176 } 00177 00178 // Send the request 00179 if (! @fwrite($this->socket, $request)) { 00180 require_once 'Zend/Http/Client/Adapter/Exception.php'; 00181 throw new Zend_Http_Client_Adapter_Exception("Error writing request to proxy server"); 00182 } 00183 00184 if(is_resource($body)) { 00185 if(stream_copy_to_stream($body, $this->socket) == 0) { 00186 require_once 'Zend/Http/Client/Adapter/Exception.php'; 00187 throw new Zend_Http_Client_Adapter_Exception('Error writing request to server'); 00188 } 00189 } 00190 00191 return $request; 00192 } 00193 00202 protected function connectHandshake($host, $port = 443, $http_ver = '1.1', array &$headers = array()) 00203 { 00204 $request = "CONNECT $host:$port HTTP/$http_ver\r\n" . 00205 "Host: " . $this->config['proxy_host'] . "\r\n"; 00206 00207 // Add the user-agent header 00208 if (isset($this->config['useragent'])) { 00209 $request .= "User-agent: " . $this->config['useragent'] . "\r\n"; 00210 } 00211 00212 // If the proxy-authorization header is set, send it to proxy but remove 00213 // it from headers sent to target host 00214 if (isset($headers['proxy-authorization'])) { 00215 $request .= "Proxy-authorization: " . $headers['proxy-authorization'] . "\r\n"; 00216 unset($headers['proxy-authorization']); 00217 } 00218 00219 $request .= "\r\n"; 00220 00221 // Send the request 00222 if (! @fwrite($this->socket, $request)) { 00223 require_once 'Zend/Http/Client/Adapter/Exception.php'; 00224 throw new Zend_Http_Client_Adapter_Exception("Error writing request to proxy server"); 00225 } 00226 00227 // Read response headers only 00228 $response = ''; 00229 $gotStatus = false; 00230 while ($line = @fgets($this->socket)) { 00231 $gotStatus = $gotStatus || (strpos($line, 'HTTP') !== false); 00232 if ($gotStatus) { 00233 $response .= $line; 00234 if (!chop($line)) break; 00235 } 00236 } 00237 00238 // Check that the response from the proxy is 200 00239 if (Zend_Http_Response::extractCode($response) != 200) { 00240 require_once 'Zend/Http/Client/Adapter/Exception.php'; 00241 throw new Zend_Http_Client_Adapter_Exception("Unable to connect to HTTPS proxy. Server response: " . $response); 00242 } 00243 00244 // If all is good, switch socket to secure mode. We have to fall back 00245 // through the different modes 00246 $modes = array( 00247 STREAM_CRYPTO_METHOD_TLS_CLIENT, 00248 STREAM_CRYPTO_METHOD_SSLv3_CLIENT, 00249 STREAM_CRYPTO_METHOD_SSLv23_CLIENT, 00250 STREAM_CRYPTO_METHOD_SSLv2_CLIENT 00251 ); 00252 00253 $success = false; 00254 foreach($modes as $mode) { 00255 $success = stream_socket_enable_crypto($this->socket, true, $mode); 00256 if ($success) break; 00257 } 00258 00259 if (! $success) { 00260 require_once 'Zend/Http/Client/Adapter/Exception.php'; 00261 throw new Zend_Http_Client_Adapter_Exception("Unable to connect to" . 00262 " HTTPS server through proxy: could not negotiate secure connection."); 00263 } 00264 } 00265 00270 public function close() 00271 { 00272 parent::close(); 00273 $this->negotiated = false; 00274 } 00275 00280 public function __destruct() 00281 { 00282 if ($this->socket) $this->close(); 00283 } 00284 }