Adjust the read/write watermarks according to the TCP send buffer.
authorreyk <reyk@openbsd.org>
Wed, 6 Aug 2014 09:36:31 +0000 (09:36 +0000)
committerreyk <reyk@openbsd.org>
Wed, 6 Aug 2014 09:36:31 +0000 (09:36 +0000)
This fixes sending of large files.  Previously, httpd was reading the
input file too quickly and could run out of memory when filling the
input buffer.

Found by jsg@
OK florian@

usr.sbin/httpd/httpd.h
usr.sbin/httpd/server.c
usr.sbin/httpd/server_file.c

index 0983ce2..449c10f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: httpd.h,v 1.47 2014/08/06 02:04:42 jsing Exp $        */
+/*     $OpenBSD: httpd.h,v 1.48 2014/08/06 09:36:31 reyk Exp $ */
 
 /*
  * Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -273,6 +273,7 @@ struct client {
        struct evbuffer         *clt_output;
        struct event             clt_ev;
        void                    *clt_desc;
+       int                      clt_sndbufsiz;
 
        int                      clt_fd;
        struct ressl            *clt_ressl_ctx;
index e3727ae..b9d3c75 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: server.c,v 1.31 2014/08/06 04:39:50 jsg Exp $ */
+/*     $OpenBSD: server.c,v 1.32 2014/08/06 09:36:31 reyk Exp $        */
 
 /*
  * Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -631,6 +631,7 @@ server_input(struct client *clt)
        struct server_config    *srv_conf = clt->clt_srv_conf;
        evbuffercb               inrd = server_read;
        evbuffercb               inwr = server_write;
+       socklen_t                slen;
 
        if (server_httpdesc_init(clt) == -1) {
                server_close(clt, "failed to allocate http descriptor");
@@ -640,6 +641,13 @@ server_input(struct client *clt)
        clt->clt_toread = TOREAD_HTTP_HEADER;
        inrd = server_read_http;
 
+       slen = sizeof(clt->clt_sndbufsiz);
+       if (getsockopt(clt->clt_s, SOL_SOCKET, SO_SNDBUF,
+           &clt->clt_sndbufsiz, &slen) == -1) {
+               server_close(clt, "failed to get send buffer size");
+               return;
+       }
+
        /*
         * Client <-> Server
         */
@@ -657,6 +665,10 @@ server_input(struct client *clt)
                    server_ssl_writecb, clt->clt_bev);
        }
 
+       /* Adjust write watermark to the socket buffer output size */
+       bufferevent_setwatermark(clt->clt_bev, EV_WRITE,
+           clt->clt_sndbufsiz, 0);
+
        bufferevent_settimeout(clt->clt_bev,
            srv_conf->timeout.tv_sec, srv_conf->timeout.tv_sec);
        bufferevent_enable(clt->clt_bev, EV_READ|EV_WRITE);
index 4989f19..5b72aaf 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: server_file.c,v 1.29 2014/08/04 17:43:20 reyk Exp $   */
+/*     $OpenBSD: server_file.c,v 1.30 2014/08/06 09:36:31 reyk Exp $   */
 
 /*
  * Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -201,6 +201,10 @@ server_file(struct httpd *env, struct client *clt)
                goto fail;
        }
 
+       /* Adjust read watermark to the socket output buffer size */
+       bufferevent_setwatermark(clt->clt_srvbev, EV_READ, 0,
+           clt->clt_sndbufsiz);
+
        bufferevent_settimeout(clt->clt_srvbev,
            srv_conf->timeout.tv_sec, srv_conf->timeout.tv_sec);
        bufferevent_enable(clt->clt_srvbev, EV_READ);