xfree_null (req->headers);
xfree (req);
}
+
+/* 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, report an error. */
+
+static int
+post_file (int sock, const char *file_name, long promised_size)
+{
+ static char chunk[8192];
+ long written = 0;
+ int write_error;
+ FILE *fp;
+
+ DEBUGP (("[writing POST file %s ... ", file_name));
+
+ fp = fopen (file_name, "rb");
+ if (!fp)
+ return -1;
+ while (!feof (fp) && written < promised_size)
+ {
+ int towrite;
+ int length = fread (chunk, 1, sizeof (chunk), fp);
+ if (length == 0)
+ break;
+ towrite = MIN (promised_size - written, length);
+ write_error = fd_write (sock, chunk, towrite, -1);
+ if (write_error < 0)
+ {
+ fclose (fp);
+ return -1;
+ }
+ written += towrite;
+ }
+ fclose (fp);
+
+ /* If we've written less than was promised, report a (probably
+ nonsensical) error rather than break the promise. */
+ if (written < promised_size)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ assert (written == promised_size);
+ DEBUGP (("done]\n"));
+ return 0;
+}
\f
static const char *
head_terminator (const char *hunk, int oldlen, int peeklen)
*entity_length_ptr = num;
return 1;
}
-\f
-/* 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, report an error. */
-static int
-post_file (int sock, const char *file_name, long promised_size)
-{
- static char chunk[8192];
- long written = 0;
- int write_error;
- FILE *fp;
-
- DEBUGP (("[writing POST file %s ... ", file_name));
-
- fp = fopen (file_name, "rb");
- if (!fp)
- return -1;
- while (!feof (fp) && written < promised_size)
- {
- int towrite;
- int length = fread (chunk, 1, sizeof (chunk), fp);
- if (length == 0)
- break;
- towrite = MIN (promised_size - written, length);
- write_error = fd_write (sock, chunk, towrite, -1);
- if (write_error < 0)
- {
- fclose (fp);
- return -1;
- }
- written += towrite;
- }
- fclose (fp);
+/* Read the body of the request, but don't store it anywhere. This is
+ useful when reading error responses that are not logged anywhere,
+ but which need to be read so the same connection can be reused. */
- /* If we've written less than was promised, report a (probably
- nonsensical) error rather than break the promise. */
- if (written < promised_size)
- {
- errno = EINVAL;
- return -1;
- }
+static void
+skip_body (int fd, long contlen)
+{
+ int oldverbose;
+ long dummy;
+
+ /* 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;
- assert (written == promised_size);
- DEBUGP (("done]\n"));
- return 0;
+ oldverbose = opt.verbose;
+ opt.verbose = 0;
+ fd_read_body (fd, NULL, contlen, 1, 0, &dummy, NULL);
+ opt.verbose = oldverbose;
}
\f
/* Persistent connections. Currently, we cache the most recently used
if (pconn_active && (fd) == pconn.socket) \
invalidate_persistent (); \
else \
- fd_close (fd); \
+ { \
+ fd_close (fd); \
+ fd = -1; \
+ } \
} \
} while (0)
is done. */
int keep_alive;
- /* Flag that detects having received a keep-alive response. */
- int keep_alive_confirmed;
-
/* Whether keep-alive should be inhibited. */
int inhibit_keep_alive = !opt.http_keep_alive;
int host_lookup_failed = 0;
#ifdef HAVE_SSL
- /* Initialize the SSL context. After the first run, this is a
- no-op. */
- switch (ssl_init ())
+ if (u->scheme == SCHEME_HTTPS)
{
- case SSLERRCTXCREATE:
- /* this is fatal */
- logprintf (LOG_NOTQUIET, _("Failed to set up an SSL context\n"));
- return SSLERRCTXCREATE;
- case SSLERRCERTFILE:
- /* try without certfile */
- logprintf (LOG_NOTQUIET,
- _("Failed to load certificates from %s\n"),
- opt.sslcertfile);
- logprintf (LOG_NOTQUIET,
- _("Trying without the specified certificate\n"));
- break;
- case SSLERRCERTKEY:
- logprintf (LOG_NOTQUIET,
- _("Failed to get certificate key from %s\n"),
- opt.sslcertkey);
- logprintf (LOG_NOTQUIET,
- _("Trying without the specified certificate\n"));
- break;
- default:
- break;
+ /* Initialize the SSL context. After this has once been done,
+ it becomes a no-op. */
+ switch (ssl_init ())
+ {
+ case SSLERRCTXCREATE:
+ /* this is fatal */
+ logprintf (LOG_NOTQUIET, _("Failed to set up an SSL context\n"));
+ return SSLERRCTXCREATE;
+ case SSLERRCERTFILE:
+ /* try without certfile */
+ logprintf (LOG_NOTQUIET,
+ _("Failed to load certificates from %s\n"),
+ opt.sslcertfile);
+ logprintf (LOG_NOTQUIET,
+ _("Trying without the specified certificate\n"));
+ break;
+ case SSLERRCERTKEY:
+ logprintf (LOG_NOTQUIET,
+ _("Failed to get certificate key from %s\n"),
+ opt.sslcertkey);
+ logprintf (LOG_NOTQUIET,
+ _("Trying without the specified certificate\n"));
+ break;
+ default:
+ break;
+ }
}
#endif /* HAVE_SSL */
for the Digest authorization scheme.) */
keep_alive = 0;
- keep_alive_confirmed = 0;
/* Establish the connection. */
else if (opt.post_file_name && post_data_size != 0)
write_error = post_file (sock, opt.post_file_name, post_data_size);
}
- DEBUGP (("---request end---\n"));
if (write_error < 0)
{
}
logprintf (LOG_VERBOSE, _("%s request sent, awaiting response... "),
proxy ? "Proxy" : "HTTP");
- contlen = contrange = -1;
+ contlen = -1;
+ contrange = 0;
type = NULL;
statcode = -1;
*dt &= ~RETROKF;
print_server_response (resp, " ");
}
+ if (response_header_copy (resp, "Content-Length", hdrval, sizeof (hdrval)))
+ contlen = strtol (hdrval, NULL, 10);
+
+ /* Check for keep-alive related responses. */
+ if (!inhibit_keep_alive && contlen != -1)
+ {
+ if (response_header_copy (resp, "Keep-Alive", NULL, 0))
+ keep_alive = 1;
+ else if (response_header_copy (resp, "Connection", hdrval,
+ sizeof (hdrval)))
+ {
+ if (0 == strcasecmp (hdrval, "Keep-Alive"))
+ keep_alive = 1;
+ }
+ }
+ 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. */
- CLOSE_INVALIDATE (sock); /* would be CLOSE_FINISH, but there
- might be more bytes in the body. */
+ skip_body (sock, contlen);
+ CLOSE_FINISH (sock);
if (auth_tried_already || !(user && passwd))
{
/* If we have tried it already, then there is not point
else
hs->error = xstrdup (message);
- if (response_header_copy (resp, "Content-Length", hdrval, sizeof (hdrval)))
- contlen = strtol (hdrval, NULL, 10);
type = response_header_strdup (resp, "Content-Type");
if (type)
{
&entity_length))
contrange = first_byte_pos;
}
-
- /* Check for keep-alive related responses. */
- if (!inhibit_keep_alive && contlen != -1)
- {
- if (response_header_copy (resp, "Keep-Alive", NULL, 0))
- keep_alive = 1;
- else if (response_header_copy (resp, "Connection", hdrval,
- sizeof (hdrval)))
- {
- if (0 == strcasecmp (hdrval, "Keep-Alive"))
- keep_alive = 1;
- }
- }
response_free (resp);
- 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);
-
/* 20x responses are counted among successful by default. */
if (H_20X (statcode))
*dt |= RETROKF;
_("Location: %s%s\n"),
hs->newloc ? hs->newloc : _("unspecified"),
hs->newloc ? _(" [following]") : "");
- CLOSE_INVALIDATE (sock); /* would be CLOSE_FINISH, but there
- might be more bytes in the body. */
+ if (keep_alive)
+ skip_body (sock, contlen);
+ CLOSE_FINISH (sock);
xfree_null (type);
return NEWLOCATION;
}
}
}
- if (contrange == -1)
+ if (contrange == 0 && hs->restval > 0)
{
- /* We did not get a content-range header. This means that the
- server did not honor our `Range' request. Normally, this
- means we should reset hs->restval and continue normally. */
+ /* The download starts from the beginning, presumably because
+ the server did not honor our `Range' request. Normally we'd
+ just reset hs->restval and start the download from
+ scratch. */
/* However, if `-c' is used, we need to be a bit more careful:
1. If `-c' is specified and the file already existed when
- Wget was started, it would be a bad idea for us to start
- downloading it from scratch, effectively truncating it. I
- believe this cannot happen unless `-c' was specified.
+ Wget was started, it would be a bad idea to start downloading
+ it from scratch, effectively truncating the file.
2. If `-c' is used on a file that is already fully
downloaded, we're requesting bytes after the end of file,
- which can result in server not honoring `Range'. If this is
- the case, `Content-Length' will be equal to the length of the
- file. */
+ which can result in the server not honoring `Range'. If this
+ is the case, `Content-Length' will be equal to the length of
+ the file. */
if (opt.always_rest)
{
/* Check for condition #2. */
- if (hs->restval > 0 /* restart was requested. */
- && contlen != -1 /* we got content-length. */
- && hs->restval >= contlen /* file fully downloaded
- or has shrunk. */
+ if (contlen != -1 /* we got content-length. */
+ && hs->restval >= contlen /* file fully downloaded
+ or has shrunk. */
)
{
logputs (LOG_VERBOSE, _("\
Continued download failed on this file, which conflicts with `-c'.\n\
Refusing to truncate existing file `%s'.\n\n"), *hs->local_file);
xfree_null (type);
- CLOSE_INVALIDATE (sock);
+ CLOSE_INVALIDATE (sock); /* see above */
return CONTNOTSUPPORTED;
}
CLOSE_INVALIDATE (sock);
return RANGEERR;
}
-
- if (hs->restval)
- {
- if (contlen != -1)
- contlen += contrange;
- else
- contrange = -1; /* If conent-length was not sent,
- content-range will be ignored. */
- }
- hs->contlen = contlen;
+ hs->contlen = contlen + contrange;
if (opt.verbose)
{
logputs (LOG_VERBOSE, _("Length: "));
if (contlen != -1)
{
- logputs (LOG_VERBOSE, legible (contlen));
- if (contrange != -1)
- logprintf (LOG_VERBOSE, _(" (%s to go)"),
- legible (contlen - contrange));
+ logputs (LOG_VERBOSE, legible (contlen + contrange));
+ if (contrange)
+ logprintf (LOG_VERBOSE, _(" (%s to go)"), legible (contlen));
}
else
logputs (LOG_VERBOSE,
hs->len = 0L;
hs->res = 0;
xfree_null (type);
- CLOSE_INVALIDATE (sock); /* would be CLOSE_FINISH, but there
- might be more bytes in the body. */
+ /* Pre-1.10 Wget used CLOSE_INVALIDATE here. Now we trust the
+ servers not to send body in response to a HEAD request. If
+ you encounter such a server (more likely a broken CGI), use
+ `--no-http-keep-alive'. */
+ CLOSE_FINISH (sock);
return RETRFINISHED;
}
if (opt.save_headers)
fwrite (head, 1, strlen (head), fp);
- /* Get the contents of the document. */
- hs->res = fd_read_body (sock, fp, &hs->len, hs->restval,
- (contlen != -1 ? contlen : 0),
- keep_alive, &hs->dltime);
+ /* Download the request body. */
+ hs->res = fd_read_body (sock, fp, contlen != -1 ? contlen : 0, keep_alive,
+ hs->restval, &hs->len, &hs->dltime);
+ hs->len += contrange;
if (hs->res >= 0)
CLOSE_FINISH (sock);