This is an automated email from the ASF dual-hosted git repository. paziz pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push: new b115de7 option for using the host field for response lookup b115de7 is described below commit b115de779c4399199989ddce7b745cf18f2d9a86 Author: Persia Aziz <per...@yahoo-inc.com> AuthorDate: Tue Dec 12 19:01:07 2017 -0600 option for using the host field for response lookup --- tests/gold_tests/autest-site/microserver.test.ext | 57 ++++++++++++++++--- tests/gold_tests/remap/gold/lookupTest.gold | 14 +++++ tests/gold_tests/remap/remap_http.test.py | 21 ++++++- tests/tools/microServer/uWServer.py | 67 ++++++++++++++++++----- 4 files changed, 134 insertions(+), 25 deletions(-) diff --git a/tests/gold_tests/autest-site/microserver.test.ext b/tests/gold_tests/autest-site/microserver.test.ext index 1ca1cb4..4ab6783 100644 --- a/tests/gold_tests/autest-site/microserver.test.ext +++ b/tests/gold_tests/autest-site/microserver.test.ext @@ -49,16 +49,54 @@ def addResponse(self, filename, testName, request_header, response_header): self.Setup.CopyAs(absFilepath, self.Variables.DataDir) return +def getHeaderFieldVal(request_header, field): + requestline = request_header["headers"].split("\r\n")[0] + requestline = requestline.split(" ")[1] + field = field+':' + valField = request_header["headers"].split(field,1); + val="" + if len(valField)>1: + field_v = valField[1].split("\r\n",1) + if len(field_v)>0: + val = field_v[0].strip() + return val # addResponse adds customized response with respect to request_header. request_header and response_header are both dictionaries def addResponse(self, filename, request_header, response_header): requestline = request_header["headers"].split("\r\n")[0] - requestline = requestline.split(" ")[1] - resourceLocation = requestline.split("/", 1) - if len(resourceLocation) > 1: - rl = resourceLocation[1] - else: - rl = "" + host_ = "" + path_ = "" + if requestline: + url_part = requestline.split(" ") + if len(url_part)>1: + if url_part[1].startswith("http"): + path_ = url_part[1].split("/",2)[2] + host_,path_ = path_.split("/",1) + else: + path_ = url_part[1].split("/",1)[1] + + kpath = "" + #print("Format of lookup key",self.Variables.lookup_key) + + argsList = [] + keyslist = self.Variables.lookup_key.split("}") + for keystr in keyslist: + if keystr == '{PATH': + kpath = kpath+path_ + continue + if keystr == '{HOST': + kpath = kpath + host_ + continue + if keystr == '': #empty + continue + stringk = keystr.replace("{%","") + argsList.append(stringk) + KeyList = [] + for argsL in argsList: + field_val = getHeaderFieldVal(request_header,argsL) + if field_val!=None: + KeyList.append(field_val) + rl = "".join(KeyList)+kpath txn = dict() txn["timestamp"] = "" txn["uuid"] = rl @@ -103,7 +141,7 @@ def makeHeader(self, requestString, **kwargs): return headerStr -def MakeOriginServer(obj, name, port=False, ip=False, delay=False, ssl=False, options={}): +def MakeOriginServer(obj, name, port=False, ip=False, delay=False, ssl=False, lookup_key='{PATH}', options={}): server_path = os.path.join(obj.Variables.AtsTestToolsDir, 'microServer/uWServer.py') data_dir = os.path.join(obj.RunDirectory, name) # create Process @@ -114,8 +152,8 @@ def MakeOriginServer(obj, name, port=False, ip=False, delay=False, ssl=False, op ip = '127.0.0.1' if (delay == False): delay = 0 - command = "python3 {0} --data-dir {1} --port {2} --ip_address {3} --delay {4} -m test --ssl {5}".format( - server_path, data_dir, port, ip, delay, ssl) + command = "python3 {0} --data-dir {1} --port {2} --ip_address {3} --delay {4} -m test --ssl {5} --lookupkey '{6}'".format( + server_path, data_dir, port, ip, delay, ssl,lookup_key) for flag, value in options.items(): command += " {} {}".format(flag, value) @@ -123,6 +161,7 @@ def MakeOriginServer(obj, name, port=False, ip=False, delay=False, ssl=False, op p.Command = command p.Setup.MakeDir(data_dir) p.Variables.DataDir = data_dir + p.Variables.lookup_key = lookup_key p.Ready = When.PortOpen(port, ip) p.ReturnCode = Any(None,0) AddMethodToInstance(p, addResponse) diff --git a/tests/gold_tests/remap/gold/lookupTest.gold b/tests/gold_tests/remap/gold/lookupTest.gold new file mode 100644 index 0000000..bdf7213 --- /dev/null +++ b/tests/gold_tests/remap/gold/lookupTest.gold @@ -0,0 +1,14 @@ +`` +> GET http://www.testexample.com/test`` +> Host: www.testexample.com`` +> User-Agent: curl/`` +> Accept: */* +`` +< HTTP/1.1 200 OK +< Date: `` +< Age: `` +< Transfer-Encoding: chunked +< Proxy-Connection: keep-alive +< Server: ATS/`` +< +`` diff --git a/tests/gold_tests/remap/remap_http.test.py b/tests/gold_tests/remap/remap_http.test.py index 1be7211..7249f28 100644 --- a/tests/gold_tests/remap/remap_http.test.py +++ b/tests/gold_tests/remap/remap_http.test.py @@ -28,6 +28,7 @@ Test.ContinueOnFail = True # Define default ATS ts = Test.MakeATSProcess("ts") server = Test.MakeOriginServer("server") +server2 = Test.MakeOriginServer("server2",lookup_key="{%Host}{PATH}") dns = Test.MakeDNServer("dns") Test.testName = "" @@ -35,11 +36,16 @@ request_header = {"headers": "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n", # expected response from the origin server response_header = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", "timestamp": "1469733493.993", "body": ""} +request_header2 = {"headers": "GET /test HTTP/1.1\r\nHost: www.testexample.com\r\n\r\n", "timestamp": "1469733493.993", "body": ""} +# expected response from the origin server +response_header2 = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", "timestamp": "1469733493.993", "body": ""} + # add response to the server dictionary server.addResponse("sessionfile.log", request_header, response_header) +server2.addResponse("sessionfile.log",request_header2, response_header2) ts.Disk.records_config.update({ 'proxy.config.diags.debug.enabled': 1, - 'proxy.config.diags.debug.tags': 'http.*|dns', + 'proxy.config.diags.debug.tags': 'http.*|dns|conf_remap', 'proxy.config.http.referer_filter': 1, 'proxy.config.dns.nameservers': '127.0.0.1:{0}'.format(dns.Variables.Port), 'proxy.config.dns.resolv_conf': 'NULL' @@ -61,7 +67,12 @@ ts.Disk.remap_config.AddLine( 'map http://testDNS.com http://audrey.hepburn.com:{0}'.format(server.Variables.Port) ) +ts.Disk.remap_config.AddLine( + 'map http://www.testexample.com http://127.0.0.1:{0} @plugin=conf_remap.so @pparam=proxy.config.url_remap.pristine_host_hdr=1'.format(server2.Variables.Port) +) + dns.addRecords(records={"audrey.hepburn.com.": ["127.0.0.1"]}) +dns.addRecords(records={"whatever.com.": ["127.0.0.1"]}) # call localhost straight tr = Test.AddTestRun() @@ -135,3 +146,11 @@ tr.Processes.Default.Command = 'curl --proxy 127.0.0.1:{0} "http://testDNS.com" ts.Variables.port) tr.Processes.Default.ReturnCode = 0 tr.Processes.Default.Streams.stderr = "gold/remap-DNS-200.gold" + +# microserver lookup test +tr = Test.AddTestRun() +tr.Processes.Default.Command = 'curl --proxy 127.0.0.1:{0} "http://www.testexample.com/test" -H "Host: www.testexample.com" --verbose'.format(ts.Variables.port) +tr.Processes.Default.ReturnCode = 0 +tr.Processes.Default.StartBefore(server2) +tr.Processes.Default.Streams.stderr = "gold/lookupTest.gold" +tr.StillRunningAfter = server2 diff --git a/tests/tools/microServer/uWServer.py b/tests/tools/microServer/uWServer.py index 97aaaec..b646608 100644 --- a/tests/tools/microServer/uWServer.py +++ b/tests/tools/microServer/uWServer.py @@ -35,6 +35,7 @@ import socket import importlib.util import time test_mode_enabled = True +lookup_key_ = "{PATH}" __version__ = "1.0" @@ -168,17 +169,43 @@ class MyHandler(BaseHTTPRequestHandler): else: readChunks() - def getTestName(self, requestline): - key = None - keys = requestline.split(" ") - # print(keys) - if keys: - rkey = keys[1] - key = rkey.split("/", 1)[1] - if key + "/" in G_replay_dict: - key = key + "/" - elif len(key) > 1 and key[:-1] in G_replay_dict: - key = key[:-1] + def getLookupKey(self, requestline): + global lookup_key_ + kpath= "" + path = "" + url_part = requestline.split(" ") + if url_part: + if url_part[1].startswith("http"): + path = url_part[1].split("/",2)[2] + host_, path = path.split("/",1) + else: + path = url_part[1].split("/",1)[1] + argsList = [] + keyslist = lookup_key_.split("}") + for keystr in keyslist: + if keystr == '{PATH': + kpath = kpath+path + continue # do not include path in the list of header fields + if keystr == '{HOST': + kpath = kpath+host_ + continue + stringk = keystr.replace("{%","") + argsList.append(stringk) + KeyList = [] + for argsL in argsList: + print("args",argsL,len(argsL)) + if len(argsL)>0: + val = self.headers.get(argsL) + if val: + field_val,__ = cgi.parse_header(val) + else: + field_val=None + if field_val!=None: + KeyList.append(field_val) + key = "".join(KeyList)+kpath + print("lookup key",key, len(key)) + + return key def parseRequestline(self, requestline): @@ -370,7 +397,7 @@ class MyHandler(BaseHTTPRequestHandler): global G_replay_dict, test_mode_enabled if test_mode_enabled: time.sleep(time_delay) - request_hash = self.getTestName(self.requestline) + request_hash = self.getLookupKey(self.requestline) else: request_hash, __ = cgi.parse_header(self.headers.get('Content-MD5')) # print("key:",request_hash) @@ -445,7 +472,7 @@ class MyHandler(BaseHTTPRequestHandler): def do_HEAD(self): global G_replay_dict, test_mode_enabled if test_mode_enabled: - request_hash = self.getTestName(self.requestline) + request_hash = self.getLookupKey(self.requestline) else: request_hash, __ = cgi.parse_header(self.headers.get('Content-MD5')) @@ -483,7 +510,7 @@ class MyHandler(BaseHTTPRequestHandler): chunkedResponse = False global G_replay_dict, test_mode_enabled if test_mode_enabled: - request_hash = self.getTestName(self.requestline) + request_hash = self.getLookupKey(self.requestline) else: request_hash, __ = cgi.parse_header(self.headers.get('Content-MD5')) try: @@ -653,6 +680,15 @@ def main(): type=str, default='', help="A file which will install observers on hooks") + parser.add_argument("--lookupkey", + type=str, + default="{PATH}", + help="format string used as a key for response lookup: \ + example: \"{%Host}{%Server}{PATH}\", \"{HOST}{PATH}\", \"{PATH}\"\ + All the args preceded by % are header fields in the request\ + The only two acceptable arguments which are not header fields are : fqdn (represented by HOST) and the url path (represented by PATH) in a request line.\ + Example: given a client request as << GET /some/resource/location HTTP/1.1\nHost: hahaha.com\n\n >>, if the user wishes the host field and the path to be used for the response lookup\ + then the required format will be {%Host}{PATH}") args = parser.parse_args() options = args @@ -668,7 +704,8 @@ def main(): try: socket_timeout = args.timeout test_mode_enabled = args.mode == "test" - + global lookup_key_ + lookup_key_ = args.lookupkey MyHandler.protocol_version = HTTP_VERSION if options.ssl == "True" or options.ssl == "true": server = SSLServer((options.ip_address, options.port), MyHandler, options) -- To stop receiving notification emails like this one, please contact ['"commits@trafficserver.apache.org" <commits@trafficserver.apache.org>'].