GithubHelp home page GithubHelp logo

reactphp / http Goto Github PK

View Code? Open in Web Editor NEW
721.0 38.0 142.0 1.43 MB

Event-driven, streaming HTTP client and server implementation for ReactPHP.

Home Page: https://reactphp.org/http/

License: MIT License

PHP 100.00%
response-stream php reactphp http http-server http-client https streaming-request streaming-response

http's People

Contributors

51imyyy avatar aaronbonneau avatar andig avatar arnaud-lb avatar beaucollins avatar carusogabriel avatar cboden avatar christoph-kluge avatar clue avatar dinooo13 avatar ebimmel-ysp avatar fritz-gerneth avatar greevex avatar iannsp avatar igorw avatar jorrit avatar jsor avatar kalessil avatar legionth avatar marenzo avatar nhedger avatar nopolabs avatar onigoetz avatar pablojoan avatar pavog avatar reedy avatar seregazhuk avatar simonfrings avatar slava-vishnyakov avatar wyrihaximus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

http's Issues

Package guzzle/parser is abandoned

When installing react/http through composer, the following error is issued:

Package guzzle/parser is abandoned, you should avoid using it. Use guzzle/guzzle instead.

The error can be ignored, but it would probably be wise to update that dependency.

RequestHeaderParser causing server unusable when POST body exceeds 4096

The header size limits here, evaluates the entire HTTP request's size strlen($data) where $data contains everything read from Stream, whose data event emitted here.

My solution is to change:

        if (strlen($this->buffer) + strlen($data) > $this->maxSize) {

into:

        @list($header,) = explode("\r\n\r\n", $data);
        if (strlen($this->buffer) + strlen($header) > $this->maxSize) {

If it's ok, then I'll submit a PR regarding this issue.

Handling data and end events

Why next code not working with 0.4 version?

$loop = \React\EventLoop\Factory::create();
$socket = new \React\Socket\Server($loop);
$http = new \React\Http\Server($socket);
$http->on('request', function (\React\Http\Request $request, \React\Http\Response $response) {

    $contentLength = 0;
    $request->on('data', function ($data) use (&$contentLength) {
        $contentLength += strlen($data);
    });

    $request->on('end', function () use ($response, &$contentLength){
        $response->writeHead(200, array('Content-Type' => 'text/plain'));
        $response->end("The length of the submitted request body is: " . $contentLength);
    });

    // an error occures e.g. on invalid chunked encoded data or an unexpected 'end' event
    $request->on('error', function (\Exception $exception) use ($response, &$contentLength) {
        $response->writeHead(400, array('Content-Type' => 'text/plain'));
        $response->end("An error occured while reading at length: " . $contentLength);
    });

});
$socket->listen(8080);
$loop->run();

seems that end event not emmiting

Support detecting request body

Proper detection of request message bodies requires:

  • Content-Length
  • Chunked transfer encoding (#96)
  • Empty bodies for certain requests

See https://tools.ietf.org/html/rfc7230#section-3.3

This means that we should take these into account and only emit data events for what is actually part of the given request and then emit an end and close event.

This is also a prerequisite for #39.

Chrome only: Emits additional `error` events for HTTPS only (Unable to complete SSL/TLS handshake)

When i run the 02-hello-world-https.php example, it does work (seeing "hello world" in a browser).

But I am also seeing this error:

php examples/02-hello-world-https.php 
Listening on https://0.0.0.0:8443
exception 'UnexpectedValueException' with message 'Unable to complete SSL/TLS handshake: ' in /Users/*********/Projects/http/vendor/react/socket/src/StreamEncryption.php:112
Stack trace:
#0 /Users/*********/Projects/http/vendor/react/socket/src/StreamEncryption.php(78): React\Socket\StreamEncryption->toggleCrypto(Resource id #28, Object(React\Promise\Deferred), true)
#1 [internal function]: React\Socket\StreamEncryption->React\Socket\{closure}(Resource id #28, Object(React\EventLoop\StreamSelectLoop))
#2 /Users/*********/Projects/http/vendor/react/event-loop/src/StreamSelectLoop.php(232): call_user_func(Object(Closure), Resource id #28, Object(React\EventLoop\StreamSelectLoop))
#3 /Users/*********/Projects/http/vendor/react/event-loop/src/StreamSelectLoop.php(201): React\EventLoop\StreamSelectLoop->waitForStreamActivity(NULL)
#4 /Users/*********/Projects/http/examples/02-hello-world-https.php(29): React\EventLoop\StreamSelectLoop->run()
#5 {main}exception 'UnexpectedValueException' with message 'Unable to complete SSL/TLS handshake: ' in /Users/*********/Projects/http/vendor/react/socket/src/StreamEncryption.php:112
Stack trace:
#0 /Users/*********/Projects/http/vendor/react/socket/src/StreamEncryption.php(78): React\Socket\StreamEncryption->toggleCrypto(Resource id #55, Object(React\Promise\Deferred), true)
#1 [internal function]: React\Socket\StreamEncryption->React\Socket\{closure}(Resource id #55, Object(React\EventLoop\StreamSelectLoop))
#2 /Users/*********/Projects/http/vendor/react/event-loop/src/StreamSelectLoop.php(232): call_user_func(Object(Closure), Resource id #55, Object(React\EventLoop\StreamSelectLoop))
#3 /Users/*********/Projects/http/vendor/react/event-loop/src/StreamSelectLoop.php(201): React\EventLoop\StreamSelectLoop->waitForStreamActivity(NULL)
#4 /Users/*********/Projects/http/examples/02-hello-world-https.php(29): React\EventLoop\StreamSelectLoop->run()
#5 {main}

Also I think the response time might be low side.

I did have to include a cafile in the example code

$loop = Factory::create();
$socket = new Server(isset($argv[1]) ? $argv[1] : '0.0.0.0:8443', $loop);
$socket = new SecureServer($socket, $loop, array(
    'local_cert' => $argv[2]. '/bin/combined.pem',
    'cafile' => $argv[2]. '/bin/intermediate.pem',
));

stop server but continue loop

Is it possible to stop server, but continue main loop?

I am trying with

        $this->socket->shutdown();

but it ends whole script.

Testing the response

I'm trying to write a unit test, in an application that uses https://packagist.org/packages/react/react, where I want to know if the Response objects has been written successfully. You know, header is set properly to return status 200, it contains some text that is going to be returned to the browser, maybe that isWriteable() is false and all of that.

What is the proper way of checking that?

Getting a request's body seems overly complex

So just been in chat asking about getting the request body. I just think it could be improved and this seems like a better forum, since it's got longer text.

@igorw and @cboden pointed out that it's meant to be streamed/piped. And were helpful in pointing me in the direction of the information to get the request body. I can achieve getting the body data in multiple ways, but in each case it seems that I'm getting the data after the request has finished. This could just be me doing it wrong. My latest trial can be found at https://gist.github.com/icambridge/d8c1ea63cce6733bc5d5 I did also manage to get the data using the on data event and again this was executed after the request was over.

I think personally that the body should be an attribute in request object as it clearly belongs to that request. I also think it should be easy to fetch. I do understand the desire to keep memory low when you don't know what size the body will be, however in some cases you have a rough idea and that it could be small. So my idea is to refactor the server class so you can change RequestHeaderParser if you desire to so it returns a BodiedRequest object so if you want it to be a simple getBody you can do so. I'm willing to do the leg work I just don't want to spend time doing then have some point out all the things wrong with that approach.

Request Draining

I want to restart my React/HTTP server process periodically based on various criteria. Is there a way to make sure that all active connections/requests are finished, & to stop accepting new requests while they are finishing, before I shut down the server process?

The current code looks something like this:

$request->on('end', function () {
  // blah blah blah...
  $response->writeHead($status_code, $output_headers);
  $response->end($returnContent);
  // Auto-recycling of daemon.
  if ($current_memory_usage > $memory_limit || $requests_served > $request_limit || time() >= $time_to_live) {
    $response->close();
    shell_exec('/usr/local/bin/supervisorctl restart daemonchild:' . $pid);
   }
});

Currently the shutdown code prevents the request that triggered it from completing, i.e., no data is returned to the client, even though $response->end($returnContent); is called before the shutdown code. In addition, it seems that any new requests coming in while the server is shutting down will fail as well.

So, is connection draining a possibility?

PS: I have also tried putting the shutdown code in $request->on('close', function()});, but with the same result.

Response is never sent

I'm try the hello world example . Copied it to my directory as index.php then run:

ฮป php index.php 8080

Got:

Listening on http://127.0.0.1:8080

But when I access http://127.0.0.1:8080 in Chrome it just hangs on "Loading..." infinitely.

Any clues?

Env:

ฮป ver&&php -v&&cat composer.json                                                        
                                                                                        
Microsoft Windows [Version 10.0.15063]                                                  
PHP 7.1.3 (cli) (built: Mar 14 2017 23:33:39) ( ZTS MSVC14 (Visual C++ 2015) x64 )      
Copyright (c) 1997-2017 The PHP Group                                                   
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies                           
{                                                                                       
    "require": {                                                                        
        "react/http": "^0.6.0"                                                          
    }                                                                                   
}                                                                                       

PSR-7 Message Implementation: ringcentral vs guzzle

I've recently started noticing my build to fail when testing for lowest version constraint on its dependencies. Turns our this is caused by a conflict between reactphp/http@dev-master and guzzlehttp/[email protected]:

Error:

PHP Fatal error:  Cannot redeclare GuzzleHttp\Psr7\str() (previously declared in /home/travis/build/volkszaehler/volkszaehler.org/vendor/guzzlehttp/psr7/src/functions.php:17) in /home/travis/build/volkszaehler/volkszaehler.org/vendor/ringcentral/psr7/src/functions.php on line 39
Fatal error: Cannot redeclare GuzzleHttp\Psr7\str() (previously declared in /home/travis/build/volkszaehler/volkszaehler.org/vendor/guzzlehttp/psr7/src/functions.php:17) in /home/travis/build/volkszaehler/volkszaehler.org/vendor/ringcentral/psr7/src/functions.php on line 39

Conflicting versions:

Installing guzzlehttp/psr7 (1.0.0) Loading from cache
Installing ringcentral/psr7 (1.0.0) Downloading: 100%

Working versions:

Installing ringcentral/psr7 (1.2.1) Downloading: 100%
Installing guzzlehttp/psr7 (1.3.1) Loading from cache

As of 6.0, guzzle requires guzzlehttp/psr7:~1.0 just as reactphp/http requires ringcentral/psr7:~1.0. Conflict seems to be resolved as of ringcentral/psr7:^1.2 independently from the guzzlehttp version (tested starting at 6.0).

I'd like to propose to either switch to guzzlehttp/psr7 or upgrade ringcentral/psr7:^1.2 to avoid this conflict (couldn't find out which benefits ringcentral has- definitely less often used according to packagist).

Of course it's possible to work around this on client side but... time consuming :/

Update realized ringcentral is needed for PHP 5.3 compatibility (brrrh). So upgrading to 1.2 would be the suggested approach. On the other hand react/eventloop already demands 5.4 so 5.3 support is out of question anyway? guzzlehttp/psr7 is on php 5.4 as of v1.0.

Timeout

How can I timeout a request after like 10 seconds?

Allow Higher versions of Guzzle

with v3.9.2 out there are issues creeping up since react relies on the 3.0.* parser and http from guzzle.

In my case I was just messing around with BowerPHP.

Warning: unable to shutdown socket

When I close browser tab.

I get log.
Warning: unable to shutdown socket [57]: Socket is not connected in /Users/vahan/Development/tcp-server/vendor/react/socket/src/Connection.php on line 27

Question: What is the right way to send huge content or live stream content?

Seems above code does not work as I expect.
How can force flush the content to the browser.

$loop = React\EventLoop\Factory::create();
$socket = new React\Socket\Server($loop);

$http = new React\Http\Server($socket);
$http->on('request', function ($request, $response) {
    $response->writeHead(200, array('Content-Type' => 'video/mp4'));
    $fp = fopen('Path/to/some/real/big/video.mp4', 'r');
    while (!feof($fp)) {
        $response->write(fread($fp, 1024 * 10));
    }
    fclose($fp);

    $response->end();
});

$socket->listen(1337);
$loop->run();

Request getBody() method

Hi guys I am trying to implement reactphp with symfony version 2.8 by following this tutorial ( https://gnugat.github.io/2016/04/13/super-speed-sf-react-php.html ).

Symfony request constructor need following parameters

  • Constructor.
  • @param array $query The GET parameters
  • @param array $request The POST parameters
  • @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...)
  • @param array $cookies The COOKIE parameters
  • @param array $files The FILES parameters
  • @param array $server The SERVER parameters
  • @param string|resource $content The raw body data

in older version of react we have method
getBody() and getFile() and two classes RequestParser and MultiPartParser

I want to ask how I get body content to parse post and FIles to send post and FILES to symfony 2.8.

Raw Body Content

Is there a way of accessing the raw body content of requests sent to React HTTP Server? For example, PATCH requests to an API where the content-type submitted is JSON, XML, or similar.

If not, do you think this will get implemented at some point in the near or far future? I'd try it myself but most of this is way over my head ๐Ÿ˜ข

POST w/ empty data causes exception

Hi, POST w/ empty data causes exception w/ message: "Undefined index: content-type":

POST /path/to/endpoint HTTP/1.1
Host: example.com
Connection: keep-alive
Content-Length: 0  <-- POST data is empty, XMLHttpRequest set it to 0
Pragma: no-cache
Cache-Control: no-cache
Accept: application/json, text/javascript, */*; q=0.01
Origin: http://example2.com/
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36
Referer: http://example2.com/test.html
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8

Possible patch:

--- a/src/StreamingBodyParser/Factory.php
+++ b/src/StreamingBodyParser/Factory.php
@@ -16,7 +16,8 @@ class Factory
         $headers = array_change_key_case($headers, CASE_LOWER);

         if (
-            !isset($headers['content-type']) && !isset($headers['content-length'])
+            (!isset($headers['content-type']) && !isset($headers['content-length'])) ||
+            (isset($headers['content-length']) && $headers['content-length'] == 0)
         ) {
             return new NoBodyParser($request);
         }

Thanks

Header names are not case-sensitive

https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2

Each header field consists of a name followed by a colon (":") and the field value. Field names are case-insensitive

Currently the code heavily relies on case-sensitive names.

Also Content-Type can contain a charset or additional information after ; character. Example: Content-Type: application/x-www-form-urlencoded; charset=utf-8 Such header break currently content parsing because of this.

We tried to fix it in PPM: https://github.com/php-pm/php-pm/blob/master/React/RequestParser.php#L18, but I believe we should fix it directly in reactphp/http.

Add write possibility to HttpBodyStream

Will this be correct if we'll change current write method in this way:

old:

public function write($string)
{
    throw new \BadMethodCallException();
}

new:

public function write($string)
{
    $this->input->emit('data', [$string]);
    return strlen($string);
}

I think it will make HttpBodyStream more compatible with PSR-7. I'm sure other changes need to be added, but just want to throw an idea.

Implement PSR-7

I think it would be useful to implement PSR-7 Request\Response. Is it possible?

Actually "unstable"?

I noticed the repo description says "unstable". I'm not very familiar with the project. Is that still accurate?

Pause/resume on request not working

Hi,

Why do we have this code in Server class?

$request->on('pause', function () use ($conn) {
    $conn->emit('pause');
});
$request->on('resume', function () use ($conn) {
    $conn->emit('resume');
});

I have changed emit's to correct methods (pause/resume), like this:

$request->on('pause', function () use ($conn) {
    $conn->pause();
});
$request->on('resume', function () use ($conn) {
    $conn->resume();
});

And now pausing works.

Is this a leak or something?

Versions:

$ uname -a
Linux dev.qfox.ru 3.2.0-4-486 #1 Debian 3.2.51-1 i686 GNU/Linux
$ php -v
PHP 5.4.38-1~dotdeb.1 (cli) (built: Feb 19 2015 22:21:23)
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2014 Zend Technologies
    with Xdebug v2.3.1, Copyright (c) 2002-2015, by Derick Rethans

I have a simple file app.php:

require 'vendor/autoload.php';

$app = function ($request, $response) {
    $response->writeHead(200, array('Content-Type' => 'text/plain'));
    $response->end("Hello World\n");
};

$loop = React\EventLoop\Factory::create();
$socket = new React\Socket\Server($loop);
$http = new React\Http\Server($socket, $loop);

$http->on('request', $app);
echo "Server running at http://0.0.0.0:1337\n";

$socket->listen(1337, '0.0.0.0');
$loop->run();

With installed react/http (here is my composer.json):

{
    "require": {
        "react/http": "0.3.*"
    }
}

Running it:

$ php app.php
Server running at http://127.0.0.1:1337

And sending 10k requests:

$ ab -n 10000 -c 500 http://localhost:1337/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
apr_socket_recv: Connection reset by peer (104)
Total of 9953 requests completed

Why some of requests was reseted by peer? Something is wrong?

Parse request body

We should provide an easier way to access the parsed request body, i.e. $_POST values from HTML forms, file uploads etc.

This depends on detecting actual message lengths first, see #104.

I'm filing this mostly for the reference, there's been some discussion to wait for PSR-7 message support (#28) first.

[BUG] Invalid POSTfields parsing in RequestParser

There some bug in a postfields parsing in file
https://github.com/reactphp/http/blob/master/src/RequestParser.php#L138

Need to replace

parse_str(urldecode($content), $result);

with

parse_str($content, $result);

Example:

// example postfields
$data = [
    'url' => 'http://somedomain/?field1=v1&field2=v2',
    'flag' => 1
];

$string = http_build_query($data);
// encoded to post body as
// url=http%3A%2F%2Fsomedomain%2F%3Ffield1%3Dv1%26field2%3Dv2&flag=1

// So, right way to parse
$result = null;
parse_str($string, $result);
var_dump($result);

array(2) {
  'url' =>
  string(38) "http://somedomain/?field1=v1&field2=v2"
  'flag' =>
  string(1) "1"
}

// and wrong way to parse
$result = null;
parse_str(urldecode($string), $result);
var_dump($result);

array(3) {
  'url' =>
  string(28) "http://somedomain/?field1=v1"
  'field2' =>
  string(2) "v2"
  'flag' =>
  string(1) "1"
}

Merge HttpClient component into this component

Here's the current situation:

  • This Http component: Event-driven, streaming plaintext HTTP and secure HTTPS server for ReactPHP.
  • HttpClient component: Asynchronous HTTP client library.

This is not exactly ideal, they share quite a bit of common code.

Also, I believe this situation may be a bit confusing for consumers of this package. In particular our Datagram component provides both client and server side for datagram sockets (UDP).

As such, I'd vote for merging these two components into a single Http component.

Roadmap to stable v1.0.0

Let's face it, this project is currently beta, but has been used in production for years :shipit:

We're currently following a v0.X.Y release scheme (http://sentimentalversioning.org/).

We should finally make this stable and fully adhere to SemVer and release a stable v1.0.0.

To a large extend, a stable v1.0.0 helps making BC breaks more explicit and thus the whole project more reliable from a consumer perspective. This project is actively maintained and has received some major updates in the last weeks and has some major updates planned in the next weeks. Given our current versioning scheme, we'd like to ensure all anticipated BC breaks will be merged before the planned v1.0.0 release.

As such, I've set up a roadmap that enlists only the major changes for each version among with planned release dates towards a stable v1.0.0 release:

v0.4.4 โœ…

  • Released 2017-02-13
  • Headers PSR-7 and case-insensitive
  • Version constraints
  • Stream empty data events and back-pressure

v0.5.0 โœ…

  • Released 2017-02-16
  • Request PSR-7 methods
  • Reduce public API
  • Socket component v0.5 and secure HTTPS

v0.6.0 โœ…

  • Released 2017-03-09
  • Chunked transfer encoding and Content-Length
  • Stream data, end and close behavior
  • Stream v0.5 API
  • HTTP/1.1 and HTTP/1.0
  • No longer considered beta quality

v0.7.0 โœ…

  • Released 2017-05-29
  • Streaming PSR-7 support
  • Request-In-Response-Out callbacks

v0.8.0 โœ…

  • Released 2017-12-12
  • Full PSR-7 support
  • Form submissions, including POST fields and file uploads
  • Middleware request handler arrays

v1.0.0 โœ…

  • Released 2020-07-11
  • New HTTP client
  • Clean up Server APIs
  • LTS

This ticket aims to serve as a basic overview and does not contain every single change. Please also see the milestone links and the CHANGELOG for more details.

Obviously, this roadmap is subject to change and I'll try to keep it updated as we progress. In order to avoid cluttering this, please keep discussion in this ticket to a minimum and consider reaching out to us through new tickets or Twitter etc.

http and pawl within same loop

Hey folks,

ist this possible? I want to expose a HTTP POST request and forward to Ratchet Websocket Server.
I would like in detail NOT open and close a socket connection with every POST. So the idea with one same loop.

$loop = React\EventLoop\Factory::create();
$socket = new React\Socket\Server($loop);
$connector = new Ratchet\Client\Connector($loop);


$http = new React\Http\Server($socket);
$http->on('request', function ($request, $response, $connector, $loop) {

    if ($request->getMethod() == "POST") {

        $connector('ws://127.0.0.1:1338')
            ->then(function (Ratchet\Client\WebSocket $conn) {
                $conn->on('message', function (\Ratchet\RFC6455\Messaging\MessageInterface $msg) use ($conn) {
                    echo "Received: {$msg}\n";
                    $conn->close();
                });

                $conn->on('close', function ($code = null, $reason = null) {
                    echo "Connection closed ({$code} - {$reason})\n";
                });

                $conn->send(json_encode([
                    'id' => rand(1, 5),
                    'type' => 'Typoe',
                    'message' => 'Lorem lipsum',
                    'source' => 'Test',
                    'good' => rand(0, 1),
                    'bad' => rand(0, 1)
                ]));

            }, function (\Exception $e) use ($loop) {
                echo "Could not connect: {$e->getMessage()}\n";
                $loop->stop();
            });


        $response->writeHead(200, array('Content-Type' => 'text/plain'));
        $response->end("Hello World!\n" . print_r($request->getMethod()));

    } else {
        $response->writeHead(501, array('Content-Type' => 'text/plain'));
        $response->end("Not Implemented!\n" . print_r($request->getMethod()));
    }
});


$socket->listen(5000);
$loop->run();

Error:
Fatal error: Uncaught Error: Function name must be a string in http.php:22
Line 22 is:
$connector('ws://127.0.0.1:1338')

PS: Thanks for pushing PHP to the next level :-)

Header Problems

Problem:
Array to String Converstion

Description:
PSR-7 dictates the format of the Headers as a key with a collection of header-lines.

Offending Code:
https://github.com/reactphp/http/blob/master/src/Response.php#L85

Reproducible:
Yes

Context:
I was attempting to bridge Slim's PSR-7 HTTP objects into React.

Code:

    try {
        /** @var $slimResponse  Response */
        $slimResponse = $slim($slimRequest, new Response());

        //This below line constructs the React Response with Slim Data
        $response->writeHead($slimResponse->getStatusCode(), $slimResponse->getHeaders());
        $slimResponse->getBody()->rewind();
        $response->end($slimResponse->getBody()->getContents());
    } catch (Exception $e) {
        $response->writeHead(500, array('Content-Type' => 'text/html'));
        $response->end('Internal Server Error');
    }

Question: why are my handlers being called twice?

I have the following snippet, which is a class method:

public function start(OutputInterface &$output)
{
    $loop = Factory::create();
    $socket = new Server($loop);
    $http = new \React\Http\Server($socket);
    $http->on('request', [$this, 'manageRequest']);
    $socket->listen(3440);
    $loop->run();
}

Now, my class has the 'manageRequest' method:

public function manageRequest($request, $response)
{
    echo "I'm managing a request!", PHP_EOL;
}

When accessing http://localhost:3440, I get the correct message: I'm managing a request!.

However, if I decide to respond to the browser request with a message, I get the I'm managing a request! message twice:

public function manageRequest($request, $response)
{
    echo "I'm managing a request!", PHP_EOL;
    $response->writeHead(200, ['Content-type' => 'text/plain']);
    $response->end('My response');
}

One page hit prints the message twice:

I'm managing a request!
I'm managing a request!

How do I make my webserver respond only once?

Provide Interfaces

Would you be open to programming React Against a set of interfaces?

That way I can use other PSR-7 HTTP and embed the react interface in an extension of an already existing PSR-7 http object.

Support Content-Encoding: gzip

as mentioned in #35 (comment)
could be interesting to implement gzip encoding for server responses.

So I've started some impl and researches.

Now I have some questions:

  • should it be encoded automatically when got Accept-Encoding: gzip in major qvalue?
  • should force encoding be triggered by specifying Content-Encoding: gzip header by a user?

Retry request on error

I have a React HTTP server that has a persistent connection to a MongoDB server. When the MongoDB server restarts, the React HTTP server still has the old connection in memory. When a request comes in, React gives an http->on('error', ...) error.

I want to listen for this error, correct the MongoDB connection, & resend the request, which will use the new connection & not error out the second time.

I try to do:

 $http->on('error', function (Exception $error) use ($request, $response, $other_variables) {
    $error_message = $error->getMessage();
    // Recover from MongoDB connection errors.
    if (strpos($error_message, 'ailed to send') !== FALSE || strpos($error_message, 'o suitable servers') !== FALSE || strpos($error_message, 'onnection closed') !== FALSE) {
      // Establish new MongoDB connection.
      mongodb();
      // Retry the request.
      daemonchild_finish($request, $response, $other_variables);
    }
  });

However, it appears the $request & $response that are available in the other $http listeners are not available in the error listener, for when I pass them into a function to resend the request (the same function I use in the 'end' listener to handle the request/response when there are no errors) I get the following error:

|Error: Call to a member function writeHead() on null in {closure}()

That's $response->writeHead($status_code, $output_headers);, so $response is null when I try to pass it into the function, but it's available in the other listeners.

Is there any way to access the request & response objects inside the 'error' listener?

Empty post body

Using https://github.com/reactphp/http/tree/cd15204bd15d106d7832c680e4fb0ca0ce2f5e30 I've noticed that I'm no longer receiving post bodies:

โžœ  vz git:(next) โœ— curl  -m 3 -X POST -d '{"data":[{"uuid":"a16e7380-ccf7-11e6-aa5c-1195f3e90cce","tuples":[[1,1,1]]}]}' 

This is the code:

function __construct(ReactSocketServer $socket, MiddlewareAdapter $hub) {
	parent::__construct($socket);
	$this->hub = $hub;
	$this->on('request', array($this, 'onRequest'));
}

/**
 * main push request/ websocket response loop
 */
function onRequest(Request $request, Response $response) {
	$content = '';
	$headers = $request->getHeaders();
	$contentLength = isset($headers['Content-Length']) ? (int) $headers['Content-Length'] : null;

	// length required, chunked encoding not supported
	if (null === $contentLength) {
		$response->writeHead(411);
		$response->end();
		return;
	}

	$request->on('data', function($data) use ($request, $response, &$content, $contentLength) {
		// read data (may be empty for GET request)
		$content .= $data;

		// handle request after receive
		if (strlen($content) >= $contentLength) {
	
		}
	});

Imho on('request')->on('data') should still work but the inner on is only called once with empty data (string(0) "").

Any idea why/where this suddenly fails? Definitely working before...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.