Commit 196c8242 authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa Committed by Yang Tse
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.
parent 424bb358
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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 */
+2 −6
Original line number Diff line number Diff line
@@ -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");
+1 −1
Original line number Diff line number Diff line
@@ -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",
+40 −12
Original line number Diff line number Diff line
@@ -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.
 */
+9 −1
Original line number Diff line number Diff line
@@ -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"
Loading