]> sjero.net Git - wget/blobdiff - src/http.c
[svn] Change orders of parameters of base64_encode, so it makes more sense.
[wget] / src / http.c
index c509b4aea1fcace5e612339dc917d6f870ddf993..19ba3a8314cdd3c45c391abefd82834e9c6a17ce 100644 (file)
@@ -234,7 +234,13 @@ request_set_header (struct request *req, char *name, char *value,
   struct request_header *hdr;
   int i;
   if (!value)
-    return;
+    {
+      /* 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);
+      return;
+    }
   for (i = 0; i < req->hcount; i++)
     {
       hdr = &req->headers[i];
@@ -358,7 +364,7 @@ request_free (struct request *req)
   xfree (req);
 }
 
-/* Send the contents of FILE_NAME to SOCK/SSL.  Make sure that exactly
+/* Send the contents of FILE_NAME to SOCK.  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, report an error.  */
 
@@ -711,22 +717,8 @@ resp_free (struct response *resp)
   xfree (resp);
 }
 
-/* Print [b, e) to the log, omitting the trailing CRLF.  */
-
-static void
-print_server_response_1 (const char *prefix, const char *b, const char *e)
-{
-  char *ln;
-  if (b < e && e[-1] == '\n')
-    --e;
-  if (b < e && e[-1] == '\r')
-    --e;
-  BOUNDED_TO_ALLOCA (b, e, ln);
-  logprintf (LOG_VERBOSE, "%s%s\n", prefix, escnonprint (ln));
-}
-
-/* Print the server response, line by line, omitting the trailing CR
-   characters, prefixed with PREFIX.  */
+/* Print the server response, line by line, omitting the trailing CRLF
+   from individual header lines, and prefixed with PREFIX.  */
 
 static void
 print_server_response (const struct response *resp, const char *prefix)
@@ -735,7 +727,18 @@ print_server_response (const struct response *resp, const char *prefix)
   if (!resp->headers)
     return;
   for (i = 0; resp->headers[i + 1]; i++)
-    print_server_response_1 (prefix, resp->headers[i], resp->headers[i + 1]);
+    {
+      const char *b = resp->headers[i];
+      const char *e = resp->headers[i + 1];
+      /* Skip CRLF */
+      if (b < e && e[-1] == '\n')
+       --e;
+      if (b < e && e[-1] == '\r')
+       --e;
+      /* This is safe even on printfs with broken handling of "%.<n>s"
+        because resp->headers ends with \0.  */
+      logprintf (LOG_VERBOSE, "%s%.*s\n", prefix, e - b, b);
+    }
 }
 
 /* Parse the `Content-Range' header and extract the information it
@@ -782,30 +785,54 @@ parse_content_range (const char *hdr, wgint *first_byte_ptr,
 }
 
 /* Read the body of the request, but don't store it anywhere and don't
-   display a progress gauge.  This is useful for reading the error
-   responses whose bodies don't need to be displayed or logged, but
-   which need to be read anyway.  */
+   display a progress gauge.  This is useful for reading the bodies of
+   administrative responses to which we will soon issue another
+   request.  The response is not useful to the user, but reading it
+   allows us to continue using the same connection to the server.
 
-static void
+   If reading fails, 0 is returned, non-zero otherwise.  In debug
+   mode, the body is displayed for debugging purposes.  */
+
+static int
 skip_short_body (int fd, wgint contlen)
 {
-  /* Skipping the body doesn't make sense if the content length is
-     unknown because, in that case, persistent connections cannot be
-     used.  (#### This is not the case with HTTP/1.1 where they can
-     still be used with the magic of the "chunked" transfer!)  */
-  if (contlen == -1)
-    return;
-  DEBUGP (("Skipping %s bytes of body data... ", number_to_static_string (contlen)));
+  enum {
+    SKIP_SIZE = 512,           /* size of the download buffer */
+    SKIP_THRESHOLD = 4096      /* the largest size we read */
+  };
+  char dlbuf[SKIP_SIZE + 1];
+  dlbuf[SKIP_SIZE] = '\0';     /* so DEBUGP can safely print it */
+
+  /* We shouldn't get here with unknown contlen.  (This will change
+     with HTTP/1.1, which supports "chunked" transfer.)  */
+  assert (contlen != -1);
+
+  /* If the body is too large, it makes more sense to simply close the
+     connection than to try to read the body.  */
+  if (contlen > SKIP_THRESHOLD)
+    return 0;
+
+  DEBUGP (("Skipping %s bytes of body: [", number_to_static_string (contlen)));
 
   while (contlen > 0)
     {
-      char dlbuf[512];
-      int ret = fd_read (fd, dlbuf, MIN (contlen, sizeof (dlbuf)), -1);
+      int ret = fd_read (fd, dlbuf, MIN (contlen, SKIP_SIZE), -1);
       if (ret <= 0)
-       return;
+       {
+         /* Don't normally report the error since this is an
+            optimization that should be invisible to the user.  */
+         DEBUGP (("] aborting (%s).\n",
+                  ret < 0 ? strerror (errno) : "EOF received"));
+         return 0;
+       }
       contlen -= ret;
+      /* Safe even if %.*s bogusly expects terminating \0 because
+        we've zero-terminated dlbuf above.  */
+      DEBUGP (("%.*s", ret, dlbuf));
     }
-  DEBUGP (("done.\n"));
+
+  DEBUGP (("] done.\n"));
+  return 1;
 }
 \f
 /* Persistent connections.  Currently, we cache the most recently used
@@ -1105,7 +1132,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
      causing it to not close the connection and leave both the proxy
      and the client hanging.  */
   int inhibit_keep_alive =
-    !opt.http_keep_alive || opt.ignore_length /*|| proxy != NULL*/;
+    !opt.http_keep_alive || opt.ignore_length || proxy != NULL;
 
   /* Headers sent when using POST. */
   wgint post_data_size = 0;
@@ -1557,8 +1584,10 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
   if (statcode == HTTP_STATUS_UNAUTHORIZED)
     {
       /* Authorization is required.  */
-      skip_short_body (sock, contlen);
-      CLOSE_FINISH (sock);
+      if (skip_short_body (sock, contlen))
+       CLOSE_FINISH (sock);
+      else
+       CLOSE_INVALIDATE (sock);
       if (auth_tried_already || !(user && passwd))
        {
          /* If we have tried it already, then there is not point
@@ -1672,8 +1701,12 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
                     hs->newloc ? escnonprint_uri (hs->newloc) : _("unspecified"),
                     hs->newloc ? _(" [following]") : "");
          if (keep_alive)
-           skip_short_body (sock, contlen);
-         CLOSE_FINISH (sock);
+           {
+             if (skip_short_body (sock, contlen))
+               CLOSE_FINISH (sock);
+             else
+               CLOSE_INVALIDATE (sock);
+           }
          xfree_null (type);
          return NEWLOCATION;
        }
@@ -1803,7 +1836,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
        fp = fopen (*hs->local_file, "wb");
       else
        {
-         fp = fopen_excl (*hs->local_file, 0);
+         fp = fopen_excl (*hs->local_file, 1);
          if (!fp && errno == EEXIST)
            {
              /* We cannot just invent a new name and use it (which is
@@ -2574,29 +2607,35 @@ http_atotm (const char *time_string)
   return -1;
 }
 \f
-/* Authorization support: We support two authorization schemes:
+/* Authorization support: We support three authorization schemes:
 
    * `Basic' scheme, consisting of base64-ing USER:PASSWORD string;
 
    * `Digest' scheme, added by Junio Hamano <junio@twinsun.com>,
    consisting of answering to the server's challenge with the proper
-   MD5 digests.  */
+   MD5 digests.
+
+   * `NTLM' ("NT Lan Manager") scheme, based on code written by Daniel
+   Stenberg for libcurl.  Like digest, NTLM is based on a
+   challenge-response mechanism, but unlike digest, it is non-standard
+   (authenticates TCP connections rather than requests), undocumented
+   and Microsoft-specific.  */
 
 /* Create the authentication header contents for the `Basic' scheme.
    This is done by encoding the string `USER:PASS' in base64 and
    prepending `HEADER: Basic ' to it.  */
+
 static char *
 basic_authentication_encode (const char *user, const char *passwd)
 {
   char *t1, *t2;
   int len1 = strlen (user) + 1 + strlen (passwd);
-  int len2 = BASE64_LENGTH (len1);
 
   t1 = (char *)alloca (len1 + 1);
   sprintf (t1, "%s:%s", user, passwd);
 
-  t2 = (char *)alloca (len2 + 1);
-  base64_encode (t1, t2, len1);
+  t2 = (char *)alloca (BASE64_LENGTH (len1) + 1);
+  base64_encode (t1, len1, t2);
 
   return concat_strings ("Basic ", t2, (char *) 0);
 }