Put in first stab at fastcgi. Very early work in progress. Putting it
authorflorian <florian@openbsd.org>
Thu, 31 Jul 2014 09:23:53 +0000 (09:23 +0000)
committerflorian <florian@openbsd.org>
Thu, 31 Jul 2014 09:23:53 +0000 (09:23 +0000)
in now so that we can quickly work on it in tree. Requested by reyk@.
deraadt@ is OK with this according to reyk@.

usr.sbin/httpd/Makefile
usr.sbin/httpd/httpd.h
usr.sbin/httpd/server_fcgi.c [new file with mode: 0644]
usr.sbin/httpd/server_http.c

index aca6355..e9de76c 100644 (file)
@@ -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
index 7fa00ef..852a93f 100644 (file)
@@ -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 (file)
index 0000000..0e847f2
--- /dev/null
@@ -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);
+}
index 8e4de31..da60d15 100644 (file)
@@ -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);