httpclient : add rawData support

httpclient : add getContent () method
httpclient : solve a bug when the Content-Length = 0 (waiting socket not needed)


git-svn-id: https://svn.fournier38.fr/svn/ProgSVN/trunk@4809 bf3deb0d-5f1a-0410-827f-c0cc1f45334c
This commit is contained in:
2018-12-27 15:22:13 +00:00
parent a46300881d
commit b1e2f45e6a

View File

@@ -4,8 +4,6 @@
* @author Dominique Fournier <dominique@fournier38.fr>
*/
namespace vendor\domframework;
/** This programe allow to get a HTTP page from a site, and examine the content.
* It will store the Cookies, allow to do the redirects, follow links and
* get form / input and send the values.
@@ -53,6 +51,10 @@ class Httpclient
*/
private $tcpclient = null;
/** The SSL Options parameters (if set)
*/
private $ssloptions = array ();
/** The maximum maxsize allowed
*/
private $maxsize;
@@ -83,6 +85,10 @@ class Httpclient
*/
private $formData = array ();
/** The raw data to send
*/
private $rawData = "";
/** The timeout in second before expiring the connection
*/
private $timeout = 30;
@@ -123,6 +129,7 @@ class Httpclient
if ($maxsize === 0)
$maxsize = 8000000000;
$this->maxsize = $maxsize;
$this->headersReset ();
}
// }}}
@@ -169,6 +176,7 @@ class Httpclient
return $this->method;
if (! is_string ($method))
throw new \Exception ("Invalid method to set : not an string", 406);
$method = strtoupper ($method);
if (! in_array ($method, array ("GET", "POST", "PUT", "DELETE", "HEAD")))
throw new \Exception ("Invalid method to set : not in list", 406);
$this->method = $method;
@@ -194,6 +202,28 @@ class Httpclient
}
// }}}
/** Set the headers to initial value
*/
public function headersReset ()
// {{{
{
$this->headersSent = array ();
return $this;
}
// }}}
/** Add a new header to be sent to the server
* @param string $header The header to add/update
* @param string $value The value to save
*/
public function headerAdd ($header, $value)
// {{{
{
$this->headersSent[$header] = $value;
return $this;
}
// }}}
/** Get the port used for connection
*/
public function port ()
@@ -245,7 +275,7 @@ class Httpclient
* If value is like "@/tmp/file", use the /tmp/file as content
* @param array|null $formData The data to send to the server
*/
public function formData ($formData)
public function formData ($formData = null)
// {{{
{
if ($formData === null)
@@ -253,6 +283,25 @@ class Httpclient
if (! is_array ($formData))
throw new \Exception ("Invalid form data provided : not an array", 406);
$this->formData = $formData;
$this->rawData = "";
return $this;
}
// }}}
/** Set / Get the content Data
* The data is in raw format and will not be modified.
* Overwrite the eventually previous form data and rawData
* @param string|null $rawData The data to use
*/
public function rawData ($rawData = null)
// {{{
{
if ($rawData === null)
return $this->rawData;
if (! is_string ($rawData))
throw new \Exception ("Invalid raw data provided : not a string", 406);
$this->rawData = $rawData;
$this->formData = array ();
return $this;
}
// }}}
@@ -400,39 +449,7 @@ class Httpclient
$this->method ("GET");
$this->url ($url);
$this->connect ($ssloptions);
$content = "";
while ($tmp = $this->read (1000000))
{
$content .= $tmp;
if (strlen ($content) > $this->maxsize)
throw new \Exception ("File to get exceeded maxsize", 500);
}
$this->disconnect ();
if ($this->httpCode === 301 || $this->httpCode === 302 ||
key_exists ("Location", $this->headersReceived))
{
if (! key_exists ("Location", $this->headersReceived))
throw new \Exception ("Redirect without location provided", 406);
$this->redirectCount++;
if ($this->redirectCount > $this->redirectMaxCount)
throw new \Exception ("Redirect exceed maximum limit", 406);
// echo "REDIRECT TO ".$this->headersReceived["Location"]."\n";
$location = $this->headersReceived["Location"];
$parseURLInit = parse_url ($url);
$parseURLLocation = parse_url ($location);
if (! key_exists ("port", $parseURLLocation) &&
key_exists ("port", $parseURLInit))
$location = ":".$parseURLInit["port"].$location;
if (! key_exists ("host", $parseURLLocation))
$location = $parseURLInit["host"].$location;
if (! key_exists ("scheme", $parseURLLocation))
$location = $parseURLInit["scheme"]."://".$location;
$this->log (1, "REDIRECT $this->httpCode to $location");
$content = $this->getPage ($location, $ssloptions);
}
$this->referer = $url;
$this->redirectCount = 0;
return $content;
return $this->getContent ();
}
// }}}
@@ -445,6 +462,7 @@ class Httpclient
// {{{
{
$this->log (2, "## URL Start $this->method $this->url");
$this->ssloptions = $ssloptions;
$this->headersReceived = array ();
$this->bodySize = null;
$this->httpCode = null;
@@ -507,20 +525,21 @@ class Httpclient
// Prepare the headers to be sent
// {{{
$this->headersSent = array ();
$this->headersSent[] = "$this->method $path HTTP/1.1";
$this->headersSent[] = "Host: ".$parseURL["host"];
unset ($this->headersSent[0]);
array_unshift ($this->headersSent,
"$this->method $path HTTP/1.1");
$this->headersSent["Host"] = $parseURL["host"];
if ($this->acceptEncoding !== "")
$this->headersSent[] = "Accept-Encoding: $this->acceptEncoding";
$this->headersSent["Accept-Encoding"] = $this->acceptEncoding;
if ($this->acceptLanguage !== "")
$this->headersSent[] = "Accept-Language: $this->acceptLanguage";
$this->headersSent["Accept-Language"] = $this->acceptLanguage;
if ($this->accept != "")
$this->headersSent[] = "Accept: $this->accept";
$this->headersSent["Accept"] = $this->accept;
if ($this->useragent !== "")
$this->headersSent[] = "User-Agent: $this->useragent";
$this->headersSent["User-Agent"] = $this->useragent;
if ($this->referer !== "")
$this->headersSent[] = "Referer: $this->referer";
$this->headersSent[] = "Connection: keep-alive";
$this->headersSent["Referer"] = $this->referer;
$this->headersSent["Connection"] = "keep-alive";
$cookies = $this->cookieToSend ($this->url);
if (! empty ($cookies))
{
@@ -528,7 +547,7 @@ class Httpclient
}
if ($this->method !== "GET" && ! empty ($this->formData))
{
$this->headersSent[] = "Content-Type: application/x-www-form-urlencoded";
$this->headersSent["Content-Type"] = "application/x-www-form-urlencoded";
$len = 0;
foreach ($this->formData as $key => $val)
{
@@ -546,8 +565,16 @@ class Httpclient
else
$len += strlen (rawurlencode ($val));
}
$this->headersSent[] = "Content-Length: $len";
$this->headersSent["Content-Length"] = $len;
}
if ($this->method !== "GET" && $this->rawData !== "")
{
if (! key_exists ("Content-Type", $this->headersSent))
$this->headersSent["Content-Type"] =
"application/x-www-form-urlencoded";
$this->headersSent["Content-Length"] = strlen ($this->rawData);
}
$this->log (2, "Headers Send :");
$this->log (2, $this->headersSent);
// }}}
@@ -561,12 +588,15 @@ class Httpclient
$this->tcpclient->timeout ($this->timeout);
$this->tcpclient->connect ();
if ($parseURL["scheme"] === "https")
$this->tcpclient->cryptoEnable (true, null, $ssloptions);
$this->tcpclient->cryptoEnable (true, null, $this->ssloptions);
}
$this->tcpclient->readMode ("text");
foreach ($this->headersSent as $header)
$this->tcpclient->send ($this->headersSent[0]."\r\n");
foreach ($this->headersSent as $header => $value)
{
$this->tcpclient->send ("$header\r\n");
if ($header === 0)
continue;
$this->tcpclient->send ("$header: $value\r\n");
}
$this->tcpclient->send ("\r\n");
// }}}
@@ -595,6 +625,10 @@ class Httpclient
$i ++;
}
}
elseif ($this->method !== "GET" && $this->rawData !== "")
{
$this->tcpclient->send ($this->rawData);
}
// }}}
// Get the result header from the server
@@ -649,8 +683,7 @@ class Httpclient
$this->contentMethod = "chunked";
$this->bodySize = 0;
}
elseif (key_exists ("Content-Length", $headers) &&
$headers["Content-Length"] > 0)
elseif (key_exists ("Content-Length", $headers))
{
$this->contentMethod = "Content-Length";
$this->bodySize = $headers["Content-Length"];
@@ -667,12 +700,59 @@ class Httpclient
}
if ($this->contentMethod === "chunked")
$this->log (1, "URL $this->method $this->url $this->httpCode Chunked");
elseif (is_int ($this->bodySize))
elseif (is_numeric ($this->bodySize))
$this->log (1, "URL $this->method $this->url $this->httpCode ".
$this->bodySize);
else
$this->log (1, "URL $this->method $this->url $this->httpCode 0");
// }}}
return $this;
}
// }}}
/** Get the content from the server and put it in memory
*/
public function getContent ()
// {{{
{
$url = $this->url;
$content = "";
while ($tmp = $this->read (1000000))
{
$content .= $tmp;
if (strlen ($content) > $this->maxsize)
throw new \Exception ("File to get exceeded maxsize", 500);
}
$this->disconnect ();
if ($this->httpCode === 301 || $this->httpCode === 302 ||
key_exists ("Location", $this->headersReceived))
{
if (! key_exists ("Location", $this->headersReceived))
throw new \Exception ("Redirect without location provided", 406);
$this->redirectCount++;
if ($this->redirectCount > $this->redirectMaxCount)
throw new \Exception ("Redirect exceed maximum limit", 406);
// echo "REDIRECT TO ".$this->headersReceived["Location"]."\n";
$location = $this->headersReceived["Location"];
$parseURLInit = parse_url ($url);
$parseURLLocation = parse_url ($location);
if ($parseURLLocation["path"]{0} !== "/" &&
key_exists ("path", $parseURLInit))
$location = dirname ($parseURLInit["path"]).$location;
if (! key_exists ("port", $parseURLLocation) &&
key_exists ("port", $parseURLInit))
$location = ":".$parseURLInit["port"].$location;
if (! key_exists ("host", $parseURLLocation))
$location = $parseURLInit["host"].$location;
if (! key_exists ("scheme", $parseURLLocation))
$location = $parseURLInit["scheme"]."://".$location;
$this->log (1, "REDIRECT $this->httpCode to $location");
$this->log (2, " content=$content\n");
$content = $this->getPage ($location, $this->ssloptions);
}
$this->referer = $url;
$this->redirectCount = 0;
return $content;
}
// }}}
@@ -688,12 +768,6 @@ class Httpclient
if ($this->tcpclient === null)
throw new \Exception ("HTTPClient : can not read non connected URL", 406);
$this->tcpclient->timeout ($this->timeout);
/* if ($this->contentMethod === false)
{
// If the server will never send anything, code 204 by example, do not try
// to get data
return "";
}*/
$content = "";
if ($this->contentMethod === "chunked" && $this->bodySize === 0)
{
@@ -711,7 +785,8 @@ class Httpclient
if ($toBeRead > $maxsize)
$toBeRead = $maxsize;
$this->tcpclient->readMode ("binary");
$content = $this->tcpclient->read ($toBeRead);
if ($toBeRead > 0)
$content = $this->tcpclient->read ($toBeRead);
// In close mode, the bodySize is not set and should not be updated
if ($this->bodySize !== null)
$this->bodySize = $this->bodySize - strlen ($content);