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];
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. */
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)
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
}
/* 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
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;
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
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;
}
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
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);
}