summaryrefslogtreecommitdiffhomepage
path: root/src/nxt_php_sapi.c
diff options
context:
space:
mode:
authorAndrew Clayton <a.clayton@nginx.com>2022-09-16 14:38:53 +0100
committerAndrew Clayton <a.clayton@nginx.com>2022-11-02 14:22:39 +0000
commita03274456b54cbc39e220b9dd73c3fc3fb935e46 (patch)
treeb0ba7a067a1399f2a56f1d6cad8198e874683740 /src/nxt_php_sapi.c
parent58248a6220540db89e69c928a5d8ad6be2a326fb (diff)
downloadunit-a03274456b54cbc39e220b9dd73c3fc3fb935e46.tar.gz
unit-a03274456b54cbc39e220b9dd73c3fc3fb935e46.tar.bz2
PHP: allowed to specify URLs without a trailing '/'.
Both @lucatacconi & @mwoodpatrick reported what appears to be the same issue on GitHub. Namely that when using the PHP language module and trying to access a URL that is a directory but without specifying the trailing '/', they were getting a '503 Service Unavailable' error. Note: This is when _not_ using the 'script' option. E.g with the following config { "listeners": { "[::1]:8080": { "pass": "applications/php" } }, "applications": { "php": { "type": "php", "root": "/var/tmp/unit-php" } } } and with a directory path of /var/tmp/unit-php/foo containing an index.php, you would see the following $ curl http://localhost/foo <title>Error 503</title> Error 503 However $ curl http://localhost/foo/ would work and serve up the index.php This commit fixes the above so you get the desired behaviour without specifying the trailing '/' by doing the following 1] If the URL doesn't end in .php and doesn't have a trailing '/' then check if the requested path is a directory. 2) If it is a directory then create a 301 re-direct pointing to it. This matches the behaviour of the likes of nginx, Apache and lighttpd. This also matches the behaviour of the "share" action in Unit. This doesn't effect the behaviour of the 'script' option which bypasses the nxt_php_dynamic_request() function. This also adds a couple of tests to test/test_php_application.py to ensure this continues to work. Closes: <https://github.com/nginx/unit/issues/717> Closes: <https://github.com/nginx/unit/issues/753> Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
Diffstat (limited to 'src/nxt_php_sapi.c')
-rw-r--r--src/nxt_php_sapi.c90
1 files changed, 84 insertions, 6 deletions
diff --git a/src/nxt_php_sapi.c b/src/nxt_php_sapi.c
index ca49b289..924dd4e6 100644
--- a/src/nxt_php_sapi.c
+++ b/src/nxt_php_sapi.c
@@ -14,6 +14,7 @@
#include <nxt_router.h>
#include <nxt_unit.h>
#include <nxt_unit_request.h>
+#include <nxt_http.h>
#if (PHP_VERSION_ID >= 50400)
@@ -100,6 +101,8 @@ static void nxt_php_str_trim_trail(nxt_str_t *str, u_char t);
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 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);
@@ -920,6 +923,63 @@ nxt_realpath(const void *c)
}
+static nxt_int_t
+nxt_php_do_301(nxt_unit_request_info_t *req)
+{
+ char *p, *url, *port;
+ uint32_t size;
+ const char *proto;
+ nxt_unit_request_t *r;
+
+ r = req->request;
+
+ url = nxt_malloc(sizeof("https://") - 1
+ + r->server_name_length
+ + r->local_port_length + 1
+ + r->path_length + 1
+ + r->query_length + 1
+ + 1);
+ if (nxt_slow_path(url == NULL)) {
+ return NXT_UNIT_ERROR;
+ }
+
+ proto = r->tls ? "https://" : "http://";
+ p = nxt_cpymem(url, proto, strlen(proto));
+ p = nxt_cpymem(p, nxt_unit_sptr_get(&r->server_name),
+ r->server_name_length);
+
+ port = nxt_unit_sptr_get(&r->local_port);
+ if (r->local_port_length > 0
+ && !(r->tls && strcmp(port, "443") == 0)
+ && !(!r->tls && strcmp(port, "80") == 0))
+ {
+ *p++ = ':';
+ p = nxt_cpymem(p, port, r->local_port_length);
+ }
+
+ p = nxt_cpymem(p, nxt_unit_sptr_get(&r->path), r->path_length);
+ *p++ = '/';
+
+ if (r->query_length > 0) {
+ *p++ = '?';
+ p = nxt_cpymem(p, nxt_unit_sptr_get(&r->query), r->query_length);
+ }
+
+ *p = '\0';
+
+ size = p - url;
+
+ nxt_unit_response_init(req, NXT_HTTP_MOVED_PERMANENTLY, 1,
+ nxt_length("Location") + size);
+ nxt_unit_response_add_field(req, "Location", nxt_length("Location"),
+ url, size);
+
+ nxt_free(url);
+
+ return NXT_UNIT_OK;
+}
+
+
static void
nxt_php_request_handler(nxt_unit_request_info_t *req)
{
@@ -975,15 +1035,33 @@ nxt_php_dynamic_request(nxt_php_run_ctx_t *ctx, nxt_unit_request_t *r)
} else if (path.start[path.length - 1] == '/') {
script_name = *ctx->index;
- } else {
- if (nxt_slow_path(path.length < 4
- || nxt_memcmp(path.start + (path.length - 4),
- ".php", 4)))
- {
- nxt_unit_request_done(ctx->req, NXT_UNIT_ERROR);
+ } else if (path.length < 4
+ || nxt_memcmp(path.start + (path.length - 4), ".php", 4) != 0)
+ {
+ char tpath[PATH_MAX];
+ nxt_int_t ec;
+ struct stat sb;
+
+ ec = NXT_UNIT_ERROR;
+
+ if (ctx->root->length + path.length + 1 > PATH_MAX) {
+ nxt_unit_request_done(ctx->req, ec);
return;
}
+
+ p = nxt_cpymem(tpath, ctx->root->start, ctx->root->length);
+ p = nxt_cpymem(p, path.start, path.length);
+ *p = '\0';
+
+ ret = stat(tpath, &sb);
+ if (ret == 0 && S_ISDIR(sb.st_mode)) {
+ ec = nxt_php_do_301(ctx->req);
+ }
+
+ nxt_unit_request_done(ctx->req, ec);
+
+ return;
}
ctx->script_filename.length = ctx->root->length