free(data);
}
+static int stream_write_data_free_err(trie_val_t *val, void *null)
+{
+ on_pkt_write(*val, kr_error(EIO));
+ return 0;
+}
+
/*
* Cleanup for closed streams.
*
if (ctx->incomplete_stream == stream_id)
http_cleanup_stream(ctx);
+ trie_del(ctx->stream_write_data, (char *)&stream_id, sizeof(stream_id), NULL);
data = nghttp2_session_get_stream_user_data(h2, stream_id);
if (data)
on_pkt_write(data, error_code == 0 ? 0 : kr_error(EIO));
ctx->send_cb = send_cb;
ctx->session = session;
queue_init(ctx->streams);
+ ctx->stream_write_data = trie_create(NULL);
ctx->incomplete_stream = -1;
ctx->submitted = 0;
ctx->current_method = HTTP_METHOD_NONE;
*
* Data isn't guaranteed to be sent immediately due to underlying HTTP/2 flow control.
*/
-static int http_send_response(nghttp2_session *h2, int32_t stream_id,
+static int http_send_response(struct http_ctx *ctx, int32_t stream_id,
nghttp2_data_provider *prov)
{
+ nghttp2_session *h2 = ctx->h2;
struct http_data *data = (struct http_data*)prov->source.ptr;
int ret;
const char *directive_max_age = "max-age=";
return kr_error(EIO);
}
+ /* Keep reference to data, since we need to free it later on.
+ * Due to HTTP/2 flow control, this stream data may be sent at a later point, or not at all.
+ */
+ trie_val_t *stream_data_p = trie_get_ins(ctx->stream_write_data, (char *)&stream_id, sizeof(stream_id));
+ if (kr_fails_assert(stream_data_p)) {
+ kr_log_debug(DOH, "[%p] failed to insert to stream_write_data\n", (void *)h2);
+ free(data);
+ return kr_error(EIO);
+ }
+ *stream_data_p = data;
ret = nghttp2_session_send(h2);
if(ret < 0) {
kr_log_debug(DOH, "[%p] nghttp2_session_send failed: %s\n", (void *)h2, nghttp2_strerror(ret));
* musn't be!) called, since such errors are handled in an upper layer - in
* qr_task_step() in daemon/worker.
*/
-static int http_write_pkt(nghttp2_session *h2, knot_pkt_t *pkt, int32_t stream_id,
+static int http_write_pkt(struct http_ctx *ctx, knot_pkt_t *pkt, int32_t stream_id,
uv_write_t *req, uv_write_cb on_write)
{
struct http_data *data;
prov.source.ptr = data;
prov.read_callback = read_callback;
- return http_send_response(h2, stream_id, &prov);
+ return http_send_response(ctx, stream_id, &prov);
}
/*
if (!ctx || !ctx->h2)
return kr_error(EINVAL);
- ret = http_write_pkt(ctx->h2, pkt, stream_id, req, on_write);
+ ret = http_write_pkt(ctx, pkt, stream_id, req, on_write);
if (ret < 0)
return ret;
queue_pop(ctx->streams);
}
+ trie_apply(ctx->stream_write_data, stream_write_data_free_err, NULL);
+ trie_free(ctx->stream_write_data);
+
http_cleanup_stream(ctx);
queue_deinit(ctx->streams);
nghttp2_session_del(ctx->h2);