1
0
mirror of https://github.com/mirror/wget.git synced 2025-04-24 12:10:16 +08:00

Bugfix: Remove surrounding quotes from Metalink/HTTP key's value

* src/metalink.h: Add declaration of function dequote_metalink_string()
* src/metalink.c: Add function dequote_metalink_string() remove
  surrounding quotes from string, \' or \"
* src/metalink.c (find_key_value, find_key_values): Call dequote_metalink_string()
  to remove the surrounding quotes from the parsed value
* src/metalink.c (test_find_key_value, test_find_key_values): Add
  quoted key's values for unit-tests
* testenv/Makefile.am: Add new file
* testenv/Test-metalink-http-quoted.py: New file. Metalink/HTTP quoted
  values tests

Some Metalink/HTTP keys, like "type" [2], may have a quoted value [1]:
Link: <http://example.com/example.ext.meta4>; rel=describedby;
type="application/metalink4+xml"

Wget was expecting a dequoted value from the Metalink module. This
patch addresses this problem.

References:
 [1] Metalink/HTTP: Mirrors and Hashes
     1.1. Example Metalink Server Response
     https://tools.ietf.org/html/rfc6249#section-1.1

 [2] Additional Link Relations
     6. "type"
     https://tools.ietf.org/html/rfc6903#section-6
This commit is contained in:
Matthew White 2016-08-24 12:43:24 +02:00
parent 8aca8fc80d
commit 9532861aef
4 changed files with 163 additions and 7 deletions

View File

@ -823,6 +823,32 @@ clean_metalink_string (char **str)
*str = new;
}
/*
Remove the quotation surrounding a string.
The string is permanently modified.
*/
void
dequote_metalink_string (char **str)
{
char *new;
size_t str_len;
if (!str || !*str || ((*str)[0] != '\"' && (*str)[0] != '\''))
return;
str_len = strlen (*str); /* current string length */
/* Verify if the current string is surrounded by quotes. */
if (str_len < 2 || (*str)[0] != (*str)[str_len - 1])
return;
/* Dequoted string. */
new = xmemdup0 (*str + 1, str_len - 2);
xfree (*str);
*str = new;
}
/* Append the suffix ".badhash" to the file NAME, except without
overwriting an existing file with that name and suffix. */
void
@ -970,6 +996,7 @@ find_key_value (const char *start, const char *end, const char *key, char **valu
while (val_end < end && *val_end != ';' && !c_isspace (*val_end))
val_end++;
*value = xstrndup (val_beg, val_end - val_beg);
dequote_metalink_string (value);
return true;
}
}
@ -1070,6 +1097,7 @@ find_key_values (const char *start, const char *end, char **key, char **value)
*key = xstrndup (key_start, key_end - key_start);
*value = xstrndup (val_start, val_end - val_start);
dequote_metalink_string (value);
/* Skip trailing whitespaces. */
while (val_end < end && c_isspace (*val_end))
@ -1082,10 +1110,10 @@ find_key_values (const char *start, const char *end, char **key, char **value)
const char *
test_find_key_values (void)
{
static const char *header_data = "key1=val1;key2=val2 ;key3=val3; key4=val4"\
" ; key5=val5;key6 =val6;key7= val7; "\
"key8 = val8 ; key9 = val9 "\
" ,key10= val10,key11,key12=val12";
static const char *header_data = "key1=val1;key2=\"val2\" ;key3=val3; key4=val4"\
" ; key5=val5;key6 ='val6';key7= val7; "\
"key8 = val8 ; key9 = \"val9\" "\
" ,key10= 'val10',key11,key12=val12";
static const struct
{
const char *key;
@ -1126,9 +1154,9 @@ test_find_key_values (void)
const char *
test_find_key_value (void)
{
static const char *header_data = "key1=val1;key2=val2 ;key3=val3; key4=val4"\
" ; key5=val5;key6 =val6;key7= val7; "\
"key8 = val8 ; key9 = val9 ";
static const char *header_data = "key1=val1;key2=val2 ;key3='val3'; key4=val4"\
" ; key5='val5';key6 =val6;key7= \"val7\"; "\
"key8 = \"val8\" ; key9 = val9 ";
static const struct
{
const char *key;

View File

@ -53,6 +53,7 @@ char *last_component (char const *name);
char *get_metalink_basename (char *name);
void append_suffix_number (char **str, const char *sep, wgint num);
void clean_metalink_string (char **str);
void dequote_metalink_string (char **str);
void badhash_suffix (char *name);
void badhash_or_remove (char *name);

View File

@ -28,6 +28,7 @@
if METALINK_IS_ENABLED
METALINK_TESTS = Test-metalink-http.py \
Test-metalink-http-quoted.py \
Test-metalink-xml.py \
Test-metalink-xml-continue.py \
Test-metalink-xml-relpath.py \

View File

@ -0,0 +1,126 @@
#!/usr/bin/env python3
from sys import exit
from test.http_test import HTTPTest
from misc.wget_file import WgetFile
import hashlib
from base64 import b64encode
"""
This is to test Metalink/HTTP quoted values support in Wget.
"""
# Helper function for hostname, port and digest substitution
def SubstituteServerInfo (text, host, port, digest):
text = text.replace('{{FILE1_HASH}}', digest)
text = text.replace('{{SRV_HOST}}', host)
text = text.replace('{{SRV_PORT}}', str (port))
return text
############# File Definitions ###############################################
File1 = "Would you like some Tea?"
File1_corrupted = "Would you like some Coffee?"
File1_lowPref = "Do not take this"
File1_sha256 = b64encode (hashlib.sha256 (File1.encode ('UTF-8')).digest ()).decode ('ascii')
Signature = '''-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.7 (GNU/Linux)
This is no valid signature. But it should be downloaded.
The attempt to verify should fail but should not prevent
a successful metalink resource retrieval (the sig failure
should not be fatal).
-----END PGP SIGNATURE-----
'''
File2 = "No meta data for this file."
LinkHeaders = [
# This file has low priority and should not be picked.
"<http://{{SRV_HOST}}:{{SRV_PORT}}/File1_lowPref>; rel=\"duplicate\"; pri=\"9\"; geo=\"pl\"",
# This file should be picked second, after hash failure.
"<http://0.0.0.0/File1_try2_badconnection>; rel =\"duplicate\";pref; pri=\"7\"",
# This signature download will fail.
"<http://{{SRV_HOST}}:{{SRV_PORT}}/Sig2.asc>; rel=\"describedby\"; type=\"application/pgp-signature\"",
# Two good signatures
"<http://{{SRV_HOST}}:{{SRV_PORT}}/Sig.asc>; rel=\"describedby\"; type=\"application/pgp-signature\"",
"<http://{{SRV_HOST}}:{{SRV_PORT}}/Sig.asc>; rel=\"describedby\"; type=\"application/pgp-signature\"",
# Bad URL scheme
"<invalid_url>; rel=\"duplicate\"; pri=\"4\"",
# rel missing
"<http://{{SRV_HOST}}:{{SRV_PORT}}/File1>; pri=\"1\"; pref",
# invalid rel
"<http://{{SRV_HOST}}:{{SRV_PORT}}/File1>; rel=\"strange\"; pri=\"4\"",
# This file should be picked first, because it has the lowest pri among preferred.
"<http://{{SRV_HOST}}:{{SRV_PORT}}/File1_try1_corrupted>; rel=\"duplicate\"; geo=\"su\"; pri=\"4\"; pref",
# This file should NOT be picked third due to preferred location set to 'uk'
"<http://{{SRV_HOST}}:{{SRV_PORT}}/File1_badgeo>; rel =\"duplicate\";pri=\"5\"",
# This file should be picked as third try, and it should succeed
"<http://{{SRV_HOST}}:{{SRV_PORT}}/File1_try3_ok>; rel=\'duplicate\'; pri=\"5\";geo=\"uk\""
]
DigestHeader = "SHA-256=\'{{FILE1_HASH}}\'"
# This will be filled as soon as we know server hostname and port
MetaFileRules = {'SendHeader' : {}}
FileOkServer = WgetFile ("File1_try3_ok", File1)
FileBadPref = WgetFile ("File1_lowPref", File1_lowPref)
FileBadHash = WgetFile ("File1_try1_corrupted", File1_corrupted)
MetaFile = WgetFile ("test.meta", rules=MetaFileRules)
# In case of Metalink over HTTP, the local file name is
# derived from the URL suffix.
FileOkLocal = WgetFile ("test.meta", File1)
SigFile = WgetFile ("Sig.asc", Signature)
FileNoMeta = WgetFile ("File2", File2)
WGET_OPTIONS = "--metalink-over-http --preferred-location=uk"
WGET_URLS = [["test.meta", "File2"]]
Files = [[FileOkServer, FileBadPref, FileBadHash, MetaFile, SigFile, FileNoMeta]]
Existing_Files = []
ExpectedReturnCode = 0
ExpectedDownloadedFiles = [FileNoMeta, FileOkLocal]
RequestList = [
[
"HEAD /test.meta",
"GET /Sig2.asc",
"GET /Sig.asc",
"GET /File1_try1_corrupted",
"GET /File1_try3_ok",
"HEAD /File2",
"GET /File2",
]
]
################ Pre and Post Test Hooks #####################################
pre_test = {
"ServerFiles" : Files,
"LocalFiles" : Existing_Files
}
test_options = {
"WgetCommands" : WGET_OPTIONS,
"Urls" : WGET_URLS
}
post_test = {
"ExpectedFiles" : ExpectedDownloadedFiles,
"ExpectedRetcode" : ExpectedReturnCode,
"FilesCrawled" : RequestList,
}
http_test = HTTPTest (
pre_hook=pre_test,
test_params=test_options,
post_hook=post_test,
)
http_test.server_setup()
srv_host, srv_port = http_test.servers[0].server_inst.socket.getsockname ()
MetaFileRules["SendHeader"] = {
'Link': [ SubstituteServerInfo (LinkHeader, srv_host, srv_port, File1_sha256)
for LinkHeader in LinkHeaders ],
'Digest': SubstituteServerInfo (DigestHeader, srv_host, srv_port, File1_sha256),
}
err = http_test.begin ()
exit (err)