#include "utils.h"
#include "url.h"
#include "host.h"
-#include "rbuf.h"
#include "retr.h"
-#include "headers.h"
#include "connect.h"
#include "netrc.h"
#ifdef HAVE_SSL
if (length == 0)
break;
towrite = WMIN (promised_size - written, length);
- write_error = xwrite (sock, chunk, towrite, -1);
+ write_error = fd_write (sock, chunk, towrite, -1);
if (write_error < 0)
{
fclose (fp);
return 0;
}
\f
+static const char *
+next_header (const char *h)
+{
+ const char *end = NULL;
+ const char *p = h;
+ do
+ {
+ p = strchr (p, '\n');
+ if (!p)
+ return end;
+ end = ++p;
+ }
+ while (*p == ' ' || *p == '\t');
+
+ return end;
+}
+
+/* Skip LWS (linear white space), if present. Returns number of
+ characters to skip. */
+static int
+skip_lws (const char *string)
+{
+ const char *p = string;
+
+ while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
+ ++p;
+ return p - string;
+}
+
+/* Check whether HEADER begins with NAME and, if yes, skip the `:' and
+ the whitespace, and call PROCFUN with the arguments of HEADER's
+ contents (after the `:' and space) and ARG. Otherwise, return 0. */
+int
+header_process (const char *header, const char *name,
+ int (*procfun) (const char *, void *),
+ void *arg)
+{
+ /* Check whether HEADER matches NAME. */
+ while (*name && (TOLOWER (*name) == TOLOWER (*header)))
+ ++name, ++header;
+ if (*name || *header++ != ':')
+ return 0;
+
+ header += skip_lws (header);
+
+ return ((*procfun) (header, arg));
+}
+\f
+/* Helper functions for use with header_process(). */
+
+/* Extract a long integer from HEADER and store it to CLOSURE. If an
+ error is encountered, return 0, else 1. */
+int
+header_extract_number (const char *header, void *closure)
+{
+ const char *p = header;
+ long result;
+
+ for (result = 0; ISDIGIT (*p); p++)
+ result = 10 * result + (*p - '0');
+
+ /* Failure if no number present. */
+ if (p == header)
+ return 0;
+
+ /* Skip trailing whitespace. */
+ p += skip_lws (p);
+
+ /* Indicate failure if trailing garbage is present. */
+ if (*p)
+ return 0;
+
+ *(long *)closure = result;
+ return 1;
+}
+
+/* Strdup HEADER, and place the pointer to CLOSURE. */
+int
+header_strdup (const char *header, void *closure)
+{
+ *(char **)closure = xstrdup (header);
+ return 1;
+}
+
+/* Write the value 1 into the integer pointed to by CLOSURE. */
+int
+header_exists (const char *header, void *closure)
+{
+ *(int *)closure = 1;
+ return 1;
+}
+\f
/* Functions to be used as arguments to header_process(): */
struct http_process_range_closure {
{
DEBUGP (("Disabling further reuse of socket %d.\n", pconn.socket));
pconn_active = 0;
- xclose (pconn.socket);
+ fd_close (pconn.socket);
xfree (pconn.host);
xzero (pconn);
}
return 0;
}
- found = address_list_find (al, &ip);
+ found = address_list_contains (al, &ip);
address_list_release (al);
if (!found)
if (pconn_active && (fd) == pconn.socket) \
invalidate_persistent (); \
else \
- xclose (fd); \
+ fd_close (fd); \
} \
} while (0)
if (pconn_active && (fd) == pconn.socket) \
invalidate_persistent (); \
else \
- xclose (fd); \
+ fd_close (fd); \
} while (0)
\f
struct http_stat
will print it if there is enough information to do so (almost
always), returning the error to the caller (i.e. http_loop).
- Various HTTP parameters are stored to hs. Although it parses the
- response code correctly, it is not used in a sane way. The caller
- can do that, though.
+ Various HTTP parameters are stored to hs.
If PROXY is non-NULL, the connection will be made to the proxy
server, and u->url will be requested. */
char *pragma_h, *referer, *useragent, *range, *wwwauth;
char *authenticate_h;
char *proxyauth;
- char *all_headers;
char *port_maybe;
char *request_keep_alive;
- int sock, hcount, all_length, statcode;
+ int sock, hcount, statcode;
int write_error;
long contlen, contrange;
struct url *conn;
FILE *fp;
int auth_tried_already;
- struct rbuf rbuf;
int using_ssl = 0;
char *cookies = NULL;
+ char *head;
+ const char *hdr_beg, *hdr_end;
+
/* Whether this connection will be kept alive after the HTTP request
is done. */
int keep_alive;
logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET,
_("Unable to establish SSL connection.\n"));
- xclose (sock);
+ fd_close (sock);
return CONSSLERR;
}
using_ssl = 1;
xfree (full_path);
/* Send the request to server. */
- write_error = xwrite (sock, request, strlen (request), -1);
+ write_error = fd_write (sock, request, strlen (request), -1);
if (write_error >= 0)
{
if (opt.post_data)
{
DEBUGP (("[POST data: %s]\n", opt.post_data));
- write_error = xwrite (sock, opt.post_data, post_data_size, -1);
+ write_error = fd_write (sock, opt.post_data, post_data_size, -1);
}
else if (opt.post_file_name && post_data_size != 0)
write_error = post_file (sock, opt.post_file_name, post_data_size);
statcode = -1;
*dt &= ~RETROKF;
- /* Before reading anything, initialize the rbuf. */
- rbuf_initialize (&rbuf, sock);
- all_headers = NULL;
- all_length = 0;
-
DEBUGP (("\n---response begin---\n"));
- /* Header-fetching loop. */
- hcount = 0;
- while (1)
+ head = fd_read_head (sock);
+ if (!head)
{
- char *hdr;
- int status;
-
- ++hcount;
- /* Get the header. */
- status = header_get (&rbuf, &hdr,
- /* Disallow continuations for status line. */
- (hcount == 1 ? HG_NO_CONTINUATIONS : HG_NONE));
-
- /* Check for errors. */
- if (status == HG_EOF && *hdr)
+ logputs (LOG_VERBOSE, "\n");
+ if (errno == 0)
{
- /* This used to be an unconditional error, but that was
- somewhat controversial, because of a large number of
- broken CGI's that happily "forget" to send the second EOL
- before closing the connection of a HEAD request.
-
- So, the deal is to check whether the header is empty
- (*hdr is zero if it is); if yes, it means that the
- previous header was fully retrieved, and that -- most
- probably -- the request is complete. "...be liberal in
- what you accept." Oh boy. */
- logputs (LOG_VERBOSE, "\n");
- logputs (LOG_NOTQUIET, _("End of file while parsing headers.\n"));
- xfree (hdr);
- xfree_null (type);
- xfree_null (all_headers);
+ logputs (LOG_NOTQUIET, _("No data received.\n"));
CLOSE_INVALIDATE (sock);
return HEOF;
}
- else if (status == HG_ERROR)
+ else
{
- logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, _("Read error (%s) in headers.\n"),
strerror (errno));
- xfree (hdr);
- xfree_null (type);
- xfree_null (all_headers);
CLOSE_INVALIDATE (sock);
return HERR;
}
+ }
- /* If the headers are to be saved to a file later, save them to
- memory now. */
- if (opt.save_headers)
- {
- int lh = strlen (hdr);
- all_headers = (char *)xrealloc (all_headers, all_length + lh + 2);
- memcpy (all_headers + all_length, hdr, lh);
- all_length += lh;
- all_headers[all_length++] = '\n';
- all_headers[all_length] = '\0';
- }
+ /* Loop through the headers and process them. */
+
+ hcount = 0;
+ for (hdr_beg = head;
+ (hdr_end = next_header (hdr_beg));
+ hdr_beg = hdr_end)
+ {
+ char *hdr = strdupdelim (hdr_beg, hdr_end);
+ {
+ char *tmp = hdr + strlen (hdr);
+ if (tmp > hdr && tmp[-1] == '\n')
+ *--tmp = '\0';
+ if (tmp > hdr && tmp[-1] == '\r')
+ *--tmp = '\0';
+ }
+ ++hcount;
/* Check for status line. */
if (hcount == 1)
CLOSE_INVALIDATE (sock); /* would be CLOSE_FINISH, but there
might be more bytes in the body. */
xfree_null (type);
- xfree_null (all_headers);
return NEWLOCATION;
}
}
/* Mark as successfully retrieved. */
*dt |= RETROKF;
xfree_null (type);
- xfree_null (all_headers);
CLOSE_INVALIDATE (sock); /* would be CLOSE_FINISH, but there
might be more bytes in the body. */
return RETRUNNEEDED;
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);
- xfree_null (all_headers);
CLOSE_INVALIDATE (sock);
return CONTNOTSUPPORTED;
}
/* This means the whole request was somehow misunderstood by the
server. Bail out. */
xfree_null (type);
- xfree_null (all_headers);
CLOSE_INVALIDATE (sock);
return RANGEERR;
}
hs->len = 0L;
hs->res = 0;
xfree_null (type);
- xfree_null (all_headers);
CLOSE_INVALIDATE (sock); /* would be CLOSE_FINISH, but there
might be more bytes in the body. */
return RETRFINISHED;
logprintf (LOG_NOTQUIET, "%s: %s\n", *hs->local_file, strerror (errno));
CLOSE_INVALIDATE (sock); /* would be CLOSE_FINISH, but there
might be more bytes in the body. */
- xfree_null (all_headers);
return FOPENERR;
}
}
/* #### This confuses the code that checks for file size. There
should be some overhead information. */
if (opt.save_headers)
- fwrite (all_headers, 1, all_length, fp);
+ fwrite (head, 1, strlen (head), fp);
/* Get the contents of the document. */
- hs->res = get_contents (sock, fp, &hs->len, hs->restval,
+ hs->res = fd_read_body (sock, fp, &hs->len, hs->restval,
(contlen != -1 ? contlen : 0),
- &rbuf, keep_alive, &hs->dltime);
+ keep_alive, &hs->dltime);
if (hs->res >= 0)
CLOSE_FINISH (sock);
if (flush_res == EOF)
hs->res = -2;
}
- xfree_null (all_headers);
if (hs->res == -2)
return FWRITEERR;
return RETRFINISHED;