Skip to content

Commit 8a73fc2

Browse files
committed
feat(HTTPClient): Provide wrapped access to Guzzle's asyncRequest()
Signed-off-by: Joas Schilling <[email protected]>
1 parent 09c5f99 commit 8a73fc2

5 files changed

Lines changed: 637 additions & 15 deletions

File tree

lib/private/Http/Client/Client.php

Lines changed: 223 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,16 @@
3434
namespace OC\Http\Client;
3535

3636
use GuzzleHttp\Client as GuzzleClient;
37+
use GuzzleHttp\Promise\PromiseInterface;
3738
use GuzzleHttp\RequestOptions;
3839
use OCP\Http\Client\IClient;
40+
use OCP\Http\Client\IPromise;
3941
use OCP\Http\Client\IResponse;
4042
use OCP\Http\Client\LocalServerException;
4143
use OCP\ICertificateManager;
4244
use OCP\IConfig;
4345
use OCP\Security\IRemoteHostValidator;
46+
use Psr\Log\LoggerInterface;
4447
use function parse_url;
4548

4649
/**
@@ -61,7 +64,8 @@ public function __construct(
6164
IConfig $config,
6265
ICertificateManager $certificateManager,
6366
GuzzleClient $client,
64-
IRemoteHostValidator $remoteHostValidator
67+
IRemoteHostValidator $remoteHostValidator,
68+
protected LoggerInterface $logger,
6569
) {
6670
$this->config = $config;
6771
$this->client = $client;
@@ -205,7 +209,7 @@ protected function preventLocalAddress(string $uri, array $options): void {
205209
* 'headers' => [
206210
* 'foo' => 'bar',
207211
* ],
208-
* 'cookies' => ['
212+
* 'cookies' => [
209213
* 'foo' => 'bar',
210214
* ],
211215
* 'allow_redirects' => [
@@ -236,7 +240,7 @@ public function get(string $uri, array $options = []): IResponse {
236240
* 'headers' => [
237241
* 'foo' => 'bar',
238242
* ],
239-
* 'cookies' => ['
243+
* 'cookies' => [
240244
* 'foo' => 'bar',
241245
* ],
242246
* 'allow_redirects' => [
@@ -271,7 +275,7 @@ public function head(string $uri, array $options = []): IResponse {
271275
* 'headers' => [
272276
* 'foo' => 'bar',
273277
* ],
274-
* 'cookies' => ['
278+
* 'cookies' => [
275279
* 'foo' => 'bar',
276280
* ],
277281
* 'allow_redirects' => [
@@ -312,7 +316,7 @@ public function post(string $uri, array $options = []): IResponse {
312316
* 'headers' => [
313317
* 'foo' => 'bar',
314318
* ],
315-
* 'cookies' => ['
319+
* 'cookies' => [
316320
* 'foo' => 'bar',
317321
* ],
318322
* 'allow_redirects' => [
@@ -347,7 +351,7 @@ public function put(string $uri, array $options = []): IResponse {
347351
* 'headers' => [
348352
* 'foo' => 'bar',
349353
* ],
350-
* 'cookies' => ['
354+
* 'cookies' => [
351355
* 'foo' => 'bar',
352356
* ],
353357
* 'allow_redirects' => [
@@ -370,7 +374,7 @@ public function delete(string $uri, array $options = []): IResponse {
370374
}
371375

372376
/**
373-
* Sends a options request
377+
* Sends an OPTIONS request
374378
*
375379
* @param string $uri
376380
* @param array $options Array such as
@@ -382,7 +386,7 @@ public function delete(string $uri, array $options = []): IResponse {
382386
* 'headers' => [
383387
* 'foo' => 'bar',
384388
* ],
385-
* 'cookies' => ['
389+
* 'cookies' => [
386390
* 'foo' => 'bar',
387391
* ],
388392
* 'allow_redirects' => [
@@ -403,4 +407,215 @@ public function options(string $uri, array $options = []): IResponse {
403407
$response = $this->client->request('options', $uri, $this->buildRequestOptions($options));
404408
return new Response($response);
405409
}
410+
411+
protected function wrapGuzzlePromise(PromiseInterface $promise): IPromise {
412+
return new GuzzlePromiseAdapter(
413+
$promise,
414+
$this->logger
415+
);
416+
}
417+
418+
/**
419+
* Sends an asynchronous GET request
420+
*
421+
* @param string $uri
422+
* @param array $options Array such as
423+
* 'query' => [
424+
* 'field' => 'abc',
425+
* 'other_field' => '123',
426+
* 'file_name' => fopen('/path/to/file', 'r'),
427+
* ],
428+
* 'headers' => [
429+
* 'foo' => 'bar',
430+
* ],
431+
* 'cookies' => [
432+
* 'foo' => 'bar',
433+
* ],
434+
* 'allow_redirects' => [
435+
* 'max' => 10, // allow at most 10 redirects.
436+
* 'strict' => true, // use "strict" RFC compliant redirects.
437+
* 'referer' => true, // add a Referer header
438+
* 'protocols' => ['https'] // only allow https URLs
439+
* ],
440+
* 'sink' => '/path/to/file', // save to a file or a stream
441+
* 'verify' => true, // bool or string to CA file
442+
* 'debug' => true,
443+
* 'timeout' => 5,
444+
* @return IPromise
445+
*/
446+
public function getAsync(string $uri, array $options = []): IPromise {
447+
$this->preventLocalAddress($uri, $options);
448+
$response = $this->client->requestAsync('get', $uri, $this->buildRequestOptions($options));
449+
return $this->wrapGuzzlePromise($response);
450+
}
451+
452+
/**
453+
* Sends an asynchronous HEAD request
454+
*
455+
* @param string $uri
456+
* @param array $options Array such as
457+
* 'headers' => [
458+
* 'foo' => 'bar',
459+
* ],
460+
* 'cookies' => [
461+
* 'foo' => 'bar',
462+
* ],
463+
* 'allow_redirects' => [
464+
* 'max' => 10, // allow at most 10 redirects.
465+
* 'strict' => true, // use "strict" RFC compliant redirects.
466+
* 'referer' => true, // add a Referer header
467+
* 'protocols' => ['https'] // only allow https URLs
468+
* ],
469+
* 'sink' => '/path/to/file', // save to a file or a stream
470+
* 'verify' => true, // bool or string to CA file
471+
* 'debug' => true,
472+
* 'timeout' => 5,
473+
* @return IPromise
474+
*/
475+
public function headAsync(string $uri, array $options = []): IPromise {
476+
$this->preventLocalAddress($uri, $options);
477+
$response = $this->client->requestAsync('head', $uri, $this->buildRequestOptions($options));
478+
return $this->wrapGuzzlePromise($response);
479+
}
480+
481+
/**
482+
* Sends an asynchronous POST request
483+
*
484+
* @param string $uri
485+
* @param array $options Array such as
486+
* 'body' => [
487+
* 'field' => 'abc',
488+
* 'other_field' => '123',
489+
* 'file_name' => fopen('/path/to/file', 'r'),
490+
* ],
491+
* 'headers' => [
492+
* 'foo' => 'bar',
493+
* ],
494+
* 'cookies' => [
495+
* 'foo' => 'bar',
496+
* ],
497+
* 'allow_redirects' => [
498+
* 'max' => 10, // allow at most 10 redirects.
499+
* 'strict' => true, // use "strict" RFC compliant redirects.
500+
* 'referer' => true, // add a Referer header
501+
* 'protocols' => ['https'] // only allow https URLs
502+
* ],
503+
* 'sink' => '/path/to/file', // save to a file or a stream
504+
* 'verify' => true, // bool or string to CA file
505+
* 'debug' => true,
506+
* 'timeout' => 5,
507+
* @return IPromise
508+
*/
509+
public function postAsync(string $uri, array $options = []): IPromise {
510+
$this->preventLocalAddress($uri, $options);
511+
512+
if (isset($options['body']) && is_array($options['body'])) {
513+
$options['form_params'] = $options['body'];
514+
unset($options['body']);
515+
}
516+
517+
return $this->wrapGuzzlePromise($this->client->requestAsync('post', $uri, $this->buildRequestOptions($options)));
518+
}
519+
520+
/**
521+
* Sends an asynchronous PUT request
522+
*
523+
* @param string $uri
524+
* @param array $options Array such as
525+
* 'body' => [
526+
* 'field' => 'abc',
527+
* 'other_field' => '123',
528+
* 'file_name' => fopen('/path/to/file', 'r'),
529+
* ],
530+
* 'headers' => [
531+
* 'foo' => 'bar',
532+
* ],
533+
* 'cookies' => [
534+
* 'foo' => 'bar',
535+
* ],
536+
* 'allow_redirects' => [
537+
* 'max' => 10, // allow at most 10 redirects.
538+
* 'strict' => true, // use "strict" RFC compliant redirects.
539+
* 'referer' => true, // add a Referer header
540+
* 'protocols' => ['https'] // only allow https URLs
541+
* ],
542+
* 'sink' => '/path/to/file', // save to a file or a stream
543+
* 'verify' => true, // bool or string to CA file
544+
* 'debug' => true,
545+
* 'timeout' => 5,
546+
* @return IPromise
547+
*/
548+
public function putAsync(string $uri, array $options = []): IPromise {
549+
$this->preventLocalAddress($uri, $options);
550+
$response = $this->client->requestAsync('put', $uri, $this->buildRequestOptions($options));
551+
return $this->wrapGuzzlePromise($response);
552+
}
553+
554+
/**
555+
* Sends an asynchronous DELETE request
556+
*
557+
* @param string $uri
558+
* @param array $options Array such as
559+
* 'body' => [
560+
* 'field' => 'abc',
561+
* 'other_field' => '123',
562+
* 'file_name' => fopen('/path/to/file', 'r'),
563+
* ],
564+
* 'headers' => [
565+
* 'foo' => 'bar',
566+
* ],
567+
* 'cookies' => [
568+
* 'foo' => 'bar',
569+
* ],
570+
* 'allow_redirects' => [
571+
* 'max' => 10, // allow at most 10 redirects.
572+
* 'strict' => true, // use "strict" RFC compliant redirects.
573+
* 'referer' => true, // add a Referer header
574+
* 'protocols' => ['https'] // only allow https URLs
575+
* ],
576+
* 'sink' => '/path/to/file', // save to a file or a stream
577+
* 'verify' => true, // bool or string to CA file
578+
* 'debug' => true,
579+
* 'timeout' => 5,
580+
* @return IPromise
581+
*/
582+
public function deleteAsync(string $uri, array $options = []): IPromise {
583+
$this->preventLocalAddress($uri, $options);
584+
$response = $this->client->requestAsync('delete', $uri, $this->buildRequestOptions($options));
585+
return $this->wrapGuzzlePromise($response);
586+
}
587+
588+
/**
589+
* Sends an asynchronous OPTIONS request
590+
*
591+
* @param string $uri
592+
* @param array $options Array such as
593+
* 'body' => [
594+
* 'field' => 'abc',
595+
* 'other_field' => '123',
596+
* 'file_name' => fopen('/path/to/file', 'r'),
597+
* ],
598+
* 'headers' => [
599+
* 'foo' => 'bar',
600+
* ],
601+
* 'cookies' => [
602+
* 'foo' => 'bar',
603+
* ],
604+
* 'allow_redirects' => [
605+
* 'max' => 10, // allow at most 10 redirects.
606+
* 'strict' => true, // use "strict" RFC compliant redirects.
607+
* 'referer' => true, // add a Referer header
608+
* 'protocols' => ['https'] // only allow https URLs
609+
* ],
610+
* 'sink' => '/path/to/file', // save to a file or a stream
611+
* 'verify' => true, // bool or string to CA file
612+
* 'debug' => true,
613+
* 'timeout' => 5,
614+
* @return IPromise
615+
*/
616+
public function optionsAsync(string $uri, array $options = []): IPromise {
617+
$this->preventLocalAddress($uri, $options);
618+
$response = $this->client->requestAsync('options', $uri, $this->buildRequestOptions($options));
619+
return $this->wrapGuzzlePromise($response);
620+
}
406621
}

lib/private/Http/Client/ClientService.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
use OCP\IConfig;
3838
use OCP\Security\IRemoteHostValidator;
3939
use Psr\Http\Message\RequestInterface;
40+
use Psr\Log\LoggerInterface;
4041

4142
/**
4243
* Class ClientService
@@ -59,6 +60,7 @@ public function __construct(
5960
DnsPinMiddleware $dnsPinMiddleware,
6061
IRemoteHostValidator $remoteHostValidator,
6162
IEventLogger $eventLogger,
63+
protected LoggerInterface $logger,
6264
) {
6365
$this->config = $config;
6466
$this->certificateManager = $certificateManager;
@@ -87,6 +89,7 @@ public function newClient(): IClient {
8789
$this->certificateManager,
8890
$client,
8991
$this->remoteHostValidator,
92+
$this->logger,
9093
);
9194
}
9295
}

0 commit comments

Comments
 (0)