mohawk

Check-in [a3939c5c55]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:some fixes + make cgipattern in configuration
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: a3939c5c55a16b7ace96ac48373371cc2dedacb6
User & Date: bapt@FreeBSD.org 2010-10-05 00:51:04.000
Context
2010-10-05
00:51
Merge branch 'master' of git://repo.bsdsx.fr/zhttpd check-in: 55fac5a901 user: bapt@FreeBSD.org tags: trunk
00:51
some fixes + make cgipattern in configuration check-in: a3939c5c55 user: bapt@FreeBSD.org tags: trunk
2010-09-27
16:06
Make vhost work correctly check-in: 702893a660 user: bapt@FreeBSD.org tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to mini_httpd.c.
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
static void do_file(struct client *, char *);
static void do_dir(struct client *, char *);
static char *file_details(const char *dir, const char *name, const char *script_name);
static void strencode(char *to, size_t tosize, const char *from);
static void do_cgi(struct client *, char *);
static void cgi_interpose_input(struct client *cl, int wfd);
static void cgi_interpose_output(struct client *cl, int rfd, int parse_headers);
static char **make_argp(char *);
static char **make_envp(struct client *);
static char *build_env(char *fmt, char *arg);
static void auth_check(struct client *, char *dirname);
static void send_authenticate(struct client *cl, char *realm);
static void send_error(struct client *, int s, char *title, char *extra_header, char *text);
static void send_error_body(struct client *, int s, char *title, char *text);
static int send_error_file(struct client *, char *filename);







|







173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
static void do_file(struct client *, char *);
static void do_dir(struct client *, char *);
static char *file_details(const char *dir, const char *name, const char *script_name);
static void strencode(char *to, size_t tosize, const char *from);
static void do_cgi(struct client *, char *);
static void cgi_interpose_input(struct client *cl, int wfd);
static void cgi_interpose_output(struct client *cl, int rfd, int parse_headers);
static char **make_argp(char *, char *);
static char **make_envp(struct client *);
static char *build_env(char *fmt, char *arg);
static void auth_check(struct client *, char *dirname);
static void send_authenticate(struct client *cl, char *realm);
static void send_error(struct client *, int s, char *title, char *extra_header, char *text);
static void send_error_body(struct client *, int s, char *title, char *text);
static int send_error_file(struct client *, char *filename);
518
519
520
521
522
523
524

525
526
527
528
529
530
531
		cl->protocol = NULL;
		cl->status = 0;
		cl->bytes = -1;

		sz = sizeof(cl->ss);

		cl->fd = accept(ke.ident, (struct sockaddr *)&cl->ss, &sz);


		if (cl->fd < 0)
		{
			if (errno == EINTR || errno == EAGAIN)
				continue;	/* try again */
#ifdef EPROTO
			if (errno == EPROTO)







>







518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
		cl->protocol = NULL;
		cl->status = 0;
		cl->bytes = -1;

		sz = sizeof(cl->ss);

		cl->fd = accept(ke.ident, (struct sockaddr *)&cl->ss, &sz);
		cl->remote_addr = ntop(&cl->ss);

		if (cl->fd < 0)
		{
			if (errno == EINTR || errno == EAGAIN)
				continue;	/* try again */
#ifdef EPROTO
			if (errno == EPROTO)
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806

	/* Check authorization for this directory. */
	auth_check(cl, dirname(filepath));
	filename = basename(filepath);

	/* Check if the filename is the AUTH_FILE itself - that's verboten. */
	if (strcmp(filename, AUTH_FILE) == 0) {
		syslog(LOG_NOTICE, "%.80s URL \"%.80s\" tried to retrieve an auth file", ntop(&cl->ss), cl->script_name);
		send_error(cl, 403, "Forbidden", "", "File is protected.");
		return;
	}

	/* Is it CGI? */
	if (conf.cgi_pattern != NULL && fnmatch(conf.cgi_pattern, filename, FNM_CASEFOLD)) {
		do_cgi(cl, filepath);
		return;
	}

	fd = open(filepath, O_RDONLY);
	if (fd < 0) {
		syslog(LOG_INFO, "%.80s File \"%.80s\" is protected", ntop(&cl->ss), cl->script_name);
		send_error(cl, 403, "Forbidden", "", "File is protected.");
		return;
	}
	mime_type = figure_mime(filepath, mime_encodings, sizeof(mime_encodings));
	snprintf(fixed_mime_type, sizeof(fixed_mime_type), mime_type, conf.charset);

	if (cl->if_modified_since != -1 &&







|





|






|







780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807

	/* Check authorization for this directory. */
	auth_check(cl, dirname(filepath));
	filename = basename(filepath);

	/* Check if the filename is the AUTH_FILE itself - that's verboten. */
	if (strcmp(filename, AUTH_FILE) == 0) {
		syslog(LOG_NOTICE, "%.80s URL \"%.80s\" tried to retrieve an auth file", cl->remote_addr, cl->script_name);
		send_error(cl, 403, "Forbidden", "", "File is protected.");
		return;
	}

	/* Is it CGI? */
	if (conf.cgi_pattern != NULL && fnmatch(conf.cgi_pattern, filename, FNM_CASEFOLD) == 0) {
		do_cgi(cl, filepath);
		return;
	}

	fd = open(filepath, O_RDONLY);
	if (fd < 0) {
		syslog(LOG_INFO, "%.80s File \"%.80s\" is protected", cl->remote_addr, cl->script_name);
		send_error(cl, 403, "Forbidden", "", "File is protected.");
		return;
	}
	mime_type = figure_mime(filepath, mime_encodings, sizeof(mime_encodings));
	snprintf(fixed_mime_type, sizeof(fixed_mime_type), mime_type, conf.charset);

	if (cl->if_modified_since != -1 &&
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
	char *name_info;

	/* Check authorization for this directory. */
	auth_check(cl, path);

	n = scandir(path, &dl, NULL, alphasort);
	if (n < 0) {
		syslog(LOG_INFO, "%.80s Directory \"%.80s\" is protected", ntop(&cl->ss), cl->script_name);
		send_error(cl, 403, "Forbidden", "", "Directory is protected.");
		return;
	}

	buflen = snprintf(buf, sizeof(buf), "\
<HTML>\n\
<HEAD><TITLE>Index of %s</TITLE></HEAD>\n\







|







844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
	char *name_info;

	/* Check authorization for this directory. */
	auth_check(cl, path);

	n = scandir(path, &dl, NULL, alphasort);
	if (n < 0) {
		syslog(LOG_INFO, "%.80s Directory \"%.80s\" is protected", cl->remote_addr, cl->script_name);
		send_error(cl, 403, "Forbidden", "", "Directory is protected.");
		return;
	}

	buflen = snprintf(buf, sizeof(buf), "\
<HTML>\n\
<HEAD><TITLE>Index of %s</TITLE></HEAD>\n\
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
		*/
	}

	/* Make the environment vector. */
	envp = make_envp(cl);

	/* Make the argument vector. */
	argp = make_argp(cl->query_string);

	/* Set up stdin.  For POSTs we may have to set up a pipe from an
	** interposer process, depending on if we've read some of the data
	** into our buffer.  We also have to do this for all SSL CGIs.
	*/
#ifdef USE_SSL
	if ((cl->method == METHOD_POST && strlen(cl->request) > request_idx) || do_ssl)
#else /* USE_SSL */
	if ((cl->method == METHOD_POST && strlen(cl->request) > request_idx))
#endif /* USE_SSL */
	{
		int p[2];
		int r;

		if (pipe(p) < 0)
			send_error(cl, 500, "Internal Error", "", "Something unexpected went wrong making a pipe.");







|






|

|







955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
		*/
	}

	/* Make the environment vector. */
	envp = make_envp(cl);

	/* Make the argument vector. */
	argp = make_argp(cl->query_string, filepath);

	/* Set up stdin.  For POSTs we may have to set up a pipe from an
	** interposer process, depending on if we've read some of the data
	** into our buffer.  We also have to do this for all SSL CGIs.
	*/
#ifdef USE_SSL
	if ((cl->method == METHOD_POST) || do_ssl)
#else /* USE_SSL */
	if (cl->method == METHOD_POST)
#endif /* USE_SSL */
	{
		int p[2];
		int r;

		if (pipe(p) < 0)
			send_error(cl, 500, "Internal Error", "", "Something unexpected went wrong making a pipe.");
1016
1017
1018
1019
1020
1021
1022
1023
1024

1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080

1081
1082
1083
1084
1085

1086
1087
1088
1089
1090
1091
1092
		int r;

		if (pipe(p) < 0)
			send_error(cl, 500, "Internal Error", "", "Something unexpected went wrong making a pipe.");
		r = fork();
		if (r < 0)
			send_error(cl, 500, "Internal Error", "", "Something unexpected went wrong forking an interposer.");
		if (r == 0)
		{

			/* Interposer process. */
			(void) close(p[1]);
			cgi_interpose_output(cl, p[0], parse_headers);
			exit(0);
		}
		(void) close(p[0]);
		if (p[1] != STDOUT_FILENO)
			(void) dup2(p[1], STDOUT_FILENO);
		if (p[1] != STDERR_FILENO)
			(void) dup2(p[1], STDERR_FILENO);
		if (p[1] != STDOUT_FILENO && p[1] != STDERR_FILENO)
			(void) close(p[1]);
	}
	else
	{
		/* Otherwise, the request socket is stdout/stderr. */
		if (cl->fd != STDOUT_FILENO)
			(void) dup2(cl->fd, STDOUT_FILENO);
		if (cl->fd != STDERR_FILENO)
			(void) dup2(cl->fd, STDERR_FILENO);
	}

	/* At this point we would like to set conn_fd to be close-on-exec.
	** Unfortunately there seems to be a Linux problem here - if we
	** do this close-on-exec in Linux, the socket stays open but stderr
	** gets closed - the last fd duped from the socket.  What a mess.
	** So we'll just leave the socket as is, which under other OSs means
	** an extra file descriptor gets passed to the child process.  Since
	** the child probably already has that file open via stdin stdout
	** and/or stderr, this is not a problem.
	*/
	/* (void) fcntl(conn_fd, F_SETFD, 1); */

	/* Close syslog. */
	closelog();

	/* Set priority. */
	(void) nice(CGI_NICE);

	/* Split the program into directory and binary, so we can chdir()
	** to the program's own directory.  This isn't in the CGI 1.1
	** spec, but it's what other HTTP servers do.
	*/
	directory = strdup(file);
	binary = strrchr(directory, '/');
	if (binary == (char*) 0)
		binary = file;
	else
	{
		*binary++ = '\0';
		(void) chdir(directory);	/* ignore errors */
	}

	/* Default behavior for SIGPIPE. */
	(void) sigset(SIGPIPE, SIG_DFL);


	/* Run the program. */
	(void) execve(binary, argp, envp);

	/* Something went wrong. */
	send_error(cl, 500, "Internal Error", "", "Something unexpected went wrong running a CGI program.");

}

/* This routine is used only for POST requests.  It reads the data
** from the request and sends it to the child process.  The only reason
** we need to do it this way instead of just letting the child read
** directly is that we have already read part of the data into our
** buffer.







<
|
>

|

|

|

|

|

|
<
|
<



















|


|





|



|
<

|



|

>

|

<

>







1017
1018
1019
1020
1021
1022
1023

1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037

1038

1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071

1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082

1083
1084
1085
1086
1087
1088
1089
1090
1091
		int r;

		if (pipe(p) < 0)
			send_error(cl, 500, "Internal Error", "", "Something unexpected went wrong making a pipe.");
		r = fork();
		if (r < 0)
			send_error(cl, 500, "Internal Error", "", "Something unexpected went wrong forking an interposer.");


		if (r == 0) {
			/* Interposer process. */
			close(p[1]);
			cgi_interpose_output(cl, p[0], parse_headers);
			return;
		}
		close(p[0]);
		if (p[1] != STDOUT_FILENO)
			dup2(p[1], STDOUT_FILENO);
		if (p[1] != STDERR_FILENO)
			dup2(p[1], STDERR_FILENO);
		if (p[1] != STDOUT_FILENO && p[1] != STDERR_FILENO)
			close(p[1]);

	} else {

		/* Otherwise, the request socket is stdout/stderr. */
		if (cl->fd != STDOUT_FILENO)
			(void) dup2(cl->fd, STDOUT_FILENO);
		if (cl->fd != STDERR_FILENO)
			(void) dup2(cl->fd, STDERR_FILENO);
	}

	/* At this point we would like to set conn_fd to be close-on-exec.
	** Unfortunately there seems to be a Linux problem here - if we
	** do this close-on-exec in Linux, the socket stays open but stderr
	** gets closed - the last fd duped from the socket.  What a mess.
	** So we'll just leave the socket as is, which under other OSs means
	** an extra file descriptor gets passed to the child process.  Since
	** the child probably already has that file open via stdin stdout
	** and/or stderr, this is not a problem.
	*/
	/* (void) fcntl(conn_fd, F_SETFD, 1); */

	/* Close syslog. */
	/*closelog();*/

	/* Set priority. */
	nice(CGI_NICE);

	/* Split the program into directory and binary, so we can chdir()
	** to the program's own directory.  This isn't in the CGI 1.1
	** spec, but it's what other HTTP servers do.
	*/
	directory = strdup(filepath);
	binary = strrchr(directory, '/');
	if (binary == (char*) 0)
		binary = file;
	else {

		*binary++ = '\0';
		chdir(directory);	/* ignore errors */
	}

	/* Default behavior for SIGPIPE. */
	sigset(SIGPIPE, SIG_DFL);

	syslog(LOG_ERR,"kikoo %s %s", filepath, binary);
	/* Run the program. */
	execve( binary, argp, envp );


	send_error(cl, 500, "Internal Error", "", "Something unexpected went wrong running a CGI program.");
	exit (1);
}

/* This routine is used only for POST requests.  It reads the data
** from the request and sends it to the child process.  The only reason
** we need to do it this way instead of just letting the child read
** directly is that we have already read part of the data into our
** buffer.
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
	char buf[1024];

	if (! parse_headers)
	{
		/* If we're not parsing headers, write out the default status line
		** and proceed to the echo phase.
		*/
		char http_head[] = "HTTP/1.0 200 OK\015\012";
		zhttpd_write(cl->fd, http_head, sizeof(http_head));
	}
	else
	{
		/* Header parsing.  The idea here is that the CGI can return special
		** headers such as "Status:" and "Location:" which change the return
		** status of the response.  Since the return status has to be the very







|







1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
	char buf[1024];

	if (! parse_headers)
	{
		/* If we're not parsing headers, write out the default status line
		** and proceed to the echo phase.
		*/
		char http_head[] = "HTTP/1.0 200 OK\r\n";
		zhttpd_write(cl->fd, http_head, sizeof(http_head));
	}
	else
	{
		/* Header parsing.  The idea here is that the CGI can return special
		** headers such as "Status:" and "Location:" which change the return
		** status of the response.  Since the return status has to be the very
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269






1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
}

/* Set up CGI argument vector.  We don't have to worry about freeing
** stuff since we're a sub-process.  This gets done after make_envp() because
** we scribble on query.
*/
static char**
make_argp(char *query)
{
	char** argp;
	int argn;
	char *cp1;
	char *cp2;







	/* By allocating an arg slot for every character in the query, plus
	** one for the filename and one for the NULL, we are guaranteed to
	** have enough.  We could actually use strlen/2.
	*/
	argp = (char**) malloc((strlen(query) + 2) * sizeof(char*));
	if (argp == (char**) 0)
		return (char**) 0;

	argp[0] = strrchr(file, '/');
	if (argp[0] != (char*) 0)
		++argp[0];
	else
		argp[0] = file;

	argn = 1;
	/* According to the CGI spec at http://hoohoo.ncsa.uiuc.edu/cgi/cl.html,
	** "The server should search the query information for a non-encoded =
	** character to determine if the command line is to be used, if it finds
	** one, the command line is not to be used."
	*/
	if (strchr(query, '=') == (char*) 0)
	{
		for (cp1 = cp2 = query; *cp2 != '\0'; ++cp2)
		{
			if (*cp2 == '+')
			{
				*cp2 = '\0';
				strdecode(cp1, cp1);
				argp[argn++] = cp1;
				cp1 = cp2 + 1;
			}
		}
		if (cp2 != cp1)
		{
			strdecode(cp1, cp1);
			argp[argn++] = cp1;
		}
	}

	argp[argn] = NULL;
	return argp;







|





>
>
>
>
>
>





|
|
|

|
|


|







|
<
|
<
|
<






|
<







1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296

1297

1298

1299
1300
1301
1302
1303
1304
1305

1306
1307
1308
1309
1310
1311
1312
}

/* Set up CGI argument vector.  We don't have to worry about freeing
** stuff since we're a sub-process.  This gets done after make_envp() because
** we scribble on query.
*/
static char**
make_argp(char *query, char *filepath)
{
	char** argp;
	int argn;
	char *cp1;
	char *cp2;
	size_t len;

	if (query == NULL)
		len = 2;
	else
		len = strlen(query) + 2;

	/* By allocating an arg slot for every character in the query, plus
	** one for the filename and one for the NULL, we are guaranteed to
	** have enough.  We could actually use strlen/2.
	*/
	argp = malloc(len * sizeof(char*));
	if (argp == NULL)
		return NULL;

	argp[0] = strrchr(filepath, '/');
	if (argp[0] != NULL)
		++argp[0];
	else
		argp[0] = filepath;

	argn = 1;
	/* According to the CGI spec at http://hoohoo.ncsa.uiuc.edu/cgi/cl.html,
	** "The server should search the query information for a non-encoded =
	** character to determine if the command line is to be used, if it finds
	** one, the command line is not to be used."
	*/
	if (query != NULL && strchr(query, '=') == NULL) {

		for (cp1 = cp2 = query; *cp2 != '\0'; ++cp2) {

			if (*cp2 == '+') {

				*cp2 = '\0';
				strdecode(cp1, cp1);
				argp[argn++] = cp1;
				cp1 = cp2 + 1;
			}
		}
		if (cp2 != cp1) {

			strdecode(cp1, cp1);
			argp[argn++] = cp1;
		}
	}

	argp[argn] = NULL;
	return argp;
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
	envp[envn++] = build_env("SCRIPT_NAME=%s", cl->script_name);
	if (cl->path_info != NULL)
	{
		envp[envn++] = build_env("PATH_INFO=/%s", cl->path_info);
		(void) snprintf(buf, sizeof(buf), "/%s", cl->path_info);
		envp[envn++] = build_env("PATH_TRANSLATED=%s", buf);
	}
	if (cl->query_string[0] != '\0')
		envp[envn++] = build_env("QUERY_STRING=%s", cl->query_string);
	envp[envn++] = build_env("REMOTE_ADDR=%s", ntop(&cl->ss));
	if (cl->referer[0] != '\0')
		envp[envn++] = build_env("HTTP_REFERER=%s", cl->referer);
	if (cl->user_agent[0] != '\0')
		envp[envn++] = build_env("HTTP_USER_AGENT=%s", cl->user_agent);
	if (cl->cookie != NULL)
		envp[envn++] = build_env("HTTP_COOKIE=%s", cl->cookie);
	if (cl->host != NULL)
		envp[envn++] = build_env("HTTP_HOST=%s", cl->host);
	if (cl->content_type != NULL)
		envp[envn++] = build_env("CONTENT_TYPE=%s", cl->content_type);







|

|
|

|







1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
	envp[envn++] = build_env("SCRIPT_NAME=%s", cl->script_name);
	if (cl->path_info != NULL)
	{
		envp[envn++] = build_env("PATH_INFO=/%s", cl->path_info);
		(void) snprintf(buf, sizeof(buf), "/%s", cl->path_info);
		envp[envn++] = build_env("PATH_TRANSLATED=%s", buf);
	}
	if (cl->query_string != NULL)
		envp[envn++] = build_env("QUERY_STRING=%s", cl->query_string);
	envp[envn++] = build_env("REMOTE_ADDR=%s", cl->remote_addr);
	if (cl->referer != NULL)
		envp[envn++] = build_env("HTTP_REFERER=%s", cl->referer);
	if (cl->user_agent != NULL)
		envp[envn++] = build_env("HTTP_USER_AGENT=%s", cl->user_agent);
	if (cl->cookie != NULL)
		envp[envn++] = build_env("HTTP_COOKIE=%s", cl->cookie);
	if (cl->host != NULL)
		envp[envn++] = build_env("HTTP_HOST=%s", cl->host);
	if (cl->content_type != NULL)
		envp[envn++] = build_env("CONTENT_TYPE=%s", cl->content_type);
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
	/* Open the password file. */
	fp = fopen(authpath, "r");
	if (fp == (FILE*) 0)
	{
		/* The file exists but we can't open it?  Disallow access. */
		syslog(
			LOG_ERR, "%.80s auth file %.80s could not be opened - %m",
			ntop(&cl->ss), authpath);
		send_error(cl, 403, "Forbidden", "", "File is protected.");
	}

	/* Read it. */
	while (fgets(line, sizeof(line), fp) != (char*) 0)
	{
		/* Nuke newline. */







|







1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
	/* Open the password file. */
	fp = fopen(authpath, "r");
	if (fp == (FILE*) 0)
	{
		/* The file exists but we can't open it?  Disallow access. */
		syslog(
			LOG_ERR, "%.80s auth file %.80s could not be opened - %m",
			cl->remote_addr, authpath);
		send_error(cl, 403, "Forbidden", "", "File is protected.");
	}

	/* Read it. */
	while (fgets(line, sizeof(line), fp) != (char*) 0)
	{
		/* Nuke newline. */
Changes to parse.y.
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
			TAILQ_INSERT_HEAD(&conf.vhosts, vh, entry);
		}
		;

set		: SET STRING STRING {
			if (!strcmp($2, "servername")) {
				conf.servername = $3;
			} else if (!strcmp($2, "cgi_pattern")) {
				conf.cgi_pattern = $3;
			} else if (!strcmp($2, "charset")) {
				conf.charset = $3;
			} else if (!strcmp($2, "logfile")) {
				conf.logfile = $3;
			} else if (!strcmp($2, "chroot")) {
				conf.chroot = $3;







|







134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
			TAILQ_INSERT_HEAD(&conf.vhosts, vh, entry);
		}
		;

set		: SET STRING STRING {
			if (!strcmp($2, "servername")) {
				conf.servername = $3;
			} else if (!strcmp($2, "cgipattern")) {
				conf.cgi_pattern = $3;
			} else if (!strcmp($2, "charset")) {
				conf.charset = $3;
			} else if (!strcmp($2, "logfile")) {
				conf.logfile = $3;
			} else if (!strcmp($2, "chroot")) {
				conf.chroot = $3;
Changes to zhttpd.conf.

1
2
3
4
5
6
7

#set cgi_pattern *.cgi
#set chroot
#set debug
set rootdir /tmp
listen on 127.0.0.1 port 7777
listen on :: port 8888

>







1
2
3
4
5
6
7
8
set cgipattern *.cgi
#set cgi_pattern *.cgi
#set chroot
#set debug
set rootdir /tmp
listen on 127.0.0.1 port 7777
listen on :: port 8888

Changes to zhttpd.h.
34
35
36
37
38
39
40

41
42
43
44
45
46
47
	char *user;
	int debug;
	int maxage;
};

struct client {
	int fd;

	struct sockaddr_storage ss;
	int method;
	char *response;
	char *request;
	char *body;
	char *script_name;
	char *query_string;;







>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
	char *user;
	int debug;
	int maxage;
};

struct client {
	int fd;
	char *remote_addr;
	struct sockaddr_storage ss;
	int method;
	char *response;
	char *request;
	char *body;
	char *script_name;
	char *query_string;;