fix cgi support for PATH_INFO

looks for files immediately after the cgidir, and anything after that file
if there are '/'s becomes PATH_INFO.

also adds a function strip_trailing_slash which may be useful in other parts too.
This commit is contained in:
aabacchus 2021-11-01 18:17:45 +00:00
parent 8efcdb7512
commit aa1affb6c2
Signed by untrusted user: phoebos
GPG Key ID: B02F7D053AC351D3
2 changed files with 41 additions and 10 deletions

47
main.c
View File

@ -20,7 +20,7 @@
#include "opts.h" #include "opts.h"
#include "utils.h" #include "utils.h"
/* lenght of "gemini://" */ /* length of "gemini://" */
#define GEMINI_PART 9 #define GEMINI_PART 9
/* /*
@ -38,6 +38,7 @@ void echdir (const char *);
void status (const int, const char *); void status (const int, const char *);
void status_redirect(const int, const char *); void status_redirect(const int, const char *);
void status_error(const int, const char *); void status_error(const int, const char *);
void strip_trailing_slash(char *path);
int uridecode (char *); int uridecode (char *);
@ -304,6 +305,17 @@ cgi(const char *cgicmd)
exit(1); exit(1);
} }
void
strip_trailing_slash(char *path)
{
size_t end = strlen(path);
if (end == 0)
return;
end--;
while (path[end] == '/')
path[end--] = '\0';
}
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
@ -454,7 +466,25 @@ main(int argc, char **argv)
* found, then requested file is actually a directory * found, then requested file is actually a directory
*/ */
if (strlen(dir) > 0) { if (strlen(dir) > 0) {
pos = strrchr(dir, '/'); /*
* if in cgidir, only the first file after cgidir/FILE is to be executed
* the rest is PATH_INFO
*/
/* find the string of cgidir without chroot_dir prefix */
char tmp [PATH_MAX] = {'\0'};
char *cgipp;
strip_trailing_slash(chroot_dir);
strip_trailing_slash(cgidir);
estrlcpy(tmp, cgidir + strlen(chroot_dir), sizeof(tmp));
cgipp = tmp;
if (tmp[0] == '/')
cgipp++;
if (docgi && strncmp(dir, cgipp, strlen(cgipp)) == 0) {
pos = strchr(dir+strlen(cgipp), '/');
} else {
pos = strrchr(dir, '/');
}
if (pos != NULL) { if (pos != NULL) {
estrlcpy(file, pos + 1, sizeof(file)); /* +1 : no leading '/' */ estrlcpy(file, pos + 1, sizeof(file)); /* +1 : no leading '/' */
pos[0] = '\0'; pos[0] = '\0';
@ -491,15 +521,12 @@ main(int argc, char **argv)
if (*query) if (*query)
esetenv("QUERY_STRING", query, 1); esetenv("QUERY_STRING", query, 1);
/* look for an extension to find PATH_INFO */
pos = strrchr(file, '.'); /* if we've got here and file contains a '/', it should be interpreted as PATH_INFO */
pos = strchr(file, '/');
if (pos != NULL) { if (pos != NULL) {
/* found a dot */ setenv("PATH_INFO", pos, 1);
pos = strchr(pos, '/'); pos[0] = '\0'; /* keep only script name */
if (pos != NULL) {
setenv("PATH_INFO", pos, 1);
pos[0] = '\0'; /* keep only script name */
}
} }
esetenv("SCRIPT_NAME", file, 1); esetenv("SCRIPT_NAME", file, 1);
esetenv("SERVER_NAME", hostname, 1); esetenv("SERVER_NAME", hostname, 1);

View File

@ -91,6 +91,10 @@ if ! [ $OUT = "fa065a67d1f7c973501d4a9e3ca2ea57" ] ; then echo "error" ; exit 1
OUT=$(printf "gemini://host.name/cgi-bin/nope\r\n" | ../vger -d var/gemini/ -c var/gemini/cgi-bin | tee /dev/stderr | MD5) OUT=$(printf "gemini://host.name/cgi-bin/nope\r\n" | ../vger -d var/gemini/ -c var/gemini/cgi-bin | tee /dev/stderr | MD5)
if ! [ $OUT = "74ba4b36dcebec9ce9dae33033f3378a" ] ; then echo "error" ; exit 1 ; fi if ! [ $OUT = "74ba4b36dcebec9ce9dae33033f3378a" ] ; then echo "error" ; exit 1 ; fi
# cgi with PATH_INFO
OUT=$(printf "gemini://host.name/cgi-bin/test.cgi/path/info\r\n" | ../vger -d var/gemini -c var/gemini/cgi-bin | tee /dev/stderr | MD5)
if ! [ $OUT = "ec64da76dc578ffb479fbfb23e3a7a5b" ] ; then echo "error" ; exit 1 ; fi
# virtualhost + cgi # virtualhost + cgi
OUT=$(printf "gemini://perso.pw/cgi-bin/test.cgi\r\n" | ../vger -v -d var/gemini/ -c var/gemini/perso.pw/cgi-bin | tee /dev/stderr | MD5) OUT=$(printf "gemini://perso.pw/cgi-bin/test.cgi\r\n" | ../vger -v -d var/gemini/ -c var/gemini/perso.pw/cgi-bin | tee /dev/stderr | MD5)
if ! [ $OUT = "666e48200f90018b5e96c2cf974882dc" ] ; then echo "error" ; exit 1 ; fi if ! [ $OUT = "666e48200f90018b5e96c2cf974882dc" ] ; then echo "error" ; exit 1 ; fi