Async HTTP/1.1+2 client for PHP based on Amp.

Overview

HTTP Client

This package provides an asynchronous HTTP client for PHP based on Amp. Its API simplifies standards-compliant HTTP resource traversal and RESTful web service consumption without obscuring the underlying protocol. The library manually implements HTTP over TCP sockets; as such it has no dependency on ext/curl.

Features

Installation

This package can be installed as a Composer dependency.

composer require amphp/http-client

Additionally, you might want to install the nghttp2 library to take advantage of FFI to speed up and reduce the memory usage on PHP 7.4.

Documentation

Documentation is bundled within this repository in the docs directory.

Examples

More extensive code examples reside in the examples directory.

Versioning

amphp/http-client follows the semver semantic versioning specification like all other amphp packages.

Everything in an Internal namespace or marked as @internal is not public API and therefore not covered by BC guarantees.

4.x

Stable and recommended version.

3.x

Legacy version. Use amphp/artax as package name instead.

2.x

No longer maintained. Use amphp/artax as package name instead.

1.x

No longer maintained. Use amphp/artax as package name instead.

Security

If you discover any security related issues, please email [email protected] instead of using the issue tracker.

License

The MIT License (MIT). Please see LICENSE for more information.

Comments
  • Stop the client request in 1 second

    Stop the client request in 1 second

    $client = new Amp\Artax\DefaultClient;
    

    I want to stop all the client requests with 1s, if they not completed.

    Is it possible ? and could you suggest the best way?

    question 
    opened by sajumani 26
  • Async Simple request

    Async Simple request

    I'm not sure, but I don't think the async client is for this. But how do you do a simple asynchronous GET, POST, PUT or DELETE. That is, simply sending the request, but not caring about the retrieval or waiting for the retrieval?

    opened by CMCDragonkai 20
  • Cannot multiplex requests on a single H2 connection

    Cannot multiplex requests on a single H2 connection

    Spotted at https://github.com/symfony/symfony/pull/35115#issuecomment-572057741

    The following script adapted from the examples doesn't multiplex the requests. Note that we limit to one single connection. If we remove this limit, one connection per request is made and all works concurrently - but then this is no different than using HTTP/1.1.

    <?php
    
    use Amp\Http\Client\Connection\LimitedConnectionPool;
    use Amp\Http\Client\Connection\UnlimitedConnectionPool;
    use Amp\Http\Client\HttpClientBuilder;
    use Amp\Http\Client\HttpException;
    use Amp\Http\Client\Request;
    use Amp\Http\Client\Response;
    use Amp\Loop;
    use Amp\Sync\LocalKeyedSemaphore;
    
    require __DIR__ . '/vendor/autoload.php';
    
    Loop::run(static function () use ($argv) {
        $uris = [];
    
        for ($i = 0; $i < 379; ++$i) {
            $uris[] = "https://http2.akamai.com/demo/tile-$i.png";
        }
    
        // Instantiate the HTTP client
        $pool = LimitedConnectionPool::byHost(new UnlimitedConnectionPool, new LocalKeyedSemaphore(1));
        $client = (new HttpClientBuilder)
                ->usingPool($pool)
                ->build();
    
        $requestHandler = static function (string $uri) use ($client) {
            /** @var Response $response */
            $response = yield $client->request(new Request($uri));
    
            return yield $response->getBody()->buffer();
        };
    
        try {
            $promises = [];
    
            foreach ($uris as $uri) {
                $promises[$uri] = Amp\call($requestHandler, $uri);
            }
    
            $bodies = yield $promises;
    
            foreach ($bodies as $uri => $body) {
                print $uri . " - " . \strlen($body) . " bytes" . PHP_EOL;
            }
        } catch (HttpException $error) {
            // If something goes wrong Amp will throw the exception where the promise was yielded.
            // The HttpClient::request() method itself will never throw directly, but returns a promise.
            echo $error;
        }
    });
    
    opened by nicolas-grekas 19
  • Segmentation Fault

    Segmentation Fault

    Can't pin down what's causing the segmentation fault, but here's all of the available information for a possible diagnosis. It seems to happen with responses that have JSON bodies of 1KB+.

    This URL is has a large response: https://gist.github.com/2upmedia/5e6dd469237a652f43703ccd964d9d0e#file-amp-concurrency-test-php-L94

    This one is small: https://gist.github.com/2upmedia/5e6dd469237a652f43703ccd964d9d0e#file-amp-concurrency-test-php-L95

    You may have to run it several times to see the problem with the following command:

    RUN_WITHOUT_BENCH=1 php70 -d xdebug.auto_trace=ON -d xdebug.trace_output_dir=/tmp/xdebug_trace amp-concurrent-test.php && echo $?
    

    https://gist.github.com/2upmedia/5e6dd469237a652f43703ccd964d9d0e

    xdebug 
    opened by jorgecolonconsulting 19
  • 10x+ memory usage in https vs http

    10x+ memory usage in https vs http

    PHP 7.4.12 / Amphp 4.5.2

    This is not a leak, but a stable excessive (10x+) memory usage in https vs http. There should be some overhead, but 10x+ is likely due to something wrong and very avoidable.

    This is the minimal code to replicate the problem (make sure there is no cache):

    use Amp\Http\Client\HttpClientBuilder;
    use Amp\Http\Client\Request;
    use Amp\Loop;
    
    
    Loop::run(function () {
        /**
         *   http      2-4 MB RAM, depending on OS.
         *   https   40-48 MB RAM, depending on OS
         *
         *   Try both below:
         *   (example.com is an actual working server)
         */
    
        $url = 'https://example.com';
    
        $client   = HttpClientBuilder::buildDefault();
        $promise  = $client->request(new Request($url));
        $response = yield $promise;
        $body     = yield $response->getBody()->buffer();
    
        echo 'Mem: ' . memory_get_usage(true) / 1048576 . ' MB';
    });
    
    opened by keiviv 15
  • Cannot perform GET requests to local apache webserver setup with VirtualDocumentRoot

    Cannot perform GET requests to local apache webserver setup with VirtualDocumentRoot

    Hi guys, I have a problem similar to the issue #138 but it happens in a very weird manner so I don't think is related to that issue but the error message is the same: Socket disconnected prior to response completion (Parser state: 0). I'll explain the whole story.

    I have a Mac Book Pro as a development machine and I have a simply Apache + PHP + MySQL setup. I have to work on several projects so to speedup the setup of every new project I configured Apache with VirtualDocumentRoot directive (here an example of my configuration http://roberto-montero.com/blog/how-setup-xampp-use-virtualdocumentroot-mac-os-x). I have also a virtual host configured for localhost whose document root is the root of my workspace (the directory which contains all of my projects, ~/Work/Projects). So if go to http://localhost/phpinfo.php, I get the phpinfo located in the root of all my projects (~/Work/Projects/phpinfo.php). Instead if I go to http://myproject.dev/phpinfo.php I get the phpinfo located in the directory of "myproject" (~/Work/Projects/myproject/phpinfo.php).

    Ok, given this scenario, I wanted to use this async HTTP client to perform HTTP requests against a project which I'm working on.

    So I installed artax using composer and simply copy & pasted your example n. 1 (https://github.com/amphp/artax/blob/master/examples/1-get-request.php) to perform a simple GET request.

    First I tried with the URL provided in the example (https://httpbin.org/user-agent) and it worked. But then, I tried with my local project using the URL http://myproject.dev/phpinfo.php, and this last trial didn't work. I got the error Socket disconnected prior to response completion (Parser state: 0). After several trials I figured out that if I use http://localhost/phpinfo.php it works. So I tried with several different request to other resources/projects and the pattern that I found is that:

    • Requests to resources under http://localhost/ are working
    • Requests to resources under VirtualDocumentRoot virtual hosts (like http://myproject.dev/) are not working.

    Please note that all of them are served from my dev machine (so Apache is the same, PHP is the same, etc...) and all my trials are with the same sample script.

    So it seems (but I would like to confirm) that there is some weird circumstance that cause that error only if use a VirtualDocumentRoot virtual host.

    Now, I would like to understand what the f**k is going on but I have no idea where to start. Do you guys have any suggestion? 😄

    Thank you.

    opened by mmenozzi 14
  • Add connection-limiting pool

    Add connection-limiting pool

    Not sure on the name, suggestions welcome.

    Should we deprecate LimitedConnectionPool or rename it (with an alias of the old name) to SingleStreamConnectionPool or leave it as-is?

    Closes #252.

    opened by trowski 13
  • Randomly amp.http.client.har.timings.complete is missing

    Randomly amp.http.client.har.timings.complete is missing

    When using RecordHarAttributes sometimes after a response completes the attribute amp.http.client.har.timings.complete is missing.

    I cannot reproduce this consistently. It seems to be random.

    This is what i use:

    $builder = (new HttpClientBuilder)
                ->interceptNetwork(new DecompressResponse());
    
    $client = $builder->build();
    
    $promise = call(function () use ($client, $url) {
        $request = new Request($url);
        $request->addEventListener(new RecordHarAttributes());
    
        $response = yield $client->request($request);
        yield $response->getBody()->buffer();
    
        ///   Symfony\Component\Debug\Exception\FatalThrowableError  : The requested attribute 'amp.http.client.har.timings.complete' does not exist
         $responseTime = $response->getOriginalRequest()->getAttribute(HarAttributes::TIME_COMPLETE) - $response->getOriginalRequest()->getAttribute(HarAttributes::TIME_START);
    
    });
    $responses = wait(all([$promise]));
    

    It is possible that its related to redirects, some of the domains i try do have redirects, but it still happens randomly

    question 
    opened by duronrulez 13
  • Request hangs with keep alive and non-native loop driver

    Request hangs with keep alive and non-native loop driver

    Sometimes requests hang infinetely (or until socket is closed remotely). Insights so far: Request hangs in read loop in DefaultClient::doRead after header is received. Normally it hangs in the last response chunk. Symptom before hang: 0 bytes are read from reader stream (ResourceInputStream) and then the socket never becomes readable again.

    Script to reproduce:

    https://gist.github.com/brstgt/3533deadce54dac4d1807a01de6f2d82

    Problem normally appears after 10-200 iterations.

    IMPORTANT: Problem does NOT occur if connection is not keep-alive (header 'Connection: close') OR if the NativeDriver is used

    bug 
    opened by brstgt 13
  • out of Memory

    out of Memory

    I am using Artax to replace Guzzle for non-blocking async requests. everything works fine but I found that the memory usage is increased rapidly.

    $request = new Artax\Request($url, $method);
    
    switch ($method) {
    	case "POST":
    		$request = $request->withHeader('Content-Type', 'application/json');
    		$request = $request->withBody(json_encode($data));
    		break;
    }
    
    $client = new Artax\DefaultClient;
    $client->setOption(Artax\Client::OP_TRANSFER_TIMEOUT, 5000);
    $response = yield $client->request($request);
    $body = yield $response->getBody();
    
    opened by shtse8 13
  • Crypto negotiation failed

    Crypto negotiation failed

    codes used

    
    $promises[$URI] = Amp\call(function () use ($client, $URI) {
                        // "yield" inside a coroutine awaits the resolution of the promise
                        // returned from Client::request(). The generator is then continued.
                        $response = yield $client->request($URI);
    
                        // Same for the body here. Yielding an Amp\ByteStream\Message
                        // buffers the entire message.
                        $body = yield $response->getStatus();
    
                        return $body;
                    });
    
                $responses = Amp\Promise\wait(Amp\Promise\all($promises));
    
    

    below is error output

    Fatal error: Uncaught Amp\Socket\CryptoException: Crypto negotiation failed: stream_socket_enable_crypto(): SSL operation failed with code 1. OpenSSL Error messages:
    error:1414D172:SSL routines:tls12_check_peer_sigalg:wrong signature type in /var/www/html/vendor/amphp/socket/src/Internal/functions.php:118
    Stack trace:
    #0 /var/www/html/vendor/amphp/amp/lib/Loop/NativeDriver.php(172): Amp\Socket\Internal\{closure}('am', Resource id #293, Object(Amp\Deferred))
    #1 /var/www/html/vendor/amphp/amp/lib/Loop/NativeDriver.php(68): Amp\Loop\NativeDriver->selectStreams(Array, Array, 4.782)
    #2 /var/www/html/vendor/amphp/amp/lib/Loop/Driver.php(130): Amp\Loop\NativeDriver->dispatch(true)
    #3 /var/www/html/vendor/amphp/amp/lib/Loop/Driver.php(70): Amp\Loop\Driver->tick()
    #4 /var/www/html/vendor/amphp/amp/lib/Loop.php(76): Amp\Loop\Driver->run()
    #5 /var/www/html/vendor/amphp/amp/lib/functions.php(158): Amp\Loop::run(Object(Closure))
    #6 /var/www/html/parseradvance.php(77): Amp\Promise\wait(Object(Amp\Internal\PrivatePromise))
    #7 {main}
      t in /var/www/html/vendor/amphp/socket/src/Internal/functions.php on line 118
    
    opened by waleedmazhar 12
  • HTTP/2 connection closed via amphp/http-tunnel

    HTTP/2 connection closed via amphp/http-tunnel

    192.168.1.187:8888 is a http proxy provide by tinyproxy, I use amphp/http-tunnel to use http proxy, often see this error:

    [2023-01-04 00:01:24 715] Amp\Http\Client\Connection\Http2ConnectionException: The HTTP/2 connection from '192.168.1.60:48006' to '192.168.1.187:8888' closed in /home/web/apps/t-task-wind/releases/96/vendor/amphp/http-client/src/Connection/Internal/Http2ConnectionProcessor.php:1281
    Stack trace:
    #0 [internal function]: Amp\Http\Client\Connection\Internal\Http2ConnectionProcessor->run()
    #1 /home/web/apps/t-task-wind/releases/96/vendor/amphp/amp/lib/Coroutine.php(118): Generator->send()
    #2 /home/web/apps/t-task-wind/releases/96/vendor/amphp/amp/lib/Internal/Placeholder.php(149): Amp\Coroutine->Amp\{closure}()
    #3 /home/web/apps/t-task-wind/releases/96/vendor/amphp/amp/lib/Deferred.php(53): Amp\Promise@anonymous->resolve()
    #4 /home/web/apps/t-task-wind/releases/96/vendor/amphp/byte-stream/lib/ResourceInputStream.php(101): Amp\Deferred->resolve()
    #5 /home/web/apps/t-task-wind/releases/96/vendor/amphp/amp/lib/Loop/EvDriver.php(59): Amp\ByteStream\ResourceInputStream::Amp\ByteStream\{closure}()
    #6 [internal function]: Amp\Loop\EvDriver->Amp\Loop\{closure}()
    #7 /home/web/apps/t-task-wind/releases/96/vendor/amphp/amp/lib/Loop/EvDriver.php(234): EvLoop->run()
    #8 /home/web/apps/t-task-wind/releases/96/vendor/amphp/amp/lib/Loop/Driver.php(138): Amp\Loop\EvDriver->dispatch()
    #9 /home/web/apps/t-task-wind/releases/96/vendor/amphp/amp/lib/Loop/Driver.php(72): Amp\Loop\Driver->tick()
    #10 /home/web/apps/t-task-wind/releases/96/vendor/amphp/amp/lib/Loop/EvDriver.php(186): Amp\Loop\Driver->run()
    #11 /home/web/apps/t-task-wind/releases/96/vendor/amphp/amp/lib/Loop.php(95): Amp\Loop\EvDriver->run()
    ...
    

    And this is the log of tinyproxy at 00:01:24:

    INFO      Jan 04 00:01:11 [2273380]: Closed connection between local client (fd:7) and remote client (fd:8)
    CONNECT   Jan 04 00:01:24 [2291398]: Connect (file descriptor 7): 192.168.1.60 [192.168.1.60] at [192.168.1.187]
    CONNECT   Jan 04 00:01:24 [2291398]: Request (file descriptor 7): CONNECT example.com:443 HTTP/1.1
    INFO      Jan 04 00:01:24 [2291398]: No upstream proxy for example.com
    INFO      Jan 04 00:01:24 [2291398]: opensock: opening connection to example.com:443
    INFO      Jan 04 00:01:24 [2291398]: opensock: getaddrinfo returned for example.com:443
    CONNECT   Jan 04 00:01:24 [2291398]: Established connection to host "example.com" using file descriptor 8.
    INFO      Jan 04 00:01:24 [2291398]: Not sending client headers to remote machine
    CONNECT   Jan 04 00:01:24 [2291819]: Connect (file descriptor 7): 192.168.1.60 [192.168.1.60] at [192.168.1.187]
    CONNECT   Jan 04 00:01:24 [2291819]: Request (file descriptor 7): CONNECT login.example.com:443 HTTP/1.1
    INFO      Jan 04 00:01:24 [2291819]: No upstream proxy for login.example.com
    INFO      Jan 04 00:01:24 [2291819]: opensock: opening connection to login.example.com:443
    INFO      Jan 04 00:01:24 [2291819]: opensock: getaddrinfo returned for login.example.com:443
    CONNECT   Jan 04 00:01:24 [2291819]: Established connection to host "login.example.com" using file descriptor 8.
    INFO      Jan 04 00:01:24 [2291819]: Not sending client headers to remote machine
    INFO      Jan 04 00:01:24 [2291819]: Closed connection between local client (fd:7) and remote client (fd:8)
    CONNECT   Jan 04 00:01:24 [2304987]: Connect (file descriptor 7): 192.168.1.60 [192.168.1.60] at [192.168.1.187]
    CONNECT   Jan 04 00:01:24 [2304987]: Request (file descriptor 7): CONNECT login.example.com:443 HTTP/1.1
    INFO      Jan 04 00:01:24 [2304987]: No upstream proxy for login.example.com
    INFO      Jan 04 00:01:24 [2304987]: opensock: opening connection to login.example.com:443
    INFO      Jan 04 00:01:24 [2304987]: opensock: getaddrinfo returned for login.example.com:443
    CONNECT   Jan 04 00:01:24 [2304987]: Established connection to host "login.example.com" using file descriptor 8.
    INFO      Jan 04 00:01:24 [2304987]: Not sending client headers to remote machine
    INFO      Jan 04 00:01:24 [2304987]: Closed connection between local client (fd:7) and remote client (fd:8)
    CONNECT   Jan 04 00:01:24 [2297292]: Connect (file descriptor 7): 192.168.1.60 [192.168.1.60] at [192.168.1.187]
    CONNECT   Jan 04 00:01:24 [2297292]: Request (file descriptor 7): CONNECT login.example.com:443 HTTP/1.1
    INFO      Jan 04 00:01:24 [2297292]: No upstream proxy for login.example.com
    INFO      Jan 04 00:01:24 [2297292]: opensock: opening connection to login.example.com:443
    INFO      Jan 04 00:01:24 [2297292]: opensock: getaddrinfo returned for login.example.com:443
    CONNECT   Jan 04 00:01:24 [2297292]: Established connection to host "login.example.com" using file descriptor 8.
    INFO      Jan 04 00:01:24 [2297292]: Not sending client headers to remote machine
    INFO      Jan 04 00:01:24 [2297292]: Closed connection between local client (fd:7) and remote client (fd:8)
    CONNECT   Jan 04 00:01:27 [2283968]: Connect (file descriptor 7): 192.168.1.60 [192.168.1.60] at [192.168.1.188]
    

    I have try to change proxy to socks5 by microsocks, and use this example https://github.com/amphp/http-client/blob/master/examples/proxy/socks5.php to use socks5 proxy, the error still happend sometimes.

    opened by xpader 2
  • v5: segmentation fault (SIGPIPE using gdb) requesting some urls

    v5: segmentation fault (SIGPIPE using gdb) requesting some urls

    The following script sometimes throws "Segmentation fault" GDB shows this error when running the same script:

    alpine: Program received signal SIGPIPE, Broken pipe. 0x00007fafa0dc44a3 in ?? () from /lib/ld-musl-x86_64.so.1

    wheezy: Program received signal SIGPIPE, Broken pipe. 0x00007f5757905fb3 in __libc_write (fd=8, buf=0x560a390f44d3, nbytes=24) at ../sysdeps/unix/sysv/linux/write.c:26

    <?php
    
    use Amp\Future;
    use Amp\Http\Client\HttpClientBuilder;
    use Amp\Http\Client\HttpException;
    use Amp\Http\Client\Request;
    use function Amp\async;
    
    require(__DIR__. "/../../vendor/autoload.php");
    
    $uris = [
        "https://google.com/",
        "https://jsonplaceholder.typicode.com/todos/1",
        "https://nonexistingdomainwtfisthis.com",
    ];
    
    // Instantiate the HTTP client
    $client = HttpClientBuilder::buildDefault();
    
    $requestHandler = static function (string $uri) use ($client): string {
        $request = new Request($uri);
        $request->setHeader("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/81.0");
    
        $response = $client->request($request);
        return $response->getBody()->buffer();
    };
    
    try {
        $startGlobal = microtime(true);
    
        $futures = [];
        foreach ($uris as $uri) {
            $futures[$uri] = async(function () use ($requestHandler, $uri) {
                try {
                    $start = microtime(true);
                    $future = async(fn() => $requestHandler($uri));
                    $response = $future->await();
                    $end = microtime(true) - $start;
    
                    print $uri . " - " . strlen($response) . " bytes after $end seconds" . PHP_EOL;
                } catch (\Exception $error) {
                    printf("%s: %s\n", "test", $error->getMessage());
                }
            });
        }
    
        $ignore = Future\await($futures);
    
        $endGlobal = microtime(true) - $startGlobal;
        print "Finished after $endGlobal seconds" . PHP_EOL;
    } catch (HttpException $error) {
        // If something goes wrong Amp will throw the exception where the promise was yielded.
        // The HttpClient::request() method itself will never throw directly, but returns a promise.
        var_dump($error);
    }
    
    php -v and php -m
    bash-5.1# php -v
    PHP 8.1.12 (cli) (built: Nov 16 2022 20:54:15) (ZTS)
    Copyright (c) The PHP Group
    Zend Engine v4.1.12, Copyright (c) Zend Technologies
        with Zend OPcache v8.1.12, Copyright (c), by Zend Technologies
    bash-5.1# php -m
    [PHP Modules]
    Core
    ctype
    curl
    date
    dom
    fileinfo
    filter
    ftp
    hash
    iconv
    json
    libxml
    mbstring
    mysqlnd
    openssl
    pcntl
    pcre
    PDO
    pdo_mysql
    pdo_sqlite
    Phar
    posix
    readline
    redis
    Reflection
    session
    SimpleXML
    sodium
    SPL
    sqlite3
    standard
    tokenizer
    xml
    xmlreader
    xmlwriter
    Zend OPcache
    zlib
    
    [Zend Modules]
    Zend OPcache
    
    opened by maxgalbu 1
  • BC break: v5 `Request::setBody` should accept `null`

    BC break: v5 `Request::setBody` should accept `null`

    v5 Request::setBody should accept null because it did in v4. Also, WTF is up with int and float?

    https://github.com/amphp/http-client/blob/92b60c132de57708a0255bdf05e9b2974f4a5047/src/Request.php#L222-L230

    opened by Bilge 0
  • Implementing PSR-18 adapter for amphp/http-client v5

    Implementing PSR-18 adapter for amphp/http-client v5

    Thanks to fibers, the amphp/http-client v5 has a "sync" interface: it gets rid of promises & generators. It is now possible to implement the PSR-18: HTTP Client.

    Benefits:

    opened by GromNaN 3
  • HttpClient v5 startRequest event called multiple times.

    HttpClient v5 startRequest event called multiple times.

    I'm noticing a weird behaviour with startRequest event being called multiple times for a single request.

    I'm using an event handler based on RecordHarAttributes and I was going to count the number of requests in addition to timings. When I incremented requests count in startRequest() I noticed the number is very high and it turned out startRequest() is called 9 times with the same URI/Request object. Is that by design?

    Also, is completeReceivingResponse() called for failed requests as well? If yes, it might be the best place to increment requests count. For now I'm incrementing it in startSendingRequest().

    function fetch(Request $request, HttpClient $client, LocalSemaphore $semaphore, HttpRequestTimings $timings): string
    {
        $lock = $semaphore->acquire();
        $request->addEventListener($timings);
        $response = $client->request($request);
    
        if ($response->getStatus() !== 200) {
            throw new \Exception($response->getStatus() . " " . $response->getReason());
        }
    
        $body = $response->getBody()->buffer();
    
        $lock->release();
    
        return $body;
    }
    
    opened by whataboutpereira 0
Releases(v5.0.0-beta.7)
  • v5.0.0-beta.7(Jan 8, 2023)

    • Fixed compatibility with v2.0 of amphp/byte-stream by updating ReadableStream implementations to also implement Traversable.
    • Fixed assigning the stream ID to HTTP/2 streams to guarantee stream IDs are sent sequentially to the server
    • Fixed CancelledException being wrapped in an HttpException when a request is cancelled
    Source code(tar.gz)
    Source code(zip)
  • v5.0.0-beta.6(Nov 18, 2022)

    • Fixed HEAD requests using HTTP/2 when a Content-Length header was included in the response.
    • Fixed a memory leak in the HTTP/2 handler due to the write fiber not being destroyed.
    Source code(tar.gz)
    Source code(zip)
  • v5.0.0-beta.5(Nov 7, 2022)

  • v5.0.0-beta.4(Oct 4, 2022)

  • v5.0.0-beta.3(Jun 16, 2022)

    • Fixed a memory leak in the HTTP/2 connection processor when reusing a connection over a long period of time
    • Removed deprecated exception classes Http2ConnectionException and Http2StreamException.
    Source code(tar.gz)
    Source code(zip)
  • v5.0.0-beta.2(May 9, 2022)

    • Fixed #302 where reusing an idle HTTP/1.1 connection may cause the connection to hang.
    • Fixed reusing a closed connection in the connection pool.
    Source code(tar.gz)
    Source code(zip)
  • v5.0.0-beta.1(Apr 24, 2022)

    What's Changed

    • Based on PHP 8.1 and Fibers using Revolt.
    • Removed Promise wrapper types from return types everywhere.
    • Changed timeout unit from milliseconds to seconds.
    • Removed Amp\Htt\Client\Connection\LimitedConnectionPool, see StreamLimitingPool instead.

    New Contributors

    • @iggyvolz made their first contribution in https://github.com/amphp/http-client/pull/299

    Full Changelog: https://github.com/amphp/http-client/compare/v4.6.2...v5.0.0-beta.1

    Source code(tar.gz)
    Source code(zip)
  • v4.6.2(Oct 9, 2021)

  • v4.6.1(Jul 12, 2021)

  • v4.6.0(Jun 29, 2021)

  • v4.5.5(Dec 28, 2020)

  • v4.5.4(Nov 29, 2020)

    • Avoid increasing HTTP/2 window size if too many bytes are buffered locally, avoiding exploding buffers if the consumer is slow.
    • Fix inactivity timeout on HTTP/2 with slow consumers Slowly reading the response shouldn't result in inactivity timeouts if the server is responsive.
    • Check for HTTP/1 connection closing while idle (#279)
    Source code(tar.gz)
    Source code(zip)
  • v4.5.3(Nov 22, 2020)

    • Account for server window changes when discarding data frames If streams are cancelled, this might result in hanging connections, because the client thinks the server window is still large enough and doesn't increase it.
    • Fixed potential state synchronization errors with async event listeners
    • Write stream window increments asynchronously, avoiding increments for already closed streams
    • Improved exception messages
    Source code(tar.gz)
    Source code(zip)
  • v4.5.2(Nov 3, 2020)

  • v4.5.1(Oct 25, 2020)

    • Retry idempotent requests on Http2ConnectionException
    • Fix graceful HTTP/2 connection shutdown
    • Improve behavior if HTTP/2 connections become unresponsive
    Source code(tar.gz)
    Source code(zip)
  • v4.5.0(Jul 21, 2020)

  • v4.4.1(Jul 10, 2020)

    • Reject pushes with invalid stream ID
    • Fix potential double stream release, which might result in int → float overflows and thus type errors
    Source code(tar.gz)
    Source code(zip)
  • v4.4.0(Jun 16, 2020)

    This version fixes a security weakness that might leak sensitive request headers from the initial request to the redirected host on cross-domain redirects, which were not removed correctly. Message::setHeaders does not replace the entire set of headers, but only operates on the headers matching the given array keys, see fa79253.

    • Support direct HTTP/2 connections without TLS (#271)
    • Security: Remove headers on cross-domain redirects
    Source code(tar.gz)
    Source code(zip)
  • v4.3.1(May 16, 2020)

    • Relax "conflict" rule with amphp/file to allow dev-master installations with Composer v1.x (#267, composer/composer#8856)
    • Error if request URI provides a relative path instead of sending an invalid request (#269)
    Source code(tar.gz)
    Source code(zip)
  • v4.3.0(May 3, 2020)

    • Added inactivity timeout (#263) This provides a separate timeout while waiting for the response or streaming the body. If no data is received for the response within the given number of milliseconds, the request fails similarly to the transfer timeout.
    • Close idle connections if there are too many Requesting URLs from many hosts without reusing connections will otherwise result in resource exhaustion due to too many open files.
    • Improved types for static analysis
    Source code(tar.gz)
    Source code(zip)
  • v4.2.2(Mar 17, 2020)

  • v4.2.1(Mar 7, 2020)

  • v4.2.0(Feb 27, 2020)

    • Add improved ConnectionLimitingPool

      The new ConnectionLimitingPool limits connections instead of streams. In addition, it has improved connection handling, racing between new connections and existing connections becoming available once the limit has been reached. The older LimitedConnectionPool has been renamed to StreamLimitingPool with a class alias for backward compatibility.

    • Don't set ALPN if only HTTP/1.1 is enabled, which allows connections to certain misbehaving servers (#255)

    Source code(tar.gz)
    Source code(zip)
  • v4.1.0(Jan 17, 2020)

    • Fix possible double resolution of promises (#244)
    • Fix assertion error on invalid HTTP/2 frame (#236)
    • Fix HTTP/2 connection reuse if too many concurrent streams for one connection are in use (#246)
    • Allow skipping default accept, accept-encoding and user-agent headers (#238)
    • Keep original header case for HTTP/1 requests (#250)
    • Allow access to informational responses (1XX) (#239)
    • Await startReceiveResponse event listeners on HTTP/2 before resolving the response promise (#254)
    • Delay startReceiveResponse event until the final response is started to be received, instead of calling it for the first byte or multiple times for HTTP/2 (#254)
    • Use common HTTP/2 parser from amphp/http
    Source code(tar.gz)
    Source code(zip)
  • v4.1.0-rc1(Jan 6, 2020)

    • Removed (internal) HTTP/2 parser in this library in favor of a shared parser in amphp/http.
    • Fixed problem where occasionally a promise was resolved twice in Http1Connection (#244)
    Source code(tar.gz)
    Source code(zip)
  • v4.0.0(Dec 21, 2019)

    Initial release of amphp/http-client, the successor of amphp/artax. This is a major rewrite to support interceptors and HTTP/2.

    Major Changes

    • Support for HTTP/2 (including push)
    • Support for interceptors to customize behavior
    • Switch to a mutable Request / Response API, because streams are not immutable
    • Compatibility with amphp/socket@^1
    • Compatibility with amphp/file@^1
    • Compatibility with league/uri@^6
    Source code(tar.gz)
    Source code(zip)
  • v4.0.0-rc11(Dec 12, 2019)

    Note: This is a pre-release, there might be breaking changes in the final stable version.

    • Forbid CONNECT requests on HTTP/2
    • Upgrade to amphp/hpack@^3 to make use of nghttp2 using FFI on PHP 7.4 if available
    Source code(tar.gz)
    Source code(zip)
  • v4.0.0-rc10(Dec 4, 2019)

    Note: This is a pre-release, there might be breaking changes in the final stable version.

    • Refactored HTTP/2 to split parsing from frame handling logic.
    • Fixed upgrade handling to close the socket only on error.
    • Fixed default HTTP/2 push port.
    • Fixed HTTP/2 backpressure.
    • Fixed HTTP/2 stream weight.
    • Decoupled UnlimitedConnectionPool from hardcoded HTTP versions.
    • Responses are now only returned after sending the request finished.
    • Removed Http2Exception.
    Source code(tar.gz)
    Source code(zip)
  • v4.0.0-rc9(Nov 20, 2019)

    Note: This is a pre-release, there might be breaking changes in the final stable version.

    • Added EventListener with additional responsibilities for ConnectionPool, Stream and DelegateHttpClient implementations.
    • Added LimitedConnectionPool to limit concurrent requests per host
    • Added LogHttpArchive allowing to inspect request timings visually
    • Changed HttpClient to be a final class instead of an interface
    • Changed redirect policy to only follow automatically with GET requests
    • Application interceptors doing retries or follow-up requests must now manually clone the request if they wish to reuse it. Previously any HttpClient implementation was required to automatically clone at every layer.
    • Http1Connection::__construct() requires an instance of EncryptableSocket instead of Socket now.
    • Http1Connection reuses connections without explicit keep-alive header for idempotent requests now.
    • Pushed requests validate the authority automatically now.
    • Renamed IfOrigin to MatchOrigin and changed the implementation to map multiple origins.
    • Requests can now set an upgrade handler to opt-into connection upgrades, e.g. for WebSocket connections or CONNECT tunnels.
    • Removed default interceptors from PooledHttpClient and moved them into HttpClientBuilder
    • Removed pings on idle Http2Connection::request() improving the overall latency.
    • Removed ConditionalInterceptor
    • Renamed Request::getPushCallable() to Request::getPushHandler()
    • Renamed Request::onPush() to Request::setPushHandler()
    • Renamed DefaultConnectionPool to UnlimitedConnectionPool
    • 1XX responses are properly skipped now.
    • Removed Connection::MAX_KEEP_ALIVE_TIMEOUT constant.
    • Removed ConnectionPool::getProtocolVersions()
    Source code(tar.gz)
    Source code(zip)
  • v4.0.0-rc8(Nov 5, 2019)

    Note: This is a pre-release, there might be breaking changes in the final stable version.

    • Updated to league/uri@^6. Consequentially, PHP 7.2+ is now required.
    Source code(tar.gz)
    Source code(zip)
Owner
AMPHP
AMPHP is a collection of event-driven libraries for PHP designed with fibers and concurrency in mind.
AMPHP
Simple HTTP cURL client for PHP 7.1+ based on PSR-18

Simple HTTP cURL client for PHP 7.1+ based on PSR-18 Installation composer require sunrise/http-client-curl QuickStart composer require sunrise/http-f

Sunrise // PHP 15 Sep 5, 2022
Declarative HTTP Clients using Guzzle HTTP Library and PHP 8 Attributes

Waffler How to install? $ composer require waffler/waffler This package requires PHP 8 or above. How to test? $ composer phpunit Quick start For our e

Waffler 3 Aug 26, 2022
Guzzle, an extensible PHP HTTP client

Guzzle, PHP HTTP client Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and trivial to integrate with web services. Simple interf

Guzzle 22.3k Jan 2, 2023
A Chainable, REST Friendly, PHP HTTP Client. A sane alternative to cURL.

Httpful Httpful is a simple Http Client library for PHP 7.2+. There is an emphasis of readability, simplicity, and flexibility – basically provide the

Nate Good 1.7k Dec 21, 2022
PHP's lightweight HTTP client

Buzz - Scripted HTTP browser Buzz is a lightweight (<1000 lines of code) PHP 7.1 library for issuing HTTP requests. The library includes three clients

Kris Wallsmith 1.9k Jan 4, 2023
HTTPlug, the HTTP client abstraction for PHP

HTTPlug HTTPlug, the HTTP client abstraction for PHP. Intro HTTP client standard built on PSR-7 HTTP messages. The HTTPlug client interface is compati

The PHP HTTP group 2.4k Dec 30, 2022
Unirest in PHP: Simplified, lightweight HTTP client library.

Unirest for PHP Unirest is a set of lightweight HTTP libraries available in multiple languages, built and maintained by Mashape, who also maintain the

Kong 1.3k Dec 28, 2022
↪️ Bypass for PHP creates a custom HTTP Server to return predefined responses to client requests

Bypass for PHP provides a quick way to create a custom HTTP Server to return predefined responses to client requests.Useful for tests with Pest PHP or PHPUnit.

CiaReis 101 Dec 1, 2022
A PHP proxy to solve client browser HTTP CORS(cross-origin) restrictions.

cors-bypass-proxy A PHP proxy to solve client browser HTTP CORS(cross-origin) restrictions. A simple way to solve CORS issue when you have no access t

Gracious Emmanuel 15 Nov 17, 2022
Zenscrape package is a simple PHP HTTP client-provider that makes it easy to parsing site-pages

Zenscrape package is a simple PHP HTTP client-provider that makes it easy to parsing site-pages

Andrei 3 Jan 17, 2022
Event-driven, streaming HTTP client and server implementation for ReactPHP

HTTP Event-driven, streaming HTTP client and server implementation for ReactPHP. This HTTP library provides re-usable implementations for an HTTP clie

ReactPHP 640 Dec 29, 2022
HTTP header kit for PHP 7.1+ (incl. PHP 8) based on PSR-7

HTTP header kit for PHP 7.1+ (incl. PHP 8) based on PSR-7 Installation composer require sunrise/http-header-kit How to use? HTTP Header Collection Mor

Sunrise // PHP 63 Dec 31, 2022
TusPHP - 🚀a HTTP based protocol for resumable file uploads.

tus is a HTTP based protocol for resumable file uploads. Resumable means you can carry on where you left off without re-uploading whole data again in case of any interruptions. An interruption may happen willingly if the user wants to pause, or by accident in case of a network issue or server outage.

Ankit Pokhrel 1.3k Dec 28, 2022
LittleProxy is a high performance HTTP proxy written in Java atop Trustin Lee's excellent Netty event-based networking library

LittleProxy is a high performance HTTP proxy written in Java atop Trustin Lee's excellent Netty event-based networking library

null 1.9k Dec 26, 2022
Express.php is a new HTTP - Server especially made for RESTful APIs written in PHP.

express.php Express.php is a new HTTP - Server especially made for RESTful APIs written in PHP. Features Fast The Library is handles requests fast and

null 5 Aug 19, 2022
Requests for PHP is a humble HTTP request library. It simplifies how you interact with other sites and takes away all your worries.

Requests for PHP Requests is a HTTP library written in PHP, for human beings. It is roughly based on the API from the excellent Requests Python librar

null 3.5k Dec 31, 2022
Requests for PHP is a humble HTTP request library. It simplifies how you interact with other sites and takes away all your worries.

Requests for PHP Requests is a HTTP library written in PHP, for human beings. It is roughly based on the API from the excellent Requests Python librar

null 3.5k Dec 31, 2022
PHP Curl Class makes it easy to send HTTP requests and integrate with web APIs

PHP Curl Class: HTTP requests made easy PHP Curl Class makes it easy to send HTTP requests and integrate with web APIs. Installation Requirements Quic

null 3.1k Jan 5, 2023
A simple PHP Toolkit to parallel generate combinations, save and use the generated terms to brute force attack via the http protocol.

Brutal A simple PHP Toolkit to parallel generate combinations, save and use the generated terms to apply brute force attack via the http protocol. Bru

Jean Carlo de Souza 4 Jul 28, 2021