summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/httpd/Makefile4
-rw-r--r--usr.sbin/httpd/httpd.h6
-rw-r--r--usr.sbin/httpd/server_fcgi.c230
-rw-r--r--usr.sbin/httpd/server_http.c8
4 files changed, 243 insertions, 5 deletions
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 <reyk@openbsd.org>
@@ -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 <florian@openbsd.org>
+ *
+ * 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/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/tree.h>
+#include <sys/hash.h>
+
+#include <net/if.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <err.h>
+#include <event.h>
+
+#include <openssl/ssl.h>
+
+#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 <reyk@openbsd.org>
@@ -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);