summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrew Clayton <a.clayton@nginx.com>2023-01-26 12:09:43 +0000
committerAndrew Clayton <a.clayton@nginx.com>2023-01-27 14:46:59 +0000
commitbebc03c729df1d7efc81a5af8b8dac40b333d408 (patch)
tree6de72d17c785452f048327844c897cc2522ae2cf
parentfafdb7a57ad976e048147fe23079dca9c602e88a (diff)
downloadunit-bebc03c729df1d7efc81a5af8b8dac40b333d408.tar.gz
unit-bebc03c729df1d7efc81a5af8b8dac40b333d408.tar.bz2
PHP: Implement better error handling.
Previously the PHP module would produce one of four status codes 200 OK 301 Moved Permanently 500 Internal Server Error 503 Service Unavailable 200 for successful requests, 301 for cases where the url was a directory without a trailing '/', 500 for bad PHP or non-existing PHP file and 503 for all other errors. With this commit we now handle missing files and directories, returning 404 Not Found and files and directories that don't allow access, returning 403 Forbidden. We do these checks in two places, when we check if we should do a directory redirect (bar -> bar/) and in the nxt_php_execute() function. One snag with the latter is that the php_execute_script() function only returns success/failure (no reason). However while it took a zend_file_handle structure with the filename of the script to run, we can instead pass through an already opened file-pointer (FILE *) via that structure. So we can try opening the script ourselves and do the required checks before calling php_execute_script(). We also make use of the zend_stream_init_fp() function that initialises the zend_file_handle structure if it's available otherwise we use our own version. This is good because the zend_file_handle structure has changed over time and the zend_stream_init_fp() function should change with it. Closes: <https://github.com/nginx/unit/issues/767> Reviewed-by: Alejandro Colomar <alx@nginx.com> Cc: Andrei Zeliankou <zelenkov@nginx.com> Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
-rw-r--r--src/nxt_php_sapi.c45
1 files changed, 40 insertions, 5 deletions
diff --git a/src/nxt_php_sapi.c b/src/nxt_php_sapi.c
index b517f7c3..32a13a70 100644
--- a/src/nxt_php_sapi.c
+++ b/src/nxt_php_sapi.c
@@ -102,12 +102,13 @@ static void nxt_php_str_trim_lead(nxt_str_t *str, u_char t);
nxt_inline u_char *nxt_realpath(const void *c);
static nxt_int_t nxt_php_do_301(nxt_unit_request_info_t *req);
+static nxt_int_t nxt_php_handle_fs_err(nxt_unit_request_info_t *req);
static void nxt_php_request_handler(nxt_unit_request_info_t *req);
static void nxt_php_dynamic_request(nxt_php_run_ctx_t *ctx,
nxt_unit_request_t *r);
#if (PHP_VERSION_ID < 70400)
-static void nxt_zend_stream_init_filename(zend_file_handle *handle,
+static void nxt_zend_stream_init_fp(zend_file_handle *handle, FILE *fp,
const char *filename);
#endif
static void nxt_php_execute(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r);
@@ -984,6 +985,24 @@ nxt_php_do_301(nxt_unit_request_info_t *req)
}
+static nxt_int_t
+nxt_php_handle_fs_err(nxt_unit_request_info_t *req)
+{
+ switch (nxt_errno) {
+ case ELOOP:
+ case EACCES:
+ case ENFILE:
+ return nxt_unit_response_init(req, NXT_HTTP_FORBIDDEN, 0, 0);
+ case ENOENT:
+ case ENOTDIR:
+ case ENAMETOOLONG:
+ return nxt_unit_response_init(req, NXT_HTTP_NOT_FOUND, 0, 0);
+ }
+
+ return NXT_UNIT_ERROR;
+}
+
+
static void
nxt_php_request_handler(nxt_unit_request_info_t *req)
{
@@ -1062,6 +1081,8 @@ nxt_php_dynamic_request(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r)
ret = stat(tpath, &sb);
if (ret == 0 && S_ISDIR(sb.st_mode)) {
ec = nxt_php_do_301(ctx->req);
+ } else if (ret == -1) {
+ ec = nxt_php_handle_fs_err(ctx->req);
}
nxt_unit_request_done(ctx->req, ec);
@@ -1115,20 +1136,23 @@ nxt_php_dynamic_request(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r)
#if (PHP_VERSION_ID < 70400)
static void
-nxt_zend_stream_init_filename(zend_file_handle *handle, const char *filename)
+nxt_zend_stream_init_fp(zend_file_handle *handle, FILE *fp,
+ const char *filename)
{
nxt_memzero(handle, sizeof(zend_file_handle));
- handle->type = ZEND_HANDLE_FILENAME;
+ handle->type = ZEND_HANDLE_FP;
+ handle->handle.fp = fp;
handle->filename = filename;
}
#else
-#define nxt_zend_stream_init_filename zend_stream_init_filename
+#define nxt_zend_stream_init_fp zend_stream_init_fp
#endif
static void
nxt_php_execute(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r)
{
+ FILE *fp;
#if (PHP_VERSION_ID < 50600)
void *read_post;
#endif
@@ -1140,6 +1164,17 @@ nxt_php_execute(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r)
nxt_unit_req_debug(ctx->req, "PHP execute script %s", filename);
+ fp = fopen(filename, "re");
+ if (fp == NULL) {
+ nxt_int_t ec;
+
+ nxt_unit_req_debug(ctx->req, "PHP fopen(\"%s\") failed", filename);
+
+ ec = nxt_php_handle_fs_err(ctx->req);
+ nxt_unit_request_done(ctx->req, ec);
+ return;
+ }
+
SG(server_context) = ctx;
SG(options) |= SAPI_OPTION_NO_CHDIR;
SG(request_info).request_uri = nxt_unit_sptr_get(&r->target);
@@ -1198,7 +1233,7 @@ nxt_php_execute(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r)
nxt_php_vcwd_chdir(ctx->req, ctx->script_dirname.start);
}
- nxt_zend_stream_init_filename(&file_handle, filename);
+ nxt_zend_stream_init_fp(&file_handle, fp, filename);
php_execute_script(&file_handle TSRMLS_CC);