mirror of
https://git.sr.ht/~sircmpwn/gmnisrv
synced 2024-12-04 14:46:42 -05:00
CGI: set PATH_INFO
This commit is contained in:
parent
cc1bd152e3
commit
5d725ff4ee
64
src/serve.c
64
src/serve.c
@ -3,6 +3,7 @@
|
|||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <libgen.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -120,7 +121,7 @@ internal_error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
serve_cgi(struct gmnisrv_client *client, const char *path)
|
serve_cgi(struct gmnisrv_client *client, const char *path, const char *pathinfo)
|
||||||
{
|
{
|
||||||
int pfd[2];
|
int pfd[2];
|
||||||
if (pipe(pfd) == -1) {
|
if (pipe(pfd) == -1) {
|
||||||
@ -170,7 +171,7 @@ serve_cgi(struct gmnisrv_client *client, const char *path)
|
|||||||
setenv("SERVER_SOFTWARE", "gmnisrv/0.0.0", 1);
|
setenv("SERVER_SOFTWARE", "gmnisrv/0.0.0", 1);
|
||||||
setenv("GEMINI_URL", client->buf, 1);
|
setenv("GEMINI_URL", client->buf, 1);
|
||||||
setenv("SCRIPT_NAME", path, 1);
|
setenv("SCRIPT_NAME", path, 1);
|
||||||
//setenv("PATH_INFO", "", 1); // TODO
|
setenv("PATH_INFO", pathinfo, 1);
|
||||||
setenv("SERVER_NAME", client->host->hostname, 1);
|
setenv("SERVER_NAME", client->host->hostname, 1);
|
||||||
setenv("HOSTNAME", client->host->hostname, 1);
|
setenv("HOSTNAME", client->host->hostname, 1);
|
||||||
//setenv("SERVER_PORT", "", 1); // TODO
|
//setenv("SERVER_PORT", "", 1); // TODO
|
||||||
@ -247,18 +248,50 @@ serve_request(struct gmnisrv_client *client)
|
|||||||
|
|
||||||
assert(route->root); // TODO: reverse proxy support
|
assert(route->root); // TODO: reverse proxy support
|
||||||
|
|
||||||
char path[PATH_MAX + 1];
|
// Paths on paths on paths on paths
|
||||||
int n = snprintf(path, sizeof(path), "%s%s", route->root, url_path);
|
// My apologies to the stack
|
||||||
if ((size_t)n >= sizeof(path)) {
|
char client_path[PATH_MAX + 1] = "";
|
||||||
|
char real_path[PATH_MAX + 1] = "";
|
||||||
|
char pathinfo[PATH_MAX + 1] = "";
|
||||||
|
char temp_path[PATH_MAX + 1] = "";
|
||||||
|
int n = snprintf(real_path, sizeof(real_path), "%s%s", route->root, url_path);
|
||||||
|
if ((size_t)n >= sizeof(real_path)) {
|
||||||
client_submit_response(client, GEMINI_STATUS_PERMANENT_FAILURE,
|
client_submit_response(client, GEMINI_STATUS_PERMANENT_FAILURE,
|
||||||
"Request path exceeds PATH_MAX", NULL);
|
"Request path exceeds PATH_MAX", NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
strcpy(client_path, client->path);
|
||||||
|
|
||||||
int nlinks = 0;
|
int nlinks = 0;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
while (true) {
|
while (true) {
|
||||||
if ((n = stat(path, &st)) != 0) {
|
if ((n = stat(real_path, &st)) != 0) {
|
||||||
|
if (route->cgi) {
|
||||||
|
const char *new;
|
||||||
|
strcpy(temp_path, client_path);
|
||||||
|
new = basename((char *)temp_path);
|
||||||
|
|
||||||
|
size_t l = strlen(new), q = strlen(pathinfo);
|
||||||
|
memmove(&pathinfo[l + 1], pathinfo, q);
|
||||||
|
pathinfo[0] = '/';
|
||||||
|
memcpy(&pathinfo[1], new, l);
|
||||||
|
|
||||||
|
strcpy(temp_path, client_path);
|
||||||
|
new = dirname((char *)temp_path);
|
||||||
|
strcpy(client_path, new);
|
||||||
|
|
||||||
|
strcpy(temp_path, real_path);
|
||||||
|
new = dirname((char *)temp_path);
|
||||||
|
strcpy(real_path, new);
|
||||||
|
|
||||||
|
if (route_match(route, client_path, &url_path)) {
|
||||||
|
n = snprintf(real_path, sizeof(real_path),
|
||||||
|
"%s%s", route->root, url_path);
|
||||||
|
assert((size_t)n < sizeof(real_path));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
client_submit_response(client,
|
client_submit_response(client,
|
||||||
GEMINI_STATUS_NOT_FOUND, "Not found", NULL);
|
GEMINI_STATUS_NOT_FOUND, "Not found", NULL);
|
||||||
return;
|
return;
|
||||||
@ -266,12 +299,12 @@ serve_request(struct gmnisrv_client *client)
|
|||||||
|
|
||||||
if (S_ISDIR(st.st_mode)) {
|
if (S_ISDIR(st.st_mode)) {
|
||||||
if (route->autoindex) {
|
if (route->autoindex) {
|
||||||
serve_autoindex(client, path);
|
serve_autoindex(client, real_path);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
strncat(path,
|
strncat(real_path,
|
||||||
route->index ? route->index : "index.gmi",
|
route->index ? route->index : "index.gmi",
|
||||||
sizeof(path) - 1);
|
sizeof(real_path) - 1);
|
||||||
}
|
}
|
||||||
} else if (S_ISLNK(st.st_mode)) {
|
} else if (S_ISLNK(st.st_mode)) {
|
||||||
++nlinks;
|
++nlinks;
|
||||||
@ -283,10 +316,9 @@ serve_request(struct gmnisrv_client *client)
|
|||||||
"Not found", NULL);
|
"Not found", NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
char path2[PATH_MAX + 1];
|
ssize_t s = readlink(real_path, temp_path, sizeof(temp_path));
|
||||||
ssize_t s = readlink(path, path2, sizeof(path2));
|
|
||||||
assert(s != -1);
|
assert(s != -1);
|
||||||
strcpy(path, path2);
|
strcpy(real_path, temp_path);
|
||||||
} else if (S_ISREG(st.st_mode)) {
|
} else if (S_ISREG(st.st_mode)) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
@ -298,11 +330,11 @@ serve_request(struct gmnisrv_client *client)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (route->cgi) {
|
if (route->cgi) {
|
||||||
serve_cgi(client, path);
|
serve_cgi(client, real_path, (const char *)pathinfo);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *body = fopen(path, "r");
|
FILE *body = fopen(real_path, "r");
|
||||||
if (!body) {
|
if (!body) {
|
||||||
if (errno == ENOENT) {
|
if (errno == ENOENT) {
|
||||||
client_submit_response(client,
|
client_submit_response(client,
|
||||||
@ -310,14 +342,14 @@ serve_request(struct gmnisrv_client *client)
|
|||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
client_error(&client->addr, "error opening %s: %s",
|
client_error(&client->addr, "error opening %s: %s",
|
||||||
path, strerror(errno));
|
real_path, strerror(errno));
|
||||||
client_submit_response(client, GEMINI_STATUS_PERMANENT_FAILURE,
|
client_submit_response(client, GEMINI_STATUS_PERMANENT_FAILURE,
|
||||||
"Internal server error", NULL);
|
"Internal server error", NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *meta = gmnisrv_mimetype_for_path(path);
|
const char *meta = gmnisrv_mimetype_for_path(real_path);
|
||||||
client_submit_response(client, GEMINI_STATUS_SUCCESS, meta, body);
|
client_submit_response(client, GEMINI_STATUS_SUCCESS, meta, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user