commit 8857131d3f62c08a0b3d450582560322c36ea219 from: Omar Polo date: Tue Sep 20 21:35:58 2022 UTC support gemini code 1x 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 }} {{ render tp_foot(tp) }} {{ end }} + +{{ define tp_inputpage(struct template *tp, const char *prompt) }} + {{ render tp_head(tp, "en", "input request") }} +

The server ask for input: {{ prompt }}

+
+ + +
+{{ 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);