You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by su...@apache.org on 2014/09/03 18:23:16 UTC

git commit: [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()

Repository: trafficserver
Updated Branches:
  refs/heads/master b5b12230c -> e83b131bb


[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/e83b131b
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/e83b131b
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/e83b131b

Branch: refs/heads/master
Commit: e83b131bb9456fa0abf211b7f8c22ed20ca0ae4c
Parents: b5b1223
Author: Sudheer Vinukonda <su...@yahoo-inc.com>
Authored: Wed Sep 3 16:21:33 2014 +0000
Committer: Sudheer Vinukonda <su...@yahoo-inc.com>
Committed: Wed Sep 3 16:21:33 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/e83b131b/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/e83b131b/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