-/* $OpenBSD: httpd.h,v 1.3 2014/07/14 00:19:48 reyk Exp $ */
+/* $OpenBSD: httpd.h,v 1.4 2014/07/16 10:25:28 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
struct bufferevent *clt_file;
off_t clt_toread;
+ size_t clt_headerlen;
int clt_persist;
int clt_line;
- size_t clt_headerlen;
int clt_done;
+ int clt_inflight;
struct evbuffer *clt_log;
struct timeval clt_timeout;
struct evbuffer *, size_t);
int server_bufferevent_add(struct event *, int);
int server_bufferevent_write(struct client *, void *, size_t);
+void server_inflight_dec(struct client *, const char *);
SPLAY_PROTOTYPE(client_tree, client, clt_nodes, server_client_cmp);
-/* $OpenBSD: server.c,v 1.5 2014/07/14 00:19:48 reyk Exp $ */
+/* $OpenBSD: server.c,v 1.6 2014/07/16 10:25:28 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
server_error(struct bufferevent *bev, short error, void *arg)
{
struct client *clt = arg;
- struct evbuffer *dst;
if (error & EVBUFFER_TIMEOUT) {
server_close(clt, "buffer event timeout");
bufferevent_disable(bev, EV_READ|EV_WRITE);
clt->clt_done = 1;
-
- if (bev != clt->clt_bev) {
- dst = EVBUFFER_OUTPUT(clt->clt_bev);
- if (EVBUFFER_LENGTH(dst))
- return;
- } else
- return;
-
- if (clt->clt_persist) {
- server_reset_http(clt);
- bufferevent_enable(clt->clt_bev, EV_READ|EV_WRITE);
- return;
- } else
- server_close(clt, "done");
+ server_close(clt, "done");
return;
}
server_close(clt, "buffer event error");
clt->clt_id = ++server_cltid;
clt->clt_serverid = srv->srv_conf.id;
clt->clt_pid = getpid();
+ clt->clt_inflight = 1;
switch (ss.ss_family) {
case AF_INET:
clt->clt_port = ((struct sockaddr_in *)&ss)->sin_port;
* the client struct was not completly set up, but still
* counted as an inflight client. account for this.
*/
- server_inflight--;
- log_debug("%s: inflight decremented, now %d",
- __func__, server_inflight);
+ server_inflight_dec(clt, __func__);
}
}
+void
+server_inflight_dec(struct client *clt, const char *why)
+{
+ if (clt != NULL) {
+ /* the flight already left inflight mode. */
+ if (clt->clt_inflight == 0)
+ return;
+ clt->clt_inflight = 0;
+ }
+
+ /* the file was never opened, thus this was an inflight client. */
+ server_inflight--;
+ log_debug("%s: inflight decremented, now %d, %s",
+ __func__, server_inflight, why);
+}
+
void
server_close(struct client *clt, const char *msg)
{
bufferevent_free(clt->clt_file);
if (clt->clt_fd != -1)
close(clt->clt_fd);
-
- if (clt->clt_s != -1) {
+ if (clt->clt_s != -1)
close(clt->clt_s);
- if (/* XXX */ -1) {
- /*
- * the output was never connected,
- * thus this was an inflight client.
- */
- server_inflight--;
- log_debug("%s: clients inflight decremented, now %d",
- __func__, server_inflight);
- }
- }
+
+ server_inflight_dec(clt, __func__);
if (clt->clt_log != NULL)
evbuffer_free(clt->clt_log);
-/* $OpenBSD: server_file.c,v 1.5 2014/07/15 09:51:06 reyk Exp $ */
+/* $OpenBSD: server_file.c,v 1.6 2014/07/16 10:25:28 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
#include "httpd.h"
#include "http.h"
+void server_file_error(struct bufferevent *, short, void *);
+
int
server_file(struct httpd *env, struct client *clt)
{
if ((fd = open(path, O_RDONLY)) == -1 || fstat(fd, &st) == -1)
goto fail;
+ /* File descriptor is opened, decrement inflight counter */
+ server_inflight_dec(clt, __func__);
+
media = media_find(env->sc_mediatypes, path);
ret = server_response_http(clt, 200, media, st.st_size);
switch (ret) {
clt->clt_fd = fd;
if (clt->clt_file != NULL)
bufferevent_free(clt->clt_file);
+
clt->clt_file = bufferevent_new(clt->clt_fd, server_read,
- server_write, server_error, clt);
+ server_write, server_file_error, clt);
if (clt->clt_file == NULL) {
errstr = "failed to allocate file buffer event";
goto fail;
bufferevent_settimeout(clt->clt_file,
srv->srv_conf.timeout.tv_sec, srv->srv_conf.timeout.tv_sec);
bufferevent_enable(clt->clt_file, EV_READ);
+ bufferevent_disable(clt->clt_bev, EV_READ);
return (0);
fail:
server_abort_http(clt, 500, errstr);
return (-1);
}
+
+void
+server_file_error(struct bufferevent *bev, short error, void *arg)
+{
+ struct client *clt = arg;
+ struct evbuffer *dst;
+
+ if (error & EVBUFFER_TIMEOUT) {
+ server_close(clt, "buffer event timeout");
+ return;
+ }
+ if (error & (EVBUFFER_READ|EVBUFFER_WRITE|EVBUFFER_EOF)) {
+ bufferevent_disable(bev, EV_READ);
+
+ clt->clt_done = 1;
+
+ dst = EVBUFFER_OUTPUT(clt->clt_bev);
+ if (EVBUFFER_LENGTH(dst)) {
+ /* Finish writing all data first */
+ bufferevent_enable(clt->clt_bev, EV_WRITE);
+ return;
+ }
+
+ if (clt->clt_persist) {
+ /* Close input file and wait for next HTTP request */
+ if (clt->clt_fd != -1)
+ close(clt->clt_fd);
+ clt->clt_fd = -1;
+ clt->clt_toread = TOREAD_HTTP_HEADER;
+ server_reset_http(clt);
+ bufferevent_enable(clt->clt_bev, EV_READ|EV_WRITE);
+ return;
+ }
+ server_close(clt, "done");
+ return;
+ }
+ if (error & EVBUFFER_ERROR && errno == EFBIG) {
+ bufferevent_enable(bev, EV_READ);
+ return;
+ }
+ server_close(clt, "buffer event error");
+ return;
+}
-/* $OpenBSD: server_http.c,v 1.7 2014/07/14 09:03:08 reyk Exp $ */
+/* $OpenBSD: server_http.c,v 1.8 2014/07/16 10:25:28 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
done:
if (clt->clt_toread <= 0) {
- if (server_response(env, clt) == -1)
- return;
+ server_response(env, clt);
+ return;
}
}
if (clt->clt_done) {
clt->clt_headerlen = 0;
clt->clt_line = 0;
clt->clt_done = 0;
- clt->clt_toread = TOREAD_HTTP_HEADER;
clt->clt_bev->readcb = server_read_http;
}
if ((ret = server_file(httpd, clt)) == -1)
return (-1);
- /* XXX */
- if (!(desc->http_method == HTTP_METHOD_HEAD && clt->clt_persist == 0))
- server_reset_http(clt);
+ server_reset_http(clt);
- return (ret);
+ return (0);
fail:
server_abort_http(clt, 400, "bad request");
return (-1);