aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/tool_cfgable.h1
-rw-r--r--src/tool_getparam.c8
-rw-r--r--src/tool_help.c2
-rw-r--r--src/tool_metalink.c52
-rw-r--r--src/tool_metalink.h10
-rw-r--r--src/tool_operate.c55
-rw-r--r--src/tool_sdecls.h10
7 files changed, 97 insertions, 41 deletions
diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h
index 2183c04df..1f6f94852 100644
--- a/src/tool_cfgable.h
+++ b/src/tool_cfgable.h
@@ -201,6 +201,7 @@ struct Configurable {
long gssapi_delegation;
bool ssl_allow_beast; /* allow this SSL vulnerability */
+ bool use_metalink; /* process given URLs as metalink XML file */
metalinkfile *metalinkfile_list; /* point to the first node */
metalinkfile *metalinkfile_last; /* point to the last/current node */
}; /* struct Configurable */
diff --git a/src/tool_getparam.c b/src/tool_getparam.c
index ab8ed1d5e..4bdf0a59d 100644
--- a/src/tool_getparam.c
+++ b/src/tool_getparam.c
@@ -171,7 +171,7 @@ static const struct LongShort aliases[]= {
{"$G", "delegation", TRUE},
{"$H", "mail-auth", TRUE},
{"$I", "post303", FALSE},
- {"$J", "metalink", TRUE},
+ {"$J", "metalink", FALSE},
{"0", "http1.0", FALSE},
{"1", "tlsv1", FALSE},
{"2", "sslv2", FALSE},
@@ -824,11 +824,7 @@ ParameterError getparameter(char *flag, /* f or -long-flag */
case 'J': /* --metalink */
{
#ifdef USE_METALINK
- if(parse_metalink(config, nextarg) == -1) {
- warnf(config, "Could not parse Metalink file: %s\n", nextarg);
- /* TODO Is PARAM_BAD_USE appropriate here? */
- return PARAM_BAD_USE;
- }
+ config->use_metalink = toggle;
#else
warnf(config, "--metalink option is ignored because the binary is "
"built without the Metalink support.\n");
diff --git a/src/tool_help.c b/src/tool_help.c
index ac9246931..124f6404d 100644
--- a/src/tool_help.c
+++ b/src/tool_help.c
@@ -125,7 +125,7 @@ static const char *const helptext[] = {
" --max-filesize BYTES Maximum file size to download (H/F)",
" --max-redirs NUM Maximum number of redirects allowed (H)",
" -m, --max-time SECONDS Maximum time allowed for the transfer",
- " --metalink Process local Metalink file and use mirrors",
+ " --metalink Process given URLs as metalink XML file",
" --negotiate Use HTTP Negotiate Authentication (H)",
" -n, --netrc Must read .netrc for user name and password",
" --netrc-optional Use either .netrc or URL; overrides -n",
diff --git a/src/tool_metalink.c b/src/tool_metalink.c
index 8f6a1f870..74a0012ac 100644
--- a/src/tool_metalink.c
+++ b/src/tool_metalink.c
@@ -33,8 +33,6 @@
# include <fcntl.h>
#endif
-#include <metalink/metalink_parser.h>
-
#ifdef USE_SSLEAY
# ifdef USE_OPENSSL
# include <openssl/md5.h>
@@ -68,6 +66,7 @@
#include "tool_paramhlp.h"
#include "tool_cfgable.h"
#include "tool_metalink.h"
+#include "tool_msgs.h"
#include "memdebug.h" /* keep this as LAST include */
@@ -331,8 +330,8 @@ static int check_hash(const char *filename,
digest_context *dctx;
int check_ok;
int fd;
- fprintf(error, "Checking %s checksum of file %s\n", digest_def->hash_name,
- filename);
+ fprintf(error, "Validating %s checksum (This may take some time)...\n",
+ digest_def->hash_name);
fd = open(filename, O_RDONLY);
if(fd == -1) {
fprintf(error, "Could not open file %s: %s\n", filename, strerror(errno));
@@ -358,6 +357,12 @@ static int check_hash(const char *filename,
Curl_digest_final(dctx, result);
check_ok = memcmp(result, digest,
digest_def->dparams->digest_resultlen) == 0;
+ /* sha*sum style verdict output */
+ if(check_ok)
+ fprintf(error, "%s: OK\n", filename);
+ else
+ fprintf(error, "%s: FAILED\n", filename);
+
free(result);
close(fd);
return check_ok;
@@ -373,12 +378,6 @@ int metalink_check_hash(struct Configurable *config,
}
rv = check_hash(filename, mlfile->checksum->digest_def,
mlfile->checksum->digest, config->errors);
- if(rv == 1) {
- fprintf(config->errors, "Checksum matched\n");
- }
- else if(rv == 0) {
- fprintf(config->errors, "Checksum didn't match\n");
- }
return rv;
}
@@ -468,13 +467,15 @@ static metalinkfile *new_metalinkfile(metalink_file_t *fileinfo)
return f;
}
-int parse_metalink(struct Configurable *config, const char *infile)
+int parse_metalink(struct Configurable *config, struct OutStruct *outs)
{
metalink_error_t r;
metalink_t* metalink;
metalink_file_t **files;
- r = metalink_parse_file(infile, &metalink);
+ /* metlaink_parse_final deletes outs->metalink_parser */
+ r = metalink_parse_final(outs->metalink_parser, NULL, 0, &metalink);
+ outs->metalink_parser = NULL;
if(r != 0) {
return -1;
}
@@ -531,6 +532,33 @@ int parse_metalink(struct Configurable *config, const char *infile)
return 0;
}
+size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb,
+ void *userdata)
+{
+ struct OutStruct *outs = userdata;
+ struct Configurable *config = outs->config;
+ int rv;
+
+ /*
+ * Once that libcurl has called back tool_write_cb() the returned value
+ * is checked against the amount that was intended to be written, if
+ * it does not match then it fails with CURLE_WRITE_ERROR. So at this
+ * point returning a value different from sz*nmemb indicates failure.
+ */
+ const size_t failure = (sz * nmemb) ? 0 : 1;
+
+ if(!config)
+ return failure;
+
+ rv = metalink_parse_update(outs->metalink_parser, buffer, sz *nmemb);
+ if(rv == 0)
+ return sz * nmemb;
+ else {
+ warnf(config, "Failed to parse Metalink XML\n");
+ return failure;
+ }
+}
+
/*
* Returns nonzero if content_type includes mediatype.
*/
diff --git a/src/tool_metalink.h b/src/tool_metalink.h
index 36b4b02c7..c2568a31e 100644
--- a/src/tool_metalink.h
+++ b/src/tool_metalink.h
@@ -82,13 +82,21 @@ extern const digest_params MD5_DIGEST_PARAMS[1];
extern const digest_params SHA1_DIGEST_PARAMS[1];
extern const digest_params SHA256_DIGEST_PARAMS[1];
+#include <metalink/metalink_parser.h>
+
/*
* Counts the resource in the metalinkfile.
*/
int count_next_metalink_resource(metalinkfile *mlfile);
void clean_metalink(struct Configurable *config);
-int parse_metalink(struct Configurable *config, const char *infile);
+int parse_metalink(struct Configurable *config, struct OutStruct *outs);
+
+/*
+ * Callback function for CURLOPT_WRITEFUNCTION
+ */
+size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb,
+ void *userdata);
/*
* Returns nonzero if content_type includes "application/metalink+xml"
diff --git a/src/tool_operate.c b/src/tool_operate.c
index 8a5569bd8..6d02fb667 100644
--- a/src/tool_operate.c
+++ b/src/tool_operate.c
@@ -586,8 +586,9 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[])
}
}
- if((urlnode->flags&GETOUT_USEREMOTE) ||
- (outfile && !curlx_strequal("-", outfile)) ) {
+ if(((urlnode->flags&GETOUT_USEREMOTE) ||
+ (outfile && !curlx_strequal("-", outfile))) &&
+ (metalink || !config->use_metalink)) {
/*
* We have specified a file name to store the result in, or we have
@@ -826,8 +827,15 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[])
/* where to store */
my_setopt(curl, CURLOPT_WRITEDATA, &outs);
- /* what call to write */
- my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb);
+ if(metalink || !config->use_metalink)
+ /* what call to write */
+ my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb);
+#ifdef USE_METALINK
+ else
+ /* Set Metalink specific write callback function to parse
+ XML data progressively. */
+ my_setopt(curl, CURLOPT_WRITEFUNCTION, metalink_write_cb);
+#endif /* USE_METALINK */
/* for uploads */
input.fd = infd;
@@ -1316,6 +1324,19 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[])
#endif
for(;;) {
+#ifdef USE_METALINK
+ if(!metalink && config->use_metalink) {
+ /* If outs.metalink_parser is non-NULL, delete it first. */
+ if(outs.metalink_parser)
+ metalink_parser_context_delete(outs.metalink_parser);
+ outs.metalink_parser = metalink_parser_context_new();
+ if(outs.metalink_parser == NULL) {
+ res = CURLE_OUT_OF_MEMORY;
+ goto show_error;
+ }
+ }
+#endif /* USE_METALINK */
+
res = curl_easy_perform(curl);
if(outs.is_cd_filename && outs.stream && !config->mute &&
@@ -1569,22 +1590,12 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[])
#endif
#ifdef USE_METALINK
- if(!metalink && res == CURLE_OK && outs.filename) {
- /* Check the content-type header field and if it indicates
- Metalink file, parse it and add getout for them. */
- char *content_type;
- curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &content_type);
- if(content_type && check_metalink_content_type(content_type)) {
- if(!(config->mute)) {
- fprintf(config->errors, "\nParsing Metalink file: %s\n",
- outs.filename);
- }
- if(parse_metalink(config, outs.filename) == 0)
- fprintf(config->errors,
- "Metalink file is parsed successfully\n");
- else
- fprintf(config->errors, "Could not parse Metalink file.\n");
- }
+ if(!metalink && config->use_metalink && res == CURLE_OK) {
+ if(parse_metalink(config, &outs) == 0)
+ fprintf(config->errors,
+ "Metalink XML is parsed successfully\n");
+ else
+ fprintf(config->errors, "Could not parse Metalink XML.\n");
}
else if(metalink && res == CURLE_OK && !metalink_next_res) {
int rv = metalink_check_hash(config, mlfile, outs.filename);
@@ -1597,6 +1608,10 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[])
/* No more business with this output struct */
if(outs.alloc_filename)
Curl_safefree(outs.filename);
+#ifdef USE_METALINK
+ if(outs.metalink_parser)
+ metalink_parser_context_delete(outs.metalink_parser);
+#endif /* USE_METALINK */
memset(&outs, 0, sizeof(struct OutStruct));
hdrcbdata.outs = NULL;
diff --git a/src/tool_sdecls.h b/src/tool_sdecls.h
index da6253604..8038ad7a3 100644
--- a/src/tool_sdecls.h
+++ b/src/tool_sdecls.h
@@ -22,7 +22,9 @@
*
***************************************************************************/
#include "tool_setup.h"
-
+#ifdef USE_METALINK
+# include <metalink/metalink_parser.h>
+#endif /* USE_METALINK */
/*
* OutStruct variables keep track of information relative to curl's
@@ -55,6 +57,9 @@
*
* 'init' member holds original file size or offset at which truncation is
* taking place. Always zero unless appending to a non-empty regular file.
+ *
+ * 'metalink_parser' member is a pointer to Metalink XML parser
+ * context.
*/
struct OutStruct {
@@ -67,6 +72,9 @@ struct OutStruct {
struct Configurable *config;
curl_off_t bytes;
curl_off_t init;
+#ifdef USE_METALINK
+ metalink_parser_context_t *metalink_parser;
+#endif /* USE_METALINK */
};