@@ -332,57 +332,61 @@ public function handleResponse(ConnectionInterface $connection, ServerRequestInt
332332 return ;
333333 }
334334
335- $ response = $ response ->withProtocolVersion ($ request ->getProtocolVersion ());
335+ $ code = $ response ->getStatusCode ();
336+ $ method = $ request ->getMethod ();
337+
338+ // assign HTTP protocol version from request automatically
339+ $ version = $ request ->getProtocolVersion ();
340+ $ response = $ response ->withProtocolVersion ($ version );
336341
337- // assign default "X-Powered-By" header as first for history reasons
342+ // assign default "X-Powered-By" header automatically
338343 if (!$ response ->hasHeader ('X-Powered-By ' )) {
339344 $ response = $ response ->withHeader ('X-Powered-By ' , 'React/alpha ' );
340- }
341-
342- if ($ response ->hasHeader ('X-Powered-By ' ) && $ response ->getHeaderLine ('X-Powered-By ' ) === '' ){
345+ } elseif ($ response ->getHeaderLine ('X-Powered-By ' ) === '' ){
343346 $ response = $ response ->withoutHeader ('X-Powered-By ' );
344347 }
345348
346- $ response = $ response ->withoutHeader ('Transfer-Encoding ' );
347-
348- // assign date header if no 'date' is given, use the current time where this code is running
349+ // assign default "Date" header from current time automatically
349350 if (!$ response ->hasHeader ('Date ' )) {
350351 // IMF-fixdate = day-name "," SP date1 SP time-of-day SP GMT
351352 $ response = $ response ->withHeader ('Date ' , gmdate ('D, d M Y H:i:s ' ) . ' GMT ' );
352- }
353-
354- if ($ response ->hasHeader ('Date ' ) && $ response ->getHeaderLine ('Date ' ) === '' ){
353+ } elseif ($ response ->getHeaderLine ('Date ' ) === '' ){
355354 $ response = $ response ->withoutHeader ('Date ' );
356355 }
357356
358- if (!$ body instanceof HttpBodyStream) {
359- $ response = $ response ->withHeader ('Content-Length ' , (string )$ body ->getSize ());
360- } elseif (!$ response ->hasHeader ('Content-Length ' ) && $ request ->getProtocolVersion () === '1.1 ' ) {
357+ // assign "Content-Length" and "Transfer-Encoding" headers automatically
358+ $ chunked = false ;
359+ if (($ method === 'CONNECT ' && $ code >= 200 && $ code < 300 ) || ($ code >= 100 && $ code < 200 ) || $ code === 204 ) {
360+ // 2xx response to CONNECT and 1xx and 204 MUST NOT include Content-Length or Transfer-Encoding header
361+ $ response = $ response ->withoutHeader ('Content-Length ' )->withoutHeader ('Transfer-Encoding ' );
362+ } elseif (!$ body instanceof HttpBodyStream) {
363+ // assign Content-Length header when using a "normal" buffered body string
364+ $ response = $ response ->withHeader ('Content-Length ' , (string )$ body ->getSize ())->withoutHeader ('Transfer-Encoding ' );
365+ } elseif (!$ response ->hasHeader ('Content-Length ' ) && $ version === '1.1 ' ) {
361366 // assign chunked transfer-encoding if no 'content-length' is given for HTTP/1.1 responses
362367 $ response = $ response ->withHeader ('Transfer-Encoding ' , 'chunked ' );
368+ $ chunked = true ;
369+ } else {
370+ // remove any Transfer-Encoding headers unless automatically enabled above
371+ $ response = $ response ->withoutHeader ('Transfer-Encoding ' );
363372 }
364373
365- // HTTP/1.1 assumes persistent connection support by default
366- // we do not support persistent connections, so let the client know
367- if ($ request ->getProtocolVersion () === '1.1 ' ) {
368- $ response = $ response ->withHeader ('Connection ' , 'close ' );
369- }
370- // 2xx response to CONNECT and 1xx and 204 MUST NOT include Content-Length or Transfer-Encoding header
371- $ code = $ response ->getStatusCode ();
372- if (($ request ->getMethod () === 'CONNECT ' && $ code >= 200 && $ code < 300 ) || ($ code >= 100 && $ code < 200 ) || $ code === 204 ) {
373- $ response = $ response ->withoutHeader ('Content-Length ' )->withoutHeader ('Transfer-Encoding ' );
374- }
375-
376- // 101 (Switching Protocols) response uses Connection: upgrade header
377- // persistent connections are currently not supported, so do not use
378- // this for any other replies in order to preserve "Connection: close"
374+ // assign "Connection" header automatically
379375 if ($ code === 101 ) {
376+ // 101 (Switching Protocols) response uses Connection: upgrade header
380377 $ response = $ response ->withHeader ('Connection ' , 'upgrade ' );
378+ } elseif ($ version === '1.1 ' ) {
379+ // HTTP/1.1 assumes persistent connection support by default
380+ // we do not support persistent connections, so let the client know
381+ $ response = $ response ->withHeader ('Connection ' , 'close ' );
382+ } else {
383+ // remove any Connection headers unless automatically enabled above
384+ $ response = $ response ->withoutHeader ('Connection ' );
381385 }
382386
383387 // 101 (Switching Protocols) response (for Upgrade request) forwards upgraded data through duplex stream
384388 // 2xx (Successful) response to CONNECT forwards tunneled application data through duplex stream
385- if (($ code === 101 || ($ request -> getMethod () === 'CONNECT ' && $ code >= 200 && $ code < 300 )) && $ body instanceof HttpBodyStream && $ body ->input instanceof WritableStreamInterface) {
389+ if (($ code === 101 || ($ method === 'CONNECT ' && $ code >= 200 && $ code < 300 )) && $ body instanceof HttpBodyStream && $ body ->input instanceof WritableStreamInterface) {
386390 if ($ request ->getBody ()->isReadable ()) {
387391 // request is still streaming => wait for request close before forwarding following data from connection
388392 $ request ->getBody ()->on ('close ' , function () use ($ connection , $ body ) {
@@ -399,7 +403,7 @@ public function handleResponse(ConnectionInterface $connection, ServerRequestInt
399403 }
400404
401405 // build HTTP response header by appending status line and header fields
402- $ headers = "HTTP/ " . $ response -> getProtocolVersion () . " " . $ response -> getStatusCode () . " " . $ response ->getReasonPhrase () . "\r\n" ;
406+ $ headers = "HTTP/ " . $ version . " " . $ code . " " . $ response ->getReasonPhrase () . "\r\n" ;
403407 foreach ($ response ->getHeaders () as $ name => $ values ) {
404408 foreach ($ values as $ value ) {
405409 $ headers .= $ name . ": " . $ value . "\r\n" ;
@@ -408,14 +412,14 @@ public function handleResponse(ConnectionInterface $connection, ServerRequestInt
408412
409413 // response to HEAD and 1xx, 204 and 304 responses MUST NOT include a body
410414 // exclude status 101 (Switching Protocols) here for Upgrade request handling above
411- if ($ request -> getMethod () === 'HEAD ' || $ code === 100 || ($ code > 101 && $ code < 200 ) || $ code === 204 || $ code === 304 ) {
415+ if ($ method === 'HEAD ' || $ code === 100 || ($ code > 101 && $ code < 200 ) || $ code === 204 || $ code === 304 ) {
412416 $ body = '' ;
413417 }
414418
415419 // this is a non-streaming response body or the body stream already closed?
416420 if (!$ body instanceof ReadableStreamInterface || !$ body ->isReadable ()) {
417421 // add final chunk if a streaming body is already closed and uses `Transfer-Encoding: chunked`
418- if ($ body instanceof ReadableStreamInterface && $ response -> getHeaderLine ( ' Transfer-Encoding ' ) === ' chunked ' ) {
422+ if ($ body instanceof ReadableStreamInterface && $ chunked ) {
419423 $ body = "0 \r\n\r\n" ;
420424 }
421425
@@ -427,7 +431,7 @@ public function handleResponse(ConnectionInterface $connection, ServerRequestInt
427431
428432 $ connection ->write ($ headers . "\r\n" );
429433
430- if ($ response -> getHeaderLine ( ' Transfer-Encoding ' ) === ' chunked ' ) {
434+ if ($ chunked ) {
431435 $ body = new ChunkedEncoder ($ body );
432436 }
433437
0 commit comments