You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by jp...@apache.org on 2014/03/29 00:31:29 UTC

[07/13] git commit: TS-2675: metalink: Handle the end of the input independently from the TS_EVENT_VCONN_WRITE_COMPLETE event from downstream

TS-2675: metalink: Handle the end of the input independently from the TS_EVENT_VCONN_WRITE_COMPLETE event from downstream


Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/52622d28
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/52622d28
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/52622d28

Branch: refs/heads/master
Commit: 52622d2809464ace2ab36e888a19f51a9edb508e
Parents: d25b00c
Author: Jack Bates <ja...@nottheoilrig.com>
Authored: Thu Mar 13 12:56:53 2014 -0700
Committer: James Peach <jp...@apache.org>
Committed: Fri Mar 28 16:23:54 2014 -0700

----------------------------------------------------------------------
 plugins/experimental/metalink/metalink.cc | 170 +++++++++++++------------
 1 file changed, 88 insertions(+), 82 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/52622d28/plugins/experimental/metalink/metalink.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/metalink/metalink.cc b/plugins/experimental/metalink/metalink.cc
index 77f62dc..f792d8a 100644
--- a/plugins/experimental/metalink/metalink.cc
+++ b/plugins/experimental/metalink/metalink.cc
@@ -225,20 +225,41 @@ write_handler(TSCont contp, TSEvent event, void *edata)
 }
 
 /* Copy content from the input buffer to the output buffer without modification
- * while at the same time feeding it to the message digest */
+ * and feed it through the message digest at the same time.
+ *
+ *   1. Check if any more input is possible before doing anything else to avoid
+ *      failed asserts.
+ *   2. Then deal with any input that's available now.
+ *   3. Check if the input is complete after dealing with any available input
+ *      in case it was the last of it.  If it is complete, do any bookkeeping
+ *      that downstream needs and finish computing the digest.  Otherwise
+ *      either wait for more input or abort if no more input is possible.
+ *
+ * Events are sent from downstream and don't communicate the state of the input
+ * (TS_EVENT_VCONN_WRITE_READY, TS_EVENT_VCONN_WRITE_COMPLETE, and
+ * TS_EVENT_IMMEDIATE?) Clean up the output buffer on
+ * TS_EVENT_VCONN_WRITE_COMPLETE and not before.
+ *
+ * Gather the state of the input from TSVIONTodoGet() and TSVIOReaderGet().
+ * TSVIOReaderGet() is NULL when no more input is possible and the input is
+ * complete only when TSVIONTodoGet() is zero.  Handle the end of the input
+ * independently from the TS_EVENT_VCONN_WRITE_COMPLETE event from downstream. */
 
 static int
 vconn_write_ready(TSCont contp, void * /* edata ATS_UNUSED */)
 {
   const char *value;
   int64_t length;
-  TransformData *data = (TransformData *) TSContDataGet(contp);
+
+  char digest[32];
+
+  TransformData *transform_data = (TransformData *) TSContDataGet(contp);
 
   TSVIO input_viop = TSVConnWriteVIOGet(contp);
 
   /* Initialize data here because can't call TSVConnWrite() before
    * TS_HTTP_RESPONSE_TRANSFORM_HOOK */
-  if (!data->output_bufp) {
+  if (!transform_data->output_bufp) {
 
     /* Avoid failed assert "sdk_sanity_check_iocore_structure(connp) ==
      * TS_SUCCESS" in TSVConnWrite() if the response is 304 Not Modified */
@@ -246,127 +267,112 @@ vconn_write_ready(TSCont contp, void * /* edata ATS_UNUSED */)
     if (!output_connp) {
       TSContDestroy(contp);
 
-      TSfree(data);
+      TSfree(transform_data);
 
       return 0;
     }
 
-    data->output_bufp = TSIOBufferCreate();
-    TSIOBufferReader readerp = TSIOBufferReaderAlloc(data->output_bufp);
+    transform_data->output_bufp = TSIOBufferCreate();
+    TSIOBufferReader readerp = TSIOBufferReaderAlloc(transform_data->output_bufp);
 
     /* Determines the "Content-Length: ..." header
      * (or "Transfer-Encoding: chunked") */
 
     /* Avoid failed assert "nbytes >= 0" if "Transfer-Encoding: chunked" */
     int nbytes = TSVIONBytesGet(input_viop);
-    data->output_viop = TSVConnWrite(output_connp, contp, readerp, nbytes < 0 ? INT64_MAX : nbytes);
+    transform_data->output_viop = TSVConnWrite(output_connp, contp, readerp, nbytes < 0 ? INT64_MAX : nbytes);
 
-    SHA256_Init(&data->c);
-  }
-
-  /* If the response has a "Content-Length: ..." header then ntodo will never
-   * be zero because there will instead be a TS_EVENT_VCONN_WRITE_COMPLETE
-   * event from downstream after nbytes of content.
-   *
-   * Otherwise (if the response is "Transfer-Encoding: chunked") ntodo will be
-   * zero when the upstream nbytes is known at the end of the content, because
-   * there won't be a TS_EVENT_VCONN_WRITE_COMPLETE event while the downstream
-   * nbytes is INT64_MAX.
-   *
-   * In that case to get it to send a TS_EVENT_VCONN_WRITE_COMPLETE event,
-   * update the downstream nbytes and reenable it.  Zero the downstream nbytes
-   * is a shortcut. */
-  int ntodo = TSVIONTodoGet(input_viop);
-  if (!ntodo) {
-    TSVIONBytesSet(data->output_viop, 0);
-
-    TSVIOReenable(data->output_viop);
-
-    return 0;
+    SHA256_Init(&transform_data->c);
   }
 
   /* Avoid failed assert "sdk_sanity_check_iocore_structure(readerp) ==
    * TS_SUCCESS" in TSIOBufferReaderAvail() if the client or server disconnects
-   * or the content length is zero.
-   *
-   * Don't update the downstream nbytes and reenable it because if not at the
-   * end yet and can't read any more content then can't compute the digest.
-   *
-   * (There hasn't been a TS_EVENT_VCONN_WRITE_COMPLETE event from downstream
-   * yet so if the response has a "Content-Length: ..." header, it is greater
-   * than the content so far.  ntodo is still greater than zero so if the
-   * response is "Transfer-Encoding: chunked", not at the end yet.) */
+   * or the content length is zero */
   TSIOBufferReader readerp = TSVIOReaderGet(input_viop);
-  if (!readerp) {
-    TSContDestroy(contp);
+  if (readerp) {
 
-    TSIOBufferDestroy(data->output_bufp);
-    TSfree(data);
+    int avail = TSIOBufferReaderAvail(readerp);
+    if (avail) {
+      TSIOBufferCopy(transform_data->output_bufp, readerp, avail, 0);
 
-    return 0;
-  }
-
-  int avail = TSIOBufferReaderAvail(readerp);
+      /* Feed content to the message digest */
+      TSIOBufferBlock blockp = TSIOBufferReaderStart(readerp);
+      while (blockp) {
 
-  if (avail) {
-    TSIOBufferCopy(data->output_bufp, readerp, avail, 0);
+        value = TSIOBufferBlockReadStart(blockp, readerp, &length);
+        SHA256_Update(&transform_data->c, value, length);
 
-    /* Feed content to the message digest */
-    TSIOBufferBlock blockp = TSIOBufferReaderStart(readerp);
-    while (blockp) {
+        blockp = TSIOBufferBlockNext(blockp);
+      }
 
-      value = TSIOBufferBlockReadStart(blockp, readerp, &length);
-      SHA256_Update(&data->c, value, length);
+      TSIOBufferReaderConsume(readerp, avail);
 
-      blockp = TSIOBufferBlockNext(blockp);
+      /* Call TSVIONDoneSet() for TSVIONTodoGet() condition */
+      int ndone = TSVIONDoneGet(input_viop);
+      TSVIONDoneSet(input_viop, ndone + avail);
     }
+  }
 
-    TSIOBufferReaderConsume(readerp, avail);
+  int ntodo = TSVIONTodoGet(input_viop);
+  if (ntodo) {
 
-    /* Call TSVIONDoneSet() for TSVIONTodoGet() condition */
-    int ndone = TSVIONDoneGet(input_viop);
-    TSVIONDoneSet(input_viop, ndone + avail);
+    /* Don't update the downstream nbytes because the input isn't complete */
+    if (!readerp) {
+      TSContDestroy(contp);
+
+      TSIOBufferDestroy(transform_data->output_bufp);
+      TSfree(transform_data);
 
-    TSVIOReenable(data->output_viop);
+      return 0;
+    }
+
+    TSVIOReenable(transform_data->output_viop);
 
     TSContCall(TSVIOContGet(input_viop), TS_EVENT_VCONN_WRITE_READY, input_viop);
-  }
 
-  return 0;
-}
+  } else {
 
-/* Write the digest to the cache */
+    int ndone = TSVIONDoneGet(input_viop);
+    TSVIONBytesSet(transform_data->output_viop, ndone);
 
-static int
-transform_vconn_write_complete(TSCont contp, void * /* edata ATS_UNUSED */)
-{
-  char digest[32];
+    TSVIOReenable(transform_data->output_viop);
 
-  TransformData *transform_data = (TransformData *) TSContDataGet(contp);
-  TSContDestroy(contp);
+    /* Write the digest to the cache */
 
-  TSIOBufferDestroy(transform_data->output_bufp);
+    SHA256_Final((unsigned char *) digest, &transform_data->c);
 
-  SHA256_Final((unsigned char *) digest, &transform_data->c);
+    WriteData *write_data = (WriteData *) TSmalloc(sizeof(WriteData));
+    write_data->txnp = transform_data->txnp;
 
-  WriteData *write_data = (WriteData *) TSmalloc(sizeof(WriteData));
-  write_data->txnp = transform_data->txnp;
+    write_data->key = TSCacheKeyCreate();
+    if (TSCacheKeyDigestSet(write_data->key, digest, sizeof(digest)) != TS_SUCCESS) {
 
-  TSfree(transform_data);
+      TSCacheKeyDestroy(write_data->key);
+      TSfree(write_data);
 
-  write_data->key = TSCacheKeyCreate();
-  if (TSCacheKeyDigestSet(write_data->key, digest, sizeof(digest)) != TS_SUCCESS) {
+      return 0;
+    }
 
-    TSCacheKeyDestroy(write_data->key);
-    TSfree(write_data);
+    /* Can't reuse the TSTransformCreate() continuation because don't know
+     * whether to destroy it in cache_open_write()/cache_open_write_failed() or
+     * transform_vconn_write_complete() */
+    contp = TSContCreate(write_handler, NULL);
+    TSContDataSet(contp, write_data);
 
-    return 0;
+    TSCacheWrite(contp, write_data->key);
   }
 
-  contp = TSContCreate(write_handler, NULL);
-  TSContDataSet(contp, write_data);
+  return 0;
+}
 
-  TSCacheWrite(contp, write_data->key);
+static int
+transform_vconn_write_complete(TSCont contp, void * /* edata ATS_UNUSED */)
+{
+  TransformData *data = (TransformData *) TSContDataGet(contp);
+  TSContDestroy(contp);
+
+  TSIOBufferDestroy(data->output_bufp);
+  TSfree(data);
 
   return 0;
 }