Skip to content

The development server returns 200 OK and does not report syntax errors in router scripts #13113

Closed
@exikyut

Description

@exikyut

Description

The following (very invalid) code:

<?php

bug

Results in this output:

$ php -S 0:3000 router.php
[Wed Jan 10 19:37:13 2024] PHP 8.2.7 Development Server (http://0:3000) started
[Wed Jan 10 19:37:14 2024] 127.0.0.1:55760 Accepted
[Wed Jan 10 19:37:14 2024] 127.0.0.1:55760 Closing

And:

$ curl 127.0.0.1:3000 -vvv
*   Trying 127.0.0.1:3000...
* Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0)
> GET / HTTP/1.1
> Host: 127.0.0.1:3000
> User-Agent: curl/7.88.1
> Accept: */*
> 
< HTTP/1.1 200 OK
< Host: 127.0.0.1:3000
< Date: Wed, 10 Jan 2024 07:51:07 GMT
< Connection: close
< X-Powered-By: PHP/8.2.7
< Content-type: text/html; charset=UTF-8
< 
* Closing connection 0

But I expected output along these lines instead:

[Wed Jan 10 19:37:13 2024] PHP 8.2.7 Development Server (http://0:3000) started
[Wed Jan 10 19:37:14 2024] 127.0.0.1:55760 Accepted
[Wed Jan 10 19:37:14 2024] 127.0.0.1:55760 [200] (some appropriate preamble) - syntax error, unexpected end of file in router.php (router) on line 3
[Wed Jan 10 19:37:14 2024] 127.0.0.1:55760 Closing

And something similar to:

$ curl 127.1:3000/ -vvv
*   Trying 127.0.0.1:3000...
* Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0)
> GET / HTTP/1.1
> Host: 127.0.0.1:3000
> User-Agent: curl/7.88.1
> Accept: */*
> 
* HTTP 1.0, assume close after body
< HTTP/1.0 500 Internal Server Error
< Host: 127.0.0.1:3000
< Date: Wed, 10 Jan 2024 08:58:08 GMT
< Connection: close
< X-Powered-By: PHP/8.2.7
< Content-type: text/html; charset=UTF-8
< 
* Closing connection 0

Analyses/discussion

I was curious and did a bit of code spelunking. I realized very quickly that my cursory glance around (an hour or so) wasn't going to quickly grasp the whole bigger picture so I just identified some basics.

It looks like the router path is handled by php_cli_server_dispatch_router(), while the regular URI-based path is handled by php_cli_server_dispatch_script().

The regular URI-based path has a crucial call to php_cli_server_log_response(), which is responsible for logging the request and its status code - while the router path doesn't have any equivalent! Given that the router effectively replaces file lookup, I vote that similar logging should be added to the router path. It feels like obvious common sense.

As noted in a comment in the function, php_cli_server_dispatch_router() uses zend_execute_scripts() instead of php_execute_scripts() so that you can return false; from the top level of the router script and PHP will serve a generic 404 page for you. That's pretty neat.

I think what needs to happen is that the logic that presently just checks to see if the return value IS_FALSE needs to be extended to handle script errors.

Some extremely cheeky overreaching to put a surreptitious php_debug_zval_dump(&retval, 0); just above } zend_end_try(); produces some interesting bits of signal: I can return 2; and see int(2) - or I can drop a syntax error or two and get UNKNOWN:0 instead.

There's probably a more properly idiomatic and unambiguous way to detect and surface errors though. I'm just wandering for fun :)

Generally, if I were to soapbox about what should be happening here, I'd say that the router path should be brought up to scratch to be consistent with the rest of PHP wrt. respecting error_reporting and show_errors et al, including (and particularly) to the point of dumping parse/syntax errors.

Thanks for reading!

PHP Version

8.2.7

Operating System

Debian Stable

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions