]> sjero.net Git - wget/blobdiff - src/http.c
[svn] Renamed DEBUG to ENABLE_DEBUG.
[wget] / src / http.c
index e37e14703250db66a04c65d09a47173f5f22dcaf..20010de013199f43069ab120af1412df5e69fbd0 100644 (file)
@@ -16,7 +16,17 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with Wget; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+In addition, as a special exception, the Free Software Foundation
+gives permission to link the code of its release of Wget with the
+OpenSSL project's "OpenSSL" library (or with modified versions of it
+that use the same license as the "OpenSSL" library), and distribute
+the linked executables.  You must obey the GNU General Public License
+in all respects for all of the code used other than "OpenSSL".  If you
+modify this file, you may extend this exception to your version of the
+file, but you are not obligated to do so.  If you do not wish to do
+so, delete this exception statement from your version.  */
 
 #include <config.h>
 
@@ -52,7 +62,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "retr.h"
 #include "headers.h"
 #include "connect.h"
-#include "fnmatch.h"
 #include "netrc.h"
 #ifdef HAVE_SSL
 # include "gen_sslfunc.h"
@@ -61,6 +70,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #ifdef USE_DIGEST
 # include "gen-md5.h"
 #endif
+#include "convert.h"
 
 extern char *version_string;
 
@@ -69,8 +79,10 @@ extern int errno;
 #endif
 \f
 static int cookies_loaded_p;
+struct cookie_jar *wget_cookie_jar;
 
 #define TEXTHTML_S "text/html"
+#define TEXTXHTML_S "application/xhtml+xml"
 #define HTTP_ACCEPT "*/*"
 
 /* Some status code validation macros: */
@@ -174,14 +186,13 @@ parse_http_status_line (const char *line, const char **reason_phrase_ptr)
 
 /* Send the contents of FILE_NAME to SOCK/SSL.  Make sure that exactly
    PROMISED_SIZE bytes are sent over the wire -- if the file is
-   longer, read only that much; if the file is shorter, pad it with
-   zeros.  */
+   longer, read only that much; if the file is shorter, report an error.  */
 
 static int
 post_file (int sock, void *ssl, const char *file_name, long promised_size)
 {
   static char chunk[8192];
-  int written = 0;
+  long written = 0;
   int write_error;
   FILE *fp;
 
@@ -193,10 +204,10 @@ post_file (int sock, void *ssl, const char *file_name, long promised_size)
 
   fp = fopen (file_name, "rb");
   if (!fp)
-    goto pad;
-  while (written < promised_size)
+    return -1;
+  while (!feof (fp) && written < promised_size)
     {
-      long towrite;
+      int towrite;
       int length = fread (chunk, 1, sizeof (chunk), fp);
       if (length == 0)
        break;
@@ -215,29 +226,15 @@ post_file (int sock, void *ssl, const char *file_name, long promised_size)
       written += towrite;
     }
   fclose (fp);
- pad:
+
+  /* If we've written less than was promised, report a (probably
+     nonsensical) error rather than break the promise.  */
   if (written < promised_size)
     {
-      DEBUGP (("padding ... "));
-      /* This highly unlikely case can happen only if the file has
-        shrunk while we weren't looking.  To uphold the promise, pad
-        the remaining data with zeros.  #### Should we abort
-        instead?  */
-      memset (chunk, '\0', sizeof (chunk));
-      while (written < promised_size)
-       {
-         long towrite = WMIN (promised_size - written, sizeof (chunk));
-#ifdef HAVE_SSL
-         if (ssl)
-           write_error = ssl_iwrite (ssl, chunk, towrite);
-         else
-#endif
-           write_error = iwrite (sock, chunk, towrite);
-         if (write_error < 0)
-           return -1;
-         written += towrite;
-       }
+      errno = EINVAL;
+      return -1;
     }
+
   assert (written == promised_size);
   DEBUGP (("done]\n"));
   return 0;
@@ -333,6 +330,22 @@ http_process_connection (const char *hdr, void *arg)
     *flag = 1;
   return 1;
 }
+
+/* Commit the cookie to the cookie jar. */
+
+int
+http_process_set_cookie (const char *hdr, void *arg)
+{
+  struct url *u = (struct url *)arg;
+
+  /* The jar should have been created by now. */
+  assert (wget_cookie_jar != NULL);
+
+  cookie_jar_process_set_cookie (wget_cookie_jar, u->host, u->port, u->path,
+                                hdr);
+  return 1;
+}
+
 \f
 /* Persistent connections.  Currently, we cache the most recently used
    connection as persistent, provided that the HTTP server agrees to
@@ -556,7 +569,7 @@ struct http_stat
   char *remote_time;           /* remote time-stamp string */
   char *error;                 /* textual HTTP error */
   int statcode;                        /* status code */
-  long dltime;                 /* time of the download */
+  double dltime;               /* time of the download in msecs */
   int no_truncate;             /* whether truncating the file is
                                   forbidden. */
   const char *referer;         /* value of the referer header. */
@@ -583,7 +596,7 @@ static char *basic_authentication_encode PARAMS ((const char *, const char *,
                                                  const char *));
 static int known_authentication_scheme_p PARAMS ((const char *));
 
-time_t http_atotm PARAMS ((char *));
+time_t http_atotm PARAMS ((const char *));
 
 #define BEGINS_WITH(line, string_constant)                             \
   (!strncasecmp (line, string_constant, sizeof (string_constant) - 1)  \
@@ -644,7 +657,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
 
   /* Headers sent when using POST. */
   char *post_content_type, *post_content_length;
-  long post_data_size;
+  long post_data_size = 0;
 
 #ifdef HAVE_SSL
   /* initialize ssl_ctx on first run */
@@ -737,7 +750,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
       address_list_release (al);
 
       if (sock < 0)
-       return errno == ECONNREFUSED ? CONREFUSED : CONERROR;
+       return CONNECT_ERROR (errno);
 
 #ifdef HAVE_SSL
      if (conn->scheme == SCHEME_HTTPS)
@@ -890,13 +903,14 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
     request_keep_alive = NULL;
 
   if (opt.cookies)
-    cookies = build_cookies_request (u->host, u->port, u->path,
+    cookies = cookie_jar_generate_cookie_header (wget_cookie_jar, u->host,
+                                                u->port, u->path,
 #ifdef HAVE_SSL
-                                    u->scheme == SCHEME_HTTPS
+                                                u->scheme == SCHEME_HTTPS
 #else
-                                    0
+                                                0
 #endif
-                                    );
+                                );
 
   if (opt.post_data || opt.post_file_name)
     {
@@ -1000,7 +1014,7 @@ Accept: %s\r\n\
 #endif
            write_error = iwrite (sock, opt.post_data, post_data_size);
        }
-      else if (opt.post_file_name)
+      else if (opt.post_file_name && post_data_size != 0)
        {
 #ifdef HAVE_SSL
          if (conn->scheme == SCHEME_HTTPS)
@@ -1122,7 +1136,7 @@ Accept: %s\r\n\
            hs->error = xstrdup (error);
 
          if ((statcode != -1)
-#ifdef DEBUG
+#ifdef ENABLE_DEBUG
              && !opt.debug
 #endif
              )
@@ -1167,7 +1181,7 @@ Accept: %s\r\n\
          goto done_header;
       /* Try getting cookies. */
       if (opt.cookies)
-       if (header_process (hdr, "Set-Cookie", set_cookie_header_cb, u))
+       if (header_process (hdr, "Set-Cookie", http_process_set_cookie, u))
          goto done_header;
       /* Try getting www-authentication.  */
       if (!authenticate_h)
@@ -1307,10 +1321,14 @@ Accept: %s\r\n\
        }
     }
 
-  if (type && !strncasecmp (type, TEXTHTML_S, strlen (TEXTHTML_S)))
+  /* If content-type is not given, assume text/html.  This is because
+     of the multitude of broken CGI's that "forget" to generate the
+     content-type.  */
+  if (!type ||
+        0 == strncasecmp (type, TEXTHTML_S, strlen (TEXTHTML_S)) ||
+        0 == strncasecmp (type, TEXTXHTML_S, strlen (TEXTXHTML_S)))
     *dt |= TEXTHTML;
   else
-    /* We don't assume text/html by default.  */
     *dt &= ~TEXTHTML;
 
   if (opt.html_extension && (*dt & TEXTHTML))
@@ -1487,8 +1505,12 @@ Refusing to truncate existing file `%s'.\n\n"), *hs->local_file);
 
          #### A possible solution to this would be to remember the
         file position in the output document and to seek to that
-        position, instead of rewinding.  */
-      if (!hs->restval && global_download_count == 0)
+        position, instead of rewinding.
+
+         We don't truncate stdout, since that breaks
+        "wget -O - [...] >> foo".
+      */
+      if (!hs->restval && global_download_count == 0 && opt.dfp != stdout)
        {
          /* This will silently fail for streams that don't correspond
             to regular files, but that's OK.  */
@@ -1555,10 +1577,15 @@ http_loop (struct url *u, char **newloc, char **local_file, const char *referer,
   /* This used to be done in main(), but it's a better idea to do it
      here so that we don't go through the hoops if we're just using
      FTP or whatever. */
-  if (opt.cookies && opt.cookies_input && !cookies_loaded_p)
+  if (opt.cookies)
     {
-      load_cookies (opt.cookies_input);
-      cookies_loaded_p = 1;
+      if (!wget_cookie_jar)
+       wget_cookie_jar = cookie_jar_new ();
+      if (opt.cookies_input && !cookies_loaded_p)
+       {
+         cookie_jar_load (wget_cookie_jar, opt.cookies_input);
+         cookies_loaded_p = 1;
+       }
     }
 
   *newloc = NULL;
@@ -1574,12 +1601,12 @@ http_loop (struct url *u, char **newloc, char **local_file, const char *referer,
     hstat.local_file = local_file;
   else if (local_file)
     {
-      *local_file = url_filename (u);
+      *local_file = url_file_name (u);
       hstat.local_file = local_file;
     }
   else
     {
-      dummy = url_filename (u);
+      dummy = url_file_name (u);
       hstat.local_file = &dummy;
     }
 
@@ -2152,7 +2179,7 @@ check_end (const char *p)
    it is not assigned to the FSF.  So I stuck it with strptime.  */
 
 time_t
-http_atotm (char *time_string)
+http_atotm (const char *time_string)
 {
   /* NOTE: Solaris strptime man page claims that %n and %t match white
      space, but that's not universally available.  Instead, we simply
@@ -2187,7 +2214,7 @@ http_atotm (char *time_string)
      GNU strptime does not have this problem because it recognizes
      both international and local dates.  */
 
-  for (i = 0; i < ARRAY_SIZE (time_formats); i++)
+  for (i = 0; i < countof (time_formats); i++)
     if (check_end (strptime (time_string, time_formats[i], &t)))
       return mktime_from_utc (&t);
 
@@ -2317,8 +2344,8 @@ dump_hash (unsigned char *buf, const unsigned char *hash)
 
   for (i = 0; i < MD5_HASHLEN; i++, hash++)
     {
-      *buf++ = XDIGIT_TO_xchar (*hash >> 4);
-      *buf++ = XDIGIT_TO_xchar (*hash & 0xf);
+      *buf++ = XNUM_TO_digit (*hash >> 4);
+      *buf++ = XNUM_TO_digit (*hash & 0xf);
     }
   *buf = '\0';
 }
@@ -2349,7 +2376,7 @@ digest_authentication_encode (const char *au, const char *user,
       int i;
 
       au += skip_lws (au);
-      for (i = 0; i < ARRAY_SIZE (options); i++)
+      for (i = 0; i < countof (options); i++)
        {
          int skip = extract_header_attr (au, options[i].name,
                                          options[i].variable);
@@ -2366,7 +2393,7 @@ digest_authentication_encode (const char *au, const char *user,
              break;
            }
        }
-      if (i == ARRAY_SIZE (options))
+      if (i == countof (options))
        {
          while (*au && *au != '=')
            au++;