Commit 1ad7006d authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

A LOT more H2 plumbing.

parent 35d1e519
...@@ -221,6 +221,8 @@ h2_error H2_Send(struct worker *, const struct h2_req *, ...@@ -221,6 +221,8 @@ h2_error H2_Send(struct worker *, const struct h2_req *,
struct h2_req * h2_new_req(const struct worker *, struct h2_sess *, struct h2_req * h2_new_req(const struct worker *, struct h2_sess *,
unsigned stream, struct req *); unsigned stream, struct req *);
void h2_del_req(struct worker *, struct h2_req *); void h2_del_req(struct worker *, struct h2_req *);
void h2_kill_req(struct worker *, const struct h2_sess *,
struct h2_req *, h2_error);
int h2_rxframe(struct worker *, struct h2_sess *); int h2_rxframe(struct worker *, struct h2_sess *);
h2_error h2_set_setting(struct h2_sess *, const uint8_t *); h2_error h2_set_setting(struct h2_sess *, const uint8_t *);
void h2_req_body(struct req*); void h2_req_body(struct req*);
......
...@@ -260,7 +260,6 @@ h2_deliver(struct req *req, struct boc *boc, int sendbody) ...@@ -260,7 +260,6 @@ h2_deliver(struct req *req, struct boc *boc, int sendbody)
WS_Release(req->ws, 0); WS_Release(req->ws, 0);
if (sendbody) { if (sendbody) {
VDP_push(req, h2_bytes, NULL, 1, "H2"); VDP_push(req, h2_bytes, NULL, 1, "H2");
err = VDP_DeliverObj(req); err = VDP_DeliverObj(req);
......
...@@ -190,6 +190,31 @@ h2_del_req(struct worker *wrk, struct h2_req *r2) ...@@ -190,6 +190,31 @@ h2_del_req(struct worker *wrk, struct h2_req *r2)
SES_Delete(sp, SC_RX_JUNK, NAN); SES_Delete(sp, SC_RX_JUNK, NAN);
} }
void
h2_kill_req(struct worker *wrk, const struct h2_sess *h2,
struct h2_req *r2, h2_error h2e)
{
VSLb(h2->vsl, SLT_Debug, "KILL st=%u state=%d", r2->stream, r2->state);
Lck_Lock(&h2->sess->mtx);
r2->error = h2e;
switch (r2->state) {
case H2_S_CLOS_REM:
if (r2->wrk != NULL)
AZ(pthread_cond_signal(h2->cond));
r2 = NULL;
break;
case H2_S_OPEN:
(void)h2h_decode_fini(h2, r2->decode);
break;
default:
break;
}
Lck_Unlock(&h2->sess->mtx);
if (r2 != NULL)
h2_del_req(wrk, r2);
}
/**********************************************************************/ /**********************************************************************/
static void static void
...@@ -241,8 +266,7 @@ h2_rx_ping(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2) ...@@ -241,8 +266,7 @@ h2_rx_ping(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
(void)r2; (void)r2;
if (h2->rxf_len != 8) // rfc7540,l,2364,2366 if (h2->rxf_len != 8) // rfc7540,l,2364,2366
return (H2CE_FRAME_SIZE_ERROR); return (H2CE_FRAME_SIZE_ERROR);
if (h2->rxf_stream != 0) // rfc7540,l,2359,2362 AZ(h2->rxf_stream); // rfc7540,l,2359,2362
return (H2CE_PROTOCOL_ERROR);
if (h2->rxf_flags != 0) // We never send pings if (h2->rxf_flags != 0) // We never send pings
return (H2SE_PROTOCOL_ERROR); return (H2SE_PROTOCOL_ERROR);
H2_Send_Get(wrk, h2, r2); H2_Send_Get(wrk, h2, r2);
...@@ -275,20 +299,9 @@ h2_rx_rst_stream(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2) ...@@ -275,20 +299,9 @@ h2_rx_rst_stream(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
if (h2->rxf_len != 4) // rfc7540,l,2003,2004 if (h2->rxf_len != 4) // rfc7540,l,2003,2004
return (H2CE_FRAME_SIZE_ERROR); return (H2CE_FRAME_SIZE_ERROR);
if (r2 == NULL)
return (0);
Lck_Lock(&h2->sess->mtx);
r2->error = h2_streamerror(vbe32dec(h2->rxf_data));
VSLb(h2->vsl, SLT_Debug, "H2RST %u %d %s", r2->stream, r2->state, r2->error->name);
if (r2->wrk != NULL)
AZ(pthread_cond_signal(h2->cond));
if (r2->state != H2_S_IDLE) {
r2->state = H2_S_CLOSED;
r2 = NULL;
}
Lck_Unlock(&h2->sess->mtx);
if (r2 != NULL) if (r2 != NULL)
h2_del_req(wrk, r2); h2_kill_req(wrk, h2, r2,
h2_streamerror(vbe32dec(h2->rxf_data)));
return (0); return (0);
} }
...@@ -463,7 +476,6 @@ h2_end_headers(const struct worker *wrk, const struct h2_sess *h2, ...@@ -463,7 +476,6 @@ h2_end_headers(const struct worker *wrk, const struct h2_sess *h2,
h2_error h2e; h2_error h2e;
assert(r2->state == H2_S_OPEN); assert(r2->state == H2_S_OPEN);
r2->state = H2_S_CLOS_REM;
h2e = h2h_decode_fini(h2, r2->decode); h2e = h2h_decode_fini(h2, r2->decode);
FREE_OBJ(r2->decode); FREE_OBJ(r2->decode);
if (h2e != NULL) { if (h2e != NULL) {
...@@ -480,6 +492,7 @@ h2_end_headers(const struct worker *wrk, const struct h2_sess *h2, ...@@ -480,6 +492,7 @@ h2_end_headers(const struct worker *wrk, const struct h2_sess *h2,
req->req_step = R_STP_TRANSPORT; req->req_step = R_STP_TRANSPORT;
req->task.func = h2_do_req; req->task.func = h2_do_req;
req->task.priv = req; req->task.priv = req;
r2->state = H2_S_CLOS_REM; // XXX: not _quite_ true
XXXAZ(Pool_Task(wrk->pool, &req->task, TASK_QUEUE_REQ)); XXXAZ(Pool_Task(wrk->pool, &req->task, TASK_QUEUE_REQ));
return (0); return (0);
} }
...@@ -535,7 +548,10 @@ h2_rx_headers(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2) ...@@ -535,7 +548,10 @@ h2_rx_headers(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
} }
h2e = h2h_decode_bytes(h2, r2->decode, p, l); h2e = h2h_decode_bytes(h2, r2->decode, p, l);
if (h2e != NULL) { if (h2e != NULL) {
VSL(SLT_Debug, 0, "H2H_DECODE_BYTES %s", h2e->name); VSL(SLT_Debug, 0, "H2H_DECODE_BYTES(hdr) %s", h2e->name);
(void)h2h_decode_fini(h2, r2->decode);
AZ(r2->req->ws->r);
h2_del_req(wrk, r2);
return (h2e); return (h2e);
} }
if (h2->rxf_flags & H2FF_HEADERS_END_HEADERS) if (h2->rxf_flags & H2FF_HEADERS_END_HEADERS)
...@@ -558,7 +574,10 @@ h2_rx_continuation(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2) ...@@ -558,7 +574,10 @@ h2_rx_continuation(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
req = r2->req; req = r2->req;
h2e = h2h_decode_bytes(h2, r2->decode, h2->rxf_data, h2->rxf_len); h2e = h2h_decode_bytes(h2, r2->decode, h2->rxf_data, h2->rxf_len);
if (h2e != NULL) { if (h2e != NULL) {
VSL(SLT_Debug, 0, "H2H_DECODE_BYTES %s", h2e->name); VSL(SLT_Debug, 0, "H2H_DECODE_BYTES(cont) %s", h2e->name);
(void)h2h_decode_fini(h2, r2->decode);
AZ(r2->req->ws->r);
h2_del_req(wrk, r2);
return (h2e); return (h2e);
} }
if (h2->rxf_flags & H2FF_HEADERS_END_HEADERS) if (h2->rxf_flags & H2FF_HEADERS_END_HEADERS)
...@@ -677,6 +696,7 @@ h2_req_fail(struct req *req, enum sess_close reason) ...@@ -677,6 +696,7 @@ h2_req_fail(struct req *req, enum sess_close reason)
{ {
assert(reason > 0); assert(reason > 0);
assert(req->sp->fd != 0); assert(req->sp->fd != 0);
VSLb(req->vsl, SLT_Debug, "H2FAILREQ");
} }
/**********************************************************************/ /**********************************************************************/
...@@ -836,7 +856,7 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2) ...@@ -836,7 +856,7 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2)
h2->bogosity++; h2->bogosity++;
VSLb(h2->vsl, SLT_Debug, VSLb(h2->vsl, SLT_Debug,
"H2: Unknown flags 0x%02x on %s (ignored)", "H2: Unknown flags 0x%02x on %s (ignored)",
(uint8_t)h2->rxf_flags, h2f->name); (uint8_t)h2->rxf_flags & ~h2f->flags, h2f->name);
h2->rxf_flags &= h2f->flags; h2->rxf_flags &= h2f->flags;
} }
......
...@@ -201,6 +201,10 @@ h2_ou_session(struct worker *wrk, struct h2_sess *h2, ...@@ -201,6 +201,10 @@ h2_ou_session(struct worker *wrk, struct h2_sess *h2,
if (h2_b64url_settings(h2, req)) { if (h2_b64url_settings(h2, req)) {
VSLb(h2->vsl, SLT_Debug, "H2: Bad HTTP-Settings"); VSLb(h2->vsl, SLT_Debug, "H2: Bad HTTP-Settings");
AN (req->vcl);
VCL_Rel(&req->vcl);
CNT_AcctLogCharge(wrk->stats, req);
Req_Release(req);
return (0); return (0);
} }
...@@ -317,20 +321,25 @@ h2_new_session(struct worker *wrk, void *arg) ...@@ -317,20 +321,25 @@ h2_new_session(struct worker *wrk, void *arg)
VTAILQ_FOREACH(r2, &h2->streams, list) { VTAILQ_FOREACH(r2, &h2->streams, list) {
if (r2->error == 0) if (r2->error == 0)
r2->error = h2->error; r2->error = h2->error;
#if 0
if (r2->wrk != NULL) if (r2->wrk != NULL)
AZ(pthread_cond_signal(&r2->wrk->cond)); AZ(pthread_cond_signal(&r2->wrk->cond)); // XXX Why?
#endif
} }
AZ(pthread_cond_signal(h2->cond));
while (1) { while (1) {
VTAILQ_FOREACH(r2, &h2->streams, list) VTAILQ_FOREACH(r2, &h2->streams, list)
if (r2->state == H2_S_IDLE && r2 != h2->req0) if (r2->state != H2_S_CLOS_REM && r2 != h2->req0)
break; break;
if (r2 == NULL) if (r2 == NULL)
break; break;
Lck_Unlock(&sp->mtx); Lck_Unlock(&sp->mtx);
h2_del_req(wrk, r2); h2_kill_req(wrk, h2, r2, h2->error);
Lck_Lock(&sp->mtx); Lck_Lock(&sp->mtx);
} }
VSLb(h2->vsl, SLT_Debug, "H2CLEAN done"); VSLb(h2->vsl, SLT_Debug, "H2CLEAN done");
VTAILQ_FOREACH(r2, &h2->streams, list)
VSLb(h2->vsl, SLT_Debug, "ST %u %d", r2->stream, r2->state);
Lck_Unlock(&sp->mtx); Lck_Unlock(&sp->mtx);
h2->cond = NULL; h2->cond = NULL;
h2_del_req(wrk, h2->req0); h2_del_req(wrk, h2->req0);
......
...@@ -39,7 +39,12 @@ server s1 { ...@@ -39,7 +39,12 @@ server s1 {
txresp -status 402 -bodylen 11 txresp -status 402 -bodylen 11
} -start } -start
delay .5 varnish v1 -vsl_catchup
varnish v1 -expect MEMPOOL.req0.live == 0
varnish v1 -expect MEMPOOL.req1.live == 0
varnish v1 -expect MEMPOOL.sess0.live == 0
varnish v1 -expect MEMPOOL.sess1.live == 0
varnish v1 -cliok "param.set feature +http2" varnish v1 -cliok "param.set feature +http2"
...@@ -58,7 +63,12 @@ client c1 { ...@@ -58,7 +63,12 @@ client c1 {
expect resp.bodylen == 8 expect resp.bodylen == 8
} -run } -run
delay .5 varnish v1 -vsl_catchup
varnish v1 -expect MEMPOOL.req0.live == 0
varnish v1 -expect MEMPOOL.req1.live == 0
varnish v1 -expect MEMPOOL.sess0.live == 0
varnish v1 -expect MEMPOOL.sess1.live == 0
client c1 { client c1 {
send "GET /upgrade2 HTTP/1.1\r\n" send "GET /upgrade2 HTTP/1.1\r\n"
...@@ -86,6 +96,13 @@ client c1 { ...@@ -86,6 +96,13 @@ client c1 {
} -run } -run
} -run } -run
varnish v1 -vsl_catchup
varnish v1 -expect MEMPOOL.req0.live == 0
varnish v1 -expect MEMPOOL.req1.live == 0
varnish v1 -expect MEMPOOL.sess0.live == 0
varnish v1 -expect MEMPOOL.sess1.live == 0
client c1 { client c1 {
# Illegal HTTP2-Settings # Illegal HTTP2-Settings
send "GET /noupgrade HTTP/1.1\r\n" send "GET /noupgrade HTTP/1.1\r\n"
...@@ -96,6 +113,13 @@ client c1 { ...@@ -96,6 +113,13 @@ client c1 {
expect_close expect_close
} -run } -run
varnish v1 -vsl_catchup
varnish v1 -expect MEMPOOL.req0.live == 0
varnish v1 -expect MEMPOOL.req1.live == 0
varnish v1 -expect MEMPOOL.sess0.live == 0
varnish v1 -expect MEMPOOL.sess1.live == 0
client c1 { client c1 {
# PRISM with error in last bit # PRISM with error in last bit
send "GET /noupgrade HTTP/1.1\r\n" send "GET /noupgrade HTTP/1.1\r\n"
...@@ -111,8 +135,7 @@ client c1 { ...@@ -111,8 +135,7 @@ client c1 {
expect_close expect_close
} -run } -run
# XXX: Tests temporarily neutered, they are too flakey varnish v1 -expect MEMPOOL.req0.live == 0
#varnish v1 -expect MEMPOOL.req0.live == 0 varnish v1 -expect MEMPOOL.req1.live == 0
#varnish v1 -expect MEMPOOL.req1.live == 0 varnish v1 -expect MEMPOOL.sess0.live == 0
#varnish v1 -expect MEMPOOL.sess0.live == 0 varnish v1 -expect MEMPOOL.sess1.live == 0
#varnish v1 -expect MEMPOOL.sess1.live == 0
varnishtest "H2 Stream error conditions" varnishtest "H2 Frame coverage/error conditions"
server s1 { server s1 {
rxreq rxreq
...@@ -26,6 +26,13 @@ client c1 { ...@@ -26,6 +26,13 @@ client c1 {
stream 0 -wait stream 0 -wait
} -run } -run
varnish v1 -vsl_catchup
varnish v1 -expect MEMPOOL.req0.live == 0
varnish v1 -expect MEMPOOL.req1.live == 0
varnish v1 -expect MEMPOOL.sess0.live == 0
varnish v1 -expect MEMPOOL.sess1.live == 0
####################################################################### #######################################################################
# Test reverse order stream numbers # Test reverse order stream numbers
...@@ -44,6 +51,13 @@ client c1 { ...@@ -44,6 +51,13 @@ client c1 {
stream 0 -wait stream 0 -wait
} -run } -run
varnish v1 -vsl_catchup
varnish v1 -expect MEMPOOL.req0.live == 0
varnish v1 -expect MEMPOOL.req1.live == 0
varnish v1 -expect MEMPOOL.sess0.live == 0
varnish v1 -expect MEMPOOL.sess1.live == 0
####################################################################### #######################################################################
# Test WINDOW_UPDATE error conditions # Test WINDOW_UPDATE error conditions
...@@ -68,7 +82,13 @@ client c1 { ...@@ -68,7 +82,13 @@ client c1 {
} -start } -start
stream 5 { stream 5 {
txprio txprio
sendhex "000003 08 00 00000005 010203" sendhex "000003 08 00 00000005"
delay .1
sendhex 01
delay .1
sendhex 02
delay .1
sendhex 03
} -run } -run
stream 0 -wait stream 0 -wait
} -run } -run
...@@ -93,6 +113,13 @@ client c1 { ...@@ -93,6 +113,13 @@ client c1 {
} -run } -run
} -run } -run
varnish v1 -vsl_catchup
varnish v1 -expect MEMPOOL.req0.live == 0
varnish v1 -expect MEMPOOL.req1.live == 0
varnish v1 -expect MEMPOOL.sess0.live == 0
varnish v1 -expect MEMPOOL.sess1.live == 0
####################################################################### #######################################################################
# Test PING error conditions # Test PING error conditions
...@@ -114,6 +141,22 @@ client c1 { ...@@ -114,6 +141,22 @@ client c1 {
} -run } -run
} -run } -run
client c1 {
stream 0 {
sendhex "000007 06 80 00000000 01020304050607"
rxgoaway
expect goaway.laststream == 0
expect goaway.err == FRAME_SIZE_ERROR
} -run
} -run
varnish v1 -vsl_catchup
varnish v1 -expect MEMPOOL.req0.live == 0
varnish v1 -expect MEMPOOL.req1.live == 0
varnish v1 -expect MEMPOOL.sess0.live == 0
varnish v1 -expect MEMPOOL.sess1.live == 0
####################################################################### #######################################################################
# Test PUSH_PROMISE error conditions # Test PUSH_PROMISE error conditions
...@@ -130,6 +173,14 @@ client c1 { ...@@ -130,6 +173,14 @@ client c1 {
stream 0 -wait stream 0 -wait
} -run } -run
varnish v1 -vsl_catchup
varnish v1 -expect MEMPOOL.req0.live == 0
varnish v1 -expect MEMPOOL.req1.live == 0
varnish v1 -expect MEMPOOL.sess0.live == 0
varnish v1 -expect MEMPOOL.sess1.live == 0
#######################################################################
# Test RST_STREAM error conditions # Test RST_STREAM error conditions
client c1 { client c1 {
...@@ -166,6 +217,20 @@ client c1 { ...@@ -166,6 +217,20 @@ client c1 {
} -run } -run
} -run } -run
client c1 {
stream 1 {
txreq -nohdrend
txrst -err 0x666
} -run
} -run
varnish v1 -vsl_catchup
varnish v1 -expect MEMPOOL.req0.live == 0
varnish v1 -expect MEMPOOL.req1.live == 0
varnish v1 -expect MEMPOOL.sess0.live == 0
varnish v1 -expect MEMPOOL.sess1.live == 0
####################################################################### #######################################################################
# Test SETTING error conditions # Test SETTING error conditions
...@@ -186,8 +251,7 @@ client c1 { ...@@ -186,8 +251,7 @@ client c1 {
rxgoaway rxgoaway
expect goaway.err == PROTOCOL_ERROR expect goaway.err == PROTOCOL_ERROR
expect goaway.laststream == 0 expect goaway.laststream == 0
} -run } -run } -run
} -run
client c1 { client c1 {
stream 0 { stream 0 {
...@@ -207,3 +271,112 @@ client c1 { ...@@ -207,3 +271,112 @@ client c1 {
rxping rxping
} -run } -run
} -run } -run
varnish v1 -vsl_catchup
varnish v1 -expect MEMPOOL.req0.live == 0
varnish v1 -expect MEMPOOL.req1.live == 0
varnish v1 -expect MEMPOOL.sess0.live == 0
varnish v1 -expect MEMPOOL.sess1.live == 0
#######################################################################
# Test GOAWAY error conditions
client c1 {
stream 0 {
txgoaway -err 2
} -run
expect_close
} -run
client c1 {
stream 0 {
txgoaway -err 2222
} -run
expect_close
} -run
varnish v1 -vsl_catchup
varnish v1 -expect MEMPOOL.req0.live == 0
varnish v1 -expect MEMPOOL.req1.live == 0
varnish v1 -expect MEMPOOL.sess0.live == 0
varnish v1 -expect MEMPOOL.sess1.live == 0
#######################################################################
# Test HEADERS error conditions
client c1 {
stream 1 {
txreq -nostrend
txreq -nostrend
} -run
stream 0 {
rxgoaway
} -run
expect_close
} -run
client c1 {
stream 0 {
sendhex 00000c
sendhex 01
sendhex 05
sendhex 00000001
sendhex ffffffff
sendhex ffffffff
sendhex ffffffff
rxgoaway
expect goaway.err == COMPRESSION_ERROR
} -run
} -run
varnish v1 -vsl_catchup
varnish v1 -expect MEMPOOL.req0.live == 0
varnish v1 -expect MEMPOOL.req1.live == 0
varnish v1 -expect MEMPOOL.sess0.live == 0
varnish v1 -expect MEMPOOL.sess1.live == 0
#######################################################################
# Test CONTINUATION error conditions
client c1 {
stream 1 {
txreq -nostrend
txcont -hdr "foo" "bar"
} -run
stream 0 {
rxgoaway
} -run
expect_close
} -run
client c1 {
stream 0 {
sendhex 000014
sendhex 01
sendhex 01
sendhex 00000001
sendhex {8286 8441 0f77 7777 2e65 7861 6d70 6c65 2e63 6f6d}
sendhex 00000c
sendhex 09
sendhex 04
sendhex 00000001
sendhex ffffffff
sendhex ffffffff
sendhex ffffffff
rxgoaway
expect goaway.err == COMPRESSION_ERROR
} -run
} -run
varnish v1 -vsl_catchup
varnish v1 -expect MEMPOOL.req0.live == 0
varnish v1 -expect MEMPOOL.req1.live == 0
varnish v1 -expect MEMPOOL.sess0.live == 0
varnish v1 -expect MEMPOOL.sess1.live == 0
...@@ -27,7 +27,7 @@ client c1 { ...@@ -27,7 +27,7 @@ client c1 {
txprio txprio
} -run } -run
stream 0 { stream 0 {
txgoaway -err 7 txgoaway -err 2
} -run } -run
expect_close expect_close
} -run } -run
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment