Permalink
Browse files

curl: Made --metalink option toggle Metalink functionality

In this change, --metalink option no longer takes argument.  If
it is specified, given URIs are processed as Metalink XML file.
If given URIs are remote (e.g., http URI), curl downloads it
first. Regardless URI is local file (e.g., file URI scheme) or
remote, Metalink XML file is not written to local file system and
the received data is fed into Metalink XML parser directly.  This
means with --metalink option, filename related options like -O
and -o are ignored.

Usage examples:

$ curl --metalink http://example.org/foo.metalink

This will download foo.metalink and parse it and then download
the URI described there.

$ curl --metalink file://foo.metalink

This will parse local file foo.metalink and then download the URI
described there.
  • Loading branch information...
1 parent 424bb35 commit 196c8242caa30472564290f1c89e7e19d2f04453 @tatsuhiro-t tatsuhiro-t committed with yangtse Jun 20, 2012
Showing with 97 additions and 41 deletions.
  1. +1 −0 src/tool_cfgable.h
  2. +2 −6 src/tool_getparam.c
  3. +1 −1 src/tool_help.c
  4. +40 −12 src/tool_metalink.c
  5. +9 −1 src/tool_metalink.h
  6. +35 −20 src/tool_operate.c
  7. +9 −1 src/tool_sdecls.h
View
@@ -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 */
View
@@ -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");
View
@@ -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",
View
@@ -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.
*/
View
@@ -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"
View
@@ -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;
View
@@ -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 */
};

0 comments on commit 196c824

Please sign in to comment.