ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
Sabre\HTTP\Client Class Reference

A rudimentary HTTP client. More...

+ Inheritance diagram for Sabre\HTTP\Client:
+ Collaboration diagram for Sabre\HTTP\Client:

Public Member Functions

 __construct ()
 Initializes the client. More...
 
 send (RequestInterface $request)
 Sends a request to a HTTP server, and returns a response. More...
 
 sendAsync (RequestInterface $request, callable $success=null, callable $error=null)
 Sends a HTTP request asynchronously. More...
 
 poll ()
 This method checks if any http requests have gotten results, and if so, call the appropriate success or error handlers. More...
 
 wait ()
 Processes every HTTP request in the queue, and waits till they are all completed. More...
 
 setThrowExceptions ($throwExceptions)
 If this is set to true, the Client will automatically throw exceptions upon HTTP errors. More...
 
 addCurlSetting ($name, $value)
 Adds a CURL setting. More...
 
- Public Member Functions inherited from Sabre\Event\EventEmitterInterface
 on ($eventName, callable $callBack, $priority=100)
 Subscribe to an event. More...
 
 once ($eventName, callable $callBack, $priority=100)
 Subscribe to an event exactly once. More...
 
 emit ($eventName, array $arguments=[], callable $continueCallBack=null)
 Emits an event. More...
 
 listeners ($eventName)
 Returns the list of listeners for an event. More...
 
 removeListener ($eventName, callable $listener)
 Removes a specific listener from an event. More...
 
 removeAllListeners ($eventName=null)
 Removes all listeners. More...
 

Data Fields

const STATUS_SUCCESS = 0
 
const STATUS_CURLERROR = 1
 
const STATUS_HTTPERROR = 2
 

Protected Member Functions

 doRequest (RequestInterface $request)
 This method is responsible for performing a single request. More...
 
 createCurlSettingsArray (RequestInterface $request)
 Turns a RequestInterface object into an array with settings that can be fed to curl_setopt. More...
 
 parseCurlResult ($response, $curlHandle)
 Parses the result of a curl call in a format that's a bit more convenient to work with. More...
 
 sendAsyncInternal (RequestInterface $request, callable $success, callable $error, $retryCount=0)
 Sends an asynchronous HTTP request. More...
 
 curlExec ($curlHandle)
 Calls curl_exec. More...
 
 curlStuff ($curlHandle)
 Returns a bunch of information about a curl request. More...
 

Protected Attributes

 $curlSettings = []
 
 $throwExceptions = false
 
 $maxRedirects = 5
 

Private Attributes

 $curlHandle
 
 $curlMultiHandle
 
 $curlMultiMap = []
 

Detailed Description

A rudimentary HTTP client.

This object wraps PHP's curl extension and provides an easy way to send it a Request object, and return a Response object.

This is by no means intended as the next best HTTP client, but it does the job and provides a simple integration with the rest of sabre/http.

This client emits the following events: beforeRequest(RequestInterface $request) afterRequest(RequestInterface $request, ResponseInterface $response) error(RequestInterface $request, ResponseInterface $response, bool &$retry, int $retryCount) exception(RequestInterface $request, ClientException $e, bool &$retry, int $retryCount)

The beforeRequest event allows you to do some last minute changes to the request before it's done, such as adding authentication headers.

The afterRequest event will be emitted after the request is completed succesfully.

If a HTTP error is returned (status code higher than 399) the error event is triggered. It's possible using this event to retry the request, by setting retry to true.

The amount of times a request has retried is passed as $retryCount, which can be used to avoid retrying indefinitely. The first time the event is called, this will be 0.

It's also possible to intercept specific http errors, by subscribing to for example 'error:401'.

Author
Evert Pot (http://evertpot.com/) @license http://sabre.io/license/ Modified BSD License

Definition at line 44 of file Client.php.

Constructor & Destructor Documentation

◆ __construct()

Sabre\HTTP\Client::__construct ( )

Initializes the client.

Returns
void

Definition at line 72 of file Client.php.

72 {
73
74 $this->curlSettings = [
75 CURLOPT_RETURNTRANSFER => true,
76 CURLOPT_HEADER => true,
77 CURLOPT_NOBODY => false,
78 CURLOPT_USERAGENT => 'sabre-http/' . Version::VERSION . ' (http://sabre.io/)',
79 ];
80
81 }
const VERSION
Full version number.
Definition: Version.php:17

References Sabre\HTTP\Version\VERSION.

Member Function Documentation

◆ addCurlSetting()

Sabre\HTTP\Client::addCurlSetting (   $name,
  $value 
)

Adds a CURL setting.

These settings will be included in every HTTP request.

Parameters
int$name
mixed$value
Returns
void

Definition at line 331 of file Client.php.

331 {
332
333 $this->curlSettings[$name] = $value;
334
335 }

References $name.

Referenced by Sabre\DAV\Client\__construct().

+ Here is the caller graph for this function:

◆ createCurlSettingsArray()

Sabre\HTTP\Client::createCurlSettingsArray ( RequestInterface  $request)
protected

Turns a RequestInterface object into an array with settings that can be fed to curl_setopt.

Parameters
RequestInterface$request
Returns
array

Reimplemented in Sabre\HTTP\ClientMock.

Definition at line 397 of file Client.php.

397 {
398
399 $settings = $this->curlSettings;
400
401 switch ($request->getMethod()) {
402 case 'HEAD' :
403 $settings[CURLOPT_NOBODY] = true;
404 $settings[CURLOPT_CUSTOMREQUEST] = 'HEAD';
405 $settings[CURLOPT_POSTFIELDS] = '';
406 $settings[CURLOPT_PUT] = false;
407 break;
408 case 'GET' :
409 $settings[CURLOPT_CUSTOMREQUEST] = 'GET';
410 $settings[CURLOPT_POSTFIELDS] = '';
411 $settings[CURLOPT_PUT] = false;
412 break;
413 default :
414 $body = $request->getBody();
415 if (is_resource($body)) {
416 // This needs to be set to PUT, regardless of the actual
417 // method used. Without it, INFILE will be ignored for some
418 // reason.
419 $settings[CURLOPT_PUT] = true;
420 $settings[CURLOPT_INFILE] = $request->getBody();
421 } else {
422 // For security we cast this to a string. If somehow an array could
423 // be passed here, it would be possible for an attacker to use @ to
424 // post local files.
425 $settings[CURLOPT_POSTFIELDS] = (string)$body;
426 }
427 $settings[CURLOPT_CUSTOMREQUEST] = $request->getMethod();
428 break;
429
430 }
431
432 $nHeaders = [];
433 foreach ($request->getHeaders() as $key => $values) {
434
435 foreach ($values as $value) {
436 $nHeaders[] = $key . ': ' . $value;
437 }
438
439 }
440 $settings[CURLOPT_HTTPHEADER] = $nHeaders;
441 $settings[CURLOPT_URL] = $request->getUrl();
442 // FIXME: CURLOPT_PROTOCOLS is currently unsupported by HHVM
443 if (defined('CURLOPT_PROTOCOLS')) {
444 $settings[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS;
445 }
446 // FIXME: CURLOPT_REDIR_PROTOCOLS is currently unsupported by HHVM
447 if (defined('CURLOPT_REDIR_PROTOCOLS')) {
448 $settings[CURLOPT_REDIR_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS;
449 }
450
451 return $settings;
452
453 }
foreach($paths as $path) $request
Definition: asyncclient.php:32
$key
Definition: croninfo.php:18
$values

References Sabre\HTTP\Client\$curlSettings, $key, $request, and $values.

Referenced by Sabre\HTTP\Client\doRequest(), and Sabre\HTTP\Client\sendAsyncInternal().

+ Here is the caller graph for this function:

◆ curlExec()

Sabre\HTTP\Client::curlExec (   $curlHandle)
protected

Calls curl_exec.

This method exists so it can easily be overridden and mocked.

Parameters
resource$curlHandle
Returns
string

Reimplemented in Sabre\HTTP\ClientMock.

Definition at line 576 of file Client.php.

576 {
577
578 return curl_exec($curlHandle);
579
580 }

References Sabre\HTTP\Client\$curlHandle.

Referenced by Sabre\HTTP\Client\doRequest().

+ Here is the caller graph for this function:

◆ curlStuff()

Sabre\HTTP\Client::curlStuff (   $curlHandle)
protected

Returns a bunch of information about a curl request.

This method exists so it can easily be overridden and mocked.

Parameters
resource$curlHandle
Returns
array

Reimplemented in Sabre\HTTP\ClientMock.

Definition at line 590 of file Client.php.

590 {
591
592 return [
593 curl_getinfo($curlHandle),
594 curl_errno($curlHandle),
595 curl_error($curlHandle),
596 ];
597
598 }

References Sabre\HTTP\Client\$curlHandle.

Referenced by Sabre\HTTP\Client\parseCurlResult().

+ Here is the caller graph for this function:

◆ doRequest()

Sabre\HTTP\Client::doRequest ( RequestInterface  $request)
protected

This method is responsible for performing a single request.

Parameters
RequestInterface$request
Returns
ResponseInterface

Reimplemented in Sabre\DAV\ClientMock, and Sabre\HTTP\ClientMock.

Definition at line 343 of file Client.php.

343 {
344
345 $settings = $this->createCurlSettingsArray($request);
346
347 if (!$this->curlHandle) {
348 $this->curlHandle = curl_init();
349 }
350
351 curl_setopt_array($this->curlHandle, $settings);
352 $response = $this->curlExec($this->curlHandle);
353 $response = $this->parseCurlResult($response, $this->curlHandle);
354
355 if ($response['status'] === self::STATUS_CURLERROR) {
356 throw new ClientException($response['curl_errmsg'], $response['curl_errno']);
357 }
358
359 return $response['response'];
360
361 }
parseCurlResult($response, $curlHandle)
Parses the result of a curl call in a format that's a bit more convenient to work with.
Definition: Client.php:478
createCurlSettingsArray(RequestInterface $request)
Turns a RequestInterface object into an array with settings that can be fed to curl_setopt.
Definition: Client.php:397
curlExec($curlHandle)
Calls curl_exec.
Definition: Client.php:576
$response

References $response, Sabre\HTTP\Client\createCurlSettingsArray(), Sabre\HTTP\Client\curlExec(), and Sabre\HTTP\Client\parseCurlResult().

Referenced by Sabre\HTTP\Client\send().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parseCurlResult()

Sabre\HTTP\Client::parseCurlResult (   $response,
  $curlHandle 
)
protected

Parses the result of a curl call in a format that's a bit more convenient to work with.

The method returns an array with the following elements:

  • status - one of the 3 STATUS constants.
  • curl_errno - A curl error number. Only set if status is STATUS_CURLERROR.
  • curl_errmsg - A current error message. Only set if status is STATUS_CURLERROR.
  • response - Response object. Only set if status is STATUS_SUCCESS, or STATUS_HTTPERROR.
  • http_code - HTTP status code, as an int. Only set if Only set if status is STATUS_SUCCESS, or STATUS_HTTPERROR
Parameters
string$response
resource$curlHandle
Returns
Response

Reimplemented in Sabre\HTTP\ClientMock.

Definition at line 478 of file Client.php.

478 {
479
480 list(
481 $curlInfo,
482 $curlErrNo,
483 $curlErrMsg
484 ) = $this->curlStuff($curlHandle);
485
486 if ($curlErrNo) {
487 return [
488 'status' => self::STATUS_CURLERROR,
489 'curl_errno' => $curlErrNo,
490 'curl_errmsg' => $curlErrMsg,
491 ];
492 }
493
494 $headerBlob = substr($response, 0, $curlInfo['header_size']);
495 // In the case of 204 No Content, strlen($response) == $curlInfo['header_size].
496 // This will cause substr($response, $curlInfo['header_size']) return FALSE instead of NULL
497 // An exception will be thrown when calling getBodyAsString then
498 $responseBody = substr($response, $curlInfo['header_size']) ?: null;
499
500 unset($response);
501
502 // In the case of 100 Continue, or redirects we'll have multiple lists
503 // of headers for each separate HTTP response. We can easily split this
504 // because they are separated by \r\n\r\n
505 $headerBlob = explode("\r\n\r\n", trim($headerBlob, "\r\n"));
506
507 // We only care about the last set of headers
508 $headerBlob = $headerBlob[count($headerBlob) - 1];
509
510 // Splitting headers
511 $headerBlob = explode("\r\n", $headerBlob);
512
513 $response = new Response();
514 $response->setStatus($curlInfo['http_code']);
515
516 foreach ($headerBlob as $header) {
517 $parts = explode(':', $header, 2);
518 if (count($parts) == 2) {
519 $response->addHeader(trim($parts[0]), trim($parts[1]));
520 }
521 }
522
523 $response->setBody($responseBody);
524
525 $httpCode = intval($response->getStatus());
526
527 return [
528 'status' => $httpCode >= 400 ? self::STATUS_HTTPERROR : self::STATUS_SUCCESS,
529 'response' => $response,
530 'http_code' => $httpCode,
531 ];
532
533 }
const STATUS_CURLERROR
Definition: Client.php:456
curlStuff($curlHandle)
Returns a bunch of information about a curl request.
Definition: Client.php:590
const STATUS_SUCCESS
Definition: Client.php:455
const STATUS_HTTPERROR
Definition: Client.php:457

References Sabre\HTTP\Client\$curlHandle, $header, $response, Sabre\HTTP\Client\curlStuff(), Sabre\HTTP\Client\STATUS_CURLERROR, Sabre\HTTP\Client\STATUS_HTTPERROR, and Sabre\HTTP\Client\STATUS_SUCCESS.

Referenced by Sabre\HTTP\Client\doRequest(), and Sabre\HTTP\Client\poll().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ poll()

Sabre\HTTP\Client::poll ( )

This method checks if any http requests have gotten results, and if so, call the appropriate success or error handlers.

This method will return true if there are still requests waiting to return, and false if all the work is done.

Returns
bool

Definition at line 199 of file Client.php.

199 {
200
201 // nothing to do?
202 if (!$this->curlMultiMap) {
203 return false;
204 }
205
206 do {
207 $r = curl_multi_exec(
208 $this->curlMultiHandle,
209 $stillRunning
210 );
211 } while ($r === CURLM_CALL_MULTI_PERFORM);
212
213 do {
214
215 messageQueue:
216
217 $status = curl_multi_info_read(
218 $this->curlMultiHandle,
219 $messagesInQueue
220 );
221
222 if ($status && $status['msg'] === CURLMSG_DONE) {
223
224 $resourceId = intval($status['handle']);
225 list(
226 $request,
227 $successCallback,
228 $errorCallback,
229 $retryCount,
230 ) = $this->curlMultiMap[$resourceId];
231 unset($this->curlMultiMap[$resourceId]);
232 $curlResult = $this->parseCurlResult(curl_multi_getcontent($status['handle']), $status['handle']);
233 $retry = false;
234
235 if ($curlResult['status'] === self::STATUS_CURLERROR) {
236
237 $e = new ClientException($curlResult['curl_errmsg'], $curlResult['curl_errno']);
238 $this->emit('exception', [$request, $e, &$retry, $retryCount]);
239
240 if ($retry) {
241 $retryCount++;
242 $this->sendAsyncInternal($request, $successCallback, $errorCallback, $retryCount);
243 goto messageQueue;
244 }
245
246 $curlResult['request'] = $request;
247
248 if ($errorCallback) {
249 $errorCallback($curlResult);
250 }
251
252 } elseif ($curlResult['status'] === self::STATUS_HTTPERROR) {
253
254 $this->emit('error', [$request, $curlResult['response'], &$retry, $retryCount]);
255 $this->emit('error:' . $curlResult['http_code'], [$request, $curlResult['response'], &$retry, $retryCount]);
256
257 if ($retry) {
258
259 $retryCount++;
260 $this->sendAsyncInternal($request, $successCallback, $errorCallback, $retryCount);
261 goto messageQueue;
262
263 }
264
265 $curlResult['request'] = $request;
266
267 if ($errorCallback) {
268 $errorCallback($curlResult);
269 }
270
271 } else {
272
273 $this->emit('afterRequest', [$request, $curlResult['response']]);
274
275 if ($successCallback) {
276 $successCallback($curlResult['response']);
277 }
278
279 }
280 }
281
282 } while ($messagesInQueue > 0);
283
284 return count($this->curlMultiMap) > 0;
285
286 }
sendAsyncInternal(RequestInterface $request, callable $success, callable $error, $retryCount=0)
Sends an asynchronous HTTP request.
Definition: Client.php:546
$r
Definition: example_031.php:79
emit($eventName, array $arguments=[], callable $continueCallBack=null)
Emits an event.

References $r, $request, $retry, Sabre\Event\EventEmitterInterface\emit(), Sabre\HTTP\Client\parseCurlResult(), and Sabre\HTTP\Client\sendAsyncInternal().

Referenced by Sabre\HTTP\Client\sendAsync(), and Sabre\HTTP\Client\wait().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ send()

Sabre\HTTP\Client::send ( RequestInterface  $request)

Sends a request to a HTTP server, and returns a response.

Parameters
RequestInterface$request
Returns
ResponseInterface

Definition at line 89 of file Client.php.

89 {
90
91 $this->emit('beforeRequest', [$request]);
92
93 $retryCount = 0;
94 $redirects = 0;
95
96 do {
97
98 $doRedirect = false;
99 $retry = false;
100
101 try {
102
103 $response = $this->doRequest($request);
104
105 $code = (int)$response->getStatus();
106
107 // We are doing in-PHP redirects, because curl's
108 // FOLLOW_LOCATION throws errors when PHP is configured with
109 // open_basedir.
110 //
111 // https://github.com/fruux/sabre-http/issues/12
112 if (in_array($code, [301, 302, 307, 308]) && $redirects < $this->maxRedirects) {
113
114 $oldLocation = $request->getUrl();
115
116 // Creating a new instance of the request object.
117 $request = clone $request;
118
119 // Setting the new location
120 $request->setUrl(Uri\resolve(
121 $oldLocation,
122 $response->getHeader('Location')
123 ));
124
125 $doRedirect = true;
126 $redirects++;
127
128 }
129
130 // This was a HTTP error
131 if ($code >= 400) {
132
133 $this->emit('error', [$request, $response, &$retry, $retryCount]);
134 $this->emit('error:' . $code, [$request, $response, &$retry, $retryCount]);
135
136 }
137
138 } catch (ClientException $e) {
139
140 $this->emit('exception', [$request, $e, &$retry, $retryCount]);
141
142 // If retry was still set to false, it means no event handler
143 // dealt with the problem. In this case we just re-throw the
144 // exception.
145 if (!$retry) {
146 throw $e;
147 }
148
149 }
150
151 if ($retry) {
152 $retryCount++;
153 }
154
155 } while ($retry || $doRedirect);
156
157 $this->emit('afterRequest', [$request, $response]);
158
159 if ($this->throwExceptions && $code >= 400) {
160 throw new ClientHttpException($response);
161 }
162
163 return $response;
164
165 }
doRequest(RequestInterface $request)
This method is responsible for performing a single request.
Definition: Client.php:343
$code
Definition: example_050.php:99
resolve($value)
Returns a Promise that resolves with the given value.
Definition: functions.php:111

References $code, Sabre\HTTP\Client\$maxRedirects, $request, $response, $retry, Sabre\HTTP\Client\doRequest(), Sabre\Event\EventEmitterInterface\emit(), and Sabre\Event\Promise\resolve().

Referenced by Sabre\DAV\Client\options(), Sabre\DAV\Client\propFind(), Sabre\DAV\Client\propPatch(), and Sabre\DAV\Client\request().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ sendAsync()

Sabre\HTTP\Client::sendAsync ( RequestInterface  $request,
callable  $success = null,
callable  $error = null 
)

Sends a HTTP request asynchronously.

Due to the nature of PHP, you must from time to time poll to see if any new responses came in.

After calling sendAsync, you must therefore occasionally call the poll() method, or wait().

Parameters
RequestInterface$request
callable$success
callable$error
Returns
void

Definition at line 181 of file Client.php.

181 {
182
183 $this->emit('beforeRequest', [$request]);
184 $this->sendAsyncInternal($request, $success, $error);
185 $this->poll();
186
187 }
$success
Definition: Utf8Test.php:86
poll()
This method checks if any http requests have gotten results, and if so, call the appropriate success ...
Definition: Client.php:199

References $success, Sabre\Event\EventEmitterInterface\emit(), Sabre\HTTP\Client\poll(), and Sabre\HTTP\Client\sendAsyncInternal().

+ Here is the call graph for this function:

◆ sendAsyncInternal()

Sabre\HTTP\Client::sendAsyncInternal ( RequestInterface  $request,
callable  $success,
callable  $error,
  $retryCount = 0 
)
protected

Sends an asynchronous HTTP request.

We keep this in a separate method, so we can call it without triggering the beforeRequest event and don't do the poll().

Parameters
RequestInterface$request
callable$success
callable$error
int$retryCount

Definition at line 546 of file Client.php.

546 {
547
548 if (!$this->curlMultiHandle) {
549 $this->curlMultiHandle = curl_multi_init();
550 }
551 $curl = curl_init();
552 curl_setopt_array(
553 $curl,
554 $this->createCurlSettingsArray($request)
555 );
556 curl_multi_add_handle($this->curlMultiHandle, $curl);
557 $this->curlMultiMap[intval($curl)] = [
558 $request,
559 $success,
560 $error,
561 $retryCount
562 ];
563
564 }

References $request, $success, and Sabre\HTTP\Client\createCurlSettingsArray().

Referenced by Sabre\HTTP\Client\poll(), and Sabre\HTTP\Client\sendAsync().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ setThrowExceptions()

Sabre\HTTP\Client::setThrowExceptions (   $throwExceptions)

If this is set to true, the Client will automatically throw exceptions upon HTTP errors.

This means that if a response came back with a status code greater than or equal to 400, we will throw a ClientHttpException.

This only works for the send() method. Throwing exceptions for sendAsync() is not supported.

Parameters
bool$throwExceptions
Returns
void

Definition at line 316 of file Client.php.

316 {
317
318 $this->throwExceptions = $throwExceptions;
319
320 }

References Sabre\HTTP\Client\$throwExceptions.

◆ wait()

Sabre\HTTP\Client::wait ( )

Processes every HTTP request in the queue, and waits till they are all completed.

Returns
void

Definition at line 294 of file Client.php.

294 {
295
296 do {
297 curl_multi_select($this->curlMultiHandle);
298 $stillRunning = $this->poll();
299 } while ($stillRunning);
300
301 }

References Sabre\HTTP\Client\poll().

+ Here is the call graph for this function:

Field Documentation

◆ $curlHandle

◆ $curlMultiHandle

Sabre\HTTP\Client::$curlMultiHandle
private

Definition at line 380 of file Client.php.

◆ $curlMultiMap

Sabre\HTTP\Client::$curlMultiMap = []
private

Definition at line 388 of file Client.php.

◆ $curlSettings

Sabre\HTTP\Client::$curlSettings = []
protected

Definition at line 51 of file Client.php.

Referenced by Sabre\HTTP\Client\createCurlSettingsArray().

◆ $maxRedirects

Sabre\HTTP\Client::$maxRedirects = 5
protected

Definition at line 65 of file Client.php.

Referenced by Sabre\HTTP\Client\send().

◆ $throwExceptions

Sabre\HTTP\Client::$throwExceptions = false
protected

Definition at line 58 of file Client.php.

Referenced by Sabre\HTTP\Client\setThrowExceptions().

◆ STATUS_CURLERROR

const Sabre\HTTP\Client::STATUS_CURLERROR = 1

◆ STATUS_HTTPERROR

const Sabre\HTTP\Client::STATUS_HTTPERROR = 2

Definition at line 457 of file Client.php.

Referenced by Sabre\HTTP\Client\parseCurlResult().

◆ STATUS_SUCCESS

const Sabre\HTTP\Client::STATUS_SUCCESS = 0

The documentation for this class was generated from the following file: