# endif
#endif
-#ifdef WINDOWS
-# include <winsock.h>
-#else
-# include <netdb.h> /* for h_errno */
-#endif
-
#include "wget.h"
#include "utils.h"
#include "url.h"
# include "gen_sslfunc.h"
#endif /* HAVE_SSL */
#include "cookies.h"
+#ifdef USE_DIGEST
+# include "gen-md5.h"
+#endif
extern char *version_string;
#ifndef errno
extern int errno;
#endif
-#ifndef h_errno
-# ifndef __CYGWIN__
-extern int h_errno;
-# endif
-#endif
\f
static int cookies_loaded_p;
if (!strncasecmp (hdr, "bytes", 5))
{
hdr += 5;
+ /* "JavaWebServer/1.1.1" sends "bytes: x-y/z", contrary to the
+ HTTP spec. */
+ if (*hdr == ':')
+ ++hdr;
hdr += skip_lws (hdr);
if (!*hdr)
return 0;
/* Whether a persistent connection is active. */
static int pc_active_p;
/* Host and port of currently active persistent connection. */
-static unsigned char pc_last_host_ip[4];
+static struct address_list *pc_last_host_ip;
static unsigned short pc_last_port;
/* File descriptor of the currently active persistent connection. */
#ifdef HAVE_SSL
pc_active_ssl = 0;
#endif /* HAVE_SSL */
+ if (pc_last_host_ip != NULL)
+ {
+ address_list_release (pc_last_host_ip);
+ pc_last_host_ip = NULL;
+ }
DEBUGP (("Invalidating fd %d from further reuse.\n", pc_last_fd));
}
#endif
)
{
- int success;
-
if (pc_active_p)
{
if (pc_last_fd == fd)
}
}
+ assert (pc_last_host_ip == NULL);
+
/* This lookup_host cannot fail, because it has the results in the
cache. */
- success = lookup_host (host, pc_last_host_ip);
- assert (success);
+ pc_last_host_ip = lookup_host (host, 1);
+ assert (pc_last_host_ip != NULL);
+
pc_last_port = port;
pc_last_fd = fd;
pc_active_p = 1;
DEBUGP (("Registered fd %d for persistent reuse.\n", fd));
}
+#ifdef HAVE_SSL
+# define SHUTDOWN_SSL(ssl) do { \
+ if (ssl) \
+ shutdown_ssl (ssl); \
+} while (0)
+#else
+# define SHUTDOWN_SSL(ssl)
+#endif
+
/* Return non-zero if a persistent connection is available for
connecting to HOST:PORT. */
#endif
)
{
- unsigned char this_host_ip[4];
+ int success;
+ struct address_list *this_host_ip;
+
/* First, check whether a persistent connection is active at all. */
if (!pc_active_p)
return 0;
(HOST, PORT) ordered pair. */
if (port != pc_last_port)
return 0;
+
#ifdef HAVE_SSL
/* Second, a): check if current connection is (not) ssl, too. This
test is unlikely to fail because HTTP and HTTPS typicaly use
if (ssl != pc_active_ssl)
return 0;
#endif /* HAVE_SSL */
- if (!lookup_host (host, this_host_ip))
+
+ this_host_ip = lookup_host (host, 1);
+ if (!this_host_ip)
return 0;
- if (memcmp (pc_last_host_ip, this_host_ip, 4))
+
+ /* To equate the two host names for the purposes of persistent
+ connections, they need to share all the IP addresses in the
+ list. */
+ success = address_list_match_all (pc_last_host_ip, this_host_ip);
+ address_list_release (this_host_ip);
+ if (!success)
return 0;
+
/* Third: check whether the connection is still open. This is
important because most server implement a liberal (short) timeout
on persistent connections. Wget can of course always reconnect
let's invalidate the persistent connection before returning
0. */
CLOSE (pc_last_fd);
+#ifdef HAVE_SSL
+ SHUTDOWN_SSL (pc_last_ssl);
+ pc_last_ssl = NULL;
+#endif
invalidate_persistent ();
return 0;
}
return 1;
}
-#ifdef HAVE_SSL
-# define SHUTDOWN_SSL(ssl) do { \
- if (ssl) \
- shutdown_ssl (ssl); \
-} while (0)
-#else
-# define SHUTDOWN_SSL(ssl)
-#endif
-
/* The idea behind these two CLOSE macros is to distinguish between
two cases: one when the job we've been doing is finished, and we
want to close the connection and leave, and two when something is
int sock, hcount, num_written, all_length, statcode;
long contlen, contrange;
struct url *conn;
- uerr_t err;
FILE *fp;
int auth_tried_already;
struct rbuf rbuf;
static SSL_CTX *ssl_ctx = NULL;
SSL *ssl = NULL;
#endif /* HAVE_SSL */
- struct wget_timer *timer;
char *cookies = NULL;
/* Whether this connection will be kept alive after the HTTP request
/* initialize ssl_ctx on first run */
if (!ssl_ctx)
{
- err = init_ssl (&ssl_ctx);
+ uerr_t err = init_ssl (&ssl_ctx);
if (err != 0)
{
switch (err)
#endif /* HAVE_SSL */
)
{
- logprintf (LOG_VERBOSE, _("Connecting to %s:%hu... "),
- conn->host, conn->port);
- err = make_connection (&sock, conn->host, conn->port);
- switch (err)
- {
- case HOSTERR:
- logputs (LOG_VERBOSE, "\n");
- logprintf (LOG_NOTQUIET, "%s: %s.\n", conn->host, herrmsg (h_errno));
- return HOSTERR;
- break;
- case CONSOCKERR:
- logputs (LOG_VERBOSE, "\n");
- logprintf (LOG_NOTQUIET, "socket: %s\n", strerror (errno));
- return CONSOCKERR;
- break;
- case CONREFUSED:
- logputs (LOG_VERBOSE, "\n");
- logprintf (LOG_NOTQUIET,
- _("Connection to %s:%hu refused.\n"), conn->host,
- conn->port);
- CLOSE (sock);
- return CONREFUSED;
- case CONERROR:
- logputs (LOG_VERBOSE, "\n");
- logprintf (LOG_NOTQUIET, "connect: %s\n", strerror (errno));
- CLOSE (sock);
- return CONERROR;
- break;
- case NOCONERROR:
- /* Everything is fine! */
- logputs (LOG_VERBOSE, _("connected!\n"));
- break;
- default:
- abort ();
- break;
- }
+ struct address_list *al = lookup_host (conn->host, 0);
+ if (!al)
+ return HOSTERR;
+ set_connection_host_name (conn->host);
+ sock = connect_to_many (al, conn->port, 0);
+ set_connection_host_name (NULL);
+ address_list_release (al);
+
+ if (sock < 0)
+ return errno == ECONNREFUSED ? CONREFUSED : CONERROR;
+
#ifdef HAVE_SSL
if (conn->scheme == SCHEME_HTTPS)
if (connect_ssl (&ssl, ssl_ctx,sock) != 0)
}
else
{
+ /* Use the full path, i.e. one that includes the leading
+ slash and the query string, but is independent of proxy
+ setting. */
+ char *pth = url_full_path (u);
wwwauth = create_authorization_line (authenticate_h, user, passwd,
- command, u->path);
+ command, pth);
+ xfree (pth);
}
}
if (proxy)
full_path = xstrdup (u->url);
else
+ /* Use the full path, i.e. one that includes the leading slash and
+ the query string. E.g. if u->path is "foo/bar" and u->query is
+ "param=value", full_path will be "/foo/bar?param=value". */
full_path = url_full_path (u);
/* Allocate the memory for the request. */
/* Send the request to server. */
#ifdef HAVE_SSL
- if (u->scheme == SCHEME_HTTPS)
+ if (conn->scheme == SCHEME_HTTPS)
num_written = ssl_iwrite (ssl, request, strlen (request));
else
#endif /* HAVE_SSL */
/* Before reading anything, initialize the rbuf. */
rbuf_initialize (&rbuf, sock);
#ifdef HAVE_SSL
- if (u->scheme == SCHEME_HTTPS)
+ if (conn->scheme == SCHEME_HTTPS)
rbuf.ssl = ssl;
else
rbuf.ssl = NULL;
should be some overhead information. */
if (opt.save_headers)
fwrite (all_headers, 1, all_length, fp);
- timer = wtimer_new ();
+
/* Get the contents of the document. */
hs->res = get_contents (sock, fp, &hs->len, hs->restval,
(contlen != -1 ? contlen : 0),
- &rbuf, keep_alive);
- hs->dltime = wtimer_elapsed (timer);
- wtimer_delete (timer);
+ &rbuf, keep_alive, &hs->dltime);
+
{
/* Close or flush the file. We have to be careful to check for
error here. Checking the result of fwrite() is not enough --
&& (!strcmp (suf, "html") || !strcmp (suf, "htm")))
*dt |= TEXTHTML;
- FREE_MAYBE (suf);
FREE_MAYBE (dummy);
return RETROK;
}
/* Take the line apart to find the challenge, and compose a digest
authorization header. See RFC2069 section 2.1.2. */
-char *
+static char *
digest_authentication_encode (const char *au, const char *user,
const char *passwd, const char *method,
const char *path)
/* Calculate the digest value. */
{
- MD5_CONTEXT_TYPE ctx;
+ ALLOCA_MD5_CONTEXT (ctx);
unsigned char hash[MD5_HASHLEN];
unsigned char a1buf[MD5_HASHLEN * 2 + 1], a2buf[MD5_HASHLEN * 2 + 1];
unsigned char response_digest[MD5_HASHLEN * 2 + 1];
/* A1BUF = H(user ":" realm ":" password) */
- MD5_INIT (&ctx);
- MD5_UPDATE (user, strlen (user), &ctx);
- MD5_UPDATE (":", 1, &ctx);
- MD5_UPDATE (realm, strlen (realm), &ctx);
- MD5_UPDATE (":", 1, &ctx);
- MD5_UPDATE (passwd, strlen (passwd), &ctx);
- MD5_FINISH (&ctx, hash);
+ gen_md5_init (ctx);
+ gen_md5_update ((unsigned char *)user, strlen (user), ctx);
+ gen_md5_update ((unsigned char *)":", 1, ctx);
+ gen_md5_update ((unsigned char *)realm, strlen (realm), ctx);
+ gen_md5_update ((unsigned char *)":", 1, ctx);
+ gen_md5_update ((unsigned char *)passwd, strlen (passwd), ctx);
+ gen_md5_finish (ctx, hash);
dump_hash (a1buf, hash);
/* A2BUF = H(method ":" path) */
- MD5_INIT (&ctx);
- MD5_UPDATE (method, strlen (method), &ctx);
- MD5_UPDATE (":", 1, &ctx);
- MD5_UPDATE (path, strlen (path), &ctx);
- MD5_FINISH (&ctx, hash);
+ gen_md5_init (ctx);
+ gen_md5_update ((unsigned char *)method, strlen (method), ctx);
+ gen_md5_update ((unsigned char *)":", 1, ctx);
+ gen_md5_update ((unsigned char *)path, strlen (path), ctx);
+ gen_md5_finish (ctx, hash);
dump_hash (a2buf, hash);
/* RESPONSE_DIGEST = H(A1BUF ":" nonce ":" A2BUF) */
- MD5_INIT (&ctx);
- MD5_UPDATE (a1buf, MD5_HASHLEN * 2, &ctx);
- MD5_UPDATE (":", 1, &ctx);
- MD5_UPDATE (nonce, strlen (nonce), &ctx);
- MD5_UPDATE (":", 1, &ctx);
- MD5_UPDATE (a2buf, MD5_HASHLEN * 2, &ctx);
- MD5_FINISH (&ctx, hash);
+ gen_md5_init (ctx);
+ gen_md5_update (a1buf, MD5_HASHLEN * 2, ctx);
+ gen_md5_update ((unsigned char *)":", 1, ctx);
+ gen_md5_update ((unsigned char *)nonce, strlen (nonce), ctx);
+ gen_md5_update ((unsigned char *)":", 1, ctx);
+ gen_md5_update (a2buf, MD5_HASHLEN * 2, ctx);
+ gen_md5_finish (ctx, hash);
dump_hash (response_digest, hash);
res = (char*) xmalloc (strlen (user)
#endif /* USE_DIGEST */
return wwwauth;
}
+\f
+void
+http_cleanup (void)
+{
+ if (pc_last_host_ip)
+ address_list_release (pc_last_host_ip);
+}