]> sjero.net Git - wget/blobdiff - src/http.c
warc: fix format string for off_t in CDX function.
[wget] / src / http.c
index 61001f3b0c6142eb40d2eb07ac36946ed72f984e..588847486a5ea93dfe8adafed682663bbd59265f 100644 (file)
@@ -1,6 +1,6 @@
 /* HTTP support.
    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-   2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
+   2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation,
    Inc.
 
 This file is part of GNU Wget.
@@ -231,7 +231,7 @@ release_header (struct request_header *hdr)
    */
 
 static void
-request_set_header (struct request *req, char *name, char *value,
+request_set_header (struct request *req, const char *name, const char *value,
                     enum rp release_policy)
 {
   struct request_header *hdr;
@@ -242,7 +242,7 @@ request_set_header (struct request *req, char *name, char *value,
       /* A NULL value is a no-op; if freeing the name is requested,
          free it now to avoid leaks.  */
       if (release_policy == rel_name || release_policy == rel_both)
-        xfree (name);
+        xfree ((void *)name);
       return;
     }
 
@@ -253,8 +253,8 @@ request_set_header (struct request *req, char *name, char *value,
         {
           /* Replace existing header. */
           release_header (hdr);
-          hdr->name = name;
-          hdr->value = value;
+          hdr->name = (void *)name;
+          hdr->value = (void *)value;
           hdr->release_policy = release_policy;
           return;
         }
@@ -268,8 +268,8 @@ request_set_header (struct request *req, char *name, char *value,
       req->headers = xrealloc (req->headers, req->hcapacity * sizeof (*hdr));
     }
   hdr = &req->headers[req->hcount++];
-  hdr->name = name;
-  hdr->value = value;
+  hdr->name = (void *)name;
+  hdr->value = (void *)value;
   hdr->release_policy = release_policy;
 }
 
@@ -296,7 +296,7 @@ request_set_user_header (struct request *req, const char *header)
    the header was actually removed, false otherwise.  */
 
 static bool
-request_remove_header (struct request *req, char *name)
+request_remove_header (struct request *req, const char *name)
 {
   int i;
   for (i = 0; i < req->hcount; i++)
@@ -1962,11 +1962,13 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
           int family = socket_family (pconn.socket, ENDPOINT_PEER);
           sock = pconn.socket;
           using_ssl = pconn.ssl;
+#if ENABLE_IPV6
           if (family == AF_INET6)
              logprintf (LOG_VERBOSE, _("Reusing existing connection to [%s]:%d.\n"),
                         quotearg_style (escape_quoting_style, pconn.host),
                          pconn.port);
           else
+#endif
              logprintf (LOG_VERBOSE, _("Reusing existing connection to %s:%d.\n"),
                         quotearg_style (escape_quoting_style, pconn.host),
                         pconn.port);
@@ -2030,6 +2032,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
           if (write_error < 0)
             {
               CLOSE_INVALIDATE (sock);
+              request_free (req);
               return WRITEFAILED;
             }
 
@@ -2039,6 +2042,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
               logprintf (LOG_VERBOSE, _("Failed reading proxy response: %s\n"),
                          fd_errstr (sock));
               CLOSE_INVALIDATE (sock);
+              request_free (req);
               return HERR;
             }
           message = NULL;
@@ -2059,6 +2063,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
                          quotearg_style (escape_quoting_style,
                                          _("Malformed status line")));
               xfree (head);
+              request_free (req);
               return HERR;
             }
           hs->message = xstrdup (message);
@@ -2070,6 +2075,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
               logprintf (LOG_NOTQUIET, _("Proxy tunneling failed: %s"),
                          message ? quotearg_style (escape_quoting_style, message) : "?");
               xfree_null (message);
+              request_free (req);
               return CONSSLERR;
             }
           xfree_null (message);
@@ -2082,14 +2088,16 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
 
       if (conn->scheme == SCHEME_HTTPS)
         {
-          if (!ssl_connect_wget (sock))
+          if (!ssl_connect_wget (sock, u->host))
             {
               fd_close (sock);
+              request_free (req);
               return CONSSLERR;
             }
           else if (!ssl_check_certificate (sock, u->host))
             {
               fd_close (sock);
+              request_free (req);
               return VERIFCERTERR;
             }
           using_ssl = true;
@@ -2222,6 +2230,7 @@ read_header:
                  quotearg_style (escape_quoting_style,
                                  _("Malformed status line")));
       CLOSE_INVALIDATE (sock);
+      resp_free (resp);
       request_free (req);
       xfree (head);
       return HERR;
@@ -2230,6 +2239,7 @@ read_header:
   if (H_10X (statcode))
     {
       DEBUGP (("Ignoring response\n"));
+      resp_free (resp);
       xfree (head);
       goto read_header;
     }
@@ -2450,6 +2460,8 @@ read_header:
              retrieve the file. But if the output_document was given, then this
              test was already done and the file didn't exist. Hence the !opt.output_document */
           get_file_flags (hs->local_file, dt);
+          request_free (req);
+          resp_free (resp);
           xfree (head);
           xfree_null (message);
           return RETRUNNEEDED;
@@ -2992,6 +3004,11 @@ http_loop (struct url *u, struct url *original_url, char **newloc,
   if (!opt.spider)
     send_head_first = false;
 
+  /* Send preliminary HEAD request if --content-disposition and -c are used
+     together.  */
+  if (opt.content_disposition && opt.always_rest)
+    send_head_first = true;
+
   /* Send preliminary HEAD request if -N is given and we have an existing
    * destination file. */
   file_name = url_file_name (opt.trustservernames ? u : original_url, NULL);
@@ -3108,7 +3125,7 @@ Spider mode enabled. Check if remote file exists.\n"));
         case WARC_ERR:
           /* A fatal WARC error. */
           logputs (LOG_VERBOSE, "\n");
-          logprintf (LOG_NOTQUIET, _("Cannot write to WARC file..\n"));
+          logprintf (LOG_NOTQUIET, _("Cannot write to WARC file.\n"));
           ret = err;
           goto exit;
         case WARC_TMP_FOPENERR: case WARC_TMP_FWRITEERR:
@@ -3645,19 +3662,23 @@ digest_authentication_encode (const char *au, const char *user,
                               const char *passwd, const char *method,
                               const char *path)
 {
-  static char *realm, *opaque, *nonce;
+  static char *realm, *opaque, *nonce, *qop;
   static struct {
     const char *name;
     char **variable;
   } options[] = {
     { "realm", &realm },
     { "opaque", &opaque },
-    { "nonce", &nonce }
+    { "nonce", &nonce },
+    { "qop", &qop }
   };
+  char cnonce[16] = "";
   char *res;
+  size_t res_size;
   param_token name, value;
 
-  realm = opaque = nonce = NULL;
+
+  realm = opaque = nonce = qop = NULL;
 
   au += 6;                      /* skip over `Digest' */
   while (extract_param (&au, &name, &value, ','))
@@ -3673,11 +3694,19 @@ digest_authentication_encode (const char *au, const char *user,
             break;
           }
     }
+
+  if (qop != NULL && strcmp(qop,"auth"))
+    {
+      logprintf (LOG_NOTQUIET, _("Unsupported quality of protection '%s'.\n"), qop);
+      user = NULL; /* force freeing mem and return */
+    }
+
   if (!realm || !nonce || !user || !passwd || !path || !method)
     {
       xfree_null (realm);
       xfree_null (opaque);
       xfree_null (nonce);
+      xfree_null (qop);
       return NULL;
     }
 
@@ -3706,27 +3735,69 @@ digest_authentication_encode (const char *au, const char *user,
     md5_finish_ctx (&ctx, hash);
     dump_hash (a2buf, hash);
 
-    /* RESPONSE_DIGEST = H(A1BUF ":" nonce ":" A2BUF) */
-    md5_init_ctx (&ctx);
-    md5_process_bytes ((unsigned char *)a1buf, MD5_DIGEST_SIZE * 2, &ctx);
-    md5_process_bytes ((unsigned char *)":", 1, &ctx);
-    md5_process_bytes ((unsigned char *)nonce, strlen (nonce), &ctx);
-    md5_process_bytes ((unsigned char *)":", 1, &ctx);
-    md5_process_bytes ((unsigned char *)a2buf, MD5_DIGEST_SIZE * 2, &ctx);
-    md5_finish_ctx (&ctx, hash);
+    if (!strcmp(qop,"auth"))
+      {
+        /* RFC 2617 Digest Access Authentication */
+        /* generate random hex string */
+        snprintf(cnonce, sizeof(cnonce), "%08x", random_number(INT_MAX));
+
+        /* RESPONSE_DIGEST = H(A1BUF ":" nonce ":" noncecount ":" clientnonce ":" qop ": " A2BUF) */
+        md5_init_ctx (&ctx);
+        md5_process_bytes ((unsigned char *)a1buf, MD5_DIGEST_SIZE * 2, &ctx);
+        md5_process_bytes ((unsigned char *)":", 1, &ctx);
+        md5_process_bytes ((unsigned char *)nonce, strlen (nonce), &ctx);
+        md5_process_bytes ((unsigned char *)":", 1, &ctx);
+        md5_process_bytes ((unsigned char *)"00000001", 8, &ctx); /* TODO: keep track of server nonce values */
+        md5_process_bytes ((unsigned char *)":", 1, &ctx);
+        md5_process_bytes ((unsigned char *)cnonce, strlen(cnonce), &ctx);
+        md5_process_bytes ((unsigned char *)":", 1, &ctx);
+        md5_process_bytes ((unsigned char *)qop, strlen(qop), &ctx);
+        md5_process_bytes ((unsigned char *)":", 1, &ctx);
+        md5_process_bytes ((unsigned char *)a2buf, MD5_DIGEST_SIZE * 2, &ctx);
+        md5_finish_ctx (&ctx, hash);
+      }
+    else
+      {
+        /* RFC 2069 Digest Access Authentication */
+        /* RESPONSE_DIGEST = H(A1BUF ":" nonce ":" A2BUF) */
+        md5_init_ctx (&ctx);
+        md5_process_bytes ((unsigned char *)a1buf, MD5_DIGEST_SIZE * 2, &ctx);
+        md5_process_bytes ((unsigned char *)":", 1, &ctx);
+        md5_process_bytes ((unsigned char *)nonce, strlen (nonce), &ctx);
+        md5_process_bytes ((unsigned char *)":", 1, &ctx);
+        md5_process_bytes ((unsigned char *)a2buf, MD5_DIGEST_SIZE * 2, &ctx);
+        md5_finish_ctx (&ctx, hash);
+      }
+
     dump_hash (response_digest, hash);
 
-    res = xmalloc (strlen (user)
-                   + strlen (user)
-                   + strlen (realm)
-                   + strlen (nonce)
-                   + strlen (path)
-                   + 2 * MD5_DIGEST_SIZE /*strlen (response_digest)*/
-                   + (opaque ? strlen (opaque) : 0)
-                   + 128);
-    sprintf (res, "Digest \
-username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"",
-             user, realm, nonce, path, response_digest);
+    res_size = strlen (user)
+             + strlen (user)
+             + strlen (realm)
+             + strlen (nonce)
+             + strlen (path)
+             + 2 * MD5_DIGEST_SIZE /*strlen (response_digest)*/
+             + (opaque ? strlen (opaque) : 0)
+             + (qop ? 128: 0)
+             + 128;
+
+    res = xmalloc (res_size);
+
+    if (!strcmp(qop,"auth"))
+      {
+        snprintf (res, res_size, "Digest "\
+                "username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\""\
+                ", qop=auth, nc=00000001, cnonce=\"%s\"",
+                  user, realm, nonce, path, response_digest, cnonce);
+
+      }
+    else
+      {
+        snprintf (res, res_size, "Digest "\
+                "username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"",
+                  user, realm, nonce, path, response_digest);
+      }
+
     if (opaque)
       {
         char *p = res + strlen (res);