<commit_before>/*	$Id$ */
/*
 * Copyright (c) 2014 <NAME> <<EMAIL>>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>

#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>

#include "kcgiregress.h"

static int
dochild(kcgi_regress_server child, void *carg)
{
	int	 	 s, in, rc, opt, first;
	struct sockaddr_in ad, rem;
	socklen_t	 len;
	char		 head[1024], *cp, *cpp;
	size_t		 sz;
	extern char	*__progname;

	rc = 0;
	opt = 1;
	s = in = -1;
	memset(&ad, 0, sizeof(struct sockaddr_in));

	/*
	 * Bind and listen to our reusable testing socket.
	 * We pretty much just choose a random port for this.
	 */
	if (-1 == (s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))) {
		perror("socket");
		exit(EXIT_FAILURE);
	} else if (-1 == setsockopt(s, SOL_SOCKET, 
		 SO_REUSEADDR, &opt, sizeof(opt))) {
		perror("setsockopt");
		goto out;
	}

	ad.sin_family = AF_INET;
	ad.sin_port = htons(17123);
	ad.sin_addr.s_addr = htonl(INADDR_LOOPBACK);

	if (-1 == bind(s, (struct sockaddr *)&ad, sizeof(ad))) {
		perror("bind");
		goto out;
	} else if (-1 == listen(s, 1)) {
		perror("listen");
		goto out;
	}

	/*
	 * Tell our parent that we've bound to our socket and are ready
	 * to receive data.
	 * They'll do a waitpid() to see when we're sleeping, then wake
	 * us up when we're already ready to go.
	 */
	kill(getpid(), SIGSTOP);

	/*
	 * Wait for a single testing connection.
	 */
	len = sizeof(struct sockaddr_in);
	if (-1 == (in = accept(s, (struct sockaddr *)&rem, &len))) {
		perror("accept");
		goto out;
	} 

	/*
	 * Assign the socket as our stdin and stdout.
	 * This will facilitate the CGI script in reading and write its
	 * response directly into the stream.
	 */
	if (STDIN_FILENO != dup2(in, STDIN_FILENO)) {
		perror("dup2");
		goto out;
	} else if (STDOUT_FILENO != dup2(in, STDOUT_FILENO)) {
		perror("dup2");
		goto out;
	} 

	if (NULL == (cp = strdup(__progname))) {
		perror(NULL);
		exit(EXIT_FAILURE);
	}
	setenv("SCRIPT_NAME", cp, 1);
	
	/*
	 * Read header lines.
	 * We'll do this in the simplest possible way so that there are
	 * no surprises.
	 */
	first = 1;
	while (NULL != fgets(head, sizeof(head), stdin)) {
		/* Strip off the CRLF terminator. */
		if ((sz = strlen(head)) < 2) {
			fprintf(stderr, "Bad HTTP header\n");
			goto out;
		}
		if ('\n' != head[sz - 1] || '\r' != head[sz - 2]) {
			fprintf(stderr, "Unterminated HTTP header\n");
			goto out;
		}
		head[sz - 2] = '\0';

		/* Empty line: now we're at the CGI document. */
		if ('\0' == head[0])
			break;

		/* Process our header. */
		if (first) {
			/* Snarf the first GET/POST line. */
			if (0 == strncmp(head, "GET ", 4)) {
				setenv("REQUEST_METHOD", "GET", 1);
				cp = strdup(head + 4);
			} else if (0 == strncmp(head, "POST ", 5)) {
				setenv("REQUEST_METHOD", "POST", 1);
				cp = strdup(head + 5);
			} else {
				fprintf(stderr, "Unknown HTTP "
					"first line: %s\n", head);
				goto out;
			}

			if (NULL == cp) {
				perror(NULL);
				exit(EXIT_FAILURE);
			}

			cpp = cp;
			while ('\0' != *cpp && ! isspace(*cpp))
				cpp++;
			*cpp = '\0';
			first = 0;
			setenv("PATH_INFO", cp, 1);
			continue;
		}

		/* Process header lines. */
		/*fprintf(stderr, "Skipping header: %s\n", head);*/
	}

	if (NULL == head)
		goto out;<commit_msg>Rudimentary parsing of query string for kcgi_regress(3).<commit_after>/*	$Id$ */
/*
 * Copyright (c) 2014 <NAME> <<EMAIL>>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>

#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>

#include "kcgiregress.h"

static int
dochild(kcgi_regress_server child, void *carg)
{
	int	 	 s, in, rc, opt, first;
	struct sockaddr_in ad, rem;
	socklen_t	 len;
	char		 head[1024], *cp, *path, *query;
	size_t		 sz;
	extern char	*__progname;

	rc = 0;
	opt = 1;
	s = in = -1;
	memset(&ad, 0, sizeof(struct sockaddr_in));

	/*
	 * Bind and listen to our reusable testing socket.
	 * We pretty much just choose a random port for this.
	 */
	if (-1 == (s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))) {
		perror("socket");
		exit(EXIT_FAILURE);
	} else if (-1 == setsockopt(s, SOL_SOCKET, 
		 SO_REUSEADDR, &opt, sizeof(opt))) {
		perror("setsockopt");
		goto out;
	}

	ad.sin_family = AF_INET;
	ad.sin_port = htons(17123);
	ad.sin_addr.s_addr = htonl(INADDR_LOOPBACK);

	if (-1 == bind(s, (struct sockaddr *)&ad, sizeof(ad))) {
		perror("bind");
		goto out;
	} else if (-1 == listen(s, 1)) {
		perror("listen");
		goto out;
	}

	/*
	 * Tell our parent that we've bound to our socket and are ready
	 * to receive data.
	 * They'll do a waitpid() to see when we're sleeping, then wake
	 * us up when we're already ready to go.
	 */
	kill(getpid(), SIGSTOP);

	/*
	 * Wait for a single testing connection.
	 */
	len = sizeof(struct sockaddr_in);
	if (-1 == (in = accept(s, (struct sockaddr *)&rem, &len))) {
		perror("accept");
		goto out;
	} 

	/*
	 * Assign the socket as our stdin and stdout.
	 * This will facilitate the CGI script in reading and write its
	 * response directly into the stream.
	 */
	if (STDIN_FILENO != dup2(in, STDIN_FILENO)) {
		perror("dup2");
		goto out;
	} else if (STDOUT_FILENO != dup2(in, STDOUT_FILENO)) {
		perror("dup2");
		goto out;
	} 

	if (NULL == (cp = strdup(__progname))) {
		perror(NULL);
		exit(EXIT_FAILURE);
	}
	setenv("SCRIPT_NAME", cp, 1);
	
	/*
	 * Read header lines.
	 * We'll do this in the simplest possible way so that there are
	 * no surprises.
	 */
	first = 1;
	while (NULL != fgets(head, sizeof(head), stdin)) {
		/* Strip off the CRLF terminator. */
		if ((sz = strlen(head)) < 2) {
			fprintf(stderr, "Bad HTTP header\n");
			goto out;
		}
		if ('\n' != head[sz - 1] || '\r' != head[sz - 2]) {
			fprintf(stderr, "Unterminated HTTP header\n");
			goto out;
		}
		head[sz - 2] = '\0';

		/* Empty line: now we're at the CGI document. */
		if ('\0' == head[0])
			break;

		/* Process our header. */
		if (first) {
			/* Snarf the first GET/POST line. */
			if (0 == strncmp(head, "GET ", 4)) {
				setenv("REQUEST_METHOD", "GET", 1);
				path = strdup(head + 4);
			} else if (0 == strncmp(head, "POST ", 5)) {
				setenv("REQUEST_METHOD", "POST", 1);
				path = strdup(head + 5);
			} else {
				fprintf(stderr, "Unknown HTTP "
					"first line: %s\n", head);
				goto out;
			}

			if (NULL == path) {
				perror(NULL);
				exit(EXIT_FAILURE);
			}

			cp = path;
			while ('\0' != *cp && ! isspace(*cp))
				cp++;
			*cp = '\0';
			if (NULL != (query = strchr(path, '?')))
				*query++ = '\0';

			first = 0;
			setenv("PATH_INFO", path, 1);
			if (NULL != query)
				setenv("QUERY_STRING", query, 1);
			continue;
		}

		/* Process header lines. */
		/*fprintf(stderr, "Skipping header: %s\n", head);*/
	}

	if (NULL == head)
		goto out;
{'fraction_non_alphanumeric': 0.1524895020995801, 'fraction_numerical': 0.01187762447510498, 'mean_word_length': 3.1973816717019132, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '709395', 'n_tokens_mistral': 3384, 'n_tokens_neox': 2976, 'n_words': 990}