/** Reports a local stream error */ static int vlc_h2_stream_error(void *ctx, uint_fast32_t id, uint_fast32_t code) { struct vlc_h2_conn *conn = ctx; /* NOTE: This function is used both w/ and w/o conn->lock. Care. */ if (code != VLC_H2_NO_ERROR) msg_Err(CO(conn), "local stream %"PRIuFAST32" error: " "%s (0x%"PRIXFAST32")", id, vlc_h2_strerror(code), code); else msg_Dbg(CO(conn), "local stream %"PRIuFAST32" shut down", id); return vlc_h2_output_send(conn->out, vlc_h2_frame_rst_stream(id, code)); }
int main(void) { struct vlc_http_stream *s, *s2; struct vlc_http_msg *m; struct block_t *b; uint_fast32_t sid = -1; /* Second guessed stream IDs :-/ */ conn_create(); conn_destroy(); conn_create(); conn_send(vlc_h2_frame_ping(42)); conn_expect(PING); /* Test rejected stream */ sid += 2; s = stream_open(); assert(s != NULL); conn_expect(HEADERS); conn_send(vlc_h2_frame_rst_stream(sid, VLC_H2_REFUSED_STREAM)); m = vlc_http_stream_read_headers(s); assert(m == NULL); b = vlc_http_stream_read(s); assert(b == NULL); vlc_http_stream_close(s, false); conn_expect(RST_STREAM); /* Test accepted stream */ sid += 2; s = stream_open(); assert(s != NULL); stream_reply(sid, false); m = vlc_http_msg_get_initial(s); assert(m != NULL); vlc_http_msg_destroy(m); stream_data(3, "Hello ", false); /* late data */ stream_data(3, "world!", true); conn_expect(HEADERS); conn_expect(RST_STREAM); conn_expect(RST_STREAM); conn_expect(RST_STREAM); /* Test continuation then accepted stream */ sid += 2; s = stream_open(); assert(s != NULL); stream_continuation(sid); m = vlc_http_msg_get_initial(s); assert(m != NULL); assert(vlc_http_msg_get_status(m) == 100); stream_reply(sid, false); m = vlc_http_msg_iterate(m); assert(m != NULL); stream_data(sid, "Hello ", false); stream_data(sid, "world!", true); stream_data(sid, "Stray message", false); /* data after EOS */ b = vlc_http_msg_read(m); assert(b != NULL); block_Release(b); b = vlc_http_msg_read(m); assert(b != NULL); block_Release(b); b = vlc_http_msg_read(m); assert(b == NULL); vlc_http_msg_destroy(m); conn_expect(HEADERS); conn_expect(RST_STREAM); conn_expect(RST_STREAM); /* Test accepted stream after continuation */ sid += 2; s = stream_open(); assert(s != NULL); stream_continuation(sid); stream_reply(sid, true); sid += 2; s2 = stream_open(); /* second stream to enforce test timing/ordering */ assert(s2 != NULL); stream_reply(sid, true); m = vlc_http_msg_get_initial(s2); assert(m != NULL); vlc_http_msg_destroy(m); m = vlc_http_msg_get_initial(s); assert(m != NULL); assert(vlc_http_msg_get_status(m) == 200); b = vlc_http_msg_read(m); assert(b == NULL); vlc_http_msg_destroy(m); conn_expect(HEADERS); conn_expect(HEADERS); conn_expect(RST_STREAM); conn_expect(RST_STREAM); /* Test nonexistent stream reset */ conn_send(vlc_h2_frame_rst_stream(sid + 100, VLC_H2_REFUSED_STREAM)); /* Test multiple streams in non-LIFO order */ sid += 2; s = stream_open(); assert(s != NULL); sid += 2; s2 = stream_open(); assert(s2 != NULL); stream_reply(sid, false); stream_reply(sid - 2, true); stream_data(sid, "Discarded", false); /* not read data */ m = vlc_http_msg_get_initial(s); assert(m != NULL); vlc_http_msg_destroy(m); m = vlc_http_msg_get_initial(s2); assert(m != NULL); vlc_http_msg_destroy(m); conn_expect(HEADERS); conn_expect(HEADERS); conn_expect(RST_STREAM); conn_expect(RST_STREAM); /* might or might not seen one or two extra RST_STREAM now */ /* Test graceful connection termination */ sid += 2; s = stream_open(); assert(s != NULL); conn_send(vlc_h2_frame_goaway(sid - 2, VLC_H2_NO_ERROR)); m = vlc_http_stream_read_headers(s); assert(m == NULL); /* Test stream after connection shut down */ assert(stream_open() == NULL); /* Test releasing connection before stream */ conn_destroy(); vlc_http_stream_close(s, false); return 0; }