mirror of
https://github.com/moparisthebest/wget
synced 2024-07-03 16:38:41 -04:00
Move some Metalink-related code from http.c to metalink.c.
* src/http.c: Move find_key_value, has_key, find_key_values. * src/metalink.c: To here. * src/metalink.h: Make them non-static and add prototypes here.
This commit is contained in:
parent
92a889b278
commit
225a87d4a2
317
src/http.c
317
src/http.c
@ -2462,198 +2462,6 @@ set_content_type (int *dt, const char *type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_METALINK
|
#ifdef HAVE_METALINK
|
||||||
|
|
||||||
/*
|
|
||||||
Find value of given key. This is intended for Link header, but will
|
|
||||||
work with any header that uses ';' as field separator and '=' as key-value
|
|
||||||
separator.
|
|
||||||
|
|
||||||
Link = "Link" ":" #link-value
|
|
||||||
link-value = "<" URI-Reference ">" *( ";" link-param )
|
|
||||||
link-param = ( ( "rel" "=" relation-types )
|
|
||||||
| ( "anchor" "=" <"> URI-Reference <"> )
|
|
||||||
| ( "rev" "=" relation-types )
|
|
||||||
| ( "hreflang" "=" Language-Tag )
|
|
||||||
| ( "media" "=" ( MediaDesc | ( <"> MediaDesc <"> ) ) )
|
|
||||||
| ( "title" "=" quoted-string )
|
|
||||||
| ( "title*" "=" ext-value )
|
|
||||||
| ( "type" "=" ( media-type | quoted-mt ) )
|
|
||||||
| ( link-extension ) )
|
|
||||||
link-extension = ( parmname [ "=" ( ptoken | quoted-string ) ] )
|
|
||||||
| ( ext-name-star "=" ext-value )
|
|
||||||
ext-name-star = parmname "*" ; reserved for RFC2231-profiled
|
|
||||||
; extensions. Whitespace NOT
|
|
||||||
; allowed in between.
|
|
||||||
ptoken = 1*ptokenchar
|
|
||||||
ptokenchar = "!" | "#" | "$" | "%" | "&" | "'" | "("
|
|
||||||
| ")" | "*" | "+" | "-" | "." | "/" | DIGIT
|
|
||||||
| ":" | "<" | "=" | ">" | "?" | "@" | ALPHA
|
|
||||||
| "[" | "]" | "^" | "_" | "`" | "{" | "|"
|
|
||||||
| "}" | "~"
|
|
||||||
media-type = type-name "/" subtype-name
|
|
||||||
quoted-mt = <"> media-type <">
|
|
||||||
relation-types = relation-type
|
|
||||||
| <"> relation-type *( 1*SP relation-type ) <">
|
|
||||||
relation-type = reg-rel-type | ext-rel-type
|
|
||||||
reg-rel-type = LOALPHA *( LOALPHA | DIGIT | "." | "-" )
|
|
||||||
ext-rel-type = URI
|
|
||||||
|
|
||||||
See more: rfc5988
|
|
||||||
*/
|
|
||||||
static bool
|
|
||||||
find_key_value (const char *start, const char *end, const char *key, char **value)
|
|
||||||
{
|
|
||||||
const char *eq;
|
|
||||||
size_t key_len = strlen (key);
|
|
||||||
const char *val_beg, *val_end;
|
|
||||||
const char *key_beg;
|
|
||||||
|
|
||||||
key_beg = start;
|
|
||||||
|
|
||||||
while (key_beg + key_len + 1 < end)
|
|
||||||
{
|
|
||||||
/* Skip whitespaces. */
|
|
||||||
while (key_beg + key_len + 1 < end && c_isspace (*key_beg))
|
|
||||||
key_beg++;
|
|
||||||
if (strncmp (key_beg, key, key_len))
|
|
||||||
{
|
|
||||||
/* Find next token. */
|
|
||||||
while (key_beg + key_len + 1 < end && *key_beg != ';')
|
|
||||||
key_beg++;
|
|
||||||
key_beg++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Find equals sign. */
|
|
||||||
eq = key_beg + key_len;
|
|
||||||
while (eq < end && c_isspace (*eq))
|
|
||||||
eq++;
|
|
||||||
if (eq == end)
|
|
||||||
return false;
|
|
||||||
if (*eq != '=')
|
|
||||||
{
|
|
||||||
key_beg++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
val_beg = eq + 1;
|
|
||||||
while (val_beg < end && c_isspace (*val_beg))
|
|
||||||
val_beg++;
|
|
||||||
if (val_beg == end)
|
|
||||||
return false;
|
|
||||||
val_end = val_beg + 1;
|
|
||||||
while (val_end < end && *val_end != ';' && !c_isspace (*val_end))
|
|
||||||
val_end++;
|
|
||||||
*value = xstrndup (val_beg, val_end - val_beg);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*value = NULL;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is to check if given token exists in HTTP header. Tokens are
|
|
||||||
separated by ';'. */
|
|
||||||
static bool
|
|
||||||
has_key (const char *start, const char *end, const char *key)
|
|
||||||
{
|
|
||||||
const char *pos; /* Here would the token start. */
|
|
||||||
size_t key_len = strlen (key);
|
|
||||||
|
|
||||||
pos = start;
|
|
||||||
while (pos + key_len <= end)
|
|
||||||
{
|
|
||||||
/* Skip whitespaces at beginning. */
|
|
||||||
while (pos + key_len <= end && c_isspace (*pos))
|
|
||||||
pos++;
|
|
||||||
|
|
||||||
/* Does the prefix of pos match our key? */
|
|
||||||
if (strncmp (key, pos, key_len))
|
|
||||||
{
|
|
||||||
/* This was not a match.
|
|
||||||
Skip all characters until beginning of next token. */
|
|
||||||
while (pos + key_len <= end && *pos != ';')
|
|
||||||
pos++;
|
|
||||||
pos++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* key is prefix of pos. Is it the exact token or just a prefix? */
|
|
||||||
pos += key_len;
|
|
||||||
while (pos < end && c_isspace (*pos))
|
|
||||||
pos++;
|
|
||||||
if (pos == end || *pos == ';')
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/* This was not a match (just a prefix).
|
|
||||||
Skip all characters until beginning of next token. */
|
|
||||||
while (pos + key_len <= end && *pos != ';')
|
|
||||||
pos++;
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find all key=value pairs delimited with ';' or ','. This is intended for
|
|
||||||
Digest header parsing.
|
|
||||||
The usage is:
|
|
||||||
|
|
||||||
const char *pos;
|
|
||||||
for (pos = header_beg; pos = find_key_values (pos, header_end, &key, &val); pos++)
|
|
||||||
{
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
static const char *
|
|
||||||
find_key_values (const char *start, const char *end, char **key, char **value)
|
|
||||||
{
|
|
||||||
const char *key_start, *key_end;
|
|
||||||
const char *eq;
|
|
||||||
const char *val_start, *val_end;
|
|
||||||
|
|
||||||
eq = start;
|
|
||||||
while (eq < end && *eq != '=')
|
|
||||||
{
|
|
||||||
/* Skip tokens without =value part. */
|
|
||||||
if (*eq == ';' || *eq == ',')
|
|
||||||
start = eq + 1;
|
|
||||||
eq++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eq >= end)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
key_start = start;
|
|
||||||
while (key_start < eq && c_isspace (*key_start))
|
|
||||||
key_start++;
|
|
||||||
|
|
||||||
key_end = eq - 1;
|
|
||||||
while (key_end > key_start && c_isspace (*key_end))
|
|
||||||
key_end--;
|
|
||||||
key_end++;
|
|
||||||
|
|
||||||
val_start = eq + 1;
|
|
||||||
while (val_start < end && c_isspace (*val_start))
|
|
||||||
val_start++;
|
|
||||||
|
|
||||||
val_end = val_start;
|
|
||||||
|
|
||||||
while (val_end < end && *val_end != ';' &&
|
|
||||||
*val_end != ',' && !c_isspace (*val_end))
|
|
||||||
val_end++;
|
|
||||||
|
|
||||||
*key = xstrndup (key_start, key_end - key_start);
|
|
||||||
*value = xstrndup (val_start, val_end - val_start);
|
|
||||||
|
|
||||||
/* Skip trailing whitespaces. */
|
|
||||||
while (val_end < end && c_isspace (*val_end))
|
|
||||||
val_end++;
|
|
||||||
|
|
||||||
return val_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Will return proper metalink_t structure if enough data was found in
|
/* Will return proper metalink_t structure if enough data was found in
|
||||||
http response resp. Otherwise returns NULL.
|
http response resp. Otherwise returns NULL.
|
||||||
Two exit points: one for success and one for failure. */
|
Two exit points: one for success and one for failure. */
|
||||||
@ -4999,131 +4807,6 @@ ensure_extension (struct http_stat *hs, const char *ext, int *dt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TESTING
|
#ifdef TESTING
|
||||||
|
|
||||||
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 struct
|
|
||||||
{
|
|
||||||
const char *key;
|
|
||||||
const char *val;
|
|
||||||
} test_array[] =
|
|
||||||
{
|
|
||||||
{ "key1", "val1" },
|
|
||||||
{ "key2", "val2" },
|
|
||||||
{ "key3", "val3" },
|
|
||||||
{ "key4", "val4" },
|
|
||||||
{ "key5", "val5" },
|
|
||||||
{ "key6", "val6" },
|
|
||||||
{ "key7", "val7" },
|
|
||||||
{ "key8", "val8" },
|
|
||||||
{ "key9", "val9" },
|
|
||||||
{ "key10", "val10" },
|
|
||||||
{ "key12", "val12" }
|
|
||||||
};
|
|
||||||
const char *pos;
|
|
||||||
char *key, *value;
|
|
||||||
size_t i = 0;
|
|
||||||
|
|
||||||
for (pos = header_data; (pos = find_key_values (pos,
|
|
||||||
header_data + strlen (header_data),
|
|
||||||
&key, &value)); pos++)
|
|
||||||
{
|
|
||||||
mu_assert ("test_find_key_values: wrong result",
|
|
||||||
!strcmp (test_array[i].val, value) &&
|
|
||||||
!strcmp (test_array[i].key, key));
|
|
||||||
xfree (key);
|
|
||||||
xfree (value);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 struct
|
|
||||||
{
|
|
||||||
const char *key;
|
|
||||||
const char *val;
|
|
||||||
bool result;
|
|
||||||
} test_array[] =
|
|
||||||
{
|
|
||||||
{ "key1", "val1", true },
|
|
||||||
{ "key2", "val2", true },
|
|
||||||
{ "key3", "val3", true },
|
|
||||||
{ "key4", "val4", true },
|
|
||||||
{ "key5", "val5", true },
|
|
||||||
{ "key6", "val6", true },
|
|
||||||
{ "key7", "val7", true },
|
|
||||||
{ "key8", "val8", true },
|
|
||||||
{ "key9", "val9", true },
|
|
||||||
{ "key10", NULL, false },
|
|
||||||
{ "ey1", NULL, false },
|
|
||||||
{ "dey1", NULL, false }
|
|
||||||
};
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for (i=0; i < countof (test_array); ++i)
|
|
||||||
{
|
|
||||||
bool result;
|
|
||||||
char *value;
|
|
||||||
|
|
||||||
result = find_key_value (header_data,
|
|
||||||
header_data + strlen(header_data),
|
|
||||||
test_array[i].key, &value);
|
|
||||||
|
|
||||||
mu_assert ("test_find_key_value: wrong result",
|
|
||||||
result == test_array[i].result &&
|
|
||||||
((!test_array[i].result && !value) ||
|
|
||||||
!strcmp (value, test_array[i].val)));
|
|
||||||
|
|
||||||
xfree (value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *
|
|
||||||
test_has_key (void)
|
|
||||||
{
|
|
||||||
static const char *header_data = "key1=val2;token1;xyz; token2;xyz;token3 ;"\
|
|
||||||
"xyz; token4 ;xyz; token5 ";
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
const char *token;
|
|
||||||
bool result;
|
|
||||||
} test_array[] =
|
|
||||||
{
|
|
||||||
{ "key1=val2", true },
|
|
||||||
{ "token1", true },
|
|
||||||
{ "token2", true },
|
|
||||||
{ "token3", true },
|
|
||||||
{ "token4", true },
|
|
||||||
{ "token5", true },
|
|
||||||
{ "token6", false },
|
|
||||||
{ "oken1", false },
|
|
||||||
{ "poken1", false },
|
|
||||||
{ "key1=val2", true }
|
|
||||||
};
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for (i = 0; i < countof (test_array); ++i)
|
|
||||||
mu_assert ("test_has_key: wrong result",
|
|
||||||
has_key (header_data, header_data + strlen (header_data),
|
|
||||||
test_array[i].token) == test_array[i].result);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
test_parse_content_disposition(void)
|
test_parse_content_disposition(void)
|
||||||
{
|
{
|
||||||
|
322
src/metalink.c
322
src/metalink.c
@ -35,6 +35,7 @@ as that of the covered work. */
|
|||||||
#include "exits.h"
|
#include "exits.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "sha256.h"
|
#include "sha256.h"
|
||||||
|
#include "xstrndup.h"
|
||||||
#include <sys/errno.h>
|
#include <sys/errno.h>
|
||||||
#include <unistd.h> /* For unlink. */
|
#include <unistd.h> /* For unlink. */
|
||||||
#include <metalink/metalink_parser.h>
|
#include <metalink/metalink_parser.h>
|
||||||
@ -43,6 +44,10 @@ as that of the covered work. */
|
|||||||
#include <fcntl.h> /* For open and close. */
|
#include <fcntl.h> /* For open and close. */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef TESTING
|
||||||
|
#include "test.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Loop through all files in metalink structure and retrieve them.
|
/* Loop through all files in metalink structure and retrieve them.
|
||||||
Returns RETROK if all files were downloaded.
|
Returns RETROK if all files were downloaded.
|
||||||
Returns last retrieval error (from retrieve_url) if some files
|
Returns last retrieval error (from retrieve_url) if some files
|
||||||
@ -445,4 +450,321 @@ int metalink_res_cmp (const void* v1, const void* v2)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Find value of given key. This is intended for Link header, but will
|
||||||
|
work with any header that uses ';' as field separator and '=' as key-value
|
||||||
|
separator.
|
||||||
|
|
||||||
|
Link = "Link" ":" #link-value
|
||||||
|
link-value = "<" URI-Reference ">" *( ";" link-param )
|
||||||
|
link-param = ( ( "rel" "=" relation-types )
|
||||||
|
| ( "anchor" "=" <"> URI-Reference <"> )
|
||||||
|
| ( "rev" "=" relation-types )
|
||||||
|
| ( "hreflang" "=" Language-Tag )
|
||||||
|
| ( "media" "=" ( MediaDesc | ( <"> MediaDesc <"> ) ) )
|
||||||
|
| ( "title" "=" quoted-string )
|
||||||
|
| ( "title*" "=" ext-value )
|
||||||
|
| ( "type" "=" ( media-type | quoted-mt ) )
|
||||||
|
| ( link-extension ) )
|
||||||
|
link-extension = ( parmname [ "=" ( ptoken | quoted-string ) ] )
|
||||||
|
| ( ext-name-star "=" ext-value )
|
||||||
|
ext-name-star = parmname "*" ; reserved for RFC2231-profiled
|
||||||
|
; extensions. Whitespace NOT
|
||||||
|
; allowed in between.
|
||||||
|
ptoken = 1*ptokenchar
|
||||||
|
ptokenchar = "!" | "#" | "$" | "%" | "&" | "'" | "("
|
||||||
|
| ")" | "*" | "+" | "-" | "." | "/" | DIGIT
|
||||||
|
| ":" | "<" | "=" | ">" | "?" | "@" | ALPHA
|
||||||
|
| "[" | "]" | "^" | "_" | "`" | "{" | "|"
|
||||||
|
| "}" | "~"
|
||||||
|
media-type = type-name "/" subtype-name
|
||||||
|
quoted-mt = <"> media-type <">
|
||||||
|
relation-types = relation-type
|
||||||
|
| <"> relation-type *( 1*SP relation-type ) <">
|
||||||
|
relation-type = reg-rel-type | ext-rel-type
|
||||||
|
reg-rel-type = LOALPHA *( LOALPHA | DIGIT | "." | "-" )
|
||||||
|
ext-rel-type = URI
|
||||||
|
|
||||||
|
See more: rfc5988
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
find_key_value (const char *start, const char *end, const char *key, char **value)
|
||||||
|
{
|
||||||
|
const char *eq;
|
||||||
|
size_t key_len = strlen (key);
|
||||||
|
const char *val_beg, *val_end;
|
||||||
|
const char *key_beg;
|
||||||
|
|
||||||
|
key_beg = start;
|
||||||
|
|
||||||
|
while (key_beg + key_len + 1 < end)
|
||||||
|
{
|
||||||
|
/* Skip whitespaces. */
|
||||||
|
while (key_beg + key_len + 1 < end && c_isspace (*key_beg))
|
||||||
|
key_beg++;
|
||||||
|
if (strncmp (key_beg, key, key_len))
|
||||||
|
{
|
||||||
|
/* Find next token. */
|
||||||
|
while (key_beg + key_len + 1 < end && *key_beg != ';')
|
||||||
|
key_beg++;
|
||||||
|
key_beg++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Find equals sign. */
|
||||||
|
eq = key_beg + key_len;
|
||||||
|
while (eq < end && c_isspace (*eq))
|
||||||
|
eq++;
|
||||||
|
if (eq == end)
|
||||||
|
return false;
|
||||||
|
if (*eq != '=')
|
||||||
|
{
|
||||||
|
key_beg++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
val_beg = eq + 1;
|
||||||
|
while (val_beg < end && c_isspace (*val_beg))
|
||||||
|
val_beg++;
|
||||||
|
if (val_beg == end)
|
||||||
|
return false;
|
||||||
|
val_end = val_beg + 1;
|
||||||
|
while (val_end < end && *val_end != ';' && !c_isspace (*val_end))
|
||||||
|
val_end++;
|
||||||
|
*value = xstrndup (val_beg, val_end - val_beg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*value = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is to check if given token exists in HTTP header. Tokens are
|
||||||
|
separated by ';'. */
|
||||||
|
bool
|
||||||
|
has_key (const char *start, const char *end, const char *key)
|
||||||
|
{
|
||||||
|
const char *pos; /* Here would the token start. */
|
||||||
|
size_t key_len = strlen (key);
|
||||||
|
|
||||||
|
pos = start;
|
||||||
|
while (pos + key_len <= end)
|
||||||
|
{
|
||||||
|
/* Skip whitespaces at beginning. */
|
||||||
|
while (pos + key_len <= end && c_isspace (*pos))
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
/* Does the prefix of pos match our key? */
|
||||||
|
if (strncmp (key, pos, key_len))
|
||||||
|
{
|
||||||
|
/* This was not a match.
|
||||||
|
Skip all characters until beginning of next token. */
|
||||||
|
while (pos + key_len <= end && *pos != ';')
|
||||||
|
pos++;
|
||||||
|
pos++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* key is prefix of pos. Is it the exact token or just a prefix? */
|
||||||
|
pos += key_len;
|
||||||
|
while (pos < end && c_isspace (*pos))
|
||||||
|
pos++;
|
||||||
|
if (pos == end || *pos == ';')
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* This was not a match (just a prefix).
|
||||||
|
Skip all characters until beginning of next token. */
|
||||||
|
while (pos + key_len <= end && *pos != ';')
|
||||||
|
pos++;
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find all key=value pairs delimited with ';' or ','. This is intended for
|
||||||
|
Digest header parsing.
|
||||||
|
The usage is:
|
||||||
|
|
||||||
|
const char *pos;
|
||||||
|
for (pos = header_beg; pos = find_key_values (pos, header_end, &key, &val); pos++)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
const char *
|
||||||
|
find_key_values (const char *start, const char *end, char **key, char **value)
|
||||||
|
{
|
||||||
|
const char *key_start, *key_end;
|
||||||
|
const char *eq;
|
||||||
|
const char *val_start, *val_end;
|
||||||
|
|
||||||
|
eq = start;
|
||||||
|
while (eq < end && *eq != '=')
|
||||||
|
{
|
||||||
|
/* Skip tokens without =value part. */
|
||||||
|
if (*eq == ';' || *eq == ',')
|
||||||
|
start = eq + 1;
|
||||||
|
eq++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eq >= end)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
key_start = start;
|
||||||
|
while (key_start < eq && c_isspace (*key_start))
|
||||||
|
key_start++;
|
||||||
|
|
||||||
|
key_end = eq - 1;
|
||||||
|
while (key_end > key_start && c_isspace (*key_end))
|
||||||
|
key_end--;
|
||||||
|
key_end++;
|
||||||
|
|
||||||
|
val_start = eq + 1;
|
||||||
|
while (val_start < end && c_isspace (*val_start))
|
||||||
|
val_start++;
|
||||||
|
|
||||||
|
val_end = val_start;
|
||||||
|
|
||||||
|
while (val_end < end && *val_end != ';' &&
|
||||||
|
*val_end != ',' && !c_isspace (*val_end))
|
||||||
|
val_end++;
|
||||||
|
|
||||||
|
*key = xstrndup (key_start, key_end - key_start);
|
||||||
|
*value = xstrndup (val_start, val_end - val_start);
|
||||||
|
|
||||||
|
/* Skip trailing whitespaces. */
|
||||||
|
while (val_end < end && c_isspace (*val_end))
|
||||||
|
val_end++;
|
||||||
|
|
||||||
|
return val_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TESTING
|
||||||
|
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 struct
|
||||||
|
{
|
||||||
|
const char *key;
|
||||||
|
const char *val;
|
||||||
|
} test_array[] =
|
||||||
|
{
|
||||||
|
{ "key1", "val1" },
|
||||||
|
{ "key2", "val2" },
|
||||||
|
{ "key3", "val3" },
|
||||||
|
{ "key4", "val4" },
|
||||||
|
{ "key5", "val5" },
|
||||||
|
{ "key6", "val6" },
|
||||||
|
{ "key7", "val7" },
|
||||||
|
{ "key8", "val8" },
|
||||||
|
{ "key9", "val9" },
|
||||||
|
{ "key10", "val10" },
|
||||||
|
{ "key12", "val12" }
|
||||||
|
};
|
||||||
|
const char *pos;
|
||||||
|
char *key, *value;
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
for (pos = header_data; (pos = find_key_values (pos,
|
||||||
|
header_data + strlen (header_data),
|
||||||
|
&key, &value)); pos++)
|
||||||
|
{
|
||||||
|
mu_assert ("test_find_key_values: wrong result",
|
||||||
|
!strcmp (test_array[i].val, value) &&
|
||||||
|
!strcmp (test_array[i].key, key));
|
||||||
|
xfree (key);
|
||||||
|
xfree (value);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 struct
|
||||||
|
{
|
||||||
|
const char *key;
|
||||||
|
const char *val;
|
||||||
|
bool result;
|
||||||
|
} test_array[] =
|
||||||
|
{
|
||||||
|
{ "key1", "val1", true },
|
||||||
|
{ "key2", "val2", true },
|
||||||
|
{ "key3", "val3", true },
|
||||||
|
{ "key4", "val4", true },
|
||||||
|
{ "key5", "val5", true },
|
||||||
|
{ "key6", "val6", true },
|
||||||
|
{ "key7", "val7", true },
|
||||||
|
{ "key8", "val8", true },
|
||||||
|
{ "key9", "val9", true },
|
||||||
|
{ "key10", NULL, false },
|
||||||
|
{ "ey1", NULL, false },
|
||||||
|
{ "dey1", NULL, false }
|
||||||
|
};
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i=0; i < countof (test_array); ++i)
|
||||||
|
{
|
||||||
|
bool result;
|
||||||
|
char *value;
|
||||||
|
|
||||||
|
result = find_key_value (header_data,
|
||||||
|
header_data + strlen(header_data),
|
||||||
|
test_array[i].key, &value);
|
||||||
|
|
||||||
|
mu_assert ("test_find_key_value: wrong result",
|
||||||
|
result == test_array[i].result &&
|
||||||
|
((!test_array[i].result && !value) ||
|
||||||
|
!strcmp (value, test_array[i].val)));
|
||||||
|
|
||||||
|
xfree (value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
test_has_key (void)
|
||||||
|
{
|
||||||
|
static const char *header_data = "key1=val2;token1;xyz; token2;xyz;token3 ;"\
|
||||||
|
"xyz; token4 ;xyz; token5 ";
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
const char *token;
|
||||||
|
bool result;
|
||||||
|
} test_array[] =
|
||||||
|
{
|
||||||
|
{ "key1=val2", true },
|
||||||
|
{ "token1", true },
|
||||||
|
{ "token2", true },
|
||||||
|
{ "token3", true },
|
||||||
|
{ "token4", true },
|
||||||
|
{ "token5", true },
|
||||||
|
{ "token6", false },
|
||||||
|
{ "oken1", false },
|
||||||
|
{ "poken1", false },
|
||||||
|
{ "key1=val2", true }
|
||||||
|
};
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < countof (test_array); ++i)
|
||||||
|
mu_assert ("test_has_key: wrong result",
|
||||||
|
has_key (header_data, header_data + strlen (header_data),
|
||||||
|
test_array[i].token) == test_array[i].result);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* HAVE_METALINK */
|
#endif /* HAVE_METALINK */
|
||||||
|
@ -47,4 +47,14 @@ uerr_t retrieve_from_metalink (const metalink_t *metalink);
|
|||||||
|
|
||||||
int metalink_res_cmp (const void *res1, const void *res2);
|
int metalink_res_cmp (const void *res1, const void *res2);
|
||||||
|
|
||||||
|
bool find_key_value (const char *start,
|
||||||
|
const char *end,
|
||||||
|
const char *key,
|
||||||
|
char **value);
|
||||||
|
bool has_key (const char *start, const char *end, const char *key);
|
||||||
|
const char *find_key_values (const char *start,
|
||||||
|
const char *end,
|
||||||
|
char **key,
|
||||||
|
char **value);
|
||||||
|
|
||||||
#endif /* METALINK_H */
|
#endif /* METALINK_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user