1#!/usr/bin/env python3
2from sys import exit
3from test.http_test import HTTPTest
4from misc.wget_file import WgetFile
5import hashlib
6from base64 import b64encode
7
8"""
9    This is to test Metalink/HTTP with Metalink/XML Link headers.
10
11    With --trust-server-names, trust the metalink:file names.
12
13    Without --trust-server-names, don't trust the metalink:file names:
14    use the basename of --input-metalink, and add a sequential number
15    (e.g. .#1, .#2, etc.).
16
17    Strip the directory from unsafe paths.
18"""
19
20############# File Definitions ###############################################
21bad = "Ouch!"
22bad_sha256 = hashlib.sha256 (bad.encode ('UTF-8')).hexdigest ()
23
24File1 = "Would you like some Tea?"
25File1_lowPref = "Do not take this"
26File1_sha256 = hashlib.sha256 (File1.encode ('UTF-8')).hexdigest ()
27
28File2 = "This is gonna be good"
29File2_lowPref = "Not this one too"
30File2_sha256 = hashlib.sha256 (File2.encode ('UTF-8')).hexdigest ()
31
32File3 = "A little more, please"
33File3_lowPref = "That's just too much"
34File3_sha256 = hashlib.sha256 (File3.encode ('UTF-8')).hexdigest ()
35
36File4 = "Maybe a biscuit?"
37File4_lowPref = "No, thanks"
38File4_sha256 = hashlib.sha256 (File4.encode ('UTF-8')).hexdigest ()
39
40File5 = "More Tea...?"
41File5_lowPref = "I have to go..."
42File5_sha256 = hashlib.sha256 (File5.encode ('UTF-8')).hexdigest ()
43
44MetaXml1 = \
45"""<?xml version="1.0" encoding="utf-8"?>
46<metalink version="3.0" xmlns="http://www.metalinker.org/">
47  <publisher>
48    <name>GNU Wget</name>
49  </publisher>
50  <license>
51    <name>GNU GPL</name>
52    <url>http://www.gnu.org/licenses/gpl.html</url>
53  </license>
54  <identity>Wget Test Files</identity>
55  <version>1.2.3</version>
56  <description>Wget Test Files description</description>
57  <files>
58    <file name="dir/File1">
59      <verification>
60        <hash type="sha256">{{FILE1_HASH}}</hash>
61      </verification>
62      <resources>
63        <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
64        <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
65        <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File1_lowPref</url>
66        <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File1</url>
67      </resources>
68    </file>
69    <file name="dir/File2">
70      <verification>
71        <hash type="sha256">{{FILE2_HASH}}</hash>
72      </verification>
73      <resources>
74        <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
75        <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
76        <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File2_lowPref</url>
77        <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File2</url>
78      </resources>
79    </file>
80    <file name="/dir/File3"> <!-- rejected by libmetalink -->
81      <verification>
82        <hash type="sha256">{{FILE3_HASH}}</hash>
83      </verification>
84      <resources>
85        <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
86        <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
87        <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File3_lowPref</url>
88        <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File3</url>
89      </resources>
90    </file>
91    <file name="dir/File4">
92      <verification>
93        <hash type="sha256">{{FILE4_HASH}}</hash>
94      </verification>
95      <resources>
96        <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
97        <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
98        <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File4_lowPref</url>
99        <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File4</url>
100      </resources>
101    </file>
102    <file name="dir/File5">
103      <verification>
104        <hash type="sha256">{{FILE5_HASH}}</hash>
105      </verification>
106      <resources>
107        <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
108        <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
109        <url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File5_lowPref</url>
110        <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File5</url>
111      </resources>
112    </file>
113  </files>
114</metalink>
115"""
116
117MetaXml2 = \
118"""<?xml version="1.0" encoding="utf-8"?>
119<metalink version="3.0" xmlns="http://www.metalinker.org/">
120  <publisher>
121    <name>GNU Wget</name>
122  </publisher>
123  <license>
124    <name>GNU GPL</name>
125    <url>http://www.gnu.org/licenses/gpl.html</url>
126  </license>
127  <identity>Wget Test Files</identity>
128  <version>1.2.3</version>
129  <description>Wget Test Files description</description>
130  <files>
131    <file name="bad">
132      <verification>
133        <hash type="sha256">{{BAD_HASH}}</hash>
134      </verification>
135      <resources>
136        <url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
137        <url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
138        <url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/bad</url>
139      </resources>
140    </file>
141  </files>
142</metalink>
143"""
144
145LinkHeaders = [
146    # This file has the lowest priority, and should go last
147    "<http://{{SRV_HOST}}:{{SRV_PORT}}/test1.metalink>; rel=describedby; pri=2; type=\"application/metalink4+xml\"",
148    # This file has the highest priority, and should go first
149    "<http://{{SRV_HOST}}:{{SRV_PORT}}/test2.metalink>; rel=describedby; pri=1; type=\"application/metalink4+xml\""
150]
151
152# This will be filled as soon as we know server hostname and port
153MetaHTTPRules = {'SendHeader' : {}}
154
155MetaHTTP = WgetFile ("main.metalink", rules=MetaHTTPRules)
156
157wrong_file = WgetFile ("wrong_file", bad)
158
159File1_orig = WgetFile ("File1", File1)
160File1_down = WgetFile ("dir/File1", File1)
161File1_nono = WgetFile ("File1_lowPref", File1_lowPref)
162
163File2_orig = WgetFile ("File2", File2)
164File2_down = WgetFile ("dir/File2", File2)
165File2_nono = WgetFile ("File2_lowPref", File2_lowPref)
166
167# rejected by libmetalink
168File3_orig = WgetFile ("File3", File3)
169File3_nono = WgetFile ("File3_lowPref", File3_lowPref)
170
171File4_orig = WgetFile ("File4", File4)
172File4_down = WgetFile ("dir/File4", File4)
173File4_nono = WgetFile ("File4_lowPref", File4_lowPref)
174
175File5_orig = WgetFile ("File5", File5)
176File5_down = WgetFile ("dir/File5", File5)
177File5_nono = WgetFile ("File5_lowPref", File5_lowPref)
178
179MetaFile1 = WgetFile ("test1.metalink", MetaXml1)
180MetaFile1_down = WgetFile ("test1.metalink", MetaXml1)
181
182MetaFile2 = WgetFile ("test2.metalink", MetaXml2)
183
184WGET_OPTIONS = "--trust-server-names --metalink-over-http --metalink-index=2"
185WGET_URLS = [["main.metalink"]]
186
187RequestList = [[
188    "HEAD /main.metalink",
189    "GET /404",
190    "GET /wrong_file",
191    "GET /test1.metalink",
192    "GET /File1",
193    "GET /File2",
194    "GET /File4",
195    "GET /File5"
196]]
197
198Files = [[
199    MetaHTTP,
200    wrong_file,
201    MetaFile1, MetaFile2,
202    File1_orig, File1_nono,
203    File2_orig, File2_nono,
204    File3_orig, File3_nono,
205    File4_orig, File4_nono,
206    File5_orig, File5_nono
207]]
208Existing_Files = []
209
210ExpectedReturnCode = 0
211ExpectedDownloadedFiles = [
212    MetaFile1_down,
213    File1_down,
214    File2_down,
215    File4_down,
216    File5_down
217]
218
219################ Pre and Post Test Hooks #####################################
220pre_test = {
221    "ServerFiles"       : Files,
222    "LocalFiles"        : Existing_Files
223}
224test_options = {
225    "WgetCommands"      : WGET_OPTIONS,
226    "Urls"              : WGET_URLS
227}
228post_test = {
229    "ExpectedFiles"     : ExpectedDownloadedFiles,
230    "ExpectedRetcode"   : ExpectedReturnCode,
231    "FilesCrawled"      : RequestList
232}
233
234http_test = HTTPTest (
235                pre_hook=pre_test,
236                test_params=test_options,
237                post_hook=post_test
238)
239
240http_test.server_setup()
241### Get and use dynamic server sockname
242srv_host, srv_port = http_test.servers[0].server_inst.socket.getsockname ()
243
244MetaXml1 = MetaXml1.replace('{{FILE1_HASH}}', File1_sha256)
245MetaXml1 = MetaXml1.replace('{{FILE2_HASH}}', File2_sha256)
246MetaXml1 = MetaXml1.replace('{{FILE3_HASH}}', File3_sha256)
247MetaXml1 = MetaXml1.replace('{{FILE4_HASH}}', File4_sha256)
248MetaXml1 = MetaXml1.replace('{{FILE5_HASH}}', File5_sha256)
249MetaXml1 = MetaXml1.replace('{{SRV_HOST}}', srv_host)
250MetaXml1 = MetaXml1.replace('{{SRV_PORT}}', str (srv_port))
251MetaFile1.content = MetaXml1
252MetaFile1_down.content = MetaXml1
253
254MetaXml2 = MetaXml2.replace('{{BAD_HASH}}', bad_sha256)
255MetaXml2 = MetaXml2.replace('{{SRV_HOST}}', srv_host)
256MetaXml2 = MetaXml2.replace('{{SRV_PORT}}', str (srv_port))
257MetaFile2.content = MetaXml2
258
259# Helper function for hostname, port and digest substitution
260def SubstituteServerInfo (text, host, port):
261    text = text.replace('{{SRV_HOST}}', host)
262    text = text.replace('{{SRV_PORT}}', str (port))
263    return text
264
265MetaHTTPRules["SendHeader"] = {
266        'Link': [ SubstituteServerInfo (LinkHeader, srv_host, srv_port)
267                    for LinkHeader in LinkHeaders ]
268}
269
270err = http_test.begin ()
271
272exit (err)
273