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:31 UTC

[09/13] git commit: TS-2675: metalink: Don't finish computing the digest more than once and test that the proxy rewrites the Location header if the file is already cached

TS-2675: metalink: Don't finish computing the digest more than once and test that the proxy rewrites the Location header if the file is already cached


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

Branch: refs/heads/master
Commit: f9d74b9feefa2f7a4c8d59b6633efe9de8415d50
Parents: ea2f6f3
Author: Jack Bates <ja...@nottheoilrig.com>
Authored: Mon Mar 17 09:19:31 2014 -0700
Committer: James Peach <jp...@apache.org>
Committed: Fri Mar 28 16:23:54 2014 -0700

----------------------------------------------------------------------
 plugins/experimental/metalink/metalink.cc   |  13 ++-
 plugins/experimental/metalink/test/location | 124 +++++++++++++++++++++++
 2 files changed, 136 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f9d74b9f/plugins/experimental/metalink/metalink.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/metalink/metalink.cc b/plugins/experimental/metalink/metalink.cc
index 3ad589d..ae8771c 100644
--- a/plugins/experimental/metalink/metalink.cc
+++ b/plugins/experimental/metalink/metalink.cc
@@ -367,7 +367,15 @@ vconn_write_ready(TSCont contp, void */* edata ATS_UNUSED */)
 
     TSContCall(TSVIOContGet(input_viop), TS_EVENT_VCONN_WRITE_READY, input_viop);
 
-  } else {
+  /* Don't finish computing the digest (and tell downstream and thank upstream)
+   * more than once!  There might be multiple TS_EVENT_IMMEDIATE events between
+   * the end of the input and the TS_EVENT_VCONN_WRITE_COMPLETE event from
+   * downstream, e.g. INKVConnInternal::reenable() is called by
+   * HttpTunnel::producer_handler() when more input is available and
+   * TransformVConnection::do_io_shutdown() is called by
+   * HttpSM::tunnel_handler_transform_write() when we send our own
+   * TS_EVENT_VCONN_WRITE_COMPLETE event upstream. */
+  } else if (transform_data->txnp) {
 
     int ndone = TSVIONDoneGet(input_viop);
     TSVIONBytesSet(transform_data->output_viop, ndone);
@@ -388,6 +396,9 @@ vconn_write_ready(TSCont contp, void */* edata ATS_UNUSED */)
     WriteData *write_data = (WriteData *) TSmalloc(sizeof(WriteData));
     write_data->txnp = transform_data->txnp;
 
+    /* Don't finish computing the digest more than once! */
+    transform_data->txnp = NULL;
+
     write_data->key = TSCacheKeyCreate();
     if (TSCacheKeyDigestSet(write_data->key, digest, sizeof(digest)) != TS_SUCCESS) {
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f9d74b9f/plugins/experimental/metalink/test/location
----------------------------------------------------------------------
diff --git a/plugins/experimental/metalink/test/location b/plugins/experimental/metalink/test/location
new file mode 100755
index 0000000..77b601e
--- /dev/null
+++ b/plugins/experimental/metalink/test/location
@@ -0,0 +1,124 @@
+#!/usr/bin/env python
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership.  The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License.  You may obtain a copy of the
+# License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.  See the License for the specific language governing
+# permissions and limitations under the License.
+
+print '''1..2 location
+# The proxy rewrites the Location header if the file is already cached'''
+
+from twisted.internet import error, protocol, reactor, tcp
+from twisted.web import http
+
+def callback():
+  print 'not ok 1 - Why didn\'t the test finish yet?'
+
+  reactor.stop()
+
+reactor.callLater(1, callback)
+
+class factory(http.HTTPFactory):
+  class protocol(http.HTTPChannel):
+    class requestFactory(http.Request):
+      def requestReceived(ctx, method, target, version):
+
+        ctx.client = None
+        ctx.clientproto = version
+
+        if target == '/location':
+
+          ctx.write('location')
+          ctx.finish()
+
+        else:
+
+          ctx.setHeader('Digest', 'SHA-256=5urqGOiF4QeIKbVt80iWvlq1FDno8LoAyxYkssVywQ4=')
+          ctx.setHeader('Location', 'http://example.com')
+          ctx.finish()
+
+origin = tcp.Port(0, factory())
+origin.startListening()
+
+print '# Listening on {0}:{1}'.format(*origin.socket.getsockname())
+
+class factory(protocol.ClientFactory):
+  def clientConnectionFailed(ctx, connector, reason):
+
+    print 'Bail out!'
+    reason.printTraceback()
+
+    reactor.stop()
+
+  class protocol(http.HTTPClient):
+    def connectionLost(ctx, reason):
+      try:
+        reactor.stop()
+
+      except error.ReactorNotRunning:
+        pass
+
+      else:
+        print 'not ok 1 - Did the proxy crash?  (The client connection closed.)'
+
+    # Get a response with a Location and a Digest header and check that the
+    # Location header is not rewritten.  Then get the same response after
+    # caching a matching file from a different URL and check that this time the
+    # header is rewritten.
+    connectionMade = lambda ctx: ctx.transport.write('GET {0}:{1} HTTP/1.1\r\n\r\nGET {0}:{1}/location HTTP/1.1\r\n\r\nGET {0}:{1} HTTP/1.1\r\n\r\n'.format(*origin.socket.getsockname()))
+
+    def handleResponsePart(ctx, data):
+      try:
+        h, r = data.split('0\r\n\r\n', 1)
+
+      except ValueError:
+        pass
+
+      else:
+
+        ctx.firstLine = True
+        ctx.setLineMode(r)
+
+    def handleStatus(ctx, version, status, message):
+      def handleHeader(k, v):
+        if k.lower() == 'location':
+          if v != 'http://example.com':
+            print 'not',
+
+          print 'ok 1 - Before'
+
+      ctx.handleHeader = handleHeader
+
+      def handleStatus(version, status, message):
+        del ctx.handleHeader
+
+        def handleStatus(version, staus, message):
+          def handleHeader(k, v):
+            if k.lower() == 'location':
+              if v != 'http://{0}:{1}/location'.format(*origin.socket.getsockname()):
+                print 'not',
+
+              print 'ok 2 - After'
+
+              reactor.stop()
+
+          ctx.handleHeader = handleHeader
+
+        ctx.handleStatus = handleStatus
+
+      ctx.handleStatus = handleStatus
+
+tcp.Connector('localhost', 8080, factory(), 30, None, reactor).connect()
+
+reactor.run()