bug-wget
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Bug-wget] [PATCH 19/27] New: Parse Metalink/HTTP header for application


From: Matthew White
Subject: [Bug-wget] [PATCH 19/27] New: Parse Metalink/HTTP header for application/metalink4+xml
Date: Thu, 29 Sep 2016 06:02:59 +0200

* src/http.c (metalink_from_http): Parse Metalink/HTTP header for
  metaurls application/metalink4+xml media types
* src/metalink.h: Add function declaration metalink_meta_cmp()
* src/metalink.c: Add function metalink_meta_cmp() compare metalink
  metaurls priorities

Add Metalink/HTTP application/metalink4+xml media types as metaurls to
the metalink variable that will be used to download the files.
---
 src/http.c     | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++------
 src/metalink.c |  9 ++++++++
 src/metalink.h |  1 +
 3 files changed, 74 insertions(+), 7 deletions(-)

diff --git a/src/http.c b/src/http.c
index 7e2c4ec..e6af7c1 100644
--- a/src/http.c
+++ b/src/http.c
@@ -2555,7 +2555,7 @@ metalink_from_http (const struct response *resp, const 
struct http_stat *hs,
   metalink_t *metalink = NULL;
   metalink_file_t *mfile = xnew0 (metalink_file_t);
   const char *val_beg, *val_end;
-  int res_count = 0, hash_count = 0, sig_count = 0, i;
+  int res_count = 0, meta_count = 0, hash_count = 0, sig_count = 0, i;
 
   DEBUGP (("Checking for Metalink in HTTP response\n"));
 
@@ -2568,6 +2568,7 @@ metalink_from_http (const struct response *resp, const 
struct http_stat *hs,
   /* Begin with 1-element array (for 0-termination). */
   mfile->checksums = xnew0 (metalink_checksum_t *);
   mfile->resources = xnew0 (metalink_resource_t *);
+  mfile->metaurls = xnew0 (metalink_metaurl_t *);
 
   /* Find all Link headers.  */
   for (i = 0;
@@ -2628,14 +2629,14 @@ metalink_from_http (const struct response *resp, const 
struct http_stat *hs,
       DEBUGP (("URL=%s\n", urlstr));
       DEBUGP (("rel=%s\n", rel));
 
+      if (!strcmp (rel, "describedby"))
+        find_key_value (attrs_beg, val_end, "type", &reltype);
+
       /* Handle signatures.
          Libmetalink only supports one signature per file. Therefore we stop
          as soon as we successfully get first supported signature.  */
       if (sig_count == 0 &&
-          !strcmp (rel, "describedby") &&
-          find_key_value (attrs_beg, val_end, "type", &reltype) &&
-          !strcmp (reltype, "application/pgp-signature")
-          )
+          reltype && !strcmp (reltype, "application/pgp-signature"))
         {
           /* Download the signature to a temporary file.  */
           FILE *_output_stream = output_stream;
@@ -2801,6 +2802,60 @@ metalink_from_http (const struct response *resp, const 
struct http_stat *hs,
               res_count++;
             }
         } /* Handle resource link (rel=duplicate).  */
+
+      /* Handle Metalink/XML resources.  */
+      else if (reltype && !strcmp (reltype, "application/metalink4+xml"))
+        {
+          metalink_metaurl_t murl = {0};
+          char *pristr;
+
+          /*
+             Valid ranges for the "pri" attribute are from
+             1 to 999999.  Mirror servers with a lower value of the "pri"
+             attribute have a higher priority, while mirrors with an undefined
+             "pri" attribute are considered to have a value of 999999, which is
+             the lowest priority.
+
+             rfc6249 section 3.1
+           */
+          murl.priority = DEFAULT_PRI;
+          if (find_key_value (url_end, val_end, "pri", &pristr))
+            {
+              long pri;
+              char *end_pristr;
+              /* Do not care for errno since 0 is error in this case.  */
+              pri = strtol (pristr, &end_pristr, 10);
+              if (end_pristr != pristr + strlen (pristr) ||
+                  !VALID_PRI_RANGE (pri))
+                {
+                  /* This is against the specification, so let's inform the 
user.  */
+                  logprintf (LOG_NOTQUIET,
+                             _("Invalid pri value. Assuming %d.\n"),
+                             DEFAULT_PRI);
+                }
+              else
+                murl.priority = pri;
+              xfree (pristr);
+            }
+
+          murl.mediatype = xstrdup (reltype);
+
+          DEBUGP (("MEDIATYPE=%s\n", murl.mediatype));
+
+          /* At this point we have validated the new resource.  */
+
+          find_key_value (url_end, val_end, "name", &murl.name);
+
+          murl.url = urlstr;
+          urlstr = NULL;
+
+          /* 1 slot from new resource, 1 slot for null-termination.  */
+          mfile->metaurls = xrealloc (mfile->metaurls,
+                                       sizeof (metalink_metaurl_t *) * 
(meta_count + 2));
+          mfile->metaurls[meta_count] = xnew0 (metalink_metaurl_t);
+          *mfile->metaurls[meta_count] = murl;
+          meta_count++;
+        } /* Handle resource link (rel=describedby).  */
       else
         DEBUGP (("This link header was not used for Metalink\n"));
 
@@ -2811,8 +2866,9 @@ metalink_from_http (const struct response *resp, const 
struct http_stat *hs,
 
   /* Null-terminate resources array.  */
   mfile->resources[res_count] = 0;
+  mfile->metaurls[meta_count] = 0;
 
-  if (res_count == 0)
+  if (res_count == 0 && meta_count == 0)
     {
       DEBUGP (("No valid metalink references found.\n"));
       goto fail;
@@ -2867,7 +2923,7 @@ metalink_from_http (const struct response *resp, const 
struct http_stat *hs,
 
     rfc6249 section 6
    */
-  if (hash_count == 0)
+  if (res_count && hash_count == 0)
     {
       logputs (LOG_VERBOSE,
                _("Could not find acceptable digest for Metalink resources.\n"
@@ -2878,6 +2934,7 @@ metalink_from_http (const struct response *resp, const 
struct http_stat *hs,
   /* Metalink data is OK. Now we just need to sort the resources based
      on their priorities, preference, and perhaps location.  */
   stable_sort (mfile->resources, res_count, sizeof (metalink_resource_t *), 
metalink_res_cmp);
+  stable_sort (mfile->metaurls, meta_count, sizeof (metalink_metaurl_t *), 
metalink_meta_cmp);
 
   /* Restore sensible preference values (in case someone cares to look).  */
   for (i = 0; i < res_count; ++i)
diff --git a/src/metalink.c b/src/metalink.c
index b7f3a72..29cfee7 100644
--- a/src/metalink.c
+++ b/src/metalink.c
@@ -913,6 +913,15 @@ int metalink_res_cmp (const void* v1, const void* v2)
   return 0;
 }
 
+int metalink_meta_cmp (const void* v1, const void* v2)
+{
+  const metalink_metaurl_t *meta1 = *(metalink_metaurl_t **) v1,
+                           *meta2 = *(metalink_metaurl_t **) v2;
+  if (meta1->priority != meta2->priority)
+    return meta1->priority - meta2->priority;
+  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
diff --git a/src/metalink.h b/src/metalink.h
index 6bd61f5..ed8c62f 100644
--- a/src/metalink.h
+++ b/src/metalink.h
@@ -46,6 +46,7 @@ as that of the covered work.  */
 uerr_t retrieve_from_metalink (const metalink_t *metalink);
 
 int metalink_res_cmp (const void *res1, const void *res2);
+int metalink_meta_cmp (const void* meta1, const void* meta2);
 
 int metalink_check_safe_path (const char *path);
 
-- 
2.7.3




reply via email to

[Prev in Thread] Current Thread [Next in Thread]