This is an automated email from the ASF dual-hosted git repository.
zwoop pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/9.0.x by this push:
new 2baa388 Dechunk chunked contents on HttpTunnel if client protocol is
HTTP/2 or HTTP/3
2baa388 is described below
commit 2baa388c3e3cb3ff71c468c8b0b4c68d8a0320fe
Author: Masaori Koshiba <[email protected]>
AuthorDate: Mon Sep 2 14:31:56 2019 +0900
Dechunk chunked contents on HttpTunnel if client protocol is HTTP/2 or
HTTP/3
(cherry picked from commit 3ac74b5157cf6705b94d5eeb910953e25a6cdfc0)
---
proxy/http/HttpTransact.cc | 15 ++++----
proxy/http2/Http2Stream.cc | 93 +++-------------------------------------------
proxy/http2/Http2Stream.h | 18 +--------
3 files changed, 15 insertions(+), 111 deletions(-)
diff --git a/proxy/http/HttpTransact.cc b/proxy/http/HttpTransact.cc
index 0664a45..918a4b0 100644
--- a/proxy/http/HttpTransact.cc
+++ b/proxy/http/HttpTransact.cc
@@ -6730,11 +6730,10 @@ HttpTransact::handle_response_keep_alive_headers(State
*s, HTTPVersion ver, HTTP
// to the client to keep the connection alive.
// Insert a Transfer-Encoding header in the response if necessary.
- // check that the client is HTTP 1.1 and the conf allows chunking or the
client
- // protocol unchunks before returning to the user agent (i.e. is http/2)
- if (s->client_info.http_version == HTTPVersion(1, 1) &&
- (s->txn_conf->chunking_enabled == 1 ||
- (s->state_machine->plugin_tag &&
(!strncmp(s->state_machine->plugin_tag, "http/2", 6)))) &&
+ // check that the client protocol is HTTP/1.1 and the conf allows chunking
or
+ // the client protocol doesn't support chunked transfer coding (i.e.
HTTP/1.0, HTTP/2, and HTTP/3)
+ if (s->state_machine->ua_txn &&
s->state_machine->ua_txn->is_chunked_encoding_supported() &&
+ s->client_info.http_version == HTTPVersion(1, 1) &&
s->txn_conf->chunking_enabled == 1 &&
// if we're not sending a body, don't set a chunked header regardless
of server response
!is_response_body_precluded(s->hdr_info.client_response.status_get(),
s->method) &&
// we do not need chunked encoding for internal error messages
@@ -6767,10 +6766,12 @@ HttpTransact::handle_response_keep_alive_headers(State
*s, HTTPVersion ver, HTTP
// Close the connection if client_info is not keep-alive.
// Otherwise, if we cannot trust the content length, we will close the
connection
- // unless we are going to use chunked encoding or the client issued
- // a PUSH request
+ // unless we are going to use chunked encoding on HTTP/1.1 or the client
issued a PUSH request
if (s->client_info.keep_alive != HTTP_KEEPALIVE) {
ka_action = KA_DISABLED;
+ } else if (s->state_machine->client_protocol &&
(IP_PROTO_TAG_HTTP_3.compare(s->state_machine->client_protocol) == 0 ||
+
strncmp(s->state_machine->client_protocol, "http/2", 6) == 0)) {
+ ka_action = KA_CONNECTION;
} else if (s->hdr_info.trust_response_cl == false &&
!(s->client_info.receive_chunked_response == true ||
(s->method == HTTP_WKSIDX_PUSH && s->client_info.keep_alive
== HTTP_KEEPALIVE))) {
diff --git a/proxy/http2/Http2Stream.cc b/proxy/http2/Http2Stream.cc
index fad170c..8d2d5c6 100644
--- a/proxy/http2/Http2Stream.cc
+++ b/proxy/http2/Http2Stream.cc
@@ -575,7 +575,7 @@ void
Http2Stream::update_write_request(IOBufferReader *buf_reader, int64_t
write_len, bool call_update)
{
if (!this->is_client_state_writeable() || closed || _proxy_ssn == nullptr ||
write_vio.mutex == nullptr ||
- (buf_reader == nullptr && write_len == 0)) {
+ (buf_reader == nullptr && write_len == 0) || this->response_reader ==
nullptr) {
return;
}
@@ -589,22 +589,7 @@ Http2Stream::update_write_request(IOBufferReader
*buf_reader, int64_t write_len,
SCOPED_MUTEX_LOCK(lock, write_vio.mutex, this_ethread());
- // if response is chunked, limit the dechunked_buffer size.
- bool is_done = false;
- if (this->chunked) {
- if (chunked_handler.dechunked_buffer &&
chunked_handler.dechunked_buffer->max_read_avail() > HTTP2_MAX_BUFFER_USAGE) {
- if (buffer_full_write_event == nullptr) {
- buffer_full_write_event = _thread->schedule_imm(this,
VC_EVENT_WRITE_READY);
- }
- } else {
- this->response_process_data(is_done);
- }
- }
-
- if (this->response_get_data_reader() == nullptr) {
- return;
- }
- int64_t bytes_avail = this->response_get_data_reader()->read_avail();
+ int64_t bytes_avail = this->response_reader->read_avail();
if (write_vio.nbytes > 0 && write_vio.ntodo() > 0) {
int64_t num_to_write = write_vio.ntodo();
if (num_to_write > write_len) {
@@ -619,7 +604,7 @@ Http2Stream::update_write_request(IOBufferReader
*buf_reader, int64_t write_len,
", reader.read_avail=%" PRId64,
write_vio.nbytes, write_vio.ndone,
write_vio.get_writer()->write_avail(), bytes_avail);
- if (bytes_avail <= 0 && !is_done) {
+ if (bytes_avail <= 0) {
return;
}
@@ -654,17 +639,7 @@ Http2Stream::update_write_request(IOBufferReader
*buf_reader, int64_t write_len,
h2_proxy_ssn->connection_state.send_headers_frame(this);
}
- // See if the response is chunked. Set up the dechunking logic if it is
- // Make sure to check if the chunk is complete and signal appropriately
- this->response_initialize_data_handling(is_done);
-
- // If there is additional data, send it along in a data frame. Or if
this was header only
- // make sure to send the end of stream
- is_done |= (write_vio.ntodo() + this->response_header.length_get()) ==
bytes_avail;
- if (this->response_is_data_available() || is_done) {
- if (is_done) {
- this->mark_body_done();
- }
+ if (this->response_reader->is_read_avail_more_than(0)) {
this->_milestones.mark(Http2StreamMilestone::START_TX_DATA_FRAMES);
this->send_response_body(call_update);
}
@@ -677,9 +652,6 @@ Http2Stream::update_write_request(IOBufferReader
*buf_reader, int64_t write_len,
break;
}
} else {
- if (write_vio.ntodo() == bytes_avail || is_done) {
- this->mark_body_done();
- }
this->_milestones.mark(Http2StreamMilestone::START_TX_DATA_FRAMES);
this->send_response_body(call_update);
}
@@ -820,7 +792,6 @@ Http2Stream::destroy()
if (header_blocks) {
ats_free(header_blocks);
}
- chunked_handler.clear();
clear_timers();
clear_io_events();
http_parser_clear(&http_parser);
@@ -829,53 +800,10 @@ Http2Stream::destroy()
THREAD_FREE(this, http2StreamAllocator, this_ethread());
}
-void
-Http2Stream::response_initialize_data_handling(bool &is_done)
-{
- is_done = false;
- int chunked_index =
response_header.value_get_index(TS_MIME_FIELD_TRANSFER_ENCODING,
TS_MIME_LEN_TRANSFER_ENCODING,
- TS_HTTP_VALUE_CHUNKED,
TS_HTTP_LEN_CHUNKED);
- // -1 means this value was not found for this field
- if (chunked_index >= 0) {
- Http2StreamDebug("Response is chunked");
- chunked = true;
- this->chunked_handler.init_by_action(this->response_reader,
ChunkedHandler::ACTION_DECHUNK);
- this->chunked_handler.state = ChunkedHandler::CHUNK_READ_SIZE;
- this->chunked_handler.dechunked_reader =
this->chunked_handler.dechunked_buffer->alloc_reader();
- this->response_reader->dealloc();
- this->response_reader = nullptr;
- // Get things going if there is already data waiting
- if (this->chunked_handler.chunked_reader->is_read_avail_more_than(0)) {
- response_process_data(is_done);
- }
- }
-}
-
-void
-Http2Stream::response_process_data(bool &done)
-{
- done = false;
- if (chunked) {
- do {
- if (chunked_handler.state == ChunkedHandler::CHUNK_FLOW_CONTROL) {
- chunked_handler.state = ChunkedHandler::CHUNK_READ_SIZE_START;
- }
- done = this->chunked_handler.process_chunked_content();
- } while (chunked_handler.state == ChunkedHandler::CHUNK_FLOW_CONTROL);
- }
-}
-
-bool
-Http2Stream::response_is_data_available() const
-{
- IOBufferReader *reader = this->response_get_data_reader();
- return reader ? reader->is_read_avail_more_than(0) : false;
-}
-
IOBufferReader *
Http2Stream::response_get_data_reader() const
{
- return (chunked) ? chunked_handler.dechunked_reader : response_reader;
+ return this->response_reader;
}
void
@@ -1053,17 +981,6 @@ Http2Stream::_switch_thread_if_not_on_right_thread(int
event, void *edata)
return true;
}
-void
-Http2Stream::mark_body_done()
-{
- body_done = true;
- if (response_is_chunked()) {
- ink_assert(chunked_handler.state == ChunkedHandler::CHUNK_READ_DONE ||
- chunked_handler.state == ChunkedHandler::CHUNK_READ_ERROR);
- this->write_vio.nbytes = response_header.length_get() +
chunked_handler.dechunked_size;
- }
-}
-
int
Http2Stream::get_transaction_priority_weight() const
{
diff --git a/proxy/http2/Http2Stream.h b/proxy/http2/Http2Stream.h
index 759b0f2..58baee6 100644
--- a/proxy/http2/Http2Stream.h
+++ b/proxy/http2/Http2Stream.h
@@ -24,9 +24,8 @@
#pragma once
#include "HTTP2.h"
-#include "../ProxyTransaction.h"
+#include "ProxyTransaction.h"
#include "Http2DebugNames.h"
-#include "../http/HttpTunnel.h" // To get ChunkedHandler
#include "Http2DependencyTree.h"
#include "tscore/History.h"
#include "Milestones.h"
@@ -107,7 +106,6 @@ public:
bool is_client_state_writeable() const;
bool is_closed() const;
- bool response_is_chunked() const;
IOBufferReader *response_get_data_reader() const;
void mark_milestone(Http2StreamMilestone type);
@@ -115,7 +113,6 @@ public:
void increment_data_length(uint64_t length);
bool payload_length_is_valid() const;
bool is_body_done() const;
- void mark_body_done();
void update_sent_count(unsigned num_bytes);
Http2StreamId get_id() const;
Http2StreamState get_state() const;
@@ -146,8 +143,6 @@ public:
Http2DependencyTree::Node *priority_node = nullptr;
private:
- void response_initialize_data_handling(bool &is_done);
- void response_process_data(bool &is_done);
bool response_is_data_available() const;
Event *send_tracked_event(Event *event, int send_event, VIO *vio);
void send_response_body(bool call_update);
@@ -173,8 +168,6 @@ private:
Milestones<Http2StreamMilestone,
static_cast<size_t>(Http2StreamMilestone::LAST_ENTRY)> _milestones;
bool trailing_header = false;
- bool body_done = false;
- bool chunked = false;
// A brief discussion of similar flags and state variables: _state, closed,
terminate_stream
//
@@ -208,7 +201,6 @@ private:
std::vector<size_t> _recent_rwnd_increment = {SIZE_MAX, SIZE_MAX, SIZE_MAX,
SIZE_MAX, SIZE_MAX};
int _recent_rwnd_increment_index = 0;
- ChunkedHandler chunked_handler;
Event *cross_thread_event = nullptr;
Event *buffer_full_write_event = nullptr;
@@ -240,7 +232,7 @@ Http2Stream::mark_milestone(Http2StreamMilestone type)
inline bool
Http2Stream::is_body_done() const
{
- return body_done;
+ return this->write_vio.ntodo() == 0;
}
inline void
@@ -301,12 +293,6 @@ Http2Stream::payload_length_is_valid() const
}
inline bool
-Http2Stream::response_is_chunked() const
-{
- return chunked;
-}
-
-inline bool
Http2Stream::allow_half_open() const
{
return false;