33namespace React \Http \Io ;
44
55use Evenement \EventEmitter ;
6+ use Psr \Http \Message \ServerRequestInterface ;
7+ use React \Socket \ConnectionInterface ;
68use RingCentral \Psr7 as g7 ;
79use Exception ;
810
1921 */
2022class RequestHeaderParser extends EventEmitter
2123{
22- private $ buffer = '' ;
2324 private $ maxSize = 8192 ;
2425
25- private $ localSocketUri ;
26- private $ remoteSocketUri ;
27-
28- public function __construct ($ localSocketUri = null , $ remoteSocketUri = null )
26+ public function handle (ConnectionInterface $ conn )
2927 {
30- $ this ->localSocketUri = $ localSocketUri ;
31- $ this ->remoteSocketUri = $ remoteSocketUri ;
32- }
28+ $ buffer = '' ;
29+ $ maxSize = $ this ->maxSize ;
30+ $ that = $ this ;
31+ $ conn ->on ('data ' , $ fn = function ($ data ) use (&$ buffer , &$ fn , $ conn , $ maxSize , $ that ) {
32+ // append chunk of data to buffer and look for end of request headers
33+ $ buffer .= $ data ;
34+ $ endOfHeader = \strpos ($ buffer , "\r\n\r\n" );
35+
36+ // reject request if buffer size is exceeded
37+ if ($ endOfHeader > $ maxSize || ($ endOfHeader === false && isset ($ buffer [$ maxSize ]))) {
38+ $ conn ->removeListener ('data ' , $ fn );
39+ $ fn = null ;
40+
41+ $ that ->emit ('error ' , array (
42+ new \OverflowException ("Maximum header size of {$ maxSize } exceeded. " , 431 ),
43+ $ conn
44+ ));
45+ return ;
46+ }
3347
34- public function feed ( $ data )
35- {
36- $ this -> buffer .= $ data ;
37- $ endOfHeader = \strpos ( $ this -> buffer , "\r\n\r\n" );
48+ // ignore incomplete requests
49+ if ( $ endOfHeader === false ) {
50+ return ;
51+ }
3852
39- if ($ endOfHeader > $ this ->maxSize || ($ endOfHeader === false && isset ($ this ->buffer [$ this ->maxSize ]))) {
40- $ this ->emit ('error ' , array (new \OverflowException ("Maximum header size of {$ this ->maxSize } exceeded. " , 431 ), $ this ));
41- $ this ->removeAllListeners ();
42- return ;
43- }
53+ // request headers received => try to parse request
54+ $ conn ->removeListener ('data ' , $ fn );
55+ $ fn = null ;
4456
45- if (false !== $ endOfHeader ) {
4657 try {
47- $ this ->parseAndEmitRequest ($ endOfHeader );
58+ $ request = $ that ->parseRequest (
59+ (string )\substr ($ buffer , 0 , $ endOfHeader ),
60+ $ conn ->getRemoteAddress (),
61+ $ conn ->getLocalAddress ()
62+ );
4863 } catch (Exception $ exception ) {
49- $ this ->emit ('error ' , array ($ exception ));
64+ $ buffer = '' ;
65+ $ that ->emit ('error ' , array (
66+ $ exception ,
67+ $ conn
68+ ));
69+ return ;
5070 }
51- $ this ->removeAllListeners ();
52- }
53- }
5471
55- private function parseAndEmitRequest ($ endOfHeader )
56- {
57- $ request = $ this ->parseRequest ((string )\substr ($ this ->buffer , 0 , $ endOfHeader ));
58- $ bodyBuffer = isset ($ this ->buffer [$ endOfHeader + 4 ]) ? \substr ($ this ->buffer , $ endOfHeader + 4 ) : '' ;
59- $ this ->emit ('headers ' , array ($ request , $ bodyBuffer ));
72+ $ bodyBuffer = isset ($ buffer [$ endOfHeader + 4 ]) ? \substr ($ buffer , $ endOfHeader + 4 ) : '' ;
73+ $ buffer = '' ;
74+ $ that ->emit ('headers ' , array ($ request , $ bodyBuffer , $ conn ));
75+ });
76+
77+ $ conn ->on ('close ' , function () use (&$ buffer , &$ fn ) {
78+ $ fn = $ buffer = null ;
79+ });
6080 }
6181
62- private function parseRequest ($ headers )
82+ /**
83+ * @param string $headers buffer string containing request headers only
84+ * @param ?string $remoteSocketUri
85+ * @param ?string $localSocketUri
86+ * @return ServerRequestInterface
87+ * @throws \InvalidArgumentException
88+ * @internal
89+ */
90+ public function parseRequest ($ headers , $ remoteSocketUri , $ localSocketUri )
6391 {
6492 // additional, stricter safe-guard for request line
6593 // because request parser doesn't properly cope with invalid ones
@@ -99,22 +127,22 @@ private function parseRequest($headers)
99127
100128 // apply REMOTE_ADDR and REMOTE_PORT if source address is known
101129 // address should always be known, unless this is over Unix domain sockets (UDS)
102- if ($ this -> remoteSocketUri !== null ) {
103- $ remoteAddress = \parse_url ($ this -> remoteSocketUri );
130+ if ($ remoteSocketUri !== null ) {
131+ $ remoteAddress = \parse_url ($ remoteSocketUri );
104132 $ serverParams ['REMOTE_ADDR ' ] = $ remoteAddress ['host ' ];
105133 $ serverParams ['REMOTE_PORT ' ] = $ remoteAddress ['port ' ];
106134 }
107135
108136 // apply SERVER_ADDR and SERVER_PORT if server address is known
109137 // address should always be known, even for Unix domain sockets (UDS)
110138 // but skip UDS as it doesn't have a concept of host/port.s
111- if ($ this -> localSocketUri !== null ) {
112- $ localAddress = \parse_url ($ this -> localSocketUri );
139+ if ($ localSocketUri !== null ) {
140+ $ localAddress = \parse_url ($ localSocketUri );
113141 if (isset ($ localAddress ['host ' ], $ localAddress ['port ' ])) {
114142 $ serverParams ['SERVER_ADDR ' ] = $ localAddress ['host ' ];
115143 $ serverParams ['SERVER_PORT ' ] = $ localAddress ['port ' ];
116144 }
117- if (isset ($ localAddress ['scheme ' ]) && $ localAddress ['scheme ' ] === 'https ' ) {
145+ if (isset ($ localAddress ['scheme ' ]) && $ localAddress ['scheme ' ] === 'tls ' ) {
118146 $ serverParams ['HTTPS ' ] = 'on ' ;
119147 }
120148 }
@@ -173,7 +201,7 @@ private function parseRequest($headers)
173201
174202 // set URI components from socket address if not already filled via Host header
175203 if ($ request ->getUri ()->getHost () === '' ) {
176- $ parts = \parse_url ($ this -> localSocketUri );
204+ $ parts = \parse_url ($ localSocketUri );
177205 if (!isset ($ parts ['host ' ], $ parts ['port ' ])) {
178206 $ parts = array ('host ' => '127.0.0.1 ' , 'port ' => 80 );
179207 }
@@ -194,8 +222,8 @@ private function parseRequest($headers)
194222 }
195223
196224 // Update request URI to "https" scheme if the connection is encrypted
197- $ parts = \parse_url ($ this -> localSocketUri );
198- if (isset ($ parts ['scheme ' ]) && $ parts ['scheme ' ] === 'https ' ) {
225+ $ parts = \parse_url ($ localSocketUri );
226+ if (isset ($ parts ['scheme ' ]) && $ parts ['scheme ' ] === 'tls ' ) {
199227 // The request URI may omit default ports here, so try to parse port
200228 // from Host header field (if possible)
201229 $ port = $ request ->getUri ()->getPort ();
0 commit comments