mirror of
https://github.com/moparisthebest/wget
synced 2024-07-03 16:38:41 -04:00
[svn] Handle multiple Set-Cookie headers sent by the server.
This commit is contained in:
parent
30aaf5a19a
commit
976c54d0e6
@ -1,3 +1,8 @@
|
|||||||
|
2005-03-06 Hrvoje Niksic <hniksic@xemacs.org>
|
||||||
|
|
||||||
|
* http.c (gethttp): Handle multiple Set-Cookie headers sent by
|
||||||
|
remote server.
|
||||||
|
|
||||||
2005-03-06 Hrvoje Niksic <hniksic@xemacs.org>
|
2005-03-06 Hrvoje Niksic <hniksic@xemacs.org>
|
||||||
|
|
||||||
* init.c (defaults): Use passive FTP by default.
|
* init.c (defaults): Use passive FTP by default.
|
||||||
|
127
src/http.c
127
src/http.c
@ -1,5 +1,5 @@
|
|||||||
/* HTTP support.
|
/* HTTP support.
|
||||||
Copyright (C) 2003 Free Software Foundation, Inc.
|
Copyright (C) 2005 Free Software Foundation, Inc.
|
||||||
|
|
||||||
This file is part of GNU Wget.
|
This file is part of GNU Wget.
|
||||||
|
|
||||||
@ -403,7 +403,7 @@ post_file (int sock, const char *file_name, wgint promised_size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
head_terminator (const char *hunk, int oldlen, int peeklen)
|
response_head_terminator (const char *hunk, int oldlen, int peeklen)
|
||||||
{
|
{
|
||||||
const char *start, *end;
|
const char *start, *end;
|
||||||
|
|
||||||
@ -441,9 +441,9 @@ head_terminator (const char *hunk, int oldlen, int peeklen)
|
|||||||
data can be treated as body. */
|
data can be treated as body. */
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
fd_read_http_head (int fd)
|
read_http_response_head (int fd)
|
||||||
{
|
{
|
||||||
return fd_read_hunk (fd, head_terminator, 512);
|
return fd_read_hunk (fd, response_head_terminator, 512);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct response {
|
struct response {
|
||||||
@ -474,10 +474,10 @@ struct response {
|
|||||||
/* Create a new response object from the text of the HTTP response,
|
/* Create a new response object from the text of the HTTP response,
|
||||||
available in HEAD. That text is automatically split into
|
available in HEAD. That text is automatically split into
|
||||||
constituent header lines for fast retrieval using
|
constituent header lines for fast retrieval using
|
||||||
response_header_*. */
|
resp_header_*. */
|
||||||
|
|
||||||
static struct response *
|
static struct response *
|
||||||
response_new (const char *head)
|
resp_new (const char *head)
|
||||||
{
|
{
|
||||||
const char *hdr;
|
const char *hdr;
|
||||||
int count, size;
|
int count, size;
|
||||||
@ -493,7 +493,7 @@ response_new (const char *head)
|
|||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Split HEAD into header lines, so that response_header_* functions
|
/* Split HEAD into header lines, so that resp_header_* functions
|
||||||
don't need to do this over and over again. */
|
don't need to do this over and over again. */
|
||||||
|
|
||||||
size = count = 0;
|
size = count = 0;
|
||||||
@ -524,27 +524,36 @@ response_new (const char *head)
|
|||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Locate the header named NAME in the request data. If found, set
|
/* Locate the header named NAME in the request data, starting with
|
||||||
*BEGPTR to its starting, and *ENDPTR to its ending position, and
|
position START. This allows the code to loop through the request
|
||||||
return 1. Otherwise return 0.
|
data, filtering for all requests of a given name. Returns the
|
||||||
|
found position, or -1 for failure. The code that uses this
|
||||||
|
function typically looks like this:
|
||||||
|
|
||||||
This function is used as a building block for response_header_copy
|
for (pos = 0; (pos = resp_header_locate (...)) != -1; pos++)
|
||||||
and response_header_strdup. */
|
... do something with header ...
|
||||||
|
|
||||||
|
If you only care about one header, use resp_header_get instead of
|
||||||
|
this function. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
response_header_bounds (const struct response *resp, const char *name,
|
resp_header_locate (const struct response *resp, const char *name, int start,
|
||||||
const char **begptr, const char **endptr)
|
const char **begptr, const char **endptr)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
const char **headers = resp->headers;
|
const char **headers = resp->headers;
|
||||||
int name_len;
|
int name_len;
|
||||||
|
|
||||||
if (!headers || !headers[1])
|
if (!headers || !headers[1])
|
||||||
return 0;
|
return -1;
|
||||||
|
|
||||||
name_len = strlen (name);
|
name_len = strlen (name);
|
||||||
|
if (start > 0)
|
||||||
|
i = start;
|
||||||
|
else
|
||||||
|
i = 1;
|
||||||
|
|
||||||
for (i = 1; headers[i + 1]; i++)
|
for (; headers[i + 1]; i++)
|
||||||
{
|
{
|
||||||
const char *b = headers[i];
|
const char *b = headers[i];
|
||||||
const char *e = headers[i + 1];
|
const char *e = headers[i + 1];
|
||||||
@ -559,26 +568,41 @@ response_header_bounds (const struct response *resp, const char *name,
|
|||||||
--e;
|
--e;
|
||||||
*begptr = b;
|
*begptr = b;
|
||||||
*endptr = e;
|
*endptr = e;
|
||||||
return 1;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find and retrieve the header named NAME in the request data. If
|
||||||
|
found, set *BEGPTR to its starting, and *ENDPTR to its ending
|
||||||
|
position, and return 1. Otherwise return 0.
|
||||||
|
|
||||||
|
This function is used as a building block for resp_header_copy
|
||||||
|
and resp_header_strdup. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
resp_header_get (const struct response *resp, const char *name,
|
||||||
|
const char **begptr, const char **endptr)
|
||||||
|
{
|
||||||
|
int pos = resp_header_locate (resp, name, 0, begptr, endptr);
|
||||||
|
return pos != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy the response header named NAME to buffer BUF, no longer than
|
/* Copy the response header named NAME to buffer BUF, no longer than
|
||||||
BUFSIZE (BUFSIZE includes the terminating 0). If the header
|
BUFSIZE (BUFSIZE includes the terminating 0). If the header
|
||||||
exists, 1 is returned, otherwise 0. If there should be no limit on
|
exists, 1 is returned, otherwise 0. If there should be no limit on
|
||||||
the size of the header, use response_header_strdup instead.
|
the size of the header, use resp_header_strdup instead.
|
||||||
|
|
||||||
If BUFSIZE is 0, no data is copied, but the boolean indication of
|
If BUFSIZE is 0, no data is copied, but the boolean indication of
|
||||||
whether the header is present is still returned. */
|
whether the header is present is still returned. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
response_header_copy (const struct response *resp, const char *name,
|
resp_header_copy (const struct response *resp, const char *name,
|
||||||
char *buf, int bufsize)
|
char *buf, int bufsize)
|
||||||
{
|
{
|
||||||
const char *b, *e;
|
const char *b, *e;
|
||||||
if (!response_header_bounds (resp, name, &b, &e))
|
if (!resp_header_get (resp, name, &b, &e))
|
||||||
return 0;
|
return 0;
|
||||||
if (bufsize)
|
if (bufsize)
|
||||||
{
|
{
|
||||||
@ -593,10 +617,10 @@ response_header_copy (const struct response *resp, const char *name,
|
|||||||
malloc. If such a header does not exist in RESP, return NULL. */
|
malloc. If such a header does not exist in RESP, return NULL. */
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
response_header_strdup (const struct response *resp, const char *name)
|
resp_header_strdup (const struct response *resp, const char *name)
|
||||||
{
|
{
|
||||||
const char *b, *e;
|
const char *b, *e;
|
||||||
if (!response_header_bounds (resp, name, &b, &e))
|
if (!resp_header_get (resp, name, &b, &e))
|
||||||
return NULL;
|
return NULL;
|
||||||
return strdupdelim (b, e);
|
return strdupdelim (b, e);
|
||||||
}
|
}
|
||||||
@ -610,7 +634,7 @@ response_header_strdup (const struct response *resp, const char *name)
|
|||||||
returned in *MESSAGE. */
|
returned in *MESSAGE. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
response_status (const struct response *resp, char **message)
|
resp_status (const struct response *resp, char **message)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
const char *p, *end;
|
const char *p, *end;
|
||||||
@ -670,7 +694,7 @@ response_status (const struct response *resp, char **message)
|
|||||||
/* Release the resources used by RESP. */
|
/* Release the resources used by RESP. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
response_free (struct response *resp)
|
resp_free (struct response *resp)
|
||||||
{
|
{
|
||||||
xfree_null (resp->headers);
|
xfree_null (resp->headers);
|
||||||
xfree (resp);
|
xfree (resp);
|
||||||
@ -1354,7 +1378,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
|
|||||||
return WRITEFAILED;
|
return WRITEFAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
head = fd_read_http_head (sock);
|
head = read_http_response_head (sock);
|
||||||
if (!head)
|
if (!head)
|
||||||
{
|
{
|
||||||
logprintf (LOG_VERBOSE, _("Failed reading proxy response: %s\n"),
|
logprintf (LOG_VERBOSE, _("Failed reading proxy response: %s\n"),
|
||||||
@ -1370,9 +1394,9 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
|
|||||||
}
|
}
|
||||||
DEBUGP (("proxy responded with: [%s]\n", head));
|
DEBUGP (("proxy responded with: [%s]\n", head));
|
||||||
|
|
||||||
resp = response_new (head);
|
resp = resp_new (head);
|
||||||
statcode = response_status (resp, &message);
|
statcode = resp_status (resp, &message);
|
||||||
response_free (resp);
|
resp_free (resp);
|
||||||
if (statcode != 200)
|
if (statcode != 200)
|
||||||
{
|
{
|
||||||
failed_tunnel:
|
failed_tunnel:
|
||||||
@ -1429,7 +1453,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
|
|||||||
contrange = 0;
|
contrange = 0;
|
||||||
*dt &= ~RETROKF;
|
*dt &= ~RETROKF;
|
||||||
|
|
||||||
head = fd_read_http_head (sock);
|
head = read_http_response_head (sock);
|
||||||
if (!head)
|
if (!head)
|
||||||
{
|
{
|
||||||
if (errno == 0)
|
if (errno == 0)
|
||||||
@ -1450,11 +1474,11 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
|
|||||||
}
|
}
|
||||||
DEBUGP (("\n---response begin---\n%s---response end---\n", head));
|
DEBUGP (("\n---response begin---\n%s---response end---\n", head));
|
||||||
|
|
||||||
resp = response_new (head);
|
resp = resp_new (head);
|
||||||
|
|
||||||
/* Check for status line. */
|
/* Check for status line. */
|
||||||
message = NULL;
|
message = NULL;
|
||||||
statcode = response_status (resp, &message);
|
statcode = resp_status (resp, &message);
|
||||||
if (!opt.server_response)
|
if (!opt.server_response)
|
||||||
logprintf (LOG_VERBOSE, "%2d %s\n", statcode,
|
logprintf (LOG_VERBOSE, "%2d %s\n", statcode,
|
||||||
message ? escnonprint (message) : "");
|
message ? escnonprint (message) : "");
|
||||||
@ -1465,7 +1489,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!opt.ignore_length
|
if (!opt.ignore_length
|
||||||
&& response_header_copy (resp, "Content-Length", hdrval, sizeof (hdrval)))
|
&& resp_header_copy (resp, "Content-Length", hdrval, sizeof (hdrval)))
|
||||||
{
|
{
|
||||||
wgint parsed;
|
wgint parsed;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
@ -1484,10 +1508,9 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
|
|||||||
/* Check for keep-alive related responses. */
|
/* Check for keep-alive related responses. */
|
||||||
if (!inhibit_keep_alive && contlen != -1)
|
if (!inhibit_keep_alive && contlen != -1)
|
||||||
{
|
{
|
||||||
if (response_header_copy (resp, "Keep-Alive", NULL, 0))
|
if (resp_header_copy (resp, "Keep-Alive", NULL, 0))
|
||||||
keep_alive = 1;
|
keep_alive = 1;
|
||||||
else if (response_header_copy (resp, "Connection", hdrval,
|
else if (resp_header_copy (resp, "Connection", hdrval, sizeof (hdrval)))
|
||||||
sizeof (hdrval)))
|
|
||||||
{
|
{
|
||||||
if (0 == strcasecmp (hdrval, "Keep-Alive"))
|
if (0 == strcasecmp (hdrval, "Keep-Alive"))
|
||||||
keep_alive = 1;
|
keep_alive = 1;
|
||||||
@ -1511,8 +1534,8 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *www_authenticate = response_header_strdup (resp,
|
char *www_authenticate = resp_header_strdup (resp,
|
||||||
"WWW-Authenticate");
|
"WWW-Authenticate");
|
||||||
/* If the authentication scheme is unknown or if it's the
|
/* If the authentication scheme is unknown or if it's the
|
||||||
"Basic" authentication (which we try by default), there's
|
"Basic" authentication (which we try by default), there's
|
||||||
no sense in retrying. */
|
no sense in retrying. */
|
||||||
@ -1552,7 +1575,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
|
|||||||
else
|
else
|
||||||
hs->error = xstrdup (message);
|
hs->error = xstrdup (message);
|
||||||
|
|
||||||
type = response_header_strdup (resp, "Content-Type");
|
type = resp_header_strdup (resp, "Content-Type");
|
||||||
if (type)
|
if (type)
|
||||||
{
|
{
|
||||||
char *tmp = strchr (type, ';');
|
char *tmp = strchr (type, ';');
|
||||||
@ -1563,27 +1586,35 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
|
|||||||
*tmp = '\0';
|
*tmp = '\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hs->newloc = response_header_strdup (resp, "Location");
|
hs->newloc = resp_header_strdup (resp, "Location");
|
||||||
hs->remote_time = response_header_strdup (resp, "Last-Modified");
|
hs->remote_time = resp_header_strdup (resp, "Last-Modified");
|
||||||
|
|
||||||
|
/* Handle (possibly multiple instances of) the Set-Cookie header. */
|
||||||
{
|
{
|
||||||
char *set_cookie = response_header_strdup (resp, "Set-Cookie");
|
int scpos;
|
||||||
if (set_cookie)
|
const char *scbeg, *scend;
|
||||||
|
/* The jar should have been created by now. */
|
||||||
|
assert (wget_cookie_jar != NULL);
|
||||||
|
for (scpos = 0;
|
||||||
|
(scpos = resp_header_locate (resp, "Set-Cookie", scpos,
|
||||||
|
&scbeg, &scend)) != -1;
|
||||||
|
++scpos)
|
||||||
{
|
{
|
||||||
/* The jar should have been created by now. */
|
char *set_cookie = strdupdelim (scbeg, scend);
|
||||||
assert (wget_cookie_jar != NULL);
|
|
||||||
cookie_handle_set_cookie (wget_cookie_jar, u->host, u->port, u->path,
|
cookie_handle_set_cookie (wget_cookie_jar, u->host, u->port, u->path,
|
||||||
set_cookie);
|
set_cookie);
|
||||||
xfree (set_cookie);
|
xfree (set_cookie);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (response_header_copy (resp, "Content-Range", hdrval, sizeof (hdrval)))
|
|
||||||
|
if (resp_header_copy (resp, "Content-Range", hdrval, sizeof (hdrval)))
|
||||||
{
|
{
|
||||||
wgint first_byte_pos, last_byte_pos, entity_length;
|
wgint first_byte_pos, last_byte_pos, entity_length;
|
||||||
if (parse_content_range (hdrval, &first_byte_pos, &last_byte_pos,
|
if (parse_content_range (hdrval, &first_byte_pos, &last_byte_pos,
|
||||||
&entity_length))
|
&entity_length))
|
||||||
contrange = first_byte_pos;
|
contrange = first_byte_pos;
|
||||||
}
|
}
|
||||||
response_free (resp);
|
resp_free (resp);
|
||||||
|
|
||||||
/* 20x responses are counted among successful by default. */
|
/* 20x responses are counted among successful by default. */
|
||||||
if (H_20X (statcode))
|
if (H_20X (statcode))
|
||||||
|
Loading…
Reference in New Issue
Block a user