Apparently Google remove tabulations when I copy/paste the patch.
Please download attachment to gets patch with tabulations.
--
Bertrand PROVOST
Index: http.h
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/http.h,v
retrieving revision 1.5
diff -u -p -r1.5 http.h
--- http.h 14 Aug 2014 10:30:52 -0000 1.5
+++ http.h 12 May 2015 13:14:21 -0000
@@ -180,6 +180,14 @@ struct http_mediatype {
{ NULL } \
}
+/* Define state of current http relay */
+enum httpstate {
+ HTTP_STATE_READ_HEADER = 0,
+ HTTP_STATE_READ_CONTENT,
+ HTTP_STATE_READ_CHUNKS,
+ HTTP_STATE_READ_DATA,
+};
+
/* Used during runtime */
struct http_descriptor {
struct kv http_pathquery;
@@ -202,6 +210,8 @@ struct http_descriptor {
/* A tree of headers and attached lists for repeated headers. */
struct kv *http_lastheader;
struct kvtree http_headers;
+
+ enum httpstate http_state;
};
#endif /* _HTTP_H */
Index: relay.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relay.c,v
retrieving revision 1.193
diff -u -p -r1.193 relay.c
--- relay.c 29 Apr 2015 08:41:24 -0000 1.193
+++ relay.c 12 May 2015 13:14:21 -0000
@@ -683,7 +683,7 @@ relay_connected(int fd, short sig, void
return;
}
con->se_out.toread = TOREAD_HTTP_HEADER;
- outrd = relay_read_http;
+ outrd = relay_read_http_cb;
break;
case RELAY_PROTO_TCP:
/* Use defaults */
@@ -734,7 +734,7 @@ relay_input(struct rsession *con)
return;
}
con->se_in.toread = TOREAD_HTTP_HEADER;
- inrd = relay_read_http;
+ inrd = relay_read_http_cb;
break;
case RELAY_PROTO_TCP:
/* Use defaults */
Index: relay_http.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relay_http.c,v
retrieving revision 1.44
diff -u -p -r1.44 relay_http.c
--- relay_http.c 29 Apr 2015 08:41:24 -0000 1.44
+++ relay_http.c 12 May 2015 13:14:21 -0000
@@ -49,8 +49,9 @@ int relay_lookup_url(struct ctl_relay_
int relay_lookup_query(struct ctl_relay_event *, struct kv *);
int relay_lookup_cookie(struct ctl_relay_event *, const char *,
struct kv *);
-void relay_read_httpcontent(struct bufferevent *, void *);
-void relay_read_httpchunks(struct bufferevent *, void *);
+int relay_read_http(struct bufferevent *, void *);
+int relay_read_httpcontent(struct bufferevent *, void *);
+int relay_read_httpchunks(struct bufferevent *, void *);
char *relay_expand_http(struct ctl_relay_event *, char *,
char *, size_t);
int relay_writeheader_kv(struct ctl_relay_event *, struct kv *);
@@ -151,7 +152,53 @@ relay_httpdesc_free(struct http_descript
kv_purge(&desc->http_headers);
}
-void
+void relay_read_http_cb(struct bufferevent *bev, void *arg) {
+ struct ctl_relay_event *cre = arg;
+ struct http_descriptor *desc = cre->desc;
+ struct rsession *con = cre->con;
+ struct evbuffer *src = EVBUFFER_INPUT(bev);
+ int rc = 0;
+ int stop = 0;
+ int try_splice = 0;
+
+ do {
+ switch (desc->http_state) {
+ case HTTP_STATE_READ_HEADER:
+ rc = relay_read_http(bev, arg);
+ if (rc != -1 && desc->http_state ==
HTTP_STATE_READ_HEADER) {
+ // The state does not change, so it can stop
here
+ // this mean the http headers has not been
fully parsed
+ // because there is not enough data available
+ stop = 1;
+ try_splice = 1;
+ }
+ break;
+ case HTTP_STATE_READ_CONTENT:
+ rc = relay_read_httpcontent(bev, arg);
+ if (rc != -1 && desc->http_state ==
HTTP_STATE_READ_CONTENT) {
+ // The state does not change, so it can stop
here
+ stop = 1;
+ try_splice = 0;
+ }
+ break;
+ case HTTP_STATE_READ_CHUNKS:
+ rc = relay_read_httpchunks(bev, arg);
+ try_splice = 0;
+ break;
+ case HTTP_STATE_READ_DATA:
+ relay_read(bev, arg);
+ return;
+ }
+ } while (!stop && rc == 0 && EVBUFFER_LENGTH(src));
+
+ if (rc == 0) {
+ bufferevent_enable(bev, EV_READ);
+ if (try_splice && relay_splice(cre) == -1)
+ relay_close(con, strerror(errno));
+ }
+}
+
+int
relay_read_http(struct bufferevent *bev, void *arg)
{
struct ctl_relay_event *cre = arg;
@@ -174,7 +221,7 @@ relay_read_http(struct bufferevent *bev,
__func__, con->se_id, size, cre->toread);
if (!size) {
if (cre->dir == RELAY_DIR_RESPONSE)
- return;
+ return 1;
cre->toread = TOREAD_HTTP_HEADER;
goto done;
}
@@ -198,7 +245,7 @@ relay_read_http(struct bufferevent *bev,
if (cre->headerlen > RELAY_MAXHEADERLENGTH) {
free(line);
relay_abort_http(con, 413, "request too large", 0);
- return;
+ return -1;
}
/*
@@ -216,7 +263,7 @@ relay_read_http(struct bufferevent *bev,
if (cre->line == 1) {
free(line);
relay_abort_http(con, 400, "malformed", 0);
- return;
+ return -1;
}
/* Append line to the last header, if present */
@@ -354,23 +401,23 @@ relay_read_http(struct bufferevent *bev,
if (cre->done) {
if (desc->http_method == HTTP_METHOD_NONE) {
relay_abort_http(con, 406, "no method", 0);
- return;
+ return -1;
}
action = relay_test(proto, cre);
if (action == RES_FAIL) {
relay_close(con, "filter rule failed");
- return;
+ return -1;
} else if (action != RES_PASS) {
relay_abort_http(con, 403, "Forbidden", con->se_label);
- return;
+ return -1;
}
switch (desc->http_method) {
case HTTP_METHOD_CONNECT:
/* Data stream */
cre->toread = TOREAD_UNLIMITED;
- bev->readcb = relay_read;
+ desc->http_state = HTTP_STATE_READ_DATA;
break;
case HTTP_METHOD_DELETE:
case HTTP_METHOD_GET:
@@ -383,24 +430,24 @@ relay_read_http(struct bufferevent *bev,
case HTTP_METHOD_RESPONSE:
/* HTTP request payload */
if (cre->toread > 0)
- bev->readcb = relay_read_httpcontent;
+ desc->http_state = HTTP_STATE_READ_CONTENT;
/* Single-pass HTTP body */
if (cre->toread < 0) {
cre->toread = TOREAD_UNLIMITED;
- bev->readcb = relay_read;
+ desc->http_state = HTTP_STATE_READ_DATA;
}
break;
default:
/* HTTP handler */
cre->toread = TOREAD_HTTP_HEADER;
- bev->readcb = relay_read_http;
+ desc->http_state = HTTP_STATE_READ_HEADER;
break;
}
if (desc->http_chunked) {
/* Chunked transfer encoding */
cre->toread = TOREAD_HTTP_CHUNK_LENGTH;
- bev->readcb = relay_read_httpchunks;
+ desc->http_state = HTTP_STATE_READ_CHUNKS;
}
if (cre->dir == RELAY_DIR_REQUEST) {
@@ -421,35 +468,32 @@ relay_read_http(struct bufferevent *bev,
cre->dst->bev == NULL) {
if (rlay->rl_conf.fwdmode == FWD_TRANS) {
relay_bindanyreq(con, 0, IPPROTO_TCP);
- return;
+ return -1;
}
if (relay_connect(con) == -1) {
relay_abort_http(con, 502, "session failed", 0);
- return;
+ return -1;
}
}
}
if (con->se_done) {
relay_close(con, "last http read (done)");
- return;
+ return -1;
}
- if (EVBUFFER_LENGTH(src) && bev->readcb != relay_read_http)
- bev->readcb(bev, arg);
- bufferevent_enable(bev, EV_READ);
- if (relay_splice(cre) == -1)
- relay_close(con, strerror(errno));
- return;
+ return 0;
fail:
relay_abort_http(con, 500, strerror(errno), 0);
- return;
+ return -1;
abort:
free(line);
+ return -1;
}
-void
+int
relay_read_httpcontent(struct bufferevent *bev, void *arg)
{
struct ctl_relay_event *cre = arg;
+ struct http_descriptor *desc = cre->desc;
struct rsession *con = cre->con;
struct evbuffer *src = EVBUFFER_INPUT(bev);
size_t size;
@@ -461,7 +505,7 @@ relay_read_httpcontent(struct buffereven
DPRINTF("%s: session %d: size %lu, to read %lld", __func__,
con->se_id, size, cre->toread);
if (!size)
- return;
+ return 1;
if (relay_spliceadjust(cre) == -1)
goto fail;
@@ -483,25 +527,24 @@ relay_read_httpcontent(struct buffereven
}
if (cre->toread == 0) {
cre->toread = TOREAD_HTTP_HEADER;
- bev->readcb = relay_read_http;
+ desc->http_state = HTTP_STATE_READ_HEADER;
}
if (con->se_done)
goto done;
- if (bev->readcb != relay_read_httpcontent)
- bev->readcb(bev, arg);
- bufferevent_enable(bev, EV_READ);
- return;
+ return 0;
done:
relay_close(con, "last http content read");
- return;
+ return -1;
fail:
relay_close(con, strerror(errno));
+ return -1;
}
-void
+int
relay_read_httpchunks(struct bufferevent *bev, void *arg)
{
struct ctl_relay_event *cre = arg;
+ struct http_descriptor *desc = cre->desc;
struct rsession *con = cre->con;
struct evbuffer *src = EVBUFFER_INPUT(bev);
char *line;
@@ -515,7 +558,7 @@ relay_read_httpchunks(struct bufferevent
DPRINTF("%s: session %d: size %lu, to read %lld", __func__,
con->se_id, size, cre->toread);
if (!size)
- return;
+ return 1;
if (relay_spliceadjust(cre) == -1)
goto fail;
@@ -541,7 +584,7 @@ relay_read_httpchunks(struct bufferevent
if (line == NULL) {
/* Ignore empty line, continue */
bufferevent_enable(bev, EV_READ);
- return;
+ return 1;
}
if (strlen(line) == 0) {
free(line);
@@ -555,7 +598,7 @@ relay_read_httpchunks(struct bufferevent
if (sscanf(line, "%llx", &llval) != 1 || llval < 0) {
free(line);
relay_close(con, "invalid chunk size");
- return;
+ return -1;
}
if (relay_bufferevent_print(cre->dst, line) == -1 ||
@@ -576,7 +619,7 @@ relay_read_httpchunks(struct bufferevent
if (line == NULL) {
/* Ignore empty line, continue */
bufferevent_enable(bev, EV_READ);
- return;
+ return -1;
}
if (relay_bufferevent_print(cre->dst, line) == -1 ||
relay_bufferevent_print(cre->dst, "\r\n") == -1) {
@@ -586,7 +629,7 @@ relay_read_httpchunks(struct bufferevent
if (strlen(line) == 0) {
/* Switch to HTTP header mode */
cre->toread = TOREAD_HTTP_HEADER;
- bev->readcb = relay_read_http;
+ desc->http_state = HTTP_STATE_READ_HEADER;
}
free(line);
break;
@@ -604,16 +647,14 @@ relay_read_httpchunks(struct bufferevent
next:
if (con->se_done)
goto done;
- if (EVBUFFER_LENGTH(src))
- bev->readcb(bev, arg);
- bufferevent_enable(bev, EV_READ);
- return;
+ return 0;
done:
relay_close(con, "last http chunk read (done)");
- return;
+ return -1;
fail:
relay_close(con, strerror(errno));
+ return -1;
}
void
Index: relayd.h
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relayd.h,v
retrieving revision 1.209
diff -u -p -r1.209 relayd.h
--- relayd.h 2 May 2015 13:15:24 -0000 1.209
+++ relayd.h 12 May 2015 13:14:21 -0000
@@ -1184,7 +1184,7 @@ void relay_http(struct relayd *);
void relay_http_init(struct relay *);
void relay_abort_http(struct rsession *, u_int, const char *,
u_int16_t);
-void relay_read_http(struct bufferevent *, void *);
+void relay_read_http_cb(struct bufferevent *, void *);
void relay_close_http(struct rsession *);
u_int relay_httpmethod_byname(const char *);
const char