simplify cgi function
Don't fork+execlp the script. There's no need to do so since on exec the new process will inherit our file descriptor table (and hence our stdout), so copying from its stdout to ours is just a waste of time. This allows to drop the ``proc'' pledge(2) promise and to (slightly) improve performance.
This commit is contained in:
parent
16a5ed7b30
commit
ee8569c6e6
2 changed files with 8 additions and 55 deletions
61
main.c
61
main.c
|
@ -99,8 +99,8 @@ drop_privileges(const char *user, const char *path)
|
||||||
* write to stdio
|
* write to stdio
|
||||||
*/
|
*/
|
||||||
if (strlen(cgibin) > 0) {
|
if (strlen(cgibin) > 0) {
|
||||||
/* cgi need execlp() (exec) and fork() (proc) */
|
/* cgi need execlp() (exec) */
|
||||||
epledge("stdio rpath exec proc", NULL);
|
epledge("stdio rpath exec", NULL);
|
||||||
} else {
|
} else {
|
||||||
epledge("stdio rpath", NULL);
|
epledge("stdio rpath", NULL);
|
||||||
}
|
}
|
||||||
|
@ -270,58 +270,11 @@ autoindex(const char *path)
|
||||||
void
|
void
|
||||||
cgi(const char *cgicmd)
|
cgi(const char *cgicmd)
|
||||||
{
|
{
|
||||||
|
execlp(cgicmd, cgicmd, NULL);
|
||||||
int pipedes[2] = {0};
|
/* if execlp is ok, this will never be reached */
|
||||||
pid_t pid;
|
status(42, "Couldn't execute CGI script");
|
||||||
|
errlog("error when trying to execlp %s", cgicmd);
|
||||||
/* get a pipe to get stdout */
|
exit(1);
|
||||||
if (pipe(pipedes) != 0) {
|
|
||||||
status(42, "text/gemini");
|
|
||||||
err(1, "pipe failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
pid = fork();
|
|
||||||
|
|
||||||
if (pid < 0) {
|
|
||||||
close(pipedes[0]);
|
|
||||||
close(pipedes[1]);
|
|
||||||
status(42, "text/gemini");
|
|
||||||
err(1, "fork failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pid > 0) { /* parent */
|
|
||||||
char buf[3];
|
|
||||||
size_t nread = 0;
|
|
||||||
FILE *output = NULL;
|
|
||||||
|
|
||||||
close(pipedes[1]); /* make sure entry is closed so fread() gets EOF */
|
|
||||||
|
|
||||||
/* use fread/fwrite because are buffered */
|
|
||||||
output = fdopen(pipedes[0], "r");
|
|
||||||
if (output == NULL) {
|
|
||||||
status(42, "text/gemini");
|
|
||||||
err(1, "fdopen failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* read pipe output */
|
|
||||||
while ((nread = fread(buf, 1, sizeof(buf), output)) != 0) {
|
|
||||||
fwrite(buf, 1, nread, stdout);
|
|
||||||
}
|
|
||||||
close(pipedes[0]);
|
|
||||||
fclose(output);
|
|
||||||
|
|
||||||
wait(NULL); /* wait for child to terminate */
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
|
|
||||||
} else if (pid == 0) { /* child */
|
|
||||||
dup2(pipedes[1], STDOUT_FILENO); /* set pipe output equal to stdout */
|
|
||||||
close(pipedes[1]); /* no need this file descriptor : it is now stdout */
|
|
||||||
execlp(cgicmd, cgicmd, NULL);
|
|
||||||
/* if execlp is ok, this will never be reached */
|
|
||||||
status(42, "text/gemini");
|
|
||||||
errlog("error when trying to execlp %s", cgicmd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -89,7 +89,7 @@ if ! [ $OUT = "fa065a67d1f7c973501d4a9e3ca2ea57" ] ; then echo "error" ; exit 1
|
||||||
|
|
||||||
# cgi with error
|
# cgi with error
|
||||||
OUT=$(printf "gemini://host.name/cgi-bin/nope\r\n" | ../vger -d var/gemini/ -c /cgi-bin | tee /dev/stderr | MD5)
|
OUT=$(printf "gemini://host.name/cgi-bin/nope\r\n" | ../vger -d var/gemini/ -c /cgi-bin | tee /dev/stderr | MD5)
|
||||||
if ! [ $OUT = "2c88347cfac44450035283a8508a29cb" ] ; then echo "error" ; exit 1 ; fi
|
if ! [ $OUT = "4156170c2aa8a6a8a0892ff5a61bf5f5" ] ; then echo "error" ; exit 1 ; fi
|
||||||
|
|
||||||
# remove ?.* if any
|
# remove ?.* if any
|
||||||
OUT=$(printf "gemini://host.name/main.gmi?anything-here\r\n" | ../vger -d var/gemini/ | tee /dev/stderr | MD5)
|
OUT=$(printf "gemini://host.name/main.gmi?anything-here\r\n" | ../vger -d var/gemini/ | tee /dev/stderr | MD5)
|
||||||
|
|
Loading…
Reference in a new issue