diff options
author | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2013-02-05 21:36:34 +0000 |
---|---|---|
committer | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2013-02-05 21:36:34 +0000 |
commit | 10786d23bf0a9f0752c06861637a141653371504 (patch) | |
tree | 56fc7d5c5146e9a5f62c3c23f982a8bd7cfb22f3 /usr.sbin | |
parent | 8d6362f5889fbf41b1541f51a5f444e6c67b8bd9 (diff) |
Rework http content and chunk handling in relayd. Use special
toread values to track the current http header or chunk state. This
allows to handle an optional chunk trailer properly. Tracking the
http state is also a prerequisite for splicing persistent http
connections.
OK and test reyk@ benno@
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/relayd/relay.c | 6 | ||||
-rw-r--r-- | usr.sbin/relayd/relay_http.c | 130 | ||||
-rw-r--r-- | usr.sbin/relayd/relayd.h | 9 |
3 files changed, 96 insertions, 49 deletions
diff --git a/usr.sbin/relayd/relay.c b/usr.sbin/relayd/relay.c index cc821a35587..b7df8059d5c 100644 --- a/usr.sbin/relayd/relay.c +++ b/usr.sbin/relayd/relay.c @@ -1,4 +1,4 @@ -/* $OpenBSD: relay.c,v 1.161 2013/01/17 20:34:18 bluhm Exp $ */ +/* $OpenBSD: relay.c,v 1.162 2013/02/05 21:36:33 bluhm Exp $ */ /* * Copyright (c) 2006 - 2012 Reyk Floeter <reyk@openbsd.org> @@ -643,6 +643,7 @@ relay_connected(int fd, short sig, void *arg) case RELAY_PROTO_HTTP: /* Check the servers's HTTP response */ if (!RB_EMPTY(&rlay->rl_proto->response_tree)) { + con->se_out.toread = TOREAD_HTTP_HEADER; outrd = relay_read_http; if ((con->se_out.nodes = calloc(proto->response_nodes, sizeof(u_int8_t))) == NULL) { @@ -699,6 +700,7 @@ relay_input(struct rsession *con) /* Check the client's HTTP request */ if (!RB_EMPTY(&rlay->rl_proto->request_tree) || proto->lateconnect) { + con->se_in.toread = TOREAD_HTTP_HEADER; inrd = relay_read_http; if ((con->se_in.nodes = calloc(proto->request_nodes, sizeof(u_int8_t))) == NULL) { @@ -974,6 +976,8 @@ relay_accept(int fd, short event, void *arg) con->se_out.con = con; con->se_in.splicelen = -1; con->se_out.splicelen = -1; + con->se_in.toread = TOREAD_UNLIMITED; + con->se_out.toread = TOREAD_UNLIMITED; con->se_relay = rlay; con->se_id = ++relay_conid; con->se_relayid = rlay->rl_conf.id; diff --git a/usr.sbin/relayd/relay_http.c b/usr.sbin/relayd/relay_http.c index f2ac3d1c63e..143c683b101 100644 --- a/usr.sbin/relayd/relay_http.c +++ b/usr.sbin/relayd/relay_http.c @@ -1,4 +1,4 @@ -/* $OpenBSD: relay_http.c,v 1.7 2013/01/22 08:26:34 reyk Exp $ */ +/* $OpenBSD: relay_http.c,v 1.8 2013/02/05 21:36:33 bluhm Exp $ */ /* * Copyright (c) 2006 - 2012 Reyk Floeter <reyk@openbsd.org> @@ -85,7 +85,7 @@ relay_read_http(struct bufferevent *bev, void *arg) if (!size) { if (cre->dir == RELAY_DIR_RESPONSE) return; - cre->toread = 0; + cre->toread = TOREAD_HTTP_HEADER; goto done; } @@ -317,6 +317,7 @@ relay_read_http(struct bufferevent *bev, void *arg) return; case HTTP_METHOD_CONNECT: /* Data stream */ + cre->toread = TOREAD_UNLIMITED; bev->readcb = relay_read; break; case HTTP_METHOD_DELETE: @@ -327,22 +328,25 @@ relay_read_http(struct bufferevent *bev, void *arg) case HTTP_METHOD_PUT: case HTTP_METHOD_RESPONSE: /* HTTP request payload */ - if (cre->toread) { + if (cre->toread > 0) bev->readcb = relay_read_httpcontent; - break; - } /* Single-pass HTTP response */ - bev->readcb = relay_read; + if (cre->toread < 0) { + cre->toread = TOREAD_UNLIMITED; + bev->readcb = relay_read; + } + break; default: /* HTTP handler */ + cre->toread = TOREAD_HTTP_HEADER; bev->readcb = relay_read_http; break; } if (cre->chunked) { /* Chunked transfer encoding */ - cre->toread = 0; + cre->toread = TOREAD_HTTP_CHUNK_LENGTH; bev->readcb = relay_read_httpchunks; } @@ -353,7 +357,7 @@ relay_read_http(struct bufferevent *bev, void *arg) relay_http_request_close(cre); done: - if (cre->dir == RELAY_DIR_REQUEST && !cre->toread && + if (cre->dir == RELAY_DIR_REQUEST && cre->toread < 0 && proto->lateconnect && cre->dst->bev == NULL) { if (rlay->rl_conf.fwdmode == FWD_TRANS) { relay_bindanyreq(con, 0, IPPROTO_TCP); @@ -390,17 +394,31 @@ relay_read_httpcontent(struct bufferevent *bev, void *arg) if (gettimeofday(&con->se_tv_last, NULL) == -1) goto fail; size = EVBUFFER_LENGTH(src); - DPRINTF("%s: size %lu, to read %lld", __func__, - size, cre->toread); + DPRINTF("%s: dir %d, size %lu, to read %lld", + __func__, cre->dir, size, cre->toread); if (!size) return; - if (relay_bufferevent_write_buffer(cre->dst, src) == -1) - goto fail; - if ((off_t)size >= cre->toread) + + if (cre->toread > 0) { + /* Read content data */ + if ((off_t)size > cre->toread) { + size = cre->toread; + if (relay_bufferevent_write_chunk(cre->dst, src, size) + == -1) + goto fail; + cre->toread = 0; + } else { + if (relay_bufferevent_write_buffer(cre->dst, src) == -1) + goto fail; + cre->toread -= size; + } + DPRINTF("%s: done, size %lu, to read %lld", __func__, + size, cre->toread); + } + if (cre->toread == 0) { + cre->toread = TOREAD_HTTP_HEADER; bev->readcb = relay_read_http; - cre->toread -= size; - DPRINTF("%s: done, size %lu, to read %lld", __func__, - size, cre->toread); + } if (con->se_done) goto done; if (bev->readcb != relay_read_httpcontent) @@ -427,19 +445,36 @@ relay_read_httpchunks(struct bufferevent *bev, void *arg) if (gettimeofday(&con->se_tv_last, NULL) == -1) goto fail; size = EVBUFFER_LENGTH(src); - DPRINTF("%s: size %lu, to read %lld", __func__, - size, cre->toread); + DPRINTF("%s: dir %d, size %lu, to read %lld", + __func__, cre->dir, size, cre->toread); if (!size) return; - if (!cre->toread) { + if (cre->toread > 0) { + /* Read chunk data */ + if ((off_t)size > cre->toread) { + size = cre->toread; + if (relay_bufferevent_write_chunk(cre->dst, src, size) + == -1) + goto fail; + cre->toread = 0; + } else { + if (relay_bufferevent_write_buffer(cre->dst, src) == -1) + goto fail; + cre->toread -= size; + } + DPRINTF("%s: done, size %lu, to read %lld", __func__, + size, cre->toread); + } + switch (cre->toread) { + case TOREAD_HTTP_CHUNK_LENGTH: line = evbuffer_readline(src); if (line == NULL) { /* Ignore empty line, continue */ bufferevent_enable(bev, EV_READ); return; } - if (!strlen(line)) { + if (strlen(line) == 0) { free(line); goto next; } @@ -458,40 +493,41 @@ relay_read_httpchunks(struct bufferevent *bev, void *arg) } free(line); - /* Last chunk is 0 bytes followed by an empty newline */ + /* Last chunk is 0 bytes followed by optional trailer */ if ((cre->toread = lval) == 0) { DPRINTF("%s: last chunk", __func__); - - line = evbuffer_readline(src); - if (line == NULL) { - relay_close(con, "invalid last chunk"); - return; - } + cre->toread = TOREAD_HTTP_CHUNK_TRAILER; + } + break; + case TOREAD_HTTP_CHUNK_TRAILER: + /* Last chunk is 0 bytes followed by trailer and empty line */ + line = evbuffer_readline(src); + if (line == NULL) { + /* Ignore empty line, continue */ + bufferevent_enable(bev, EV_READ); + return; + } + if (relay_bufferevent_print(cre->dst, line) == -1 || + relay_bufferevent_print(cre->dst, "\r\n") == -1) { free(line); - if (relay_bufferevent_print(cre->dst, "\r\n") == -1) - goto fail; - + goto fail; + } + if (strlen(line) == 0) { /* Switch to HTTP header mode */ + cre->toread = TOREAD_HTTP_HEADER; bev->readcb = relay_read_http; } - } else { - /* Read chunk data */ - if ((off_t)size > cre->toread) - size = cre->toread; - if (relay_bufferevent_write_chunk(cre->dst, src, size) == -1) + free(line); + break; + case 0: + /* Chunk is terminated by an empty newline */ + line = evbuffer_readline(src); + if (line != NULL) + free(line); + if (relay_bufferevent_print(cre->dst, "\r\n") == -1) goto fail; - cre->toread -= size; - DPRINTF("%s: done, size %lu, to read %lld", __func__, - size, cre->toread); - - if (cre->toread == 0) { - /* Chunk is terminated by an empty (empty) newline */ - line = evbuffer_readline(src); - if (line != NULL) - free(line); - if (relay_bufferevent_print(cre->dst, "\r\n") == -1) - goto fail; - } + cre->toread = TOREAD_HTTP_CHUNK_LENGTH; + break; } next: diff --git a/usr.sbin/relayd/relayd.h b/usr.sbin/relayd/relayd.h index 3a20f85ae72..bd6b8744f0e 100644 --- a/usr.sbin/relayd/relayd.h +++ b/usr.sbin/relayd/relayd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: relayd.h,v 1.163 2012/11/27 05:00:28 guenther Exp $ */ +/* $OpenBSD: relayd.h,v 1.164 2013/02/05 21:36:33 bluhm Exp $ */ /* * Copyright (c) 2006 - 2012 Reyk Floeter <reyk@openbsd.org> @@ -196,6 +196,13 @@ struct ctl_relay_event { int buflen; }; +enum httpchunk { + TOREAD_UNLIMITED = -1, + TOREAD_HTTP_HEADER = -2, + TOREAD_HTTP_CHUNK_LENGTH = -3, + TOREAD_HTTP_CHUNK_TRAILER = -4 +}; + struct ctl_natlook { objid_t id; int proc; |