1'''
2'''
3#  Licensed to the Apache Software Foundation (ASF) under one
4#  or more contributor license agreements.  See the NOTICE file
5#  distributed with this work for additional information
6#  regarding copyright ownership.  The ASF licenses this file
7#  to you under the Apache License, Version 2.0 (the
8#  "License"); you may not use this file except in compliance
9#  with the License.  You may obtain a copy of the License at
10#
11#      http://www.apache.org/licenses/LICENSE-2.0
12#
13#  Unless required by applicable law or agreed to in writing, software
14#  distributed under the License is distributed on an "AS IS" BASIS,
15#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16#  See the License for the specific language governing permissions and
17#  limitations under the License.
18
19Test.Summary = '''
20Test compress plugin
21'''
22
23# This test case is very bare-bones.  It only covers a few scenarios that have caused problems.
24
25# Skip if plugins not present.
26#
27Test.SkipUnless(
28    Condition.PluginExists('compress.so'),
29    Condition.PluginExists('conf_remap.so'),
30    Condition.HasATSFeature('TS_HAS_BROTLI')
31)
32
33server = Test.MakeOriginServer("server", options={'--load': '{}/compress_observer.py'.format(Test.TestDirectory)})
34
35
36def repeat(str, count):
37    result = ""
38    while count > 0:
39        result += str
40        count -= 1
41    return result
42
43
44# Need a fairly big body, otherwise the plugin will refuse to compress
45body = repeat("lets go surfin now everybodys learnin how\n", 24)
46body = body + "lets go surfin now everybodys learnin how"
47
48# expected response from the origin server
49response_header = {
50    "headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n" +
51    'Etag: "359670651"\r\n' +
52    "Cache-Control: public, max-age=31536000\r\n" +
53    "Accept-Ranges: bytes\r\n" +
54    "Content-Type: text/javascript\r\n" +
55    "\r\n",
56    "timestamp": "1469733493.993",
57    "body": body
58}
59for i in range(3):
60    # add request/response to the server dictionary
61    request_header = {
62        "headers": "GET /obj{} HTTP/1.1\r\nHost: just.any.thing\r\n\r\n".format(i), "timestamp": "1469733493.993", "body": ""
63    }
64    server.addResponse("sessionfile.log", request_header, response_header)
65
66
67# post for the origin server
68post_request_header = {
69    "headers": "POST /obj3 HTTP/1.1\r\nHost: just.any.thing\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 11\r\n\r\n",
70    "timestamp": "1469733493.993",
71    "body": "knock knock"}
72server.addResponse("sessionfile.log", post_request_header, response_header)
73
74
75def curl(ts, idx, encodingList):
76    return (
77        "curl --verbose --proxy http://127.0.0.1:{}".format(ts.Variables.port) +
78        " --header 'X-Ats-Compress-Test: {}/{}'".format(idx, encodingList) +
79        " --header 'Accept-Encoding: {0}' 'http://ae-{1}/obj{1}'".format(encodingList, idx) +
80        " 2>> compress_long.log ; printf '\n===\n' >> compress_long.log"
81    )
82
83
84def curl_post(ts, idx, encodingList):
85    return (
86        "curl --verbose -d 'knock knock' --proxy http://127.0.0.1:{}".format(ts.Variables.port) +
87        " --header 'X-Ats-Compress-Test: {}/{}'".format(idx, encodingList) +
88        " --header 'Accept-Encoding: {0}' 'http://ae-{1}/obj{1}'".format(encodingList, idx) +
89        " 2>> compress_long.log ; printf '\n===\n' >> compress_long.log"
90    )
91
92
93waitForServer = True
94
95waitForTs = True
96
97ts = Test.MakeATSProcess("ts", enable_cache=False)
98
99ts.Disk.records_config.update({
100    'proxy.config.diags.debug.enabled': 1,
101    'proxy.config.diags.debug.tags': 'compress',
102    'proxy.config.http.normalize_ae': 0,
103})
104
105ts.Setup.Copy("compress.config")
106ts.Setup.Copy("compress2.config")
107
108ts.Disk.remap_config.AddLine(
109    'map http://ae-0/ http://127.0.0.1:{}/'.format(server.Variables.Port) +
110    ' @plugin=compress.so @pparam={}/compress.config'.format(Test.RunDirectory)
111)
112ts.Disk.remap_config.AddLine(
113    'map http://ae-1/ http://127.0.0.1:{}/'.format(server.Variables.Port) +
114    ' @plugin=conf_remap.so @pparam=proxy.config.http.normalize_ae=1' +
115    ' @plugin=compress.so @pparam={}/compress.config'.format(Test.RunDirectory)
116)
117ts.Disk.remap_config.AddLine(
118    'map http://ae-2/ http://127.0.0.1:{}/'.format(server.Variables.Port) +
119    ' @plugin=conf_remap.so @pparam=proxy.config.http.normalize_ae=2' +
120    ' @plugin=compress.so @pparam={}/compress2.config'.format(Test.RunDirectory)
121)
122ts.Disk.remap_config.AddLine(
123    'map http://ae-3/ http://127.0.0.1:{}/'.format(server.Variables.Port) +
124    ' @plugin=compress.so @pparam={}/compress.config'.format(Test.RunDirectory)
125)
126
127for i in range(3):
128
129    tr = Test.AddTestRun()
130    if (waitForTs):
131        tr.Processes.Default.StartBefore(ts)
132    waitForTs = False
133    if (waitForServer):
134        tr.Processes.Default.StartBefore(server, ready=When.PortOpen(server.Variables.Port))
135    waitForServer = False
136    tr.Processes.Default.ReturnCode = 0
137    tr.Processes.Default.Command = curl(ts, i, 'gzip, deflate, sdch, br')
138
139    tr = Test.AddTestRun()
140    tr.Processes.Default.ReturnCode = 0
141    tr.Processes.Default.Command = curl(ts, i, "gzip")
142
143    tr = Test.AddTestRun()
144    tr.Processes.Default.ReturnCode = 0
145    tr.Processes.Default.Command = curl(ts, i, "br")
146
147    tr = Test.AddTestRun()
148    tr.Processes.Default.ReturnCode = 0
149    tr.Processes.Default.Command = curl(ts, i, "deflate")
150
151# Test Aceept-Encoding normalization.
152
153tr = Test.AddTestRun()
154tr.Processes.Default.ReturnCode = 0
155tr.Processes.Default.Command = curl(ts, 0, "gzip;q=0.666")
156
157tr = Test.AddTestRun()
158tr.Processes.Default.ReturnCode = 0
159tr.Processes.Default.Command = curl(ts, 0, "gzip;q=0.666x")
160
161tr = Test.AddTestRun()
162tr.Processes.Default.ReturnCode = 0
163tr.Processes.Default.Command = curl(ts, 0, "gzip;q=#0.666")
164
165tr = Test.AddTestRun()
166tr.Processes.Default.ReturnCode = 0
167tr.Processes.Default.Command = curl(ts, 0, "gzip; Q = 0.666")
168
169tr = Test.AddTestRun()
170tr.Processes.Default.ReturnCode = 0
171tr.Processes.Default.Command = curl(ts, 0, "gzip;q=0.0")
172
173tr = Test.AddTestRun()
174tr.Processes.Default.ReturnCode = 0
175tr.Processes.Default.Command = curl(ts, 0, "gzip;q=-0.1")
176
177tr = Test.AddTestRun()
178tr.Processes.Default.ReturnCode = 0
179tr.Processes.Default.Command = curl(ts, 0, "aaa, gzip;q=0.666, bbb")
180
181tr = Test.AddTestRun()
182tr.Processes.Default.ReturnCode = 0
183tr.Processes.Default.Command = curl(ts, 0, " br ; q=0.666, bbb")
184
185tr = Test.AddTestRun()
186tr.Processes.Default.ReturnCode = 0
187tr.Processes.Default.Command = curl(ts, 0, "aaa, gzip;q=0.666 , ")
188
189# post
190tr = Test.AddTestRun()
191tr.Processes.Default.ReturnCode = 0
192tr.Processes.Default.Command = curl_post(ts, 3, "gzip")
193
194# compress_long.log contains all the output from the curl commands.  The tr removes the carriage returns for easier
195# readability.  Curl seems to have a bug, where it will neglect to output an end of line before outputting an HTTP
196# message header line.  The sed command is a work-around for this problem.  greplog.sh uses the grep command to
197# select HTTP request/response line that should be consistent every time the test runs.
198#
199tr = Test.AddTestRun()
200tr.Processes.Default.ReturnCode = 0
201tr.Processes.Default.Command = (
202    r"tr -d '\r' < compress_long.log | sed 's/\(..*\)\([<>]\)/\1\n\2/' | {0}/greplog.sh > compress_short.log"
203).format(Test.TestDirectory)
204f = tr.Disk.File("compress_short.log")
205f.Content = "compress.gold"
206
207tr = Test.AddTestRun()
208tr.Processes.Default.Command = "echo"
209f = tr.Disk.File("compress_userver.log")
210f.Content = "compress_userver.gold"
211