1
0
mirror of https://github.com/moparisthebest/wget synced 2024-07-03 16:38:41 -04:00

[svn] Only allocate an error string on actual error.

This commit is contained in:
hniksic 2005-07-04 14:42:09 -07:00
parent 134e59c61a
commit 6f6af2d913
4 changed files with 107 additions and 66 deletions

View File

@ -1,3 +1,9 @@
2005-07-04 Hrvoje Niksic <hniksic@xemacs.org>
* openssl.c (openssl_errstr): Instead of always using a large
static buffer, only allocate the error string when there is an
actual error.
2005-07-04 Hrvoje Niksic <hniksic@xemacs.org> 2005-07-04 Hrvoje Niksic <hniksic@xemacs.org>
* xmalloc.c (debugging_free): Prefix hex pointer value with "0x" * xmalloc.c (debugging_free): Prefix hex pointer value with "0x"

View File

@ -913,7 +913,8 @@ fd_write (int fd, char *buf, int bufsize, double timeout)
used. used.
If the transport doesn't support error messages or doesn't supply If the transport doesn't support error messages or doesn't supply
one, strerror(errno) is returned. */ one, strerror(errno) is returned. The returned error message
should not be used after fd_close has been called. */
const char * const char *
fd_errstr (int fd) fd_errstr (int fd)

View File

@ -1075,7 +1075,7 @@ struct http_stat
wgint contlen; /* expected length */ wgint contlen; /* expected length */
wgint restval; /* the restart value */ wgint restval; /* the restart value */
int res; /* the result of last read */ int res; /* the result of last read */
const char *errstr; /* error message from read error */ char *rderrmsg; /* error message from read error */
char *newloc; /* new location (redirection) */ char *newloc; /* new location (redirection) */
char *remote_time; /* remote time-stamp string */ char *remote_time; /* remote time-stamp string */
char *error; /* textual HTTP error */ char *error; /* textual HTTP error */
@ -1092,6 +1092,7 @@ free_hstat (struct http_stat *hs)
xfree_null (hs->newloc); xfree_null (hs->newloc);
xfree_null (hs->remote_time); xfree_null (hs->remote_time);
xfree_null (hs->error); xfree_null (hs->error);
xfree_null (hs->rderrmsg);
/* Guard against being called twice. */ /* Guard against being called twice. */
hs->newloc = NULL; hs->newloc = NULL;
@ -1213,7 +1214,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
hs->len = 0; hs->len = 0;
hs->contlen = -1; hs->contlen = -1;
hs->res = -1; hs->res = -1;
hs->errstr = ""; hs->rderrmsg = NULL;
hs->newloc = NULL; hs->newloc = NULL;
hs->remote_time = NULL; hs->remote_time = NULL;
hs->error = NULL; hs->error = NULL;
@ -1970,7 +1971,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
else else
{ {
if (hs->res < 0) if (hs->res < 0)
hs->errstr = fd_errstr (sock); hs->rderrmsg = xstrdup (fd_errstr (sock));
CLOSE_INVALIDATE (sock); CLOSE_INVALIDATE (sock);
} }
@ -2498,7 +2499,7 @@ The sizes do not match (local %s) -- retrieving.\n"),
logprintf (LOG_VERBOSE, logprintf (LOG_VERBOSE,
_("%s (%s) - Read error at byte %s (%s)."), _("%s (%s) - Read error at byte %s (%s)."),
tms, tmrate, number_to_static_string (hstat.len), tms, tmrate, number_to_static_string (hstat.len),
hstat.errstr); hstat.rderrmsg);
printwhat (count, opt.ntry); printwhat (count, opt.ntry);
free_hstat (&hstat); free_hstat (&hstat);
continue; continue;
@ -2510,7 +2511,7 @@ The sizes do not match (local %s) -- retrieving.\n"),
tms, tmrate, tms, tmrate,
number_to_static_string (hstat.len), number_to_static_string (hstat.len),
number_to_static_string (hstat.contlen), number_to_static_string (hstat.contlen),
hstat.errstr); hstat.rderrmsg);
printwhat (count, opt.ntry); printwhat (count, opt.ntry);
free_hstat (&hstat); free_hstat (&hstat);
continue; continue;

View File

@ -234,96 +234,124 @@ ssl_init ()
return false; return false;
} }
struct openssl_transport_context {
SSL *conn; /* SSL connection handle */
char *last_error; /* last error printed with openssl_errstr */
};
static int static int
openssl_read (int fd, char *buf, int bufsize, void *ctx) openssl_read (int fd, char *buf, int bufsize, void *arg)
{ {
int ret; int ret;
SSL *ssl = ctx; struct openssl_transport_context *ctx = arg;
SSL *conn = ctx->conn;
do do
ret = SSL_read (ssl, buf, bufsize); ret = SSL_read (conn, buf, bufsize);
while (ret == -1 while (ret == -1
&& SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL && SSL_get_error (conn, ret) == SSL_ERROR_SYSCALL
&& errno == EINTR); && errno == EINTR);
return ret; return ret;
} }
static int static int
openssl_write (int fd, char *buf, int bufsize, void *ctx) openssl_write (int fd, char *buf, int bufsize, void *arg)
{ {
int ret = 0; int ret = 0;
SSL *ssl = ctx; struct openssl_transport_context *ctx = arg;
SSL *conn = ctx->conn;
do do
ret = SSL_write (ssl, buf, bufsize); ret = SSL_write (conn, buf, bufsize);
while (ret == -1 while (ret == -1
&& SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL && SSL_get_error (conn, ret) == SSL_ERROR_SYSCALL
&& errno == EINTR); && errno == EINTR);
return ret; return ret;
} }
static int static int
openssl_poll (int fd, double timeout, int wait_for, void *ctx) openssl_poll (int fd, double timeout, int wait_for, void *arg)
{ {
SSL *ssl = ctx; struct openssl_transport_context *ctx = arg;
SSL *conn = ctx->conn;
if (timeout == 0) if (timeout == 0)
return 1; return 1;
if (SSL_pending (ssl)) if (SSL_pending (conn))
return 1; return 1;
return select_fd (fd, timeout, wait_for); return select_fd (fd, timeout, wait_for);
} }
static int static int
openssl_peek (int fd, char *buf, int bufsize, void *ctx) openssl_peek (int fd, char *buf, int bufsize, void *arg)
{ {
int ret; int ret;
SSL *ssl = ctx; struct openssl_transport_context *ctx = arg;
SSL *conn = ctx->conn;
do do
ret = SSL_peek (ssl, buf, bufsize); ret = SSL_peek (conn, buf, bufsize);
while (ret == -1 while (ret == -1
&& SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL && SSL_get_error (conn, ret) == SSL_ERROR_SYSCALL
&& errno == EINTR); && errno == EINTR);
return ret; return ret;
} }
static const char * static const char *
openssl_errstr (int fd, void *ctx) openssl_errstr (int fd, void *arg)
{ {
/* Unfortunately we cannot use ERR_error_string's internal buffer struct openssl_transport_context *ctx = arg;
because we must be prepared to print more than one error. */ unsigned long errcode;
static char errbuf[512]; char *errmsg = NULL;
char *p = errbuf, *end = errbuf + sizeof errbuf; int msglen = 0;
unsigned long err;
if ((err = ERR_get_error ()) == 0) /* If there are no SSL-specific errors, just return NULL. */
/* Inform the caller that there have been no errors */ if ((errcode = ERR_get_error ()) == 0)
return NULL; return NULL;
/* Iterate over OpenSSL's error stack and print errors to ERRBUF, /* Get rid of previous contents of ctx->last_error, if any. */
separated by "; ", while being careful not to overrun ERRBUF. */ xfree_null (ctx->last_error);
do
{
ERR_error_string_n (err, p, end - p);
p = strchr (p, '\0');
err = ERR_get_error ();
if (err == 0)
break;
if (p < end) *p++ = ';';
if (p < end) *p++ = ' ';
}
while (p < end);
if (p < end) /* Iterate over OpenSSL's error stack and accumulate errors in the
*p++ = '\0'; last_error buffer, separated by "; ". This is better than using
else a static buffer, which *always* takes up space (and has to be
end[-1] = '\0'; large, to fit more than one error message), whereas these
return errbuf; allocations are only performed when there is an actual error. */
for (;;)
{
const char *str = ERR_error_string (errcode, NULL);
int len = strlen (str);
/* Allocate space for the existing message, plus two more chars
for the "; " separator and one for the terminating \0. */
errmsg = xrealloc (errmsg, msglen + len + 2 + 1);
memcpy (errmsg + msglen, str, len);
msglen += len;
/* Get next error and bail out if there are no more. */
errcode = ERR_get_error ();
if (errcode == 0)
break;
errmsg[msglen++] = ';';
errmsg[msglen++] = ' ';
}
errmsg[msglen] = '\0';
/* Store the error in ctx->last_error where openssl_close will
eventually find it and free it. */
ctx->last_error = errmsg;
return errmsg;
} }
static void static void
openssl_close (int fd, void *ctx) openssl_close (int fd, void *arg)
{ {
SSL *ssl = ctx; struct openssl_transport_context *ctx = arg;
SSL_shutdown (ssl); SSL *conn = ctx->conn;
SSL_free (ssl);
SSL_shutdown (conn);
SSL_free (conn);
xfree_null (ctx->last_error);
xfree (ctx);
#ifdef WINDOWS #ifdef WINDOWS
closesocket (fd); closesocket (fd);
@ -331,7 +359,7 @@ openssl_close (int fd, void *ctx)
close (fd); close (fd);
#endif #endif
DEBUGP (("Closed %d/SSL 0x%0lx\n", fd, (unsigned long) ssl)); DEBUGP (("Closed %d/SSL 0x%0*lx\n", fd, PTR_FORMAT (conn)));
} }
/* openssl_transport is the singleton that describes the SSL transport /* openssl_transport is the singleton that describes the SSL transport
@ -353,32 +381,36 @@ static struct transport_implementation openssl_transport = {
bool bool
ssl_connect (int fd) ssl_connect (int fd)
{ {
SSL *ssl; SSL *conn;
struct openssl_transport_context *ctx;
DEBUGP (("Initiating SSL handshake.\n")); DEBUGP (("Initiating SSL handshake.\n"));
assert (ssl_ctx != NULL); assert (ssl_ctx != NULL);
ssl = SSL_new (ssl_ctx); conn = SSL_new (ssl_ctx);
if (!ssl) if (!conn)
goto error; goto error;
if (!SSL_set_fd (ssl, fd)) if (!SSL_set_fd (conn, fd))
goto error; goto error;
SSL_set_connect_state (ssl); SSL_set_connect_state (conn);
if (SSL_connect (ssl) <= 0 || ssl->state != SSL_ST_OK) if (SSL_connect (conn) <= 0 || conn->state != SSL_ST_OK)
goto error; goto error;
ctx = xnew0 (struct openssl_transport_context);
ctx->conn = conn;
/* Register FD with Wget's transport layer, i.e. arrange that our /* Register FD with Wget's transport layer, i.e. arrange that our
functions are used for reading, writing, and polling. */ functions are used for reading, writing, and polling. */
fd_register_transport (fd, &openssl_transport, ssl); fd_register_transport (fd, &openssl_transport, ctx);
DEBUGP (("Handshake successful; connected socket %d to SSL handle 0x%0*lx\n", DEBUGP (("Handshake successful; connected socket %d to SSL handle 0x%0*lx\n",
fd, PTR_FORMAT (ssl))); fd, PTR_FORMAT (conn)));
return true; return true;
error: error:
DEBUGP (("SSL handshake failed.\n")); DEBUGP (("SSL handshake failed.\n"));
print_errors (); print_errors ();
if (ssl) if (conn)
SSL_free (ssl); SSL_free (conn);
return false; return false;
} }
@ -451,10 +483,11 @@ ssl_check_certificate (int fd, const char *host)
him about problems with the server's certificate. */ him about problems with the server's certificate. */
const char *severity = opt.check_cert ? _("ERROR") : _("WARNING"); const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
SSL *ssl = (SSL *) fd_transport_context (fd); struct openssl_transport_context *ctx = fd_transport_context (fd);
assert (ssl != NULL); SSL *conn = ctx->conn;
assert (conn != NULL);
cert = SSL_get_peer_certificate (ssl); cert = SSL_get_peer_certificate (conn);
if (!cert) if (!cert)
{ {
logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"), logprintf (LOG_NOTQUIET, _("%s: No certificate presented by %s.\n"),
@ -473,7 +506,7 @@ ssl_check_certificate (int fd, const char *host)
OPENSSL_free (issuer); OPENSSL_free (issuer);
} }
vresult = SSL_get_verify_result (ssl); vresult = SSL_get_verify_result (conn);
if (vresult != X509_V_OK) if (vresult != X509_V_OK)
{ {
/* #### We might want to print saner (and translatable) error /* #### We might want to print saner (and translatable) error