Repository: trafficserver Updated Branches: refs/heads/5.1.x ea4fec414 -> 2e52a3722
[TS-3049] - Enhance FetchSM to handle response with "Connection:Close" header Limit the response header/body duplication to non-streaming scenarios for backward compatibility with TSFetchUrl() Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/2e52a372 Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/2e52a372 Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/2e52a372 Branch: refs/heads/5.1.x Commit: 2e52a37223079fe3936c602eb3c0da6b662aac7c Parents: ea4fec4 Author: Sudheer Vinukonda <[email protected]> Authored: Wed Sep 3 16:21:33 2014 +0000 Committer: Sudheer Vinukonda <[email protected]> Committed: Wed Sep 3 16:36:14 2014 +0000 ---------------------------------------------------------------------- proxy/FetchSM.cc | 115 ++++++++++++++++++++++++++++++-------------------- proxy/FetchSM.h | 9 +++- 2 files changed, 76 insertions(+), 48 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2e52a372/proxy/FetchSM.cc ---------------------------------------------------------------------- diff --git a/proxy/FetchSM.cc b/proxy/FetchSM.cc index c8bf84d..5338d1b 100644 --- a/proxy/FetchSM.cc +++ b/proxy/FetchSM.cc @@ -119,6 +119,9 @@ FetchSM::has_body() if (check_chunked()) return true; + if (check_connection_close()) + return true; + resp_content_length = hdr->value_get_int64(MIME_FIELD_CONTENT_LENGTH, MIME_LEN_CONTENT_LENGTH); if (!resp_content_length) return false; @@ -130,7 +133,7 @@ bool FetchSM::check_body_done() { if (!check_chunked()) { - if (resp_content_length == resp_recived_body_len + resp_reader->read_avail()) + if (resp_content_length == resp_received_body_len + resp_reader->read_avail()) return true; return false; @@ -143,41 +146,57 @@ FetchSM::check_body_done() } bool -FetchSM::check_chunked() +FetchSM::check_for_field_value(char const* name, size_t name_len, char const* value, size_t value_len) { - int ret; + bool zret = false; // not found. StrList slist; HTTPHdr *hdr = &client_response_hdr; - if (resp_is_chunked >= 0) - return resp_is_chunked; + int ret = hdr->value_get_comma_list(name, name_len, &slist); ink_release_assert(header_done); - resp_is_chunked = 0; - ret = hdr->value_get_comma_list(MIME_FIELD_TRANSFER_ENCODING, - MIME_LEN_TRANSFER_ENCODING, &slist); if (ret) { for (Str *f = slist.head; f != NULL; f = f->next) { - if (f->len == 0) - continue; - - size_t len = sizeof("chunked") - 1; - len = len > f->len ? f->len : len; - if (!strncasecmp(f->str, "chunked", len)) { - resp_is_chunked = 1; - if (fetch_flags & TS_FETCH_FLAGS_DECHUNK) { - ChunkedHandler *ch = &chunked_handler; - ch->init_by_action(resp_reader, ChunkedHandler::ACTION_DECHUNK); - ch->dechunked_reader = ch->dechunked_buffer->alloc_reader(); - ch->state = ChunkedHandler::CHUNK_READ_SIZE; - resp_reader->dealloc(); - } - return true; + if (f->len == value_len && 0 == strncasecmp(f->str, value, value_len)) { + Debug(DEBUG_TAG, "[%s] field '%.*s', value '%.*s'", __FUNCTION__, static_cast<int>(name_len), name, static_cast<int>(value_len), value); + zret = true; + break; } } } + return zret; +} + +bool +FetchSM::check_chunked() +{ + static char const CHUNKED_TEXT[] = "chunked"; + static size_t const CHUNKED_LEN = sizeof(CHUNKED_TEXT) - 1; + + if (resp_is_chunked < 0) { + resp_is_chunked = static_cast<int>(this->check_for_field_value(MIME_FIELD_TRANSFER_ENCODING, MIME_LEN_TRANSFER_ENCODING, CHUNKED_TEXT, CHUNKED_LEN)); + + if (resp_is_chunked && (fetch_flags & TS_FETCH_FLAGS_DECHUNK)) { + ChunkedHandler *ch = &chunked_handler; + ch->init_by_action(resp_reader, ChunkedHandler::ACTION_DECHUNK); + ch->dechunked_reader = ch->dechunked_buffer->alloc_reader(); + ch->state = ChunkedHandler::CHUNK_READ_SIZE; + resp_reader->dealloc(); + } + } + return resp_is_chunked > 0; +} - return resp_is_chunked; +bool +FetchSM::check_connection_close() +{ + static char const CLOSE_TEXT[] = "close"; + static size_t const CLOSE_LEN = sizeof(CLOSE_TEXT) - 1; + + if (resp_received_close < 0) { + resp_received_close = static_cast<int>(this->check_for_field_value(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION, CLOSE_TEXT, CLOSE_LEN)); + } + return resp_received_close > 0; } int @@ -200,10 +219,12 @@ FetchSM::dechunk_body() } void -FetchSM::InvokePluginExt(int error_event) +FetchSM::InvokePluginExt(int fetch_event) { int event; EThread *mythread = this_ethread(); + bool read_complete_event = + (fetch_event == TS_EVENT_VCONN_READ_COMPLETE)||(fetch_event == TS_EVENT_VCONN_EOS); // // Increasing *recursion* to prevent @@ -218,8 +239,8 @@ FetchSM::InvokePluginExt(int error_event) if (!contp) goto out; - if (error_event) { - contp->handleEvent(error_event, this); + if (fetch_event && !read_complete_event) { + contp->handleEvent(fetch_event, this); goto out; } @@ -233,8 +254,8 @@ FetchSM::InvokePluginExt(int error_event) goto out; } - Debug(DEBUG_TAG, "[%s] chunked:%d, content_len: %" PRId64 ", recived_len: %" PRId64 ", avail: %" PRId64 "\n", - __FUNCTION__, resp_is_chunked, resp_content_length, resp_recived_body_len, + Debug(DEBUG_TAG, "[%s] chunked:%d, content_len: %" PRId64 ", received_len: %" PRId64 ", avail: %" PRId64 "\n", + __FUNCTION__, resp_is_chunked, resp_content_length, resp_received_body_len, resp_is_chunked > 0 ? chunked_handler.chunked_reader->read_avail() : resp_reader->read_avail()); if (resp_is_chunked > 0) { @@ -245,7 +266,7 @@ FetchSM::InvokePluginExt(int error_event) } if (!check_chunked()) { - if (!check_body_done()) + if (!check_body_done() && !read_complete_event) contp->handleEvent(TS_FETCH_EVENT_EXT_BODY_READY, this); else contp->handleEvent(TS_FETCH_EVENT_EXT_BODY_DONE, this); @@ -372,21 +393,23 @@ FetchSM::process_fetch_read(int event) switch (event) { case TS_EVENT_VCONN_READ_READY: - bytes = resp_reader->read_avail(); - Debug(DEBUG_TAG, "[%s] number of bytes in read ready %" PRId64, __FUNCTION__, bytes); - - - while (total_bytes_copied < bytes) { - int64_t actual_bytes_copied; - actual_bytes_copied = resp_buffer->write(resp_reader, bytes, 0); - Debug(DEBUG_TAG, "[%s] copied %" PRId64 " bytes", __FUNCTION__, actual_bytes_copied); - if (actual_bytes_copied <= 0) { - break; - } - total_bytes_copied += actual_bytes_copied; + // duplicate the bytes for backward compatibility with TSFetchUrl() + if (!(fetch_flags & TS_FETCH_FLAGS_STREAM)) { + bytes = resp_reader->read_avail(); + Debug(DEBUG_TAG, "[%s] number of bytes in read ready %" PRId64, __FUNCTION__, bytes); + + while (total_bytes_copied < bytes) { + int64_t actual_bytes_copied; + actual_bytes_copied = resp_buffer->write(resp_reader, bytes, 0); + Debug(DEBUG_TAG, "[%s] copied %" PRId64 " bytes", __FUNCTION__, actual_bytes_copied); + if (actual_bytes_copied <= 0) { + break; + } + total_bytes_copied += actual_bytes_copied; + } + Debug(DEBUG_TAG, "[%s] total copied %" PRId64 " bytes", __FUNCTION__, total_bytes_copied); + resp_reader->consume(total_bytes_copied); } - Debug(DEBUG_TAG, "[%s] total copied %" PRId64 " bytes", __FUNCTION__, total_bytes_copied); - resp_reader->consume(total_bytes_copied); if (header_done == 0 && ((fetch_flags & TS_FETCH_FLAGS_STREAM) || callback_options == AFTER_HEADER)) { if (client_response_hdr.parse_resp(&http_parser, resp_reader, &bytes_used, 0) == PARSE_DONE) { @@ -405,7 +428,7 @@ FetchSM::process_fetch_read(int event) case TS_EVENT_VCONN_READ_COMPLETE: case TS_EVENT_VCONN_EOS: if (fetch_flags & TS_FETCH_FLAGS_STREAM) - return InvokePluginExt(); + return InvokePluginExt(event); if(callback_options == AFTER_HEADER || callback_options == AFTER_BODY) { get_info_from_buffer(resp_reader); InvokePlugin( callback_events.success_event_id, (void *) this); @@ -589,7 +612,7 @@ FetchSM::ext_read_data(char *buf, size_t len) blk = next_blk; } - resp_recived_body_len += already; + resp_received_body_len += already; TSIOBufferReaderConsume(reader, already); read_vio->reenable(); http://git-wip-us.apache.org/repos/asf/trafficserver/blob/2e52a372/proxy/FetchSM.h ---------------------------------------------------------------------- diff --git a/proxy/FetchSM.h b/proxy/FetchSM.h index 24a79af..1200fe5 100644 --- a/proxy/FetchSM.h +++ b/proxy/FetchSM.h @@ -55,7 +55,8 @@ public: req_content_length = 0; resp_is_chunked = -1; resp_content_length = -1; - resp_recived_body_len = 0; + resp_received_body_len = 0; + resp_received_close = -1; cont_mutex.clear(); req_buffer = new_MIOBuffer(HTTP_HEADER_BUFFER_SIZE_INDEX); req_reader = req_buffer->alloc_reader(); @@ -136,10 +137,13 @@ private: } int64_t getReqLen() const { return req_reader->read_avail(); } + /// Check if the comma supproting MIME field @a name has @a value in it. + bool check_for_field_value(char const* name, size_t name_len, char const* value, size_t value_len); bool has_body(); bool check_body_done(); bool check_chunked(); + bool check_connection_close(); int dechunk_body(); int recursion; @@ -165,12 +169,13 @@ private: bool is_internal_request; IpEndpoint _addr; int resp_is_chunked; + int resp_received_close; int fetch_flags; void *user_data; bool has_sent_header; int64_t req_content_length; int64_t resp_content_length; - int64_t resp_recived_body_len; + int64_t resp_received_body_len; }; #endif
