]> sjero.net Git - wget/blobdiff - src/http.c
Rename --html-extension to --adjust-extension.
[wget] / src / http.c
index 589e18eebe8ab5627a15db7971757839caa48533..d24db5fc38f3393ef6937c32e1ba03e3e6eba24b 100644 (file)
@@ -1,6 +1,6 @@
 /* HTTP support.
    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-   2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+   2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
 This file is part of GNU Wget.
 
@@ -66,6 +66,10 @@ as that of the covered work.  */
 #include "test.h"
 #endif
 
+#ifdef __VMS
+# include "vms.h"
+#endif /* def __VMS */
+
 extern char *version_string;
 
 /* Forward decls. */
@@ -142,6 +146,8 @@ struct request {
   int hcount, hcapacity;
 };
 
+extern int numurls;
+
 /* Create a new, empty request.  At least request_set_method must be
    called before the request can be used.  */
 
@@ -1339,13 +1345,27 @@ free_hstat (struct http_stat *hs)
    && (c_isspace (line[sizeof (string_constant) - 1])                      \
        || !line[sizeof (string_constant) - 1]))
 
+#ifdef __VMS
 #define SET_USER_AGENT(req) do {                                         \
   if (!opt.useragent)                                                    \
     request_set_header (req, "User-Agent",                               \
-                        aprintf ("Wget/%s", version_string), rel_value); \
+                        aprintf ("Wget/%s (VMS %s %s)",                  \
+                        version_string, vms_arch(), vms_vers()),         \
+                        rel_value);                                      \
   else if (*opt.useragent)                                               \
     request_set_header (req, "User-Agent", opt.useragent, rel_none);     \
 } while (0)
+#else /* def __VMS */
+#define SET_USER_AGENT(req) do {                                         \
+  if (!opt.useragent)                                                    \
+    request_set_header (req, "User-Agent",                               \
+                        aprintf ("Wget/%s (%s)",                         \
+                        version_string, OS_TYPE),                        \
+                        rel_value);                                      \
+  else if (*opt.useragent)                                               \
+    request_set_header (req, "User-Agent", opt.useragent, rel_none);     \
+} while (0)
+#endif /* def __VMS [else] */
 
 /* The flags that allow clobbering the file (opening with "wb").
    Defined here to avoid repetition later.  #### This will require
@@ -1496,9 +1516,10 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
   user = user ? user : (opt.http_user ? opt.http_user : opt.user);
   passwd = passwd ? passwd : (opt.http_passwd ? opt.http_passwd : opt.passwd);
 
-  if (user && passwd
-      && !u->user) /* We only do "site-wide" authentication with "global"
-                      user/password values; URL user/password info overrides. */
+  /* We only do "site-wide" authentication with "global" user/password
+   * values unless --auth-no-challange has been requested; URL user/password
+   * info overrides. */
+  if (user && passwd && (!u->user || opt.auth_without_challenge))
     {
       /* If this is a host for which we've already received a Basic
        * challenge, we'll go ahead and send Basic authentication creds. */
@@ -1741,7 +1762,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
 
       if (conn->scheme == SCHEME_HTTPS)
         {
-          if (!ssl_connect (sock) || !ssl_check_certificate (sock, u->host))
+          if (!ssl_connect_wget (sock) || !ssl_check_certificate (sock, u->host))
             {
               fd_close (sock);
               return CONSSLERR;
@@ -1813,6 +1834,101 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
       print_server_response (resp, "  ");
     }
 
+  /* Check for keep-alive related responses. */
+  if (!inhibit_keep_alive && contlen != -1)
+    {
+      if (resp_header_copy (resp, "Keep-Alive", NULL, 0))
+        keep_alive = true;
+      else if (resp_header_copy (resp, "Connection", hdrval, sizeof (hdrval)))
+        {
+          if (0 == strcasecmp (hdrval, "Keep-Alive"))
+            keep_alive = true;
+        }
+    }
+
+  if (keep_alive)
+    /* The server has promised that it will not close the connection
+       when we're done.  This means that we can register it.  */
+    register_persistent (conn->host, conn->port, sock, using_ssl);
+
+  if (statcode == HTTP_STATUS_UNAUTHORIZED)
+    {
+      /* Authorization is required.  */
+      if (keep_alive && !head_only && skip_short_body (sock, contlen))
+        CLOSE_FINISH (sock);
+      else
+        CLOSE_INVALIDATE (sock);
+      pconn.authorized = false;
+      if (!auth_finished && (user && passwd))
+        {
+          /* IIS sends multiple copies of WWW-Authenticate, one with
+             the value "negotiate", and other(s) with data.  Loop over
+             all the occurrences and pick the one we recognize.  */
+          int wapos;
+          const char *wabeg, *waend;
+          char *www_authenticate = NULL;
+          for (wapos = 0;
+               (wapos = resp_header_locate (resp, "WWW-Authenticate", wapos,
+                                            &wabeg, &waend)) != -1;
+               ++wapos)
+            if (known_authentication_scheme_p (wabeg, waend))
+              {
+                BOUNDED_TO_ALLOCA (wabeg, waend, www_authenticate);
+                break;
+              }
+
+          if (!www_authenticate)
+            {
+              /* If the authentication header is missing or
+                 unrecognized, there's no sense in retrying.  */
+              logputs (LOG_NOTQUIET, _("Unknown authentication scheme.\n"));
+            }
+          else if (!basic_auth_finished
+                   || !BEGINS_WITH (www_authenticate, "Basic"))
+            {
+              char *pth;
+              pth = url_full_path (u);
+              request_set_header (req, "Authorization",
+                                  create_authorization_line (www_authenticate,
+                                                             user, passwd,
+                                                             request_method (req),
+                                                             pth,
+                                                             &auth_finished),
+                                  rel_value);
+              if (BEGINS_WITH (www_authenticate, "NTLM"))
+                ntlm_seen = true;
+              else if (!u->user && BEGINS_WITH (www_authenticate, "Basic"))
+                {
+                  /* Need to register this host as using basic auth,
+                   * so we automatically send creds next time. */
+                  register_basic_auth_host (u->host);
+                }
+              xfree (pth);
+              xfree_null (message);
+              resp_free (resp);
+              xfree (head);
+              goto retry_with_auth;
+            }
+          else
+            {
+              /* We already did Basic auth, and it failed. Gotta
+               * give up. */
+            }
+        }
+      logputs (LOG_NOTQUIET, _("Authorization failed.\n"));
+      request_free (req);
+      xfree_null (message);
+      resp_free (resp);
+      xfree (head);
+      return AUTHFAILED;
+    }
+  else /* statcode != HTTP_STATUS_UNAUTHORIZED */
+    {
+      /* Kludge: if NTLM is used, mark the TCP connection as authorized. */
+      if (ntlm_seen)
+        pconn.authorized = true;
+    }
+
   /* Determine the local filename if needed. Notice that if -O is used 
    * hstat.local_file is set by http_loop to the argument of -O. */
   if (!hs->local_file)
@@ -1847,6 +1963,8 @@ File %s already there; not retrieving.\n\n"), quote (hs->local_file));
           if (has_html_suffix_p (hs->local_file))
             *dt |= TEXTHTML;
 
+          xfree (head);
+          xfree_null (message);
           return RETRUNNEEDED;
         }
       else if (!ALLOW_CLOBBER)
@@ -1864,7 +1982,7 @@ File %s already there; not retrieving.\n\n"), quote (hs->local_file));
   if (opt.timestamping && !hs->timestamp_checked)
     {
       size_t filename_len = strlen (hs->local_file);
-      char *filename_plus_orig_suffix = alloca (filename_len + sizeof (".orig"));
+      char *filename_plus_orig_suffix = alloca (filename_len + sizeof (ORIG_SFX));
       bool local_dot_orig_file_exists = false;
       char *local_filename = NULL;
       struct_stat st;
@@ -1889,7 +2007,7 @@ File %s already there; not retrieving.\n\n"), quote (hs->local_file));
              --hniksic */
           memcpy (filename_plus_orig_suffix, hs->local_file, filename_len);
           memcpy (filename_plus_orig_suffix + filename_len,
-                  ".orig", sizeof (".orig"));
+                  ORIG_SFX, sizeof (ORIG_SFX));
 
           /* Try to stat() the .orig file. */
           if (stat (filename_plus_orig_suffix, &st) == 0)
@@ -1945,93 +2063,6 @@ File %s already there; not retrieving.\n\n"), quote (hs->local_file));
         contlen = parsed;
     }
 
-  /* Check for keep-alive related responses. */
-  if (!inhibit_keep_alive && contlen != -1)
-    {
-      if (resp_header_copy (resp, "Keep-Alive", NULL, 0))
-        keep_alive = true;
-      else if (resp_header_copy (resp, "Connection", hdrval, sizeof (hdrval)))
-        {
-          if (0 == strcasecmp (hdrval, "Keep-Alive"))
-            keep_alive = true;
-        }
-    }
-  if (keep_alive)
-    /* The server has promised that it will not close the connection
-       when we're done.  This means that we can register it.  */
-    register_persistent (conn->host, conn->port, sock, using_ssl);
-
-  if (statcode == HTTP_STATUS_UNAUTHORIZED)
-    {
-      /* Authorization is required.  */
-      if (keep_alive && !head_only && skip_short_body (sock, contlen))
-        CLOSE_FINISH (sock);
-      else
-        CLOSE_INVALIDATE (sock);
-      pconn.authorized = false;
-      if (!auth_finished && (user && passwd))
-        {
-          /* IIS sends multiple copies of WWW-Authenticate, one with
-             the value "negotiate", and other(s) with data.  Loop over
-             all the occurrences and pick the one we recognize.  */
-          int wapos;
-          const char *wabeg, *waend;
-          char *www_authenticate = NULL;
-          for (wapos = 0;
-               (wapos = resp_header_locate (resp, "WWW-Authenticate", wapos,
-                                            &wabeg, &waend)) != -1;
-               ++wapos)
-            if (known_authentication_scheme_p (wabeg, waend))
-              {
-                BOUNDED_TO_ALLOCA (wabeg, waend, www_authenticate);
-                break;
-              }
-
-          if (!www_authenticate)
-            {
-              /* If the authentication header is missing or
-                 unrecognized, there's no sense in retrying.  */
-              logputs (LOG_NOTQUIET, _("Unknown authentication scheme.\n"));
-            }
-          else if (!basic_auth_finished
-                   || !BEGINS_WITH (www_authenticate, "Basic"))
-            {
-              char *pth;
-              pth = url_full_path (u);
-              request_set_header (req, "Authorization",
-                                  create_authorization_line (www_authenticate,
-                                                             user, passwd,
-                                                             request_method (req),
-                                                             pth,
-                                                             &auth_finished),
-                                  rel_value);
-              if (BEGINS_WITH (www_authenticate, "NTLM"))
-                ntlm_seen = true;
-              else if (!u->user && BEGINS_WITH (www_authenticate, "Basic"))
-                {
-                  /* Need to register this host as using basic auth,
-                   * so we automatically send creds next time. */
-                  register_basic_auth_host (u->host);
-                }
-              xfree (pth);
-              goto retry_with_auth;
-            }
-          else
-            {
-              /* We already did Basic auth, and it failed. Gotta
-               * give up. */
-            }
-        }
-      logputs (LOG_NOTQUIET, _("Authorization failed.\n"));
-      request_free (req);
-      return AUTHFAILED;
-    }
-  else /* statcode != HTTP_STATUS_UNAUTHORIZED */
-    {
-      /* Kludge: if NTLM is used, mark the TCP connection as authorized. */
-      if (ntlm_seen)
-        pconn.authorized = true;
-    }
   request_free (req);
 
   hs->statcode = statcode;
@@ -2123,6 +2154,7 @@ File %s already there; not retrieving.\n\n"), quote (hs->local_file));
           else
             CLOSE_INVALIDATE (sock);
           xfree_null (type);
+          xfree (head);
           return NEWLOCATION;
         }
     }
@@ -2143,10 +2175,10 @@ File %s already there; not retrieving.\n\n"), quote (hs->local_file));
   else
     *dt &= ~TEXTCSS;
 
-  if (opt.html_extension)
+  if (opt.adjust_extension)
     {
       if (*dt & TEXTHTML)
-        /* -E / --html-extension / html_extension = on was specified,
+        /* -E / --adjust-extension / adjust_extension = on was specified,
            and this is a text/html file.  If some case-insensitive
            variation on ".htm[l]" isn't already the file's suffix,
            tack on ".html". */
@@ -2159,11 +2191,15 @@ File %s already there; not retrieving.\n\n"), quote (hs->local_file));
         }
     }
 
-  if (statcode == HTTP_STATUS_RANGE_NOT_SATISFIABLE)
+  if (statcode == HTTP_STATUS_RANGE_NOT_SATISFIABLE
+      || (hs->restval > 0 && statcode == HTTP_STATUS_OK
+          && contrange == 0 && hs->restval >= contlen)
+     )
     {
       /* If `-c' is in use and the file has been fully downloaded (or
          the remote file has shrunk), Wget effectively requests bytes
-         after the end of file and the server response with 416.  */
+         after the end of file and the server response with 416
+         (or 200 with a <= Content-Length.  */
       logputs (LOG_VERBOSE, _("\
 \n    The file is already fully retrieved; nothing to do.\n\n"));
       /* In case the caller inspects. */
@@ -2174,6 +2210,7 @@ File %s already there; not retrieving.\n\n"), quote (hs->local_file));
       xfree_null (type);
       CLOSE_INVALIDATE (sock);        /* would be CLOSE_FINISH, but there
                                    might be more bytes in the body. */
+      xfree (head);
       return RETRUNNEEDED;
     }
   if ((contrange != 0 && contrange != hs->restval)
@@ -2183,6 +2220,7 @@ File %s already there; not retrieving.\n\n"), quote (hs->local_file));
          Bail out.  */
       xfree_null (type);
       CLOSE_INVALIDATE (sock);
+      xfree (head);
       return RANGEERR;
     }
   if (contlen == -1)
@@ -2246,9 +2284,20 @@ File %s already there; not retrieving.\n\n"), quote (hs->local_file));
         CLOSE_FINISH (sock);
       else
         CLOSE_INVALIDATE (sock);
+      xfree (head);
       return RETRFINISHED;
     }
 
+/* 2005-06-17 SMS.
+   For VMS, define common fopen() optional arguments.
+*/
+#ifdef __VMS
+# define FOPEN_OPT_ARGS "fop=sqo", "acc", acc_cb, &open_id
+# define FOPEN_BIN_FLAG 3
+#else /* def __VMS */
+# define FOPEN_BIN_FLAG 1
+#endif /* def __VMS [else] */
+
   /* Open the local file.  */
   if (!output_stream)
     {
@@ -2256,9 +2305,27 @@ File %s already there; not retrieving.\n\n"), quote (hs->local_file));
       if (opt.backups)
         rotate_backups (hs->local_file);
       if (hs->restval)
-        fp = fopen (hs->local_file, "ab");
+        {
+#ifdef __VMS
+          int open_id;
+
+          open_id = 21;
+          fp = fopen (hs->local_file, "ab", FOPEN_OPT_ARGS);
+#else /* def __VMS */
+          fp = fopen (hs->local_file, "ab");
+#endif /* def __VMS [else] */
+        }
       else if (ALLOW_CLOBBER)
-        fp = fopen (hs->local_file, "wb");
+        {
+#ifdef __VMS
+          int open_id;
+
+          open_id = 22;
+          fp = fopen (hs->local_file, "wb", FOPEN_OPT_ARGS);
+#else /* def __VMS */
+          fp = fopen (hs->local_file, "wb");
+#endif /* def __VMS [else] */
+        }
       else
         {
           fp = fopen_excl (hs->local_file, true);
@@ -2272,6 +2339,7 @@ File %s already there; not retrieving.\n\n"), quote (hs->local_file));
                          _("%s has sprung into existence.\n"),
                          hs->local_file);
               CLOSE_INVALIDATE (sock);
+              xfree (head);
               return FOPEN_EXCL_ERR;
             }
         }
@@ -2279,6 +2347,7 @@ File %s already there; not retrieving.\n\n"), quote (hs->local_file));
         {
           logprintf (LOG_NOTQUIET, "%s: %s\n", hs->local_file, strerror (errno));
           CLOSE_INVALIDATE (sock);
+          xfree (head);
           return FOPENERR;
         }
     }
@@ -2350,6 +2419,7 @@ http_loop (struct url *u, char **newloc, char **local_file, const char *referer,
   struct http_stat hstat;        /* HTTP status */
   struct_stat st;
   bool send_head_first = true;
+  char *file_name;
 
   /* Assert that no value for *LOCAL_FILE was passed. */
   assert (local_file == NULL || *local_file == NULL);
@@ -2422,11 +2492,13 @@ File %s already there; not retrieving.\n\n"),
 
   /* Send preliminary HEAD request if -N is given and we have an existing 
    * destination file. */
+  file_name = url_file_name (u);
   if (opt.timestamping
       && !opt.content_disposition
-      && file_exists_p (url_file_name (u)))
+      && file_exists_p (file_name))
     send_head_first = true;
-
+  xfree (file_name);
+  
   /* THE loop */
   do
     {
@@ -2710,7 +2782,7 @@ Remote file exists.\n\n"));
                   if (finished)
                     {
                       logprintf (LOG_NONVERBOSE, 
-                                 _("%s URL:%s %2d %s\n"), 
+                                 _("%s URL: %s %2d %s\n"), 
                                  tms, u->url, hstat.statcode,
                                  hstat.message ? quotearg_style (escape_quoting_style, hstat.message) : "");
                       goto exit;
@@ -2728,16 +2800,8 @@ Remote file exists.\n\n"));
           && ((hstat.len == hstat.contlen) ||
               ((hstat.res == 0) && (hstat.contlen == -1))))
         {
-          /* #### This code repeats in http.c and ftp.c.  Move it to a
-             function!  */
           const char *fl = NULL;
-          if (opt.output_document)
-            {
-              if (output_stream_regular)
-                fl = opt.output_document;
-            }
-          else
-            fl = hstat.local_file;
+          set_local_file (&fl, hstat.local_file);
           if (fl)
             {
               time_t newtmr = -1;
@@ -2746,7 +2810,7 @@ Remote file exists.\n\n"));
                   && hstat.remote_time && hstat.remote_time[0])
                 {
                   newtmr = http_atotm (hstat.remote_time);
-                  if (newtmr != -1)
+                  if (newtmr != (time_t)-1)
                     tmr = newtmr;
                 }
               touch (fl, tmr);
@@ -2761,9 +2825,14 @@ Remote file exists.\n\n"));
         {
           if (*dt & RETROKF)
             {
+              bool write_to_stdout = (opt.output_document && HYPHENP (opt.output_document));
+
               logprintf (LOG_VERBOSE,
-                         _("%s (%s) - %s saved [%s/%s]\n\n"),
-                         tms, tmrate, quote (hstat.local_file),
+                         write_to_stdout 
+                         ? _("%s (%s) - written to stdout %s[%s/%s]\n\n")
+                         : _("%s (%s) - %s saved [%s/%s]\n\n"),
+                         tms, tmrate,
+                         write_to_stdout ? "" : quote (hstat.local_file),
                          number_to_static_string (hstat.len),
                          number_to_static_string (hstat.contlen));
               logprintf (LOG_NONVERBOSE,
@@ -2773,7 +2842,7 @@ Remote file exists.\n\n"));
                          number_to_static_string (hstat.contlen),
                          hstat.local_file, count);
             }
-          ++opt.numurls;
+          ++numurls;
           total_downloaded_bytes += hstat.len;
 
           /* Remember that we downloaded the file for later ".orig" code. */
@@ -2792,16 +2861,21 @@ Remote file exists.\n\n"));
             {
               if (*dt & RETROKF)
                 {
+                  bool write_to_stdout = (opt.output_document && HYPHENP (opt.output_document));
+
                   logprintf (LOG_VERBOSE,
-                             _("%s (%s) - %s saved [%s]\n\n"),
-                             tms, tmrate, quote (hstat.local_file),
+                             write_to_stdout
+                             ? _("%s (%s) - written to stdout %s[%s]\n\n")
+                             : _("%s (%s) - %s saved [%s]\n\n"),
+                             tms, tmrate, 
+                             write_to_stdout ? "" : quote (hstat.local_file),
                              number_to_static_string (hstat.len));
                   logprintf (LOG_NONVERBOSE,
                              "%s URL:%s [%s] -> \"%s\" [%d]\n",
                              tms, u->url, number_to_static_string (hstat.len),
                              hstat.local_file, count);
                 }
-              ++opt.numurls;
+              ++numurls;
               total_downloaded_bytes += hstat.len;
 
               /* Remember that we downloaded the file for later ".orig" code. */
@@ -2938,6 +3012,7 @@ http_atotm (const char *time_string)
                                    Netscape cookie specification.) */
   };
   const char *oldlocale;
+  char savedlocale[256];
   size_t i;
   time_t ret = (time_t) -1;
 
@@ -2945,6 +3020,16 @@ http_atotm (const char *time_string)
      non-English locales, which we work around by temporarily setting
      locale to C before invoking strptime.  */
   oldlocale = setlocale (LC_TIME, NULL);
+  if (oldlocale)
+    {
+      size_t l = strlen (oldlocale);
+      if (l >= sizeof savedlocale)
+        savedlocale[0] = '\0';
+      else
+        memcpy (savedlocale, oldlocale, l);
+    }
+  else savedlocale[0] = '\0';
+
   setlocale (LC_TIME, "C");
 
   for (i = 0; i < countof (time_formats); i++)
@@ -2964,7 +3049,8 @@ http_atotm (const char *time_string)
     }
 
   /* Restore the previous locale. */
-  setlocale (LC_TIME, oldlocale);
+  if (savedlocale[0])
+    setlocale (LC_TIME, savedlocale);
 
   return ret;
 }