| 1379 | } |
| 1380 | |
| 1381 | static void ev_stream_done(h2_proxy_session *session, int stream_id, |
| 1382 | const char *msg) |
| 1383 | { |
| 1384 | h2_proxy_stream *stream; |
| 1385 | apr_bucket *b; |
| 1386 | |
| 1387 | stream = nghttp2_session_get_stream_user_data(session->ngh2, stream_id); |
| 1388 | if (stream) { |
| 1389 | /* if the stream's connection is aborted, do not send anything |
| 1390 | * more on it. */ |
| 1391 | apr_status_t status = (stream->error_code == 0)? APR_SUCCESS : APR_EINVAL; |
| 1392 | int touched = (stream->data_sent || stream->data_received || |
| 1393 | stream_id <= session->last_stream_id); |
| 1394 | if (!stream->cfront->aborted) { |
| 1395 | ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, stream->cfront, APLOGNO(03364) |
| 1396 | "h2_proxy_sesssion(%s): stream(%d) closed " |
| 1397 | "(touched=%d, error=%d)", |
| 1398 | session->id, stream_id, touched, stream->error_code); |
| 1399 | |
| 1400 | if (status != APR_SUCCESS) { |
| 1401 | /* stream failed. If we have received (and forwarded) response |
| 1402 | * data already, we need to append an error buckt to inform |
| 1403 | * consumers. |
| 1404 | * Otherwise, we have an early fail on the connection and may |
| 1405 | * retry this request on a new one. In that case, keep the |
| 1406 | * output virgin so that a new attempt can be made. */ |
| 1407 | if (stream->data_received) { |
| 1408 | int http_status = ap_map_http_request_error(status, HTTP_BAD_REQUEST); |
| 1409 | b = ap_bucket_error_create(http_status, NULL, stream->r->pool, |
| 1410 | stream->cfront->bucket_alloc); |
| 1411 | APR_BRIGADE_INSERT_TAIL(stream->output, b); |
| 1412 | b = apr_bucket_eos_create(stream->cfront->bucket_alloc); |
| 1413 | APR_BRIGADE_INSERT_TAIL(stream->output, b); |
| 1414 | ap_pass_brigade(stream->r->output_filters, stream->output); |
| 1415 | } |
| 1416 | } |
| 1417 | else if (!stream->data_received) { |
| 1418 | /* if the response had no body, this is the time to flush |
| 1419 | * an empty brigade which will also write the response headers */ |
| 1420 | h2_proxy_stream_end_headers_out(stream); |
| 1421 | stream->data_received = 1; |
| 1422 | b = apr_bucket_flush_create(stream->cfront->bucket_alloc); |
| 1423 | APR_BRIGADE_INSERT_TAIL(stream->output, b); |
| 1424 | b = apr_bucket_eos_create(stream->cfront->bucket_alloc); |
| 1425 | APR_BRIGADE_INSERT_TAIL(stream->output, b); |
| 1426 | ap_pass_brigade(stream->r->output_filters, stream->output); |
| 1427 | } |
| 1428 | } |
| 1429 | |
| 1430 | stream->state = H2_STREAM_ST_CLOSED; |
| 1431 | h2_proxy_ihash_remove(session->streams, stream_id); |
| 1432 | h2_proxy_iq_remove(session->suspended, stream_id); |
| 1433 | if (session->done) { |
| 1434 | session->done(session, stream->r, status, touched, stream->error_code); |
| 1435 | } |
| 1436 | } |
| 1437 | |
| 1438 | switch (session->state) { |
no test coverage detected