Commit Diff


commit - 28239bac769c9db0bcc8f48bdd16db80886f84e9
commit + 8857131d3f62c08a0b3d450582560322c36ea219
blob - ca72d81c7c2c00b392c169b96e90353c7d5d1e0c
blob + 4bb8cbe2e0de72bbbc39546d4541198f274d12d1
--- fcgi.c
+++ fcgi.c
@@ -289,6 +289,7 @@ fcgi_parse_params(struct fcgi *fcgi, struct evbuffer *
 	char			 server[HOST_NAME_MAX + 1];
 	char			 path[PATH_MAX];
 	char			 query[GEMINI_MAXLEN];
+	char			 method[8];
 	int			 nlen, vlen;
 
 	while (fcgi->fcg_toread > 0) {
@@ -373,6 +374,7 @@ fcgi_parse_params(struct fcgi *fcgi, struct evbuffer *
 		    vlen > 0) {
 			fcgi->fcg_toread -= vlen;
 			evbuffer_remove(src, &query, vlen);
+			query[vlen] = '\0';
 
 			free(clt->clt_query);
 			if ((clt->clt_query = strdup(query)) == NULL)
@@ -380,6 +382,20 @@ fcgi_parse_params(struct fcgi *fcgi, struct evbuffer *
 
 			log_debug("clt %d: query: %s", clt->clt_id,
 			    clt->clt_query);
+			continue;
+		}
+
+		if (!strcmp(pname, "REQUEST_METHOD") &&
+		    (size_t)vlen < sizeof(method)) {
+			fcgi->fcg_toread -= vlen;
+			evbuffer_remove(src, &method, vlen);
+			method[vlen] = '\0';
+
+			if (!strcasecmp(method, "GET"))
+				clt->clt_method = METHOD_GET;
+			if (!strcasecmp(method, "POST"))
+				clt->clt_method = METHOD_POST;
+
 			continue;
 		}
 
@@ -389,7 +405,73 @@ fcgi_parse_params(struct fcgi *fcgi, struct evbuffer *
 
 	return (0);
 }
+
+static int
+fcgi_parse_form(struct fcgi *fcgi, struct client *clt, struct evbuffer *src)
+{
+	char			*a, *s;
+	char			 tmp[2048];
+	size_t			 len;
+
+	if (fcgi->fcg_toread == 0) {
+		clt->clt_bodydone = 1;
+		return (proxy_start_request(fcgi->fcg_env, clt));
+	}
 
+	len = sizeof(tmp) - 1;
+	if (len > (size_t)fcgi->fcg_toread)
+		len = fcgi->fcg_toread;
+
+	fcgi->fcg_toread -= len;
+	evbuffer_remove(src, &tmp, len);
+	tmp[len] = '\0';
+
+	if (clt->clt_bodydone)
+		return (0);
+
+	if (clt->clt_bodylen > GEMINI_MAXLEN) {
+		free(clt->clt_body);
+		clt->clt_body = NULL;
+		return (0);
+	}
+
+	if (clt->clt_body != NULL) {
+		if ((a = strchr(tmp, '&')) != NULL ||
+		    (a = strchr(tmp, '\r')) != NULL) {
+			*a = '\0';
+			clt->clt_bodydone = 1;
+		}
+
+		a = clt->clt_body;
+		if (asprintf(&clt->clt_body, "%s%s", a, tmp) == -1) {
+			free(a);
+			clt->clt_body = NULL;
+			return (0);
+		}
+		clt->clt_bodylen += strlen(tmp);
+		return (0);
+	}
+
+	if (clt->clt_bodylen != 0)
+		return (0); /* EOM situation */
+
+	if ((s = strstr(tmp, "q=")) == NULL)
+		return (0);
+	s += 2;
+
+	if ((a = strchr(s, '&')) != NULL ||
+	    (a = strchr(s, '\r')) != NULL) {
+		*a = '\0';
+		clt->clt_bodydone = 1;
+	}
+
+	clt->clt_bodylen = strlen(s);
+	if ((clt->clt_body = strdup(s)) == NULL)
+		return (0);
+
+	return (0);
+}
+
 void
 fcgi_read(struct bufferevent *bev, void *d)
 {
@@ -515,7 +597,11 @@ fcgi_read(struct bufferevent *bev, void *d)
 			}
 			if (fcgi->fcg_toread == 0) {
 				evbuffer_drain(src, fcgi->fcg_toread);
-				proxy_start_request(env, clt);
+				if (clt->clt_method == METHOD_GET) {
+					if (proxy_start_request(env, clt)
+					    == -1)
+						return;
+				}
 				break;
 			}
 			if (fcgi_parse_params(fcgi, src, clt) == -1) {
@@ -525,8 +611,13 @@ fcgi_read(struct bufferevent *bev, void *d)
 			}
 			break;
 		case FCGI_STDIN:
-			/* ignore */
-			evbuffer_drain(src, fcgi->fcg_toread);
+			if (clt == NULL ||
+			    clt->clt_method != METHOD_POST) {
+				evbuffer_drain(src, fcgi->fcg_toread);
+				break;
+			}
+			if (fcgi_parse_form(fcgi, clt, src) == -1)
+				return;
 			break;
 		case FCGI_ABORT_REQUEST:
 			if (clt == NULL) {
blob - f91b4726219ad3b6279cf6434b4eb645b13cc38c
blob + 01048822f1936c48ec0afb7515c540f592595f66
--- fragments.tmpl
+++ fragments.tmpl
@@ -121,3 +121,15 @@ gemini://{{ host }}{{ path }}
 	</main>
 	{{ render tp_foot(tp) }}
 {{ end }}
+
+{{ define tp_inputpage(struct template *tp, const char *prompt) }}
+	{{ render tp_head(tp, "en", "input request") }}
+	<p>The server ask for input: {{ prompt }}</p>
+	<form method="post" enctype="{{ FORM_URLENCODED }}">
+		<label for="reply">
+			<span>response </span>
+		</label>
+		<input type="text" value="" id="reply" name="q" />
+	</form>
+{{ render tp_foot(tp) }}
+{{ end }}
blob - 45fe5a76745182c85ebc18cb5f8bbbac17c3045e
blob + 37590580ae2b38c294c24ffe438fa1b2384859d5
--- galileo.h
+++ galileo.h
@@ -29,8 +29,15 @@
 #define PROXY_NUMPROC		3
 #define PROC_PARENT_SOCK_FILENO	3
 #define GEMINI_MAXLEN		(1024 + 1) /* NULL */
+#define FORM_URLENCODED		"application/x-www-form-urlencoded"
 
 enum {
+	METHOD_UNKNOWN,
+	METHOD_GET,
+	METHOD_POST,
+};
+
+enum {
 	IMSG_NONE,
 	IMSG_CFG_START,
 	IMSG_CFG_SRV,
@@ -59,6 +66,10 @@ struct client {
 	char			*clt_script_name;
 	char			*clt_path_info;
 	char			*clt_query;
+	int			 clt_method;
+	int			 clt_bodydone;
+	char			*clt_body;
+	int			 clt_bodylen;
 	struct proxy_config	*clt_pc;
 	struct event_asr	*clt_evasr;
 	struct addrinfo		*clt_addrinfo;
@@ -169,6 +180,7 @@ int	 tp_head(struct template *, const char *, const ch
 int	 tp_foot(struct template *);
 int	 tp_figure(struct template *, const char *, const char *);
 int	 tp_error(struct template *, int, const char *);
+int	 tp_inputpage(struct template *, const char *);
 
 /* galileo.c */
 int	 accept_reserve(int, struct sockaddr *, socklen_t *, int,
@@ -183,7 +195,7 @@ extern uint32_t proxy_fcg_id;
 
 void	 proxy(struct privsep *, struct privsep_proc *);
 void	 proxy_purge(struct server *);
-void	 proxy_start_request(struct galileo *, struct client *);
+int	 proxy_start_request(struct galileo *, struct client *);
 void	 proxy_client_free(struct client *);
 
 SPLAY_PROTOTYPE(fcgi_tree, fcgi, fcg_nodes, fcgi_cmp);
blob - a8313a7a6bcf16c034dd7cfc8ad9e088e2f833be
blob + 107898868bf05ee176299f6fba32f140e52e0ab9
--- proxy.c
+++ proxy.c
@@ -350,22 +350,45 @@ proxy_server_match(struct galileo *env, struct client 
 	return NULL;
 }
 
-void
+int
 proxy_start_request(struct galileo *env, struct client *clt)
 {
 	struct addrinfo		 hints;
 	struct asr_query	*query;
-	char			 port[32];
+	int			 r;
+	char			*url, port[32];
 
 	if ((clt->clt_pc = proxy_server_match(env, clt)) == NULL) {
 		if (proxy_start_reply(clt, 501, "text/html") == -1)
-			return;
+			return (-1);
 		if (tp_error(clt->clt_tp, -1, "unknown server") == -1)
-			return;
-		fcgi_end_request(clt, 1);
-		return;
+			return (-1);
+		return (fcgi_end_request(clt, 1));
+	}
+
+	if (clt->clt_bodylen != 0 && clt->clt_body == NULL) {
+		if (proxy_start_reply(clt, 400, "text/html") == -1)
+			return (-1);
+		if (tp_error(clt->clt_tp, -1, "bad request") == -1)
+			return (-1);
+		return (fcgi_end_request(clt, 1));
 	}
 
+	if (clt->clt_body) {
+		r = asprintf(&url, "%s%s?%s", clt->clt_script_name,
+		    clt->clt_path_info + 1, clt->clt_body);
+		if (r == -1)
+			return (fcgi_end_request(clt, 1));
+
+		if (proxy_start_reply(clt, 302, url) == -1 ||
+		    fcgi_end_request(clt, 1) == -1) {
+			free(url);
+			return (-1);
+		}
+		free(url);
+		return (0);
+	}
+
 	(void)snprintf(port, sizeof(port), "%d", clt->clt_pc->proxy_port);
 
 	memset(&hints, 0, sizeof(hints));
@@ -375,17 +398,17 @@ proxy_start_request(struct galileo *env, struct client
 	query = getaddrinfo_async(clt->clt_pc->proxy_addr, port, &hints, NULL);
 	if (query == NULL) {
 		log_warn("getaddrinfo_async");
-		fcgi_abort_request(clt);
-		return;
+		return (fcgi_abort_request(clt));
 	}
 
 	clt->clt_evasr = event_asr_run(query, proxy_resolved, clt);
 	if (clt->clt_evasr == NULL) {
 		log_warn("event_asr_run");
 		asr_abort(query);
-		fcgi_abort_request(clt);
-		return;
+		return (fcgi_abort_request(clt));
 	}
+
+	return (0);
 }
 
 void
@@ -587,20 +610,30 @@ proxy_start_reply(struct client *clt, int status, cons
 	csp = "Content-Security-Policy: default-src 'self'; "
 	    "script-src 'none'; object-src 'none';\r\n";
 
-	if (ctype != NULL && !strcmp(ctype, "text/html"))
-		ctype = "text/html;charset=utf-8";
-
 	if (status != 200 &&
 	    clt_printf(clt, "Status: %d\r\n", status) == -1)
 		return (-1);
 
-	if (ctype != NULL &&
-	    clt_printf(clt, "Content-Type: %s\r\n", ctype) == -1)
-		return (-1);
-
 	if (clt_puts(clt, csp) == -1)
 		return (-1);
+
+	if (status == 302) {
+		/* use "ctype" as redirect target */
+		if (clt_printf(clt, "Location: %s\r\n", ctype) == -1)
+			return (-1);
+		if (clt_puts(clt, "\r\n") == -1)
+			return (-1);
+		return (0);
+	}
 
+	if (ctype != NULL) {
+		if (!strcmp(ctype, "text/html"))
+			ctype = "text/html;charset=utf-8";
+		if (clt_printf(clt, "Content-Type: %s\r\n", ctype)
+		    == -1)
+			return (-1);
+	}
+
 	if (clt_puts(clt, "\r\n") == -1)
 		return (-1);
 
@@ -645,6 +678,13 @@ proxy_read(struct bufferevent *bev, void *d)
 	code = (hdr[0] - '0') * 10 + (hdr[1] - '0');
 
 	switch (hdr[0]) {
+	case '1':
+		if (proxy_start_reply(clt, 200, "text/html") == -1)
+			goto err;
+		if (tp_inputpage(clt->clt_tp, &hdr[3]) == -1)
+			goto err;
+		fcgi_end_request(clt, 0);
+		goto err;
 	case '2':
 		/* handled below */
 		break;
@@ -881,6 +921,7 @@ proxy_client_free(struct client *clt)
 	if (clt->clt_bev)
 		bufferevent_free(clt->clt_bev);
 
+	free(clt->clt_body);
 	free(clt->clt_tp);
 	free(clt->clt_server_name);
 	free(clt->clt_script_name);