From: florian Date: Thu, 31 Jul 2014 09:23:53 +0000 (+0000) Subject: Put in first stab at fastcgi. Very early work in progress. Putting it X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=ab07c98933d9d32ab7bd716f6d2307fe4bcf326f;p=openbsd Put in first stab at fastcgi. Very early work in progress. Putting it in now so that we can quickly work on it in tree. Requested by reyk@. deraadt@ is OK with this according to reyk@. --- diff --git a/usr.sbin/httpd/Makefile b/usr.sbin/httpd/Makefile index aca6355bcd3..e9de76c5026 100644 --- a/usr.sbin/httpd/Makefile +++ b/usr.sbin/httpd/Makefile @@ -1,9 +1,9 @@ -# $OpenBSD: Makefile,v 1.21 2014/07/27 23:52:05 deraadt Exp $ +# $OpenBSD: Makefile,v 1.22 2014/07/31 09:23:53 florian Exp $ PROG= httpd SRCS= parse.y SRCS+= config.c control.c httpd.c log.c proc.c -SRCS+= server.c server_http.c server_file.c +SRCS+= server.c server_http.c server_file.c server_fcgi.c MAN= httpd.8 httpd.conf.5 LDADD= -levent -lssl -lcrypto -lutil diff --git a/usr.sbin/httpd/httpd.h b/usr.sbin/httpd/httpd.h index 7fa00efc9f4..852a93fd596 100644 --- a/usr.sbin/httpd/httpd.h +++ b/usr.sbin/httpd/httpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: httpd.h,v 1.19 2014/07/30 13:49:48 reyk Exp $ */ +/* $OpenBSD: httpd.h,v 1.20 2014/07/31 09:23:53 florian Exp $ */ /* * Copyright (c) 2006 - 2014 Reyk Floeter @@ -254,6 +254,7 @@ struct client { int clt_fd; struct bufferevent *clt_file; + struct bufferevent *clt_fcgi; off_t clt_toread; size_t clt_headerlen; @@ -432,6 +433,9 @@ const char * /* server_file.c */ int server_file(struct httpd *, struct client *); +/* server_fcgi.c */ +int server_fcgi(struct httpd *, struct client *); + /* httpd.c */ void event_again(struct event *, int, short, void (*)(int, short, void *), diff --git a/usr.sbin/httpd/server_fcgi.c b/usr.sbin/httpd/server_fcgi.c new file mode 100644 index 00000000000..0e847f26cd3 --- /dev/null +++ b/usr.sbin/httpd/server_fcgi.c @@ -0,0 +1,230 @@ +/* $OpenBSD: server_fcgi.c,v 1.1 2014/07/31 09:23:53 florian Exp $ */ + +/* + * Copyright (c) 2014 Florian Obser + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "httpd.h" +#include "http.h" + +#define FCGI_CONTENT_SIZE 65535 +#define FCGI_PADDING_SIZE 255 +#define FCGI_RECORD_SIZE \ + (sizeof(struct fcgi_record_header) + FCGI_CONTENT_SIZE + FCGI_PADDING_SIZE) + +#define FCGI_BEGIN_REQUEST 1 +#define FCGI_ABORT_REQUEST 2 +#define FCGI_END_REQUEST 3 +#define FCGI_PARAMS 4 +#define FCGI_STDIN 5 +#define FCGI_STDOUT 6 +#define FCGI_STDERR 7 +#define FCGI_DATA 8 +#define FCGI_GET_VALUES 9 +#define FCGI_GET_VALUES_RESULT 10 +#define FCGI_UNKNOWN_TYPE 11 +#define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE) + +#define FCGI_RESPONDER 1 + +struct fcgi_record_header { + uint8_t version; + uint8_t type; + uint16_t id; + uint16_t content_len; + uint8_t padding_len; + uint8_t reserved; +}__packed; + +struct fcgi_begin_request_body { + uint16_t role; + uint8_t flags; + uint8_t reserved[5]; +}__packed; + +void server_fcgi_read(struct bufferevent *, void *); +void server_fcgi_error(struct bufferevent *, short, void *); +int fcgi_add_param(uint8_t *, char *, char *, int); + +int +server_fcgi(struct httpd *env, struct client *clt) +{ + struct server_config *srv_conf = clt->clt_srv_conf; + struct http_descriptor *desc = clt->clt_desc; + struct sockaddr_un sun; + struct fcgi_record_header *h; + struct fcgi_begin_request_body *begin; + size_t len, total_len; + int fd; + const char *errstr = NULL; + uint8_t buf[FCGI_RECORD_SIZE]; + uint8_t *params; + + log_info("server_fcgi"); + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) + goto fail; + + bzero(&sun, sizeof(sun)); + sun.sun_family = AF_UNIX; + len = strlcpy(sun.sun_path, "/run/slowcgi.sock", sizeof(sun.sun_path)); + if (len >= sizeof(sun.sun_path)) { + errstr = "socket path to long"; + goto fail; + } + sun.sun_len = len; + + log_info("path: %s", sun.sun_path); + if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) + goto fail; + + if (clt->clt_fcgi != NULL) + bufferevent_free(clt->clt_fcgi); + clt->clt_fcgi = bufferevent_new(fd, server_fcgi_read, + NULL, server_fcgi_error, clt); + if (clt->clt_fcgi == NULL) { + errstr = "failed to allocate fcgi buffer event"; + goto fail; + } + bufferevent_settimeout(clt->clt_fcgi, + srv_conf->timeout.tv_sec, srv_conf->timeout.tv_sec); + bufferevent_enable(clt->clt_fcgi, EV_READ); + + bzero(&buf, sizeof(buf)); + + h = (struct fcgi_record_header *) &buf; + h->version = 1; + h->type = FCGI_BEGIN_REQUEST; + h->id = htons(1); + h->content_len = htons(sizeof(struct fcgi_begin_request_body)); + h->padding_len = 0; + + begin = (struct fcgi_begin_request_body *) &buf[sizeof(struct + fcgi_record_header)]; + begin->role = htons(FCGI_RESPONDER); + + bufferevent_write(clt->clt_fcgi, &buf, + sizeof(struct fcgi_record_header) + + sizeof(struct fcgi_begin_request_body)); + + h->type = FCGI_PARAMS; + h->content_len = 0; + params = &buf[sizeof(struct fcgi_record_header)]; + + total_len = 0; + + len = fcgi_add_param(params, "SCRIPT_NAME", desc->http_path, + FCGI_CONTENT_SIZE); + params += len; + total_len += len; + + h->content_len = htons(total_len); + + bufferevent_write(clt->clt_fcgi, &buf, + sizeof(struct fcgi_record_header) + + ntohs(h->content_len)); + + h->content_len = 0; + + bufferevent_write(clt->clt_fcgi, &buf, + sizeof(struct fcgi_record_header)); + + h->type = FCGI_STDIN; + + bufferevent_write(clt->clt_fcgi, &buf, + sizeof(struct fcgi_record_header)); + + return (0); + fail: + if (errstr == NULL) + errstr = strerror(errno); + server_abort_http(clt, 500, errstr); + return (-1); +} + +int +fcgi_add_param(uint8_t *buf, char *key, char *val, int size) +{ + int len = 0; + log_info("%s => %s", key, val); + buf[0] = strlen(key); + len++; + buf[1] = strlen(val); + len++; + len += strlcpy(buf + len, key, size - len); + len += strlcpy(buf + len, val, size - len); + + return len; +} + +void +server_fcgi_read(struct bufferevent *bev, void *arg) +{ + struct client *clt = (struct client *) arg; + struct fcgi_record_header *h; + uint8_t buf[FCGI_RECORD_SIZE]; + size_t len; + + len = bufferevent_read(bev, &buf, FCGI_RECORD_SIZE); + + log_info("server_fcgi_read: %lu", len); + + h = (struct fcgi_record_header *) &buf; + log_info("h->version: %d", h->version); + log_info("h->type: %d", h->type); + log_info("h->id: %d", ntohs(h->id)); + log_info("h->content_len: %d", ntohs(h->content_len)); + + if (h->type == FCGI_STDOUT && ntohs(h->content_len) > 0) { + log_info("%s", (char*) &buf + + sizeof(struct fcgi_record_header)); + server_bufferevent_print(clt, "HTTP/1.1 200 OK\r\n"); + server_bufferevent_print(clt, (char*) &buf + + sizeof(struct fcgi_record_header)); + + } +} + +void +server_fcgi_error(struct bufferevent *bev, short error, void *arg) +{ + log_info("server_fcgi_error: %d", error); +} diff --git a/usr.sbin/httpd/server_http.c b/usr.sbin/httpd/server_http.c index 8e4de311747..da60d15ab99 100644 --- a/usr.sbin/httpd/server_http.c +++ b/usr.sbin/httpd/server_http.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server_http.c,v 1.21 2014/07/30 13:49:48 reyk Exp $ */ +/* $OpenBSD: server_http.c,v 1.22 2014/07/31 09:23:53 florian Exp $ */ /* * Copyright (c) 2006 - 2014 Reyk Floeter @@ -754,7 +754,11 @@ server_response(struct httpd *httpd, struct client *clt) } } - if ((ret = server_file(httpd, clt)) == -1) + if (strlen(desc->http_path) > strlen("/cgi-bin/") && + strncmp("/cgi-bin/", desc->http_path, strlen("/cgi-bin/")) == 0) { + if ((ret = server_fcgi(httpd, clt)) == -1) + return (-1); + } else if ((ret = server_file(httpd, clt)) == -1) return (-1); server_reset_http(clt);