From e3776c06c37cc197709dac60892604dfea894ac2 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Mon, 29 Nov 2010 01:34:36 +0100 Subject: Remove enc=utf-8 in VIM modeline as it is not allowed in VIM 7.3 As of VIM 7.3 it is no longer possible to specify the encoding in the modeline. This gives an error message whenever such a file is opened, thus this commit removes the enc setting from the modeline. --- inc/HTTPClient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'inc/HTTPClient.php') diff --git a/inc/HTTPClient.php b/inc/HTTPClient.php index e68679bde..b23616ef1 100644 --- a/inc/HTTPClient.php +++ b/inc/HTTPClient.php @@ -600,4 +600,4 @@ class HTTPClient { } -//Setup VIM: ex: et ts=4 enc=utf-8 : +//Setup VIM: ex: et ts=4 : -- cgit v1.2.3 From 68ee030431d00b9924366a1af38805ff0263c529 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Thu, 2 Dec 2010 18:45:03 +0100 Subject: renamed variable initialization in HTTPClient --- inc/HTTPClient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'inc/HTTPClient.php') diff --git a/inc/HTTPClient.php b/inc/HTTPClient.php index b23616ef1..43b00034c 100644 --- a/inc/HTTPClient.php +++ b/inc/HTTPClient.php @@ -92,7 +92,7 @@ class HTTPClient { var $redirect_count; // read these after a successful request - var $resp_status; + var $status; var $resp_body; var $resp_headers; -- cgit v1.2.3 From fa7c70ff4d7f9999466436e7d559eb0c81571779 Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Wed, 8 Dec 2010 17:17:40 +0100 Subject: tmp --- inc/HTTPClient.php | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'inc/HTTPClient.php') diff --git a/inc/HTTPClient.php b/inc/HTTPClient.php index 43b00034c..a9afef9f9 100644 --- a/inc/HTTPClient.php +++ b/inc/HTTPClient.php @@ -222,7 +222,7 @@ class HTTPClient { $path = $uri['path']; if(empty($path)) $path = '/'; if(!empty($uri['query'])) $path .= '?'.$uri['query']; - $port = $uri['port']; + if(isset($uri['port']) && !empty($uri['port'])) $port = $uri['port']; if(isset($uri['user'])) $this->user = $uri['user']; if(isset($uri['pass'])) $this->pass = $uri['pass']; @@ -235,7 +235,7 @@ class HTTPClient { }else{ $request_url = $path; $server = $server; - if (empty($port)) $port = ($uri['scheme'] == 'https') ? 443 : 80; + if (!isset($port)) $port = ($uri['scheme'] == 'https') ? 443 : 80; } // add SSL stream prefix if needed - needs SSL support in PHP @@ -506,12 +506,13 @@ class HTTPClient { */ function _parseHeaders($string){ $headers = array(); - $lines = explode("\n",$string); - foreach($lines as $line){ - list($key,$val) = explode(':',$line,2); - $key = strtolower(trim($key)); - $val = trim($val); - if(empty($val)) continue; + if (!preg_match_all('/^\s*([\w-]+)\s*:\s*([\S \t]+)\s*$/m', $string, + $matches, PREG_SET_ORDER)) { + return $headers; + } + foreach($matches as $match){ + list(, $key, $val) = $match; + $key = strtolower($key); if(isset($headers[$key])){ if(is_array($headers[$key])){ $headers[$key][] = $val; -- cgit v1.2.3 From 4481b2a04e9fbc3dd2696f436d5c2d2a725c8386 Mon Sep 17 00:00:00 2001 From: Tobias Sarnowski Date: Tue, 11 Jan 2011 13:12:26 +0100 Subject: added keep-alive capabilities to the http client The DokuHTTPClient is now able to keep connections alive. This feature is enabled by default. It can be disabled with $client->setKeepAlive(false); and asked with $client->isKeepAlive();. --- inc/HTTPClient.php | 84 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 12 deletions(-) (limited to 'inc/HTTPClient.php') diff --git a/inc/HTTPClient.php b/inc/HTTPClient.php index 43b00034c..d46200697 100644 --- a/inc/HTTPClient.php +++ b/inc/HTTPClient.php @@ -71,6 +71,7 @@ class DokuHTTPClient extends HTTPClient { * @link http://www.splitbrain.org/go/videodb * @author Andreas Goetz * @author Andreas Gohr + * @author Tobias Sarnowski */ class HTTPClient { //set these if you like @@ -86,6 +87,7 @@ class HTTPClient { var $headers; var $debug; var $start = 0; // for timings + var $keep_alive = true; // keep alive rocks // don't set these, read on error var $error; @@ -108,6 +110,9 @@ class HTTPClient { var $proxy_ssl; //boolean set to true if your proxy needs SSL var $proxy_except; // regexp of URLs to exclude from proxy + // list of kept alive connections + var $connections = array(); + // what we use as boundary on multipart/form-data posts var $boundary = '---DokuWikiHTTPClient--4523452351'; @@ -247,7 +252,11 @@ class HTTPClient { if($uri['port']) $headers['Host'].= ':'.$uri['port']; $headers['User-Agent'] = $this->agent; $headers['Referer'] = $this->referer; - $headers['Connection'] = 'Close'; + if ($this->isKeepAlive()) { + $headers['Connection'] = 'Keep-Alive'; + } else { + $headers['Connection'] = 'Close'; + } if($method == 'POST'){ if(is_array($data)){ if($headers['Content-Type'] == 'multipart/form-data'){ @@ -273,15 +282,29 @@ class HTTPClient { // stop time $start = time(); - // open socket - $socket = @fsockopen($server,$port,$errno, $errstr, $this->timeout); - if (!$socket){ - $this->status = -100; - $this->error = "Could not connect to $server:$port\n$errstr ($errno)"; - return false; + // already connected? + $connectionId = $this->_uniqueConnectionId($server,$port); + $this->_debug('connection pool', $this->connections); + if (isset($this->connections[$connectionId])) { + $this->_debug('reusing connection', $connectionId); + $socket = $this->connections[$connectionId]; + } else { + $this->_debug('opening connection', $connectionId); + // open socket + $socket = @fsockopen($server,$port,$errno, $errstr, $this->timeout); + if (!$socket){ + $this->status = -100; + $this->error = "Could not connect to $server:$port\n$errstr ($errno)"; + return false; + } + //set non blocking + stream_set_blocking($socket,0); + + // keep alive? + if ($this->isKeepAlive()) { + $this->connections[$connectionId] = $socket; + } } - //set non blocking - stream_set_blocking($socket,0); // build request $request = "$method $request_url HTTP/".$this->http.HTTP_NL; @@ -359,6 +382,11 @@ class HTTPClient { // check server status code to follow redirect if($this->status == 301 || $this->status == 302 ){ + // close the connection because we don't handle content retrieval here + // that's the easiest way to clean up the connection + fclose($socket); + unset($this->connections[$connectionId]); + if (empty($this->resp_headers['location'])){ $this->error = 'Redirect but no Location Header found'; return false; @@ -450,9 +478,13 @@ class HTTPClient { } } - // close socket - $status = socket_get_status($socket); - fclose($socket); + if (!$this->isKeepAlive() || + (isset($this->resp_headers['connection']) && $this->resp_headers['connection'] == 'Close')) { + // close socket + $status = socket_get_status($socket); + fclose($socket); + unset($this->connections[$connectionId]); + } // decode gzip if needed if(isset($this->resp_headers['content-encoding']) && @@ -598,6 +630,34 @@ class HTTPClient { return $out; } + /** + * Returns if the keep-alive feature is enabled or not. + * + * @return bool keep-alive enabled + * @author Tobias Sarnowski + */ + function isKeepAlive() { + return $this->keep_alive; + } + + /** + * Set the keep-alive feature status. + * + * @param bool $keep_alive if keep-alive should be enabled or not + * @author Tobias Sarnowski + */ + function setKeepAlive($keep_alive) { + $this->keep_alive = $keep_alive; + } + + /** + * Generates a unique identifier for a connection. + * + * @return string unique identifier + */ + function _uniqueConnectionId($server, $port) { + return "$server:$port"; + } } //Setup VIM: ex: et ts=4 : -- cgit v1.2.3 From 1415e8b5968a264b9a2aa5bac0d77c2a898c8e81 Mon Sep 17 00:00:00 2001 From: Tobias Sarnowski Date: Tue, 11 Jan 2011 13:18:20 +0100 Subject: keep http connections application wide alive Using a static context for the connection pool allows connection reuse throughout the whole application without additional changes in other places. --- inc/HTTPClient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'inc/HTTPClient.php') diff --git a/inc/HTTPClient.php b/inc/HTTPClient.php index d46200697..1dbcd6be1 100644 --- a/inc/HTTPClient.php +++ b/inc/HTTPClient.php @@ -111,7 +111,7 @@ class HTTPClient { var $proxy_except; // regexp of URLs to exclude from proxy // list of kept alive connections - var $connections = array(); + static $connections = array(); // what we use as boundary on multipart/form-data posts var $boundary = '---DokuWikiHTTPClient--4523452351'; -- cgit v1.2.3 From a6bacf701037fe4798658f00854ec9c5e6ddf835 Mon Sep 17 00:00:00 2001 From: Tobias Sarnowski Date: Tue, 11 Jan 2011 15:07:46 +0100 Subject: do not reuse errornous http connections As soon as something goes wrong while querying a http server do not reuse the same connection again, its state is undefined. In addition, check the connection for feof() before reusing it. --- inc/HTTPClient.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'inc/HTTPClient.php') diff --git a/inc/HTTPClient.php b/inc/HTTPClient.php index 1dbcd6be1..53b344b76 100644 --- a/inc/HTTPClient.php +++ b/inc/HTTPClient.php @@ -285,10 +285,12 @@ class HTTPClient { // already connected? $connectionId = $this->_uniqueConnectionId($server,$port); $this->_debug('connection pool', $this->connections); + $socket = null; if (isset($this->connections[$connectionId])) { $this->_debug('reusing connection', $connectionId); $socket = $this->connections[$connectionId]; - } else { + } + if (is_null($socket) || feof($socket)) { $this->_debug('opening connection', $connectionId); // open socket $socket = @fsockopen($server,$port,$errno, $errstr, $this->timeout); @@ -303,6 +305,8 @@ class HTTPClient { // keep alive? if ($this->isKeepAlive()) { $this->connections[$connectionId] = $socket; + } else { + unset($this->connections[$connectionId]); } } @@ -323,6 +327,7 @@ class HTTPClient { if($ret === false){ $this->status = -100; $this->error = 'Failed writing to socket'; + unset($this->connections[$connectionId]); return false; } $written += $ret; @@ -334,10 +339,12 @@ class HTTPClient { if(time()-$start > $this->timeout){ $this->status = -100; $this->error = sprintf('Timeout while reading headers (%.3fs)',$this->_time() - $this->start); + unset($this->connections[$connectionId]); return false; } if(feof($socket)){ $this->error = 'Premature End of File (socket)'; + unset($this->connections[$connectionId]); return false; } $r_headers .= fgets($socket,1024); @@ -350,6 +357,7 @@ class HTTPClient { if($match[1] > $this->max_bodysize){ $this->error = 'Reported content length exceeds allowed response size'; if ($this->max_bodysize_abort) + unset($this->connections[$connectionId]); return false; } } @@ -357,6 +365,7 @@ class HTTPClient { // get Status if (!preg_match('/^HTTP\/(\d\.\d)\s*(\d+).*?\n/', $r_headers, $m)) { $this->error = 'Server returned bad answer'; + unset($this->connections[$connectionId]); return false; } $this->status = $m[2]; @@ -414,6 +423,7 @@ class HTTPClient { // check if headers are as expected if($this->header_regexp && !preg_match($this->header_regexp,$r_headers)){ $this->error = 'The received headers did not match the given regexp'; + unset($this->connections[$connectionId]); return false; } @@ -425,11 +435,13 @@ class HTTPClient { do { if(feof($socket)){ $this->error = 'Premature End of File (socket)'; + unset($this->connections[$connectionId]); return false; } if(time()-$start > $this->timeout){ $this->status = -100; $this->error = sprintf('Timeout while reading chunk (%.3fs)',$this->_time() - $this->start); + unset($this->connections[$connectionId]); return false; } $byte = fread($socket,1); @@ -447,6 +459,7 @@ class HTTPClient { if($this->max_bodysize && strlen($r_body) > $this->max_bodysize){ $this->error = 'Allowed response size exceeded'; if ($this->max_bodysize_abort) + unset($this->connections[$connectionId]); return false; else break; @@ -458,6 +471,7 @@ class HTTPClient { if(time()-$start > $this->timeout){ $this->status = -100; $this->error = sprintf('Timeout while reading response (%.3fs)',$this->_time() - $this->start); + unset($this->connections[$connectionId]); return false; } $r_body .= fread($socket,4096); @@ -465,6 +479,7 @@ class HTTPClient { if($this->max_bodysize && $r_size > $this->max_bodysize){ $this->error = 'Allowed response size exceeded'; if ($this->max_bodysize_abort) + unset($this->connections[$connectionId]); return false; else break; -- cgit v1.2.3 From b58bcfed1ea9c70e4103c91723a19c845b06f300 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Wed, 12 Jan 2011 20:55:16 +0100 Subject: removed setter/getter to match coding style since we don't use setter/getters for the other options it doesn't make sense to have them for the keep-alive function --- inc/HTTPClient.php | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) (limited to 'inc/HTTPClient.php') diff --git a/inc/HTTPClient.php b/inc/HTTPClient.php index 53b344b76..7e5e40ee3 100644 --- a/inc/HTTPClient.php +++ b/inc/HTTPClient.php @@ -252,7 +252,7 @@ class HTTPClient { if($uri['port']) $headers['Host'].= ':'.$uri['port']; $headers['User-Agent'] = $this->agent; $headers['Referer'] = $this->referer; - if ($this->isKeepAlive()) { + if ($this->keep_alive) { $headers['Connection'] = 'Keep-Alive'; } else { $headers['Connection'] = 'Close'; @@ -303,7 +303,7 @@ class HTTPClient { stream_set_blocking($socket,0); // keep alive? - if ($this->isKeepAlive()) { + if ($this->keep_alive) { $this->connections[$connectionId] = $socket; } else { unset($this->connections[$connectionId]); @@ -493,7 +493,7 @@ class HTTPClient { } } - if (!$this->isKeepAlive() || + if (!$this->keep_alive || (isset($this->resp_headers['connection']) && $this->resp_headers['connection'] == 'Close')) { // close socket $status = socket_get_status($socket); @@ -645,26 +645,6 @@ class HTTPClient { return $out; } - /** - * Returns if the keep-alive feature is enabled or not. - * - * @return bool keep-alive enabled - * @author Tobias Sarnowski - */ - function isKeepAlive() { - return $this->keep_alive; - } - - /** - * Set the keep-alive feature status. - * - * @param bool $keep_alive if keep-alive should be enabled or not - * @author Tobias Sarnowski - */ - function setKeepAlive($keep_alive) { - $this->keep_alive = $keep_alive; - } - /** * Generates a unique identifier for a connection. * -- cgit v1.2.3 From 299c3423aa580b305c33bbe62c29123815f5419a Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Wed, 12 Jan 2011 20:56:13 +0100 Subject: fixed brackets --- inc/HTTPClient.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'inc/HTTPClient.php') diff --git a/inc/HTTPClient.php b/inc/HTTPClient.php index 7e5e40ee3..7011aa9ed 100644 --- a/inc/HTTPClient.php +++ b/inc/HTTPClient.php @@ -458,11 +458,12 @@ class HTTPClient { if($this->max_bodysize && strlen($r_body) > $this->max_bodysize){ $this->error = 'Allowed response size exceeded'; - if ($this->max_bodysize_abort) + if ($this->max_bodysize_abort){ unset($this->connections[$connectionId]); return false; - else + } else { break; + } } } while ($chunk_size); }else{ @@ -478,11 +479,12 @@ class HTTPClient { $r_size = strlen($r_body); if($this->max_bodysize && $r_size > $this->max_bodysize){ $this->error = 'Allowed response size exceeded'; - if ($this->max_bodysize_abort) + if ($this->max_bodysize_abort) { unset($this->connections[$connectionId]); return false; - else + } else { break; + } } if(isset($this->resp_headers['content-length']) && !isset($this->resp_headers['transfer-encoding']) && -- cgit v1.2.3 From dd47a3146c007e5609ac18a5d6db1f5271d1273a Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Sun, 6 Feb 2011 15:18:16 +0100 Subject: better stream writing in HTTPClient FS#2036 This changes the HTTP stream to blocking while writing to the stream using select() to handle timeouts. Addtionally, wwriting is done in 4k block now (as it is done with reading). This is supposed to fix a problem with writing to a SSL stream that is not quite ready. Reading from the stream continues to be non-blocking as before. --- inc/HTTPClient.php | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'inc/HTTPClient.php') diff --git a/inc/HTTPClient.php b/inc/HTTPClient.php index 1cb16714d..372769b71 100644 --- a/inc/HTTPClient.php +++ b/inc/HTTPClient.php @@ -299,8 +299,6 @@ class HTTPClient { $this->error = "Could not connect to $server:$port\n$errstr ($errno)"; return false; } - //set non blocking - stream_set_blocking($socket,0); // keep alive? if ($this->keep_alive) { @@ -310,6 +308,9 @@ class HTTPClient { } } + //set blocking + stream_set_blocking($socket,1); + // build request $request = "$method $request_url HTTP/".$this->http.HTTP_NL; $request .= $this->_buildHeaders($headers); @@ -319,11 +320,28 @@ class HTTPClient { $this->_debug('request',$request); + // select parameters + $sel_r = null; + $sel_w = array($socket); + $sel_e = null; + // send request $towrite = strlen($request); $written = 0; while($written < $towrite){ - $ret = fwrite($socket, substr($request,$written)); + // check timeout + if(time()-$start > $this->timeout){ + $this->status = -100; + $this->error = sprintf('Timeout while sending request (%.3fs)',$this->_time() - $this->start); + unset($this->connections[$connectionId]); + return false; + } + + // wait for stream ready or timeout (1sec) + if(stream_select($sel_r,$sel_w,$sel_e,1) === false) continue; + + // write to stream + $ret = fwrite($socket, substr($request,$written,4096)); if($ret === false){ $this->status = -100; $this->error = 'Failed writing to socket'; @@ -333,6 +351,9 @@ class HTTPClient { $written += $ret; } + // continue non-blocking + stream_set_blocking($socket,0); + // read headers from socket $r_headers = ''; do{ -- cgit v1.2.3