mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Support to read response headers. Required for redirection support in the
dirmngr package.
This commit is contained in:
parent
529a543bb7
commit
92550e3016
@ -1,3 +1,10 @@
|
||||
2006-09-04 Werner Koch <wk@g10code.com>
|
||||
|
||||
* http.c (http_get_header): New.
|
||||
(capitalize_header_name, store_header): New.
|
||||
(parse_response): Store headers away.
|
||||
* http.h: New flag HTTP_FLAG_NEED_HEADER.
|
||||
|
||||
2006-08-21 Werner Koch <wk@g10code.com>
|
||||
|
||||
* Makefile.am (libcommon_a_SOURCES): Added keyserver.h
|
||||
|
180
common/http.c
180
common/http.c
@ -65,6 +65,10 @@ typedef gnutls_session gnutls_session_t;
|
||||
typedef gnutls_transport_ptr gnutls_transport_ptr_t;
|
||||
#endif /*HTTP_USE_GNUTLS*/
|
||||
|
||||
#ifdef TEST
|
||||
#undef USE_DNS_SRV
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
#include "http.h"
|
||||
#ifdef USE_DNS_SRV
|
||||
@ -157,6 +161,17 @@ typedef struct cookie_s *cookie_t;
|
||||
static gpg_error_t (*tls_callback) (http_t, gnutls_session_t, int);
|
||||
#endif /*HTTP_USE_GNUTLS*/
|
||||
|
||||
|
||||
/* An object to save header lines. */
|
||||
struct header_s
|
||||
{
|
||||
struct header_s *next;
|
||||
char *value; /* The value of the header (malloced). */
|
||||
char name[1]; /* The name of the header (canonicalized). */
|
||||
};
|
||||
typedef struct header_s *header_t;
|
||||
|
||||
|
||||
/* Our handle context. */
|
||||
struct http_context_s
|
||||
{
|
||||
@ -178,6 +193,7 @@ struct http_context_s
|
||||
char *buffer; /* Line buffer. */
|
||||
size_t buffer_size;
|
||||
unsigned int flags;
|
||||
header_t headers; /* Received headers. */
|
||||
};
|
||||
|
||||
|
||||
@ -444,6 +460,13 @@ http_close (http_t hd, int keep_read_stream)
|
||||
if (hd->fp_write)
|
||||
P_ES(fclose) (hd->fp_write);
|
||||
http_release_parsed_uri (hd->uri);
|
||||
while (hd->headers)
|
||||
{
|
||||
header_t tmp = hd->headers->next;
|
||||
xfree (hd->headers->value);
|
||||
xfree (hd->headers);
|
||||
hd->headers = tmp;
|
||||
}
|
||||
xfree (hd->buffer);
|
||||
xfree (hd);
|
||||
}
|
||||
@ -1160,6 +1183,129 @@ my_read_line (
|
||||
}
|
||||
|
||||
|
||||
/* Transform a header name into a standard capitalized format; e.g.
|
||||
"Content-Type". Conversion stops at the colon. As usual we don't
|
||||
use the localized versions of ctype.h. */
|
||||
static void
|
||||
capitalize_header_name (char *name)
|
||||
{
|
||||
int first = 1;
|
||||
|
||||
for (; *name && *name != ':'; name++)
|
||||
{
|
||||
if (*name == '-')
|
||||
first = 1;
|
||||
else if (first)
|
||||
{
|
||||
if (*name >= 'a' && *name <= 'z')
|
||||
*name = *name - 'a' + 'A';
|
||||
first = 0;
|
||||
}
|
||||
else if (*name >= 'A' && *name <= 'Z')
|
||||
*name = *name - 'A' + 'a';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Store an HTTP header line in LINE away. Line continuation is
|
||||
supported as well as merging of headers with the same name. This
|
||||
function may modify LINE. */
|
||||
static gpg_error_t
|
||||
store_header (http_t hd, char *line)
|
||||
{
|
||||
size_t n;
|
||||
char *p, *value;
|
||||
header_t h;
|
||||
|
||||
n = strlen (line);
|
||||
if (n && line[n-1] == '\n')
|
||||
{
|
||||
line[--n] = 0;
|
||||
if (n && line[n-1] == '\r')
|
||||
line[--n] = 0;
|
||||
}
|
||||
if (!n) /* we are never called to hit this. */
|
||||
return gpg_error (GPG_ERR_BUG);
|
||||
if (*line == ' ' || *line == '\t')
|
||||
{
|
||||
/* Continuation. This won't happen too often as it is not
|
||||
recommended. We use a straightforward implementaion. */
|
||||
if (!hd->headers)
|
||||
return gpg_error (GPG_ERR_PROTOCOL_VIOLATION);
|
||||
n += strlen (hd->headers->value);
|
||||
p = xtrymalloc (n+1);
|
||||
if (!p)
|
||||
return gpg_error_from_errno (errno);
|
||||
strcpy (stpcpy (p, hd->headers->value), line);
|
||||
xfree (hd->headers->value);
|
||||
hd->headers->value = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
capitalize_header_name (line);
|
||||
p = strchr (line, ':');
|
||||
if (!p)
|
||||
return gpg_error (GPG_ERR_PROTOCOL_VIOLATION);
|
||||
*p++ = 0;
|
||||
while (*p == ' ' || *p == '\t')
|
||||
p++;
|
||||
value = p;
|
||||
|
||||
for (h=hd->headers; h; h = h->next)
|
||||
if ( !strcmp (h->name, line) )
|
||||
break;
|
||||
if (h)
|
||||
{
|
||||
/* We have already seen a line with that name. Thus we assume
|
||||
it is a comma separated list and merge them. */
|
||||
p = xtrymalloc (strlen (h->value) + 1 + strlen (value)+ 1);
|
||||
if (!p)
|
||||
return gpg_error_from_errno (errno);
|
||||
strcpy (stpcpy (stpcpy (p, h->value), ","), value);
|
||||
xfree (h->value);
|
||||
h->value = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Append a new header. */
|
||||
h = xtrymalloc (sizeof *h + strlen (line));
|
||||
if (!h)
|
||||
return gpg_error_from_errno (errno);
|
||||
strcpy (h->name, line);
|
||||
h->value = xtrymalloc (strlen (value)+1);
|
||||
if (!h->value)
|
||||
{
|
||||
xfree (h);
|
||||
return gpg_error_from_errno (errno);
|
||||
}
|
||||
strcpy (h->value, value);
|
||||
h->next = hd->headers;
|
||||
hd->headers = h;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Return the header NAME from the last response. The returned value
|
||||
is valid as along as HD has not been closed and no othe request has
|
||||
been send. If the header was not found, NULL is returned. Name
|
||||
must be canonicalized, that is the first letter of each dash
|
||||
delimited part must be uppercase and all other letters lowercase.
|
||||
Note that the context must have been opened with the
|
||||
HTTP_FLAG_NEED_HEADER. */
|
||||
const char *
|
||||
http_get_header (http_t hd, const char *name)
|
||||
{
|
||||
header_t h;
|
||||
|
||||
for (h=hd->headers; h; h = h->next)
|
||||
if ( !strcmp (h->name, name) )
|
||||
return h->value;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Parse the response from a server.
|
||||
* Returns: Errorcode and sets some files in the handle
|
||||
@ -1170,6 +1316,15 @@ parse_response (http_t hd)
|
||||
char *line, *p, *p2;
|
||||
size_t maxlen, len;
|
||||
|
||||
/* Delete old header lines. */
|
||||
while (hd->headers)
|
||||
{
|
||||
header_t tmp = hd->headers->next;
|
||||
xfree (hd->headers->value);
|
||||
xfree (hd->headers);
|
||||
hd->headers = tmp;
|
||||
}
|
||||
|
||||
/* Wait for the status line. */
|
||||
do
|
||||
{
|
||||
@ -1231,6 +1386,12 @@ parse_response (http_t hd)
|
||||
if ( (hd->flags & HTTP_FLAG_LOG_RESP) )
|
||||
log_info ("RESP: `%.*s'\n",
|
||||
(int)strlen(line)-(*line&&line[1]?2:0),line);
|
||||
if ( (hd->flags & HTTP_FLAG_NEED_HEADER) && *line )
|
||||
{
|
||||
gpg_error_t err = store_header (hd, line);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
while (len && *line);
|
||||
|
||||
@ -1703,6 +1864,7 @@ main (int argc, char **argv)
|
||||
gnutls_certificate_credentials certcred;
|
||||
const int certprio[] = { GNUTLS_CRT_X509, 0 };
|
||||
#endif /*HTTP_USE_GNUTLS*/
|
||||
header_t hdr;
|
||||
|
||||
#ifdef HTTP_USE_ESTREAM
|
||||
es_init ();
|
||||
@ -1792,7 +1954,8 @@ main (int argc, char **argv)
|
||||
http_release_parsed_uri (uri);
|
||||
uri = NULL;
|
||||
|
||||
rc = http_open_document (&hd, *argv, NULL, HTTP_FLAG_NO_SHUTDOWN,
|
||||
rc = http_open_document (&hd, *argv, NULL,
|
||||
HTTP_FLAG_NO_SHUTDOWN | HTTP_FLAG_NEED_HEADER,
|
||||
NULL, tls_session);
|
||||
if (rc)
|
||||
{
|
||||
@ -1801,8 +1964,19 @@ main (int argc, char **argv)
|
||||
}
|
||||
log_info ("open_http_document succeeded; status=%u\n",
|
||||
http_get_status_code (hd));
|
||||
while ((c = P_ES(getc) (http_get_read_ptr (hd))) != EOF)
|
||||
putchar (c);
|
||||
for (hdr = hd->headers; hdr; hdr = hdr->next)
|
||||
printf ("HDR: %s: %s\n", hdr->name, hdr->value);
|
||||
switch (http_get_status_code (hd))
|
||||
{
|
||||
case 200:
|
||||
while ((c = P_ES(getc) (http_get_read_ptr (hd))) != EOF)
|
||||
putchar (c);
|
||||
break;
|
||||
case 301:
|
||||
case 302:
|
||||
printf ("Redirected to `%s'\n", http_get_header (hd, "Location"));
|
||||
break;
|
||||
}
|
||||
http_close (hd, 0);
|
||||
|
||||
#ifdef HTTP_USE_GNUTLS
|
||||
|
@ -66,7 +66,8 @@ enum
|
||||
HTTP_FLAG_TRY_PROXY = 1,
|
||||
HTTP_FLAG_NO_SHUTDOWN = 2,
|
||||
HTTP_FLAG_TRY_SRV = 4,
|
||||
HTTP_FLAG_LOG_RESP = 8
|
||||
HTTP_FLAG_LOG_RESP = 8,
|
||||
HTTP_FLAG_NEED_HEADER = 16
|
||||
};
|
||||
|
||||
struct http_context_s;
|
||||
@ -106,6 +107,7 @@ FILE *http_get_read_ptr (http_t hd);
|
||||
FILE *http_get_write_ptr (http_t hd);
|
||||
#endif /*!HTTP_USE_ESTREAM*/
|
||||
unsigned int http_get_status_code (http_t hd);
|
||||
const char *http_get_header (http_t hd, const char *name);
|
||||
|
||||
char *http_escape_string (const char *string, const char *specials);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user