~ubuntu-branches/ubuntu/oneiric/gnupg2/oneiric-updates

« back to all changes in this revision

Viewing changes to common/http.c

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Viehmann
  • Date: 2008-10-04 10:25:53 UTC
  • mfrom: (5.1.15 intrepid)
  • Revision ID: james.westby@ubuntu.com-20081004102553-fv62pp8dsitxli47
Tags: 2.0.9-3.1
* Non-maintainer upload.
* agent/gpg-agent.c: Deinit the threading library before exec'ing
  the command to run in --daemon mode. And because that still doesn't
  restore the sigprocmask, do that manually. Closes: #499569

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* http.c  -  HTTP protocol handler
 
2
 * Copyright (C) 1999, 2001, 2002, 2003, 2004,
 
3
 *               2006 Free Software Foundation, Inc.
 
4
 *
 
5
 * This file is part of GnuPG.
 
6
 *
 
7
 * GnuPG is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License as published by
 
9
 * the Free Software Foundation; either version 3 of the License, or
 
10
 * (at your option) any later version.
 
11
 *
 
12
 * GnuPG is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 
19
 */
 
20
 
 
21
/* Simple HTTP client implementation.  We try to keep the code as
 
22
   self-contained as possible.  There are some contraints however:
 
23
 
 
24
  - stpcpy is required
 
25
  - fixme: list other requirements.
 
26
 
 
27
 
 
28
  - With HTTP_USE_ESTREAM defined, all I/O is done through estream.
 
29
  - With HTTP_USE_GNUTLS support for https is provided (this also
 
30
    requires estream).
 
31
  - With HTTP_NO_WSASTARTUP the socket initialization is not done
 
32
    under Windows.  This is useful if the socket layer has already
 
33
    been initialized elsewhere.  This also avoids the installation of
 
34
    an exit handler to cleanup the socket layer.
 
35
*/
 
36
 
 
37
#ifdef HAVE_CONFIG_H
 
38
# include <config.h>
 
39
#endif
 
40
#include <stdio.h>
 
41
#include <stdlib.h>
 
42
#include <stdarg.h>
 
43
#include <string.h>
 
44
#include <ctype.h>
 
45
#include <errno.h>
 
46
#include <unistd.h>
 
47
 
 
48
#ifdef HAVE_W32_SYSTEM
 
49
# include <windows.h>
 
50
#else /*!HAVE_W32_SYSTEM*/
 
51
# include <sys/types.h>
 
52
# include <sys/socket.h>
 
53
# include <sys/time.h>
 
54
# include <time.h>
 
55
# include <netinet/in.h>
 
56
# include <arpa/inet.h>
 
57
# include <netdb.h>
 
58
#endif /*!HAVE_W32_SYSTEM*/
 
59
 
 
60
#ifdef HTTP_USE_GNUTLS
 
61
# include <gnutls/gnutls.h>
 
62
/* For non-understandable reasons GNUTLS dropped the _t suffix from
 
63
   all types. yes, ISO-C might be read as this but there are still
 
64
   other name space conflicts and using _t is actually a Good
 
65
   Thing. */
 
66
typedef gnutls_session gnutls_session_t;
 
67
typedef gnutls_transport_ptr gnutls_transport_ptr_t;
 
68
#endif /*HTTP_USE_GNUTLS*/
 
69
 
 
70
#ifdef TEST
 
71
#undef USE_DNS_SRV
 
72
#endif
 
73
 
 
74
#include "util.h"
 
75
#include "i18n.h"
 
76
#include "http.h"
 
77
#ifdef USE_DNS_SRV
 
78
#include "srv.h"
 
79
#else /*!USE_DNS_SRV*/
 
80
/* If we are not compiling with SRV record support we provide stub
 
81
   data structures. */
 
82
#ifndef MAXDNAME
 
83
#define MAXDNAME 1025
 
84
#endif
 
85
struct srventry
 
86
{
 
87
  unsigned short priority;
 
88
  unsigned short weight;
 
89
  unsigned short port;
 
90
  int run_count;
 
91
  char target[MAXDNAME];
 
92
};
 
93
#endif/*!USE_DNS_SRV*/
 
94
 
 
95
 
 
96
#ifdef HAVE_W32_SYSTEM
 
97
#define sock_close(a)  closesocket(a)
 
98
#else
 
99
#define sock_close(a)  close(a)
 
100
#endif
 
101
 
 
102
#ifndef EAGAIN
 
103
#define EAGAIN  EWOULDBLOCK
 
104
#endif
 
105
 
 
106
#define HTTP_PROXY_ENV           "http_proxy"
 
107
#define MAX_LINELEN 20000  /* Max. length of a HTTP header line. */
 
108
#define VALID_URI_CHARS "abcdefghijklmnopqrstuvwxyz"   \
 
109
                        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"   \
 
110
                        "01234567890@"                 \
 
111
                        "!\"#$%&'()*+,-./:;<=>?[\\]^_{|}~"
 
112
 
 
113
/* Define a prefix to map stream functions to the estream library. */
 
114
#ifdef HTTP_USE_ESTREAM
 
115
#define P_ES(a)  es_ ## a
 
116
#else
 
117
#define P_ES(a)  a
 
118
#endif
 
119
#ifndef HTTP_USE_GNUTLS
 
120
typedef void * gnutls_session_t;
 
121
#endif
 
122
#if defined(HTTP_USE_GNUTLS) && !defined(HTTP_USE_ESTREAM)
 
123
#error Use of GNUTLS also requires support for Estream
 
124
#endif
 
125
 
 
126
static gpg_error_t do_parse_uri (parsed_uri_t uri, int only_local_part);
 
127
static int remove_escapes (char *string);
 
128
static int insert_escapes (char *buffer, const char *string,
 
129
                           const char *special);
 
130
static uri_tuple_t parse_tuple (char *string);
 
131
static gpg_error_t send_request (http_t hd,
 
132
                                 const char *auth, const char *proxy);
 
133
static char *build_rel_path (parsed_uri_t uri);
 
134
static gpg_error_t parse_response (http_t hd);
 
135
 
 
136
static int connect_server (const char *server, unsigned short port,
 
137
                           unsigned int flags, const char *srvtag);
 
138
static gpg_error_t write_server (int sock, const char *data, size_t length);
 
139
 
 
140
#ifdef HTTP_USE_ESTREAM
 
141
static ssize_t cookie_read (void *cookie, void *buffer, size_t size);
 
142
static ssize_t cookie_write (void *cookie, const void *buffer, size_t size);
 
143
static int cookie_close (void *cookie);
 
144
 
 
145
static es_cookie_io_functions_t cookie_functions =
 
146
  {
 
147
    cookie_read,
 
148
    cookie_write,
 
149
    NULL,
 
150
    cookie_close
 
151
  };
 
152
 
 
153
struct cookie_s 
 
154
{
 
155
  int fd;  /* File descriptor or -1 if already closed. */
 
156
  gnutls_session_t tls_session;  /* TLS session context or NULL if not used. */
 
157
  int keep_socket; /* Flag to communicate with teh close handler. */
 
158
};
 
159
typedef struct cookie_s *cookie_t;
 
160
 
 
161
#endif /*HTTP_USE_ESTREAM*/
 
162
 
 
163
#ifdef HTTP_USE_GNUTLS
 
164
static gpg_error_t (*tls_callback) (http_t, gnutls_session_t, int);
 
165
#endif /*HTTP_USE_GNUTLS*/
 
166
 
 
167
 
 
168
/* An object to save header lines. */
 
169
struct header_s
 
170
{
 
171
  struct header_s *next;
 
172
  char *value;    /* The value of the header (malloced).  */
 
173
  char name[1];   /* The name of the header (canonicalized). */
 
174
};
 
175
typedef struct header_s *header_t;
 
176
 
 
177
 
 
178
/* Our handle context. */
 
179
struct http_context_s 
 
180
{
 
181
  unsigned int status_code;
 
182
  int sock;
 
183
  int in_data;
 
184
#ifdef HTTP_USE_ESTREAM
 
185
  estream_t fp_read;
 
186
  estream_t fp_write;
 
187
  void *write_cookie;
 
188
#else /*!HTTP_USE_ESTREAM*/
 
189
  FILE *fp_read;
 
190
  FILE *fp_write;
 
191
#endif /*!HTTP_USE_ESTREAM*/
 
192
  void *tls_context;
 
193
  int is_http_0_9;
 
194
  parsed_uri_t uri;
 
195
  http_req_t req_type;
 
196
  char *buffer;          /* Line buffer. */
 
197
  size_t buffer_size;
 
198
  unsigned int flags;
 
199
  header_t headers;      /* Received headers. */
 
200
};
 
201
 
 
202
 
 
203
 
 
204
 
 
205
#if defined(HAVE_W32_SYSTEM) && !defined(HTTP_NO_WSASTARTUP)
 
206
 
 
207
#if GNUPG_MAJOR_VERSION == 1
 
208
#define REQ_WINSOCK_MAJOR  1
 
209
#define REQ_WINSOCK_MINOR  1
 
210
#else
 
211
#define REQ_WINSOCK_MAJOR  2
 
212
#define REQ_WINSOCK_MINOR  2
 
213
#endif
 
214
 
 
215
 
 
216
static void
 
217
deinit_sockets (void)
 
218
{
 
219
  WSACleanup();
 
220
}
 
221
 
 
222
static void
 
223
init_sockets (void)
 
224
{
 
225
  static int initialized;
 
226
  static WSADATA wsdata;
 
227
 
 
228
  if (initialized)
 
229
    return;
 
230
 
 
231
  if ( WSAStartup( MAKEWORD (REQ_WINSOCK_MINOR, REQ_WINSOCK_MAJOR), &wsdata ) ) 
 
232
    {
 
233
      log_error ("error initializing socket library: ec=%d\n", 
 
234
                 (int)WSAGetLastError () );
 
235
      return;
 
236
    }
 
237
  if ( LOBYTE(wsdata.wVersion) != REQ_WINSOCK_MAJOR  
 
238
       || HIBYTE(wsdata.wVersion) != REQ_WINSOCK_MINOR ) 
 
239
    {
 
240
      log_error ("socket library version is %x.%x - but %d.%d needed\n",
 
241
                 LOBYTE(wsdata.wVersion), HIBYTE(wsdata.wVersion),
 
242
                 REQ_WINSOCK_MAJOR, REQ_WINSOCK_MINOR);
 
243
      WSACleanup();
 
244
      return;
 
245
    }
 
246
  atexit ( deinit_sockets );
 
247
  initialized = 1;
 
248
}
 
249
#endif /*HAVE_W32_SYSTEM && !HTTP_NO_WSASTARTUP*/
 
250
 
 
251
 
 
252
 
 
253
/*
 
254
 * Helper function to create an HTTP header with hex encoded data.  A
 
255
 * new buffer is returned.  This buffer is the concatenation of the
 
256
 * string PREFIX, the hex-encoded DATA of length LEN and the string
 
257
 * SUFFIX.  On error NULL is returned and ERRNO set.
 
258
 */
 
259
static char *
 
260
make_header_line (const char *prefix, const char *suffix,
 
261
                   const void *data, size_t len )
 
262
{
 
263
  static unsigned char bintoasc[] = 
 
264
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 
265
    "abcdefghijklmnopqrstuvwxyz"
 
266
    "0123456789+/";
 
267
  const unsigned int *s = data;
 
268
  char *buffer, *p;
 
269
 
 
270
  buffer = xtrymalloc (strlen (prefix) + (len+2)/3*4 + strlen (suffix) + 1);
 
271
  if (!buffer)
 
272
    return NULL;
 
273
  p = stpcpy (buffer, prefix);
 
274
  for ( ; len >= 3 ; len -= 3, s += 3 )
 
275
    {
 
276
      *p++ = bintoasc[(s[0] >> 2) & 077];
 
277
      *p++ = bintoasc[(((s[0] <<4)&060)|((s[1] >> 4)&017))&077];
 
278
      *p++ = bintoasc[(((s[1]<<2)&074)|((s[2]>>6)&03))&077];
 
279
      *p++ = bintoasc[s[2]&077];
 
280
    }
 
281
  if ( len == 2 ) 
 
282
    {
 
283
      *p++ = bintoasc[(s[0] >> 2) & 077];
 
284
      *p++ = bintoasc[(((s[0] <<4)&060)|((s[1] >> 4)&017))&077];
 
285
      *p++ = bintoasc[((s[1]<<2)&074)];
 
286
      *p++ = '=';
 
287
    }
 
288
  else if ( len == 1 )
 
289
    {
 
290
      *p++ = bintoasc[(s[0] >> 2) & 077];
 
291
      *p++ = bintoasc[(s[0] <<4)&060];
 
292
      *p++ = '=';
 
293
      *p++ = '=';
 
294
    }
 
295
  strcpy (p, suffix);
 
296
  return buffer;
 
297
}
 
298
 
 
299
 
 
300
 
 
301
 
 
302
void
 
303
http_register_tls_callback ( gpg_error_t (*cb) (http_t, void *, int) )
 
304
{
 
305
#ifdef HTTP_USE_GNUTLS
 
306
  tls_callback = (gpg_error_t (*) (http_t, gnutls_session_t, int))cb;
 
307
#endif  
 
308
}
 
309
 
 
310
 
 
311
 
 
312
/* Start a HTTP retrieval and return on success in R_HD a context
 
313
   pointer for completing the the request and to wait for the
 
314
   response. */
 
315
gpg_error_t
 
316
http_open (http_t *r_hd, http_req_t reqtype, const char *url, 
 
317
           const char *auth, unsigned int flags, const char *proxy,
 
318
           void *tls_context)
 
319
{
 
320
  gpg_error_t err;
 
321
  http_t hd;
 
322
  
 
323
  *r_hd = NULL;
 
324
 
 
325
  if (!(reqtype == HTTP_REQ_GET || reqtype == HTTP_REQ_POST))
 
326
    return gpg_error (GPG_ERR_INV_ARG);
 
327
 
 
328
  /* Create the handle. */
 
329
  hd = xtrycalloc (1, sizeof *hd);
 
330
  if (!hd)
 
331
    return gpg_error_from_syserror ();
 
332
  hd->sock = -1;
 
333
  hd->req_type = reqtype;
 
334
  hd->flags = flags;
 
335
  hd->tls_context = tls_context;
 
336
 
 
337
  err = http_parse_uri (&hd->uri, url);
 
338
  if (!err)
 
339
    err = send_request (hd, auth, proxy);
 
340
  
 
341
  if (err)
 
342
    {
 
343
      if (!hd->fp_read && !hd->fp_write && hd->sock != -1)
 
344
        sock_close (hd->sock);
 
345
      if (hd->fp_read)
 
346
        P_ES(fclose) (hd->fp_read);
 
347
      if (hd->fp_write)
 
348
        P_ES(fclose) (hd->fp_write);
 
349
      http_release_parsed_uri (hd->uri);
 
350
      xfree (hd);
 
351
    }
 
352
  else
 
353
    *r_hd = hd;
 
354
  return err;
 
355
}
 
356
 
 
357
 
 
358
void
 
359
http_start_data (http_t hd)
 
360
{
 
361
  if (!hd->in_data)
 
362
    {
 
363
#ifdef HTTP_USE_ESTREAM
 
364
      es_fputs ("\r\n", hd->fp_write);
 
365
      es_fflush (hd->fp_write);
 
366
#else
 
367
      fflush (hd->fp_write);
 
368
      write_server (hd->sock, "\r\n", 2);
 
369
#endif
 
370
      hd->in_data = 1;
 
371
    }
 
372
  else
 
373
    P_ES(fflush) (hd->fp_write);
 
374
}
 
375
 
 
376
 
 
377
gpg_error_t
 
378
http_wait_response (http_t hd)
 
379
{
 
380
  gpg_error_t err;
 
381
 
 
382
  /* Make sure that we are in the data. */
 
383
  http_start_data (hd); 
 
384
 
 
385
  /* We dup the socket, to cope with the fact that fclose closes the
 
386
     underlying socket. In TLS mode we don't do that because we can't
 
387
     close the socket gnutls is working on; instead we make sure that
 
388
     the fclose won't close the socket in this case. */
 
389
#ifdef HTTP_USE_ESTREAM
 
390
  if (hd->write_cookie)
 
391
    {
 
392
      /* The write cookie is only set in the TLS case. */
 
393
      cookie_t cookie = hd->write_cookie;
 
394
      cookie->keep_socket = 1;
 
395
    }
 
396
  else
 
397
#endif /*HTTP_USE_ESTREAM*/
 
398
    {
 
399
      hd->sock = dup (hd->sock);
 
400
      if (hd->sock == -1)
 
401
        return gpg_error_from_syserror ();
 
402
    }
 
403
  P_ES(fclose) (hd->fp_write);
 
404
  hd->fp_write = NULL;
 
405
#ifdef HTTP_USE_ESTREAM
 
406
  hd->write_cookie = NULL;
 
407
#endif
 
408
 
 
409
  if (!(hd->flags & HTTP_FLAG_NO_SHUTDOWN))
 
410
    shutdown (hd->sock, 1);
 
411
  hd->in_data = 0;
 
412
 
 
413
#ifdef HTTP_USE_ESTREAM
 
414
  {
 
415
    cookie_t cookie;
 
416
 
 
417
    cookie = xtrycalloc (1, sizeof *cookie);
 
418
    if (!cookie)
 
419
      return gpg_error_from_syserror ();
 
420
    cookie->fd = hd->sock;
 
421
    if (hd->uri->use_tls)
 
422
      cookie->tls_session = hd->tls_context;
 
423
 
 
424
    hd->fp_read = es_fopencookie (cookie, "r", cookie_functions);
 
425
    if (!hd->fp_read)
 
426
      {
 
427
        xfree (cookie);
 
428
        return gpg_error_from_syserror ();
 
429
      }
 
430
  }
 
431
#else /*!HTTP_USE_ESTREAM*/
 
432
  hd->fp_read = fdopen (hd->sock, "r");
 
433
  if (!hd->fp_read)
 
434
    return gpg_error_from_syserror ();
 
435
#endif /*!HTTP_USE_ESTREAM*/
 
436
 
 
437
  err = parse_response (hd);
 
438
  return err;
 
439
}
 
440
 
 
441
 
 
442
/* Convenience function to send a request and wait for the response.
 
443
   Closes the handle on error.  If PROXY is not NULL, this value will
 
444
   be used as an HTTP proxy and any enabled $http_proxy gets
 
445
   ignored. */
 
446
gpg_error_t
 
447
http_open_document (http_t *r_hd, const char *document, 
 
448
                    const char *auth, unsigned int flags, const char *proxy,
 
449
                    void *tls_context)
 
450
{
 
451
  gpg_error_t err;
 
452
 
 
453
  err = http_open (r_hd, HTTP_REQ_GET, document, auth, flags,
 
454
                   proxy, tls_context);
 
455
  if (err)
 
456
    return err;
 
457
 
 
458
  err = http_wait_response (*r_hd);
 
459
  if (err)
 
460
    http_close (*r_hd, 0);
 
461
 
 
462
  return err;
 
463
}
 
464
 
 
465
 
 
466
void
 
467
http_close (http_t hd, int keep_read_stream)
 
468
{
 
469
  if (!hd)
 
470
    return;
 
471
  if (!hd->fp_read && !hd->fp_write && hd->sock != -1)
 
472
    sock_close (hd->sock);
 
473
  if (hd->fp_read && !keep_read_stream)
 
474
    P_ES(fclose) (hd->fp_read);
 
475
  if (hd->fp_write)
 
476
    P_ES(fclose) (hd->fp_write);
 
477
  http_release_parsed_uri (hd->uri);
 
478
  while (hd->headers)
 
479
    {
 
480
      header_t tmp = hd->headers->next;
 
481
      xfree (hd->headers->value);
 
482
      xfree (hd->headers);
 
483
      hd->headers = tmp;
 
484
    }
 
485
  xfree (hd->buffer);
 
486
  xfree (hd);
 
487
}
 
488
 
 
489
 
 
490
#ifdef HTTP_USE_ESTREAM
 
491
estream_t
 
492
http_get_read_ptr (http_t hd)
 
493
{
 
494
  return hd?hd->fp_read:NULL;
 
495
}
 
496
estream_t
 
497
http_get_write_ptr (http_t hd)
 
498
{
 
499
  return hd?hd->fp_write:NULL;
 
500
}
 
501
#else /*!HTTP_USE_ESTREAM*/
 
502
FILE *
 
503
http_get_read_ptr (http_t hd)
 
504
{
 
505
  return hd?hd->fp_read:NULL;
 
506
}
 
507
FILE *
 
508
http_get_write_ptr (http_t hd)
 
509
{
 
510
  return hd?hd->fp_write:NULL;
 
511
}
 
512
#endif /*!HTTP_USE_ESTREAM*/
 
513
unsigned int
 
514
http_get_status_code (http_t hd)
 
515
{
 
516
  return hd?hd->status_code:0;
 
517
}
 
518
 
 
519
 
 
520
 
 
521
/*
 
522
 * Parse an URI and put the result into the newly allocated RET_URI.
 
523
 * The caller must always use release_parsed_uri() to releases the
 
524
 * resources (even on error).
 
525
 */
 
526
gpg_error_t
 
527
http_parse_uri (parsed_uri_t * ret_uri, const char *uri)
 
528
{
 
529
  *ret_uri = xcalloc (1, sizeof **ret_uri + strlen (uri));
 
530
  strcpy ((*ret_uri)->buffer, uri);
 
531
  return do_parse_uri (*ret_uri, 0);
 
532
}
 
533
 
 
534
void
 
535
http_release_parsed_uri (parsed_uri_t uri)
 
536
{
 
537
  if (uri)
 
538
    {
 
539
      uri_tuple_t r, r2;
 
540
 
 
541
      for (r = uri->query; r; r = r2)
 
542
        {
 
543
          r2 = r->next;
 
544
          xfree (r);
 
545
        }
 
546
      xfree (uri);
 
547
    }
 
548
}
 
549
 
 
550
 
 
551
static gpg_error_t
 
552
do_parse_uri (parsed_uri_t uri, int only_local_part)
 
553
{
 
554
  uri_tuple_t *tail;
 
555
  char *p, *p2, *p3, *pp;
 
556
  int n;
 
557
 
 
558
  p = uri->buffer;
 
559
  n = strlen (uri->buffer);
 
560
 
 
561
  /* Initialize all fields to an empty string or an empty list. */
 
562
  uri->scheme = uri->host = uri->path = p + n;
 
563
  uri->port = 0;
 
564
  uri->params = uri->query = NULL;
 
565
  uri->use_tls = 0;
 
566
 
 
567
  /* A quick validity check. */
 
568
  if (strspn (p, VALID_URI_CHARS) != n)
 
569
    return gpg_error (GPG_ERR_BAD_URI); /* Invalid characters found. */
 
570
 
 
571
  if (!only_local_part)
 
572
    {
 
573
      /* Find the scheme. */
 
574
      if (!(p2 = strchr (p, ':')) || p2 == p)
 
575
        return gpg_error (GPG_ERR_BAD_URI); /* No scheme. */
 
576
      *p2++ = 0;
 
577
      for (pp=p; *pp; pp++)
 
578
       *pp = tolower (*(unsigned char*)pp);
 
579
      uri->scheme = p;
 
580
      if (!strcmp (uri->scheme, "http"))
 
581
        uri->port = 80;
 
582
#ifdef HTTP_USE_GNUTLS
 
583
      else if (!strcmp (uri->scheme, "https"))
 
584
        {
 
585
          uri->port = 443;
 
586
          uri->use_tls = 1;
 
587
        }
 
588
#endif
 
589
      else
 
590
        return gpg_error (GPG_ERR_INV_URI); /* Unsupported scheme */
 
591
 
 
592
      p = p2;
 
593
 
 
594
      /* Find the hostname */
 
595
      if (*p != '/')
 
596
        return gpg_error (GPG_ERR_INV_URI); /* Does not start with a slash. */
 
597
 
 
598
      p++;
 
599
      if (*p == '/') /* There seems to be a hostname. */
 
600
        { 
 
601
          p++;
 
602
          if ((p2 = strchr (p, '/')))
 
603
            *p2++ = 0;
 
604
 
 
605
          /* Check for username/password encoding */
 
606
          if ((p3 = strchr (p, '@')))
 
607
            {
 
608
              uri->auth = p;
 
609
              *p3++ = '\0';
 
610
              p = p3;
 
611
            }
 
612
 
 
613
          for (pp=p; *pp; pp++)
 
614
            *pp = tolower (*(unsigned char*)pp);
 
615
          uri->host = p;
 
616
          if ((p3 = strchr (p, ':')))
 
617
            {
 
618
              *p3++ = 0;
 
619
              uri->port = atoi (p3);
 
620
            }
 
621
 
 
622
          uri->host = p;
 
623
          if ((n = remove_escapes (uri->host)) < 0)
 
624
            return gpg_error (GPG_ERR_BAD_URI);
 
625
          if (n != strlen (p))
 
626
            return gpg_error (GPG_ERR_BAD_URI); /* Hostname incudes a Nul. */
 
627
          p = p2 ? p2 : NULL;
 
628
        }
 
629
    } /* End global URI part. */
 
630
 
 
631
  /* Parse the pathname part */
 
632
  if (!p || !*p)
 
633
    return 0;  /* We don't have a path.  Okay. */
 
634
 
 
635
  /* TODO: Here we have to check params. */
 
636
 
 
637
  /* Do we have a query part? */
 
638
  if ((p2 = strchr (p, '?')))
 
639
    *p2++ = 0;
 
640
 
 
641
  uri->path = p;
 
642
  if ((n = remove_escapes (p)) < 0)
 
643
    return gpg_error (GPG_ERR_BAD_URI);
 
644
  if (n != strlen (p))
 
645
    return gpg_error (GPG_ERR_BAD_URI); /* Path includes a Nul. */
 
646
  p = p2 ? p2 : NULL;
 
647
 
 
648
  if (!p || !*p)        
 
649
    return 0; /* We don't have a query string.  Okay. */
 
650
 
 
651
  /* Now parse the query string. */
 
652
  tail = &uri->query;
 
653
  for (;;)
 
654
    {
 
655
      uri_tuple_t elem;
 
656
 
 
657
      if ((p2 = strchr (p, '&')))
 
658
        *p2++ = 0;
 
659
      if (!(elem = parse_tuple (p)))
 
660
        return gpg_error (GPG_ERR_BAD_URI);
 
661
      *tail = elem;
 
662
      tail = &elem->next;
 
663
 
 
664
      if (!p2)
 
665
        break; /* Ready. */
 
666
      p = p2;
 
667
    }
 
668
 
 
669
  return 0;
 
670
}
 
671
 
 
672
 
 
673
/*
 
674
 * Remove all %xx escapes; this is done in-place.  Returns: New length
 
675
 * of the string.
 
676
 */
 
677
static int
 
678
remove_escapes (char *string)
 
679
{
 
680
  int n = 0;
 
681
  unsigned char *p, *s;
 
682
 
 
683
  for (p = s = (unsigned char*)string; *s; s++)
 
684
    {
 
685
      if (*s == '%')
 
686
        {
 
687
          if (s[1] && s[2] && isxdigit (s[1]) && isxdigit (s[2]))
 
688
            {
 
689
              s++;
 
690
              *p = *s >= '0' && *s <= '9' ? *s - '0' :
 
691
                *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10;
 
692
              *p <<= 4;
 
693
              s++;
 
694
              *p |= *s >= '0' && *s <= '9' ? *s - '0' :
 
695
                *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10;
 
696
              p++;
 
697
              n++;
 
698
            }
 
699
          else
 
700
            {
 
701
              *p++ = *s++;
 
702
              if (*s)
 
703
                *p++ = *s++;
 
704
              if (*s)
 
705
                *p++ = *s++;
 
706
              if (*s)
 
707
                *p = 0;
 
708
              return -1; /* Bad URI. */
 
709
            }
 
710
        }
 
711
      else
 
712
        {
 
713
          *p++ = *s;
 
714
          n++;
 
715
        }
 
716
    }
 
717
  *p = 0; /* Make sure to keep a string terminator. */
 
718
  return n;
 
719
}
 
720
 
 
721
 
 
722
static int
 
723
insert_escapes (char *buffer, const char *string,
 
724
                const char *special)
 
725
{
 
726
  const unsigned char *s = (const unsigned char*)string;
 
727
  int n = 0;
 
728
 
 
729
  for (; *s; s++)
 
730
    {
 
731
      if (strchr (VALID_URI_CHARS, *s) && !strchr (special, *s))
 
732
        {
 
733
          if (buffer)
 
734
            *(unsigned char*)buffer++ = *s;
 
735
          n++;
 
736
        }
 
737
      else
 
738
        {
 
739
          if (buffer)
 
740
            {
 
741
              sprintf (buffer, "%%%02X", *s);
 
742
              buffer += 3;
 
743
            }
 
744
          n += 3;
 
745
        }
 
746
    }
 
747
  return n;
 
748
}
 
749
 
 
750
 
 
751
/* Allocate a new string from STRING using standard HTTP escaping as
 
752
   well as escaping of characters given in SPECIALS.  A common pattern
 
753
   for SPECIALS is "%;?&=". However it depends on the needs, for
 
754
   example "+" and "/: often needs to be escaped too.  Returns NULL on
 
755
   failure and sets ERRNO. */
 
756
char *
 
757
http_escape_string (const char *string, const char *specials)
 
758
{
 
759
  int n;
 
760
  char *buf;
 
761
 
 
762
  n = insert_escapes (NULL, string, specials);
 
763
  buf = xtrymalloc (n+1);
 
764
  if (buf)
 
765
    {
 
766
      insert_escapes (buf, string, specials);
 
767
      buf[n] = 0;
 
768
    }
 
769
  return buf;
 
770
}
 
771
 
 
772
 
 
773
 
 
774
static uri_tuple_t
 
775
parse_tuple (char *string)
 
776
{
 
777
  char *p = string;
 
778
  char *p2;
 
779
  int n;
 
780
  uri_tuple_t tuple;
 
781
 
 
782
  if ((p2 = strchr (p, '=')))
 
783
    *p2++ = 0;
 
784
  if ((n = remove_escapes (p)) < 0)
 
785
    return NULL; /* Bad URI. */
 
786
  if (n != strlen (p))
 
787
    return NULL; /* Name with a Nul in it. */
 
788
  tuple = xtrycalloc (1, sizeof *tuple);
 
789
  if (!tuple)
 
790
    return NULL; /* Out of core. */
 
791
  tuple->name = p;
 
792
  if (!p2) /* We have only the name, so we assume an empty value string. */
 
793
    {
 
794
      tuple->value = p + strlen (p);
 
795
      tuple->valuelen = 0;
 
796
      tuple->no_value = 1; /* Explicitly mark that we have seen no '='. */
 
797
    }
 
798
  else /* Name and value. */
 
799
    {
 
800
      if ((n = remove_escapes (p2)) < 0)
 
801
        {
 
802
          xfree (tuple);
 
803
          return NULL; /* Bad URI. */
 
804
        }
 
805
      tuple->value = p2;
 
806
      tuple->valuelen = n;
 
807
    }
 
808
  return tuple;
 
809
}
 
810
 
 
811
 
 
812
/*
 
813
 * Send a HTTP request to the server
 
814
 * Returns 0 if the request was successful
 
815
 */
 
816
static gpg_error_t
 
817
send_request (http_t hd, const char *auth, const char *proxy)
 
818
{
 
819
  gnutls_session_t tls_session;
 
820
  gpg_error_t err;
 
821
  const char *server;
 
822
  char *request, *p;
 
823
  unsigned short port;
 
824
  const char *http_proxy = NULL;
 
825
  char *proxy_authstr = NULL;
 
826
  char *authstr = NULL;
 
827
  int save_errno;
 
828
 
 
829
  tls_session = hd->tls_context;
 
830
  if (hd->uri->use_tls && !tls_session)
 
831
    {
 
832
      log_error ("TLS requested but no GNUTLS context provided\n");
 
833
      return gpg_error (GPG_ERR_INTERNAL);
 
834
    }
 
835
 
 
836
  server = *hd->uri->host ? hd->uri->host : "localhost";
 
837
  port = hd->uri->port ? hd->uri->port : 80;
 
838
 
 
839
  if ( (proxy && *proxy)
 
840
       || ( (hd->flags & HTTP_FLAG_TRY_PROXY)
 
841
            && (http_proxy = getenv (HTTP_PROXY_ENV)) 
 
842
            && *http_proxy ))
 
843
    {
 
844
      parsed_uri_t uri;
 
845
 
 
846
      if (proxy)
 
847
        http_proxy = proxy;
 
848
 
 
849
      err = http_parse_uri (&uri, http_proxy);
 
850
      if (err)
 
851
        {
 
852
          log_error ("invalid HTTP proxy (%s): %s\n",
 
853
                     http_proxy, gpg_strerror (err));
 
854
          http_release_parsed_uri (uri);
 
855
          return gpg_error (GPG_ERR_CONFIGURATION);
 
856
 
 
857
        }
 
858
 
 
859
      if (uri->auth)
 
860
        {
 
861
          remove_escapes (uri->auth);
 
862
          proxy_authstr = make_header_line ("Proxy-Authorization: Basic ",
 
863
                                            "\r\n",
 
864
                                            uri->auth, strlen(uri->auth));
 
865
          if (!proxy_authstr)
 
866
            {
 
867
              err = gpg_error_from_syserror ();
 
868
              http_release_parsed_uri (uri);
 
869
              return err;
 
870
            }
 
871
        }
 
872
 
 
873
      hd->sock = connect_server (*uri->host ? uri->host : "localhost",
 
874
                                 uri->port ? uri->port : 80,
 
875
                                 hd->flags, hd->uri->scheme);
 
876
      save_errno = errno;
 
877
      http_release_parsed_uri (uri);
 
878
    }
 
879
  else
 
880
    {
 
881
      hd->sock = connect_server (server, port, hd->flags, hd->uri->scheme);
 
882
      save_errno = errno;
 
883
    }
 
884
 
 
885
  if (hd->sock == -1)
 
886
    {
 
887
      xfree (proxy_authstr);
 
888
      return (save_errno 
 
889
              ? gpg_error_from_errno (save_errno)
 
890
              : gpg_error (GPG_ERR_NOT_FOUND));
 
891
    }
 
892
 
 
893
#ifdef HTTP_USE_GNUTLS
 
894
  if (hd->uri->use_tls)
 
895
    {
 
896
      int rc;
 
897
 
 
898
      gnutls_transport_set_ptr (tls_session, (gnutls_transport_ptr_t)hd->sock);
 
899
      do
 
900
        {
 
901
          rc = gnutls_handshake (tls_session);
 
902
        }
 
903
      while (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN);
 
904
      if (rc < 0)
 
905
        {
 
906
          log_info ("TLS handshake failed: %s\n", gnutls_strerror (rc));
 
907
          xfree (proxy_authstr);
 
908
          return gpg_error (GPG_ERR_NETWORK);
 
909
        }
 
910
 
 
911
      if (tls_callback)
 
912
        {
 
913
          err = tls_callback (hd, tls_session, 0);
 
914
          if (err)
 
915
            {
 
916
              log_info ("TLS connection authentication failed: %s\n",
 
917
                        gpg_strerror (err));
 
918
              xfree (proxy_authstr);
 
919
              return err;
 
920
            }
 
921
        }
 
922
    }
 
923
#endif /*HTTP_USE_GNUTLS*/
 
924
 
 
925
  if (auth || hd->uri->auth)
 
926
    {
 
927
      char *myauth;
 
928
      
 
929
      if (auth)
 
930
        {
 
931
          myauth = xtrystrdup (auth);
 
932
          if (!myauth)
 
933
            {
 
934
              xfree (proxy_authstr);
 
935
              return gpg_error_from_syserror ();
 
936
            }
 
937
          remove_escapes (myauth);
 
938
        }
 
939
      else
 
940
        {
 
941
          remove_escapes (hd->uri->auth);
 
942
          myauth = hd->uri->auth;
 
943
        }
 
944
 
 
945
      authstr = make_header_line ("Authorization: Basic %s", "\r\n",
 
946
                                  myauth, strlen (myauth));
 
947
      if (auth)
 
948
        xfree (myauth);
 
949
 
 
950
      if (!authstr)
 
951
        {
 
952
          xfree (proxy_authstr);
 
953
          return gpg_error_from_syserror ();
 
954
        }
 
955
    }
 
956
  
 
957
  p = build_rel_path (hd->uri);
 
958
  if (!p)
 
959
    return gpg_error_from_syserror ();
 
960
 
 
961
  request = xtrymalloc (2 * strlen (server) 
 
962
                        + strlen (p)
 
963
                        + (authstr?strlen(authstr):0)
 
964
                        + (proxy_authstr?strlen(proxy_authstr):0)
 
965
                        + 100);
 
966
  if (!request)
 
967
    {
 
968
      err = gpg_error_from_syserror ();
 
969
      xfree (p);
 
970
      xfree (authstr);
 
971
      xfree (proxy_authstr);
 
972
      return err;
 
973
    }
 
974
 
 
975
  if (http_proxy && *http_proxy)
 
976
    {
 
977
      sprintf (request, "%s http://%s:%hu%s%s HTTP/1.0\r\n%s%s",
 
978
               hd->req_type == HTTP_REQ_GET ? "GET" :
 
979
               hd->req_type == HTTP_REQ_HEAD ? "HEAD" :
 
980
               hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS",
 
981
               server, port, *p == '/' ? "" : "/", p,
 
982
               authstr ? authstr : "",
 
983
               proxy_authstr ? proxy_authstr : "");
 
984
    }
 
985
  else
 
986
    {
 
987
      char portstr[35];
 
988
        
 
989
      if (port == 80)
 
990
        *portstr = 0;
 
991
      else
 
992
        sprintf (portstr, ":%u", port);
 
993
 
 
994
      sprintf (request, "%s %s%s HTTP/1.0\r\nHost: %s%s\r\n%s",
 
995
               hd->req_type == HTTP_REQ_GET ? "GET" :
 
996
               hd->req_type == HTTP_REQ_HEAD ? "HEAD" :
 
997
               hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS",
 
998
               *p == '/' ? "" : "/", p, server, portstr,
 
999
               authstr? authstr:"");
 
1000
    }
 
1001
  xfree (p);
 
1002
 
 
1003
 
 
1004
#ifdef HTTP_USE_ESTREAM
 
1005
  /* First setup estream so that we can write even the first line
 
1006
     using estream.  This is also required for the sake of gnutls. */
 
1007
  {
 
1008
    cookie_t cookie;
 
1009
 
 
1010
    cookie = xtrycalloc (1, sizeof *cookie);
 
1011
    if (!cookie)
 
1012
      {
 
1013
        err = gpg_error_from_syserror ();
 
1014
        goto leave;
 
1015
      }
 
1016
    cookie->fd = hd->sock;
 
1017
    if (hd->uri->use_tls)
 
1018
      {
 
1019
        cookie->tls_session = tls_session;
 
1020
        hd->write_cookie = cookie;
 
1021
      }
 
1022
 
 
1023
    hd->fp_write = es_fopencookie (cookie, "w", cookie_functions);
 
1024
    if (!hd->fp_write)
 
1025
      {
 
1026
        xfree (cookie);
 
1027
        err = gpg_error_from_syserror ();
 
1028
      }
 
1029
    else if (es_fputs (request, hd->fp_write) || es_fflush (hd->fp_write))
 
1030
      err = gpg_error_from_syserror ();
 
1031
    else
 
1032
      err = 0;
 
1033
  }
 
1034
 
 
1035
 leave:
 
1036
 
 
1037
#else /*!HTTP_USE_ESTREAM*/
 
1038
  /* We send out the start of the request through our own send
 
1039
     function and only then assign a stdio stream.  This allows for
 
1040
     better error reporting that through standard stdio means. */
 
1041
  err = write_server (hd->sock, request, strlen (request));
 
1042
  if (!err)
 
1043
    {
 
1044
      hd->fp_write = fdopen (hd->sock, "w");
 
1045
      if (!hd->fp_write)
 
1046
        err = gpg_error_from_syserror ();
 
1047
    }
 
1048
#endif /*!HTTP_USE_ESTREAM*/
 
1049
 
 
1050
  xfree (request);
 
1051
  xfree (authstr);
 
1052
  xfree (proxy_authstr);
 
1053
 
 
1054
  return err;
 
1055
}
 
1056
 
 
1057
 
 
1058
/*
 
1059
 * Build the relative path from the parsed URI.  Minimal
 
1060
 * implementation.  May return NULL in case of memory failure; errno
 
1061
 * is then set accordingly.
 
1062
 */
 
1063
static char *
 
1064
build_rel_path (parsed_uri_t uri)
 
1065
{
 
1066
  uri_tuple_t r;
 
1067
  char *rel_path, *p;
 
1068
  int n;
 
1069
 
 
1070
  /* Count the needed space. */
 
1071
  n = insert_escapes (NULL, uri->path, "%;?&");
 
1072
  /* TODO: build params. */
 
1073
  for (r = uri->query; r; r = r->next)
 
1074
    {
 
1075
      n++; /* '?'/'&' */
 
1076
      n += insert_escapes (NULL, r->name, "%;?&=");
 
1077
      if (!r->no_value)
 
1078
        {
 
1079
          n++; /* '=' */
 
1080
          n += insert_escapes (NULL, r->value, "%;?&=");
 
1081
        }
 
1082
    }
 
1083
  n++;
 
1084
 
 
1085
  /* Now allocate and copy. */
 
1086
  p = rel_path = xtrymalloc (n);
 
1087
  if (!p)
 
1088
    return NULL;
 
1089
  n = insert_escapes (p, uri->path, "%;?&");
 
1090
  p += n;
 
1091
  /* TODO: add params. */
 
1092
  for (r = uri->query; r; r = r->next)
 
1093
    {
 
1094
      *p++ = r == uri->query ? '?' : '&';
 
1095
      n = insert_escapes (p, r->name, "%;?&=");
 
1096
      p += n;
 
1097
      if (!r->no_value)
 
1098
        {
 
1099
          *p++ = '=';
 
1100
          /* TODO: Use valuelen. */
 
1101
          n = insert_escapes (p, r->value, "%;?&=");
 
1102
          p += n;
 
1103
        }
 
1104
    }
 
1105
  *p = 0;
 
1106
  return rel_path;
 
1107
}
 
1108
 
 
1109
 
 
1110
 
 
1111
/*
 
1112
   Same as fgets() but if the buffer is too short a larger one will be
 
1113
   allocated up to some limit *MAX_LENGTH.  A line is considered a
 
1114
   byte stream ending in a LF.  Returns the length of the line. EOF is
 
1115
   indicated by a line of length zero. The last LF may be missing due
 
1116
   to an EOF.  If MAX_LENGTH is zero on return, the line has been
 
1117
   truncated.  If the returned buffer is NULL, not enough memory was
 
1118
   enable to increase it, the return value will also be 0 and some
 
1119
   bytes might have been lost which should be no problem becuase
 
1120
   out-of-memory is pretty fatal for most applications.
 
1121
 
 
1122
   If a line has been truncated, the file pointer is internally moved
 
1123
   forward to the end of the line.
 
1124
 
 
1125
   Note: The returned buffer is allocated with enough extra space to
 
1126
   append a CR,LF,Nul
 
1127
 */
 
1128
static size_t
 
1129
my_read_line (
 
1130
#ifdef HTTP_USE_ESTREAM
 
1131
              estream_t fp,
 
1132
#else
 
1133
              FILE *fp,
 
1134
#endif
 
1135
              char **addr_of_buffer,
 
1136
              size_t *length_of_buffer, size_t *max_length)
 
1137
{
 
1138
  int c;
 
1139
  char *buffer = *addr_of_buffer;
 
1140
  size_t length = *length_of_buffer;
 
1141
  size_t nbytes = 0;
 
1142
  size_t maxlen = *max_length;
 
1143
  char *p;
 
1144
 
 
1145
  if (!buffer) /* Must allocate a new buffer. */
 
1146
    {           
 
1147
      length = 256;
 
1148
      buffer = xtrymalloc (length);
 
1149
      *addr_of_buffer = buffer;
 
1150
      if (!buffer)
 
1151
        {
 
1152
          *length_of_buffer = *max_length = 0;
 
1153
          return 0;
 
1154
        }
 
1155
      *length_of_buffer = length;
 
1156
    }
 
1157
 
 
1158
  length -= 3; /* Reserve 3 bytes (cr,lf,eol). */
 
1159
  p = buffer;
 
1160
  while ((c = P_ES(getc) (fp)) != EOF)
 
1161
    {
 
1162
      if (nbytes == length) /* Increase the buffer. */
 
1163
        {                       
 
1164
          if (length > maxlen) /* Limit reached. */
 
1165
            {
 
1166
              /* Skip the rest of the line. */
 
1167
              while (c != '\n' && (c = P_ES(getc) (fp)) != EOF)
 
1168
                ;
 
1169
              *p++ = '\n'; /* Always append a LF (we reserved some space). */
 
1170
              nbytes++;
 
1171
              *max_length = 0; /* Indicate truncation */
 
1172
              break; /*(the while loop)*/
 
1173
            }
 
1174
          length += 3; /* Adjust for the reserved bytes. */
 
1175
          length += length < 1024 ? 256 : 1024;
 
1176
          *addr_of_buffer = xtryrealloc (buffer, length);
 
1177
          if (!*addr_of_buffer)
 
1178
            {
 
1179
              int save_errno = errno;
 
1180
              xfree (buffer);
 
1181
              *length_of_buffer = *max_length = 0;
 
1182
              errno = save_errno;
 
1183
              return 0;
 
1184
            }
 
1185
          buffer = *addr_of_buffer;
 
1186
          *length_of_buffer = length;
 
1187
          length -= 3; /* And re-adjust for the reservation. */
 
1188
          p = buffer + nbytes;
 
1189
        }
 
1190
      *p++ = c;
 
1191
      nbytes++;
 
1192
      if (c == '\n')
 
1193
        break;
 
1194
    }
 
1195
  *p = 0; /* Make sure the line is a string. */
 
1196
 
 
1197
  return nbytes;
 
1198
}
 
1199
 
 
1200
 
 
1201
/* Transform a header name into a standard capitalized format; e.g.
 
1202
   "Content-Type".  Conversion stops at the colon.  As usual we don't
 
1203
   use the localized versions of ctype.h. */
 
1204
static void
 
1205
capitalize_header_name (char *name)
 
1206
{
 
1207
  int first = 1;
 
1208
 
 
1209
  for (; *name && *name != ':'; name++)
 
1210
    {
 
1211
      if (*name == '-')
 
1212
        first = 1;
 
1213
      else if (first)
 
1214
        {
 
1215
          if (*name >= 'a' && *name <= 'z')
 
1216
            *name = *name - 'a' + 'A';
 
1217
          first = 0;
 
1218
        }
 
1219
      else if (*name >= 'A' && *name <= 'Z')
 
1220
        *name = *name - 'A' + 'a';
 
1221
    }
 
1222
}
 
1223
 
 
1224
 
 
1225
/* Store an HTTP header line in LINE away.  Line continuation is
 
1226
   supported as well as merging of headers with the same name. This
 
1227
   function may modify LINE. */
 
1228
static gpg_error_t
 
1229
store_header (http_t hd, char *line)
 
1230
{
 
1231
  size_t n;
 
1232
  char *p, *value;
 
1233
  header_t h;
 
1234
 
 
1235
  n = strlen (line);
 
1236
  if (n && line[n-1] == '\n')
 
1237
    {
 
1238
      line[--n] = 0;
 
1239
      if (n && line[n-1] == '\r')
 
1240
        line[--n] = 0;
 
1241
    }
 
1242
  if (!n)  /* we are never called to hit this. */
 
1243
    return gpg_error (GPG_ERR_BUG);
 
1244
  if (*line == ' ' || *line == '\t')
 
1245
    {
 
1246
      /* Continuation. This won't happen too often as it is not
 
1247
         recommended.  We use a straightforward implementaion. */
 
1248
      if (!hd->headers)
 
1249
        return gpg_error (GPG_ERR_PROTOCOL_VIOLATION);
 
1250
      n += strlen (hd->headers->value);
 
1251
      p = xtrymalloc (n+1);
 
1252
      if (!p)
 
1253
        return gpg_error_from_syserror ();
 
1254
      strcpy (stpcpy (p, hd->headers->value), line);
 
1255
      xfree (hd->headers->value);
 
1256
      hd->headers->value = p;
 
1257
      return 0;
 
1258
    }
 
1259
 
 
1260
  capitalize_header_name (line);
 
1261
  p = strchr (line, ':');
 
1262
  if (!p)
 
1263
    return gpg_error (GPG_ERR_PROTOCOL_VIOLATION);
 
1264
  *p++ = 0;
 
1265
  while (*p == ' ' || *p == '\t')
 
1266
    p++;
 
1267
  value = p;
 
1268
  
 
1269
  for (h=hd->headers; h; h = h->next)
 
1270
    if ( !strcmp (h->name, line) )
 
1271
      break;
 
1272
  if (h)
 
1273
    {
 
1274
      /* We have already seen a line with that name.  Thus we assume
 
1275
         it is a comma separated list and merge them.  */
 
1276
      p = xtrymalloc (strlen (h->value) + 1 + strlen (value)+ 1);
 
1277
      if (!p)
 
1278
        return gpg_error_from_syserror ();
 
1279
      strcpy (stpcpy (stpcpy (p, h->value), ","), value);
 
1280
      xfree (h->value);
 
1281
      h->value = p;
 
1282
      return 0;
 
1283
    }
 
1284
 
 
1285
  /* Append a new header. */
 
1286
  h = xtrymalloc (sizeof *h + strlen (line));
 
1287
  if (!h)
 
1288
    return gpg_error_from_syserror ();
 
1289
  strcpy (h->name, line);
 
1290
  h->value = xtrymalloc (strlen (value)+1);
 
1291
  if (!h->value)
 
1292
    {
 
1293
      xfree (h);
 
1294
      return gpg_error_from_syserror ();
 
1295
    }
 
1296
  strcpy (h->value, value);
 
1297
  h->next = hd->headers;
 
1298
  hd->headers = h;
 
1299
 
 
1300
  return 0;
 
1301
}
 
1302
 
 
1303
 
 
1304
/* Return the header NAME from the last response.  The returned value
 
1305
   is valid as along as HD has not been closed and no othe request has
 
1306
   been send. If the header was not found, NULL is returned.  Name
 
1307
   must be canonicalized, that is the first letter of each dash
 
1308
   delimited part must be uppercase and all other letters lowercase.
 
1309
   Note that the context must have been opened with the
 
1310
   HTTP_FLAG_NEED_HEADER. */
 
1311
const char *
 
1312
http_get_header (http_t hd, const char *name)
 
1313
{
 
1314
  header_t h;
 
1315
 
 
1316
  for (h=hd->headers; h; h = h->next)
 
1317
    if ( !strcmp (h->name, name) )
 
1318
      return h->value;
 
1319
  return NULL;
 
1320
}
 
1321
 
 
1322
 
 
1323
 
 
1324
/*
 
1325
 * Parse the response from a server.
 
1326
 * Returns: Errorcode and sets some files in the handle
 
1327
 */
 
1328
static gpg_error_t
 
1329
parse_response (http_t hd)
 
1330
{
 
1331
  char *line, *p, *p2;
 
1332
  size_t maxlen, len;
 
1333
 
 
1334
  /* Delete old header lines.  */
 
1335
  while (hd->headers)
 
1336
    {
 
1337
      header_t tmp = hd->headers->next;
 
1338
      xfree (hd->headers->value);
 
1339
      xfree (hd->headers);
 
1340
      hd->headers = tmp;
 
1341
    }
 
1342
 
 
1343
  /* Wait for the status line. */
 
1344
  do
 
1345
    {
 
1346
      maxlen = MAX_LINELEN;
 
1347
      len = my_read_line (hd->fp_read, &hd->buffer, &hd->buffer_size, &maxlen);
 
1348
      line = hd->buffer;
 
1349
      if (!line)
 
1350
        return gpg_error_from_syserror (); /* Out of core. */
 
1351
      if (!maxlen)
 
1352
        return gpg_error (GPG_ERR_TRUNCATED); /* Line has been truncated. */
 
1353
      if (!len)
 
1354
        return gpg_error (GPG_ERR_EOF);
 
1355
      if ( (hd->flags & HTTP_FLAG_LOG_RESP) )
 
1356
        log_info ("RESP: `%.*s'\n",
 
1357
                  (int)strlen(line)-(*line&&line[1]?2:0),line);
 
1358
    }
 
1359
  while (!*line);
 
1360
 
 
1361
  if ((p = strchr (line, '/')))
 
1362
    *p++ = 0;
 
1363
  if (!p || strcmp (line, "HTTP"))
 
1364
    return 0; /* Assume http 0.9. */
 
1365
 
 
1366
  if ((p2 = strpbrk (p, " \t")))
 
1367
    {
 
1368
      *p2++ = 0;
 
1369
      p2 += strspn (p2, " \t");
 
1370
    }
 
1371
  if (!p2)
 
1372
    return 0; /* Also assume http 0.9. */
 
1373
  p = p2;
 
1374
  /* TODO: Add HTTP version number check. */
 
1375
  if ((p2 = strpbrk (p, " \t")))
 
1376
    *p2++ = 0;
 
1377
  if (!isdigit ((unsigned int)p[0]) || !isdigit ((unsigned int)p[1])
 
1378
      || !isdigit ((unsigned int)p[2]) || p[3])
 
1379
    {
 
1380
      /* Malformed HTTP status code - assume http 0.9. */
 
1381
      hd->is_http_0_9 = 1;
 
1382
      hd->status_code = 200;
 
1383
      return 0;
 
1384
    }
 
1385
  hd->status_code = atoi (p);
 
1386
 
 
1387
  /* Skip all the header lines and wait for the empty line. */
 
1388
  do
 
1389
    {
 
1390
      maxlen = MAX_LINELEN;
 
1391
      len = my_read_line (hd->fp_read, &hd->buffer, &hd->buffer_size, &maxlen);
 
1392
      line = hd->buffer;
 
1393
      if (!line)
 
1394
        return gpg_error_from_syserror (); /* Out of core. */
 
1395
      /* Note, that we can silently ignore truncated lines. */
 
1396
      if (!len)
 
1397
        return gpg_error (GPG_ERR_EOF);
 
1398
      /* Trim line endings of empty lines. */
 
1399
      if ((*line == '\r' && line[1] == '\n') || *line == '\n')
 
1400
        *line = 0;
 
1401
      if ( (hd->flags & HTTP_FLAG_LOG_RESP) )
 
1402
        log_info ("RESP: `%.*s'\n",
 
1403
                  (int)strlen(line)-(*line&&line[1]?2:0),line);
 
1404
      if ( (hd->flags & HTTP_FLAG_NEED_HEADER) && *line )
 
1405
        {
 
1406
          gpg_error_t err = store_header (hd, line);
 
1407
          if (err)
 
1408
            return err;
 
1409
        }
 
1410
    }
 
1411
  while (len && *line);
 
1412
 
 
1413
  return 0;
 
1414
}
 
1415
 
 
1416
#if 0
 
1417
static int
 
1418
start_server ()
 
1419
{
 
1420
  struct sockaddr_in mya;
 
1421
  struct sockaddr_in peer;
 
1422
  int fd, client;
 
1423
  fd_set rfds;
 
1424
  int addrlen;
 
1425
  int i;
 
1426
 
 
1427
  if ((fd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
 
1428
    {
 
1429
      log_error ("socket() failed: %s\n", strerror (errno));
 
1430
      return -1;
 
1431
    }
 
1432
  i = 1;
 
1433
  if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (byte *) & i, sizeof (i)))
 
1434
    log_info ("setsockopt(SO_REUSEADDR) failed: %s\n", strerror (errno));
 
1435
 
 
1436
  mya.sin_family = AF_INET;
 
1437
  memset (&mya.sin_addr, 0, sizeof (mya.sin_addr));
 
1438
  mya.sin_port = htons (11371);
 
1439
 
 
1440
  if (bind (fd, (struct sockaddr *) &mya, sizeof (mya)))
 
1441
    {
 
1442
      log_error ("bind to port 11371 failed: %s\n", strerror (errno));
 
1443
      sock_close (fd);
 
1444
      return -1;
 
1445
    }
 
1446
 
 
1447
  if (listen (fd, 5))
 
1448
    {
 
1449
      log_error ("listen failed: %s\n", strerror (errno));
 
1450
      sock_close (fd);
 
1451
      return -1;
 
1452
    }
 
1453
 
 
1454
  for (;;)
 
1455
    {
 
1456
      FD_ZERO (&rfds);
 
1457
      FD_SET (fd, &rfds);
 
1458
 
 
1459
      if (select (fd + 1, &rfds, NULL, NULL, NULL) <= 0)
 
1460
        continue;               /* ignore any errors */
 
1461
 
 
1462
      if (!FD_ISSET (fd, &rfds))
 
1463
        continue;
 
1464
 
 
1465
      addrlen = sizeof peer;
 
1466
      client = accept (fd, (struct sockaddr *) &peer, &addrlen);
 
1467
      if (client == -1)
 
1468
        continue;               /* oops */
 
1469
 
 
1470
      log_info ("connect from %s\n", inet_ntoa (peer.sin_addr));
 
1471
 
 
1472
      fflush (stdout);
 
1473
      fflush (stderr);
 
1474
      if (!fork ())
 
1475
        {
 
1476
          int c;
 
1477
          FILE *fp;
 
1478
 
 
1479
          fp = fdopen (client, "r");
 
1480
          while ((c = getc (fp)) != EOF)
 
1481
            putchar (c);
 
1482
          fclose (fp);
 
1483
          exit (0);
 
1484
        }
 
1485
      sock_close (client);
 
1486
    }
 
1487
 
 
1488
 
 
1489
  return 0;
 
1490
}
 
1491
#endif
 
1492
 
 
1493
/* Actually connect to a server.  Returns the file descripto or -1 on
 
1494
   error.  ERRNO is set on error. */
 
1495
static int
 
1496
connect_server (const char *server, unsigned short port,
 
1497
                unsigned int flags, const char *srvtag)
 
1498
{
 
1499
  int sock = -1;
 
1500
  int srvcount = 0;
 
1501
  int hostfound = 0;
 
1502
  int srv, connected;
 
1503
  int last_errno = 0;
 
1504
  struct srventry *serverlist = NULL;
 
1505
 
 
1506
#ifdef HAVE_W32_SYSTEM
 
1507
  unsigned long inaddr;
 
1508
 
 
1509
#ifndef HTTP_NO_WSASTARTUP
 
1510
  init_sockets ();
 
1511
#endif
 
1512
  /* Win32 gethostbyname doesn't handle IP addresses internally, so we
 
1513
     try inet_addr first on that platform only. */
 
1514
  inaddr = inet_addr(server);
 
1515
  if ( inaddr != INADDR_NONE )
 
1516
    {
 
1517
      struct sockaddr_in addr;
 
1518
      
 
1519
      memset(&addr,0,sizeof(addr));
 
1520
      
 
1521
      sock = socket(AF_INET,SOCK_STREAM,0);
 
1522
      if ( sock==INVALID_SOCKET )
 
1523
        {
 
1524
          log_error("error creating socket: ec=%d\n",(int)WSAGetLastError());
 
1525
          return -1;
 
1526
        }
 
1527
 
 
1528
      addr.sin_family = AF_INET; 
 
1529
      addr.sin_port = htons(port);
 
1530
      memcpy (&addr.sin_addr,&inaddr,sizeof(inaddr));      
 
1531
 
 
1532
      if (!connect (sock,(struct sockaddr *)&addr,sizeof(addr)) )
 
1533
        return sock;
 
1534
      sock_close(sock);
 
1535
      return -1;
 
1536
    }
 
1537
#endif /*HAVE_W32_SYSTEM*/
 
1538
 
 
1539
#ifdef USE_DNS_SRV
 
1540
  /* Do the SRV thing */
 
1541
  if ((flags & HTTP_FLAG_TRY_SRV) && srvtag)
 
1542
    {
 
1543
      /* We're using SRV, so append the tags. */
 
1544
      if (1+strlen (srvtag) + 6 + strlen (server) + 1 <= MAXDNAME)
 
1545
        {
 
1546
          char srvname[MAXDNAME];
 
1547
 
 
1548
          stpcpy (stpcpy (stpcpy (stpcpy (srvname,"_"), srvtag),
 
1549
                           "._tcp."), server);
 
1550
          srvcount = getsrv (srvname, &serverlist);
 
1551
        }
 
1552
    }
 
1553
#endif /*USE_DNS_SRV*/
 
1554
 
 
1555
  if (!serverlist)
 
1556
    {
 
1557
      /* Either we're not using SRV, or the SRV lookup failed.  Make
 
1558
         up a fake SRV record. */
 
1559
      serverlist = xtrycalloc (1, sizeof *serverlist);
 
1560
      if (!serverlist)
 
1561
        return -1; /* Out of core.  */
 
1562
      serverlist->port = port;
 
1563
      strncpy (serverlist->target, server, MAXDNAME);
 
1564
      serverlist->target[MAXDNAME-1] = '\0';
 
1565
      srvcount = 1;
 
1566
    }
 
1567
 
 
1568
#ifdef HAVE_GETADDRINFO
 
1569
  connected = 0;
 
1570
  for (srv=0; srv < srvcount && !connected; srv++)
 
1571
    {
 
1572
      struct addrinfo hints, *res, *ai;
 
1573
      char portstr[35];
 
1574
 
 
1575
      sprintf (portstr, "%hu", port);
 
1576
      memset (&hints, 0, sizeof (hints));
 
1577
      hints.ai_socktype = SOCK_STREAM;
 
1578
      if (getaddrinfo (serverlist[srv].target, portstr, &hints, &res))
 
1579
        continue; /* Not found - try next one. */
 
1580
      hostfound = 1;
 
1581
 
 
1582
      for (ai = res; ai && !connected; ai = ai->ai_next)
 
1583
        {
 
1584
          if (sock != -1)
 
1585
            sock_close (sock);
 
1586
          sock = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol);
 
1587
          if (sock == -1)
 
1588
            {
 
1589
              int save_errno = errno;
 
1590
              log_error ("error creating socket: %s\n", strerror (errno));
 
1591
              freeaddrinfo (res);
 
1592
              xfree (serverlist);
 
1593
              errno = save_errno;
 
1594
              return -1;
 
1595
            }
 
1596
          
 
1597
          if (connect (sock, ai->ai_addr, ai->ai_addrlen))
 
1598
            last_errno = errno;
 
1599
          else
 
1600
            connected = 1;
 
1601
        }
 
1602
      freeaddrinfo (res);
 
1603
    }
 
1604
#else /* !HAVE_GETADDRINFO */
 
1605
  connected = 0;
 
1606
  for (srv=0; srv < srvcount && !connected; srv++)
 
1607
    {
 
1608
      int i;
 
1609
      struct hostent *host = NULL;
 
1610
      struct sockaddr_in addr;
 
1611
 
 
1612
      /* Note: This code is not thread-safe.  */
 
1613
 
 
1614
      memset (&addr, 0, sizeof (addr));
 
1615
      host = gethostbyname (serverlist[srv].target);
 
1616
      if (!host)
 
1617
        continue;
 
1618
      hostfound = 1;
 
1619
 
 
1620
      if (sock != -1)
 
1621
        sock_close (sock);
 
1622
      sock = socket (host->h_addrtype, SOCK_STREAM, 0);
 
1623
      if (sock == -1)
 
1624
        {
 
1625
          log_error (_("error creating socket: %s\n"), strerror (errno));
 
1626
          xfree (serverlist);
 
1627
          return -1;
 
1628
        }
 
1629
      
 
1630
      addr.sin_family = host->h_addrtype;
 
1631
      if (addr.sin_family != AF_INET)
 
1632
        {
 
1633
          log_error ("unknown address family for `%s'\n",
 
1634
                     serverlist[srv].target);
 
1635
          xfree (serverlist);
 
1636
          return -1;
 
1637
        }
 
1638
      addr.sin_port = htons (serverlist[srv].port);
 
1639
      if (host->h_length != 4)
 
1640
        {
 
1641
          log_error ("illegal address length for `%s'\n",
 
1642
                     serverlist[srv].target);
 
1643
          xfree (serverlist);
 
1644
          return -1;
 
1645
        }
 
1646
 
 
1647
      /* Try all A records until one responds. */
 
1648
      for (i = 0; host->h_addr_list[i] && !connected; i++)
 
1649
        {
 
1650
          memcpy (&addr.sin_addr, host->h_addr_list[i], host->h_length);
 
1651
          if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)))
 
1652
            last_errno = errno;
 
1653
          else
 
1654
            {
 
1655
              connected = 1;
 
1656
              break;
 
1657
            }
 
1658
        }
 
1659
    }
 
1660
#endif /* !HAVE_GETADDRINFO */
 
1661
 
 
1662
  xfree (serverlist);
 
1663
 
 
1664
  if (!connected)
 
1665
    {
 
1666
#ifdef HAVE_W32_SYSTEM
 
1667
      log_error ("can't connect to `%s': %s%sec=%d\n",
 
1668
                   server,
 
1669
                   hostfound? "":_("host not found"),
 
1670
                   hostfound? "":" - ", (int)WSAGetLastError());
 
1671
#else
 
1672
      log_error ("can't connect to `%s': %s\n",
 
1673
                 server,
 
1674
                 hostfound? strerror (last_errno):"host not found");
 
1675
#endif
 
1676
      if (sock != -1)
 
1677
        sock_close (sock);
 
1678
      errno = last_errno;
 
1679
      return -1;
 
1680
    }
 
1681
  return sock;
 
1682
}
 
1683
 
 
1684
 
 
1685
static gpg_error_t
 
1686
write_server (int sock, const char *data, size_t length)
 
1687
{
 
1688
  int nleft;
 
1689
 
 
1690
  nleft = length;
 
1691
  while (nleft > 0)
 
1692
    {
 
1693
#ifdef HAVE_W32_SYSTEM
 
1694
      int nwritten;
 
1695
      
 
1696
      nwritten = send (sock, data, nleft, 0);
 
1697
      if ( nwritten == SOCKET_ERROR ) 
 
1698
        {
 
1699
          log_info ("network write failed: ec=%d\n", (int)WSAGetLastError ());
 
1700
          return gpg_error (GPG_ERR_NETWORK);
 
1701
        }
 
1702
#else /*!HAVE_W32_SYSTEM*/
 
1703
      int nwritten = write (sock, data, nleft);
 
1704
      if (nwritten == -1)
 
1705
        {
 
1706
          if (errno == EINTR)
 
1707
            continue;
 
1708
          if (errno == EAGAIN)
 
1709
            {
 
1710
              struct timeval tv;
 
1711
 
 
1712
              tv.tv_sec = 0;
 
1713
              tv.tv_usec = 50000;
 
1714
              select (0, NULL, NULL, NULL, &tv);
 
1715
              continue;
 
1716
            }
 
1717
          log_info ("network write failed: %s\n", strerror (errno));
 
1718
          return gpg_error_from_syserror ();
 
1719
        }
 
1720
#endif /*!HAVE_W32_SYSTEM*/
 
1721
      nleft -= nwritten;
 
1722
      data += nwritten;
 
1723
    }
 
1724
 
 
1725
  return 0;
 
1726
}
 
1727
 
 
1728
 
 
1729
 
 
1730
#ifdef HTTP_USE_ESTREAM
 
1731
/* Read handler for estream.  */
 
1732
static ssize_t
 
1733
cookie_read (void *cookie, void *buffer, size_t size)
 
1734
{
 
1735
  cookie_t c = cookie;
 
1736
  int nread;
 
1737
 
 
1738
#ifdef HTTP_USE_GNUTLS
 
1739
  if (c->tls_session)
 
1740
    {
 
1741
    again:
 
1742
      nread = gnutls_record_recv (c->tls_session, buffer, size);
 
1743
      if (nread < 0)
 
1744
        {
 
1745
          if (nread == GNUTLS_E_INTERRUPTED)
 
1746
            goto again;
 
1747
          if (nread == GNUTLS_E_AGAIN)
 
1748
            {
 
1749
              struct timeval tv;
 
1750
              
 
1751
              tv.tv_sec = 0;
 
1752
              tv.tv_usec = 50000;
 
1753
              select (0, NULL, NULL, NULL, &tv);
 
1754
              goto again;
 
1755
            }
 
1756
          if (nread == GNUTLS_E_REHANDSHAKE)
 
1757
            goto again; /* A client is allowed to just ignore this request. */
 
1758
          log_info ("TLS network read failed: %s\n", gnutls_strerror (nread));
 
1759
          errno = EIO;
 
1760
          return -1;
 
1761
        }
 
1762
    }
 
1763
  else
 
1764
#endif /*HTTP_USE_GNUTLS*/
 
1765
    {
 
1766
      do
 
1767
        {
 
1768
          nread = read (c->fd, buffer, size);
 
1769
        }
 
1770
      while (nread == -1 && errno == EINTR);
 
1771
    }
 
1772
 
 
1773
  return nread;
 
1774
}
 
1775
 
 
1776
/* Write handler for estream.  */
 
1777
static ssize_t
 
1778
cookie_write (void *cookie, const void *buffer, size_t size)
 
1779
{
 
1780
  cookie_t c = cookie;
 
1781
  int nwritten = 0;
 
1782
 
 
1783
#ifdef HTTP_USE_GNUTLS
 
1784
  if (c->tls_session)
 
1785
    {
 
1786
      int nleft = size;
 
1787
      while (nleft > 0)
 
1788
        {
 
1789
          nwritten = gnutls_record_send (c->tls_session, buffer, nleft); 
 
1790
          if (nwritten <= 0)
 
1791
            {
 
1792
              if (nwritten == GNUTLS_E_INTERRUPTED)
 
1793
                continue;
 
1794
              if (nwritten == GNUTLS_E_AGAIN)
 
1795
                {
 
1796
                  struct timeval tv;
 
1797
                  
 
1798
                  tv.tv_sec = 0;
 
1799
                  tv.tv_usec = 50000;
 
1800
                  select (0, NULL, NULL, NULL, &tv);
 
1801
                  continue;
 
1802
                }
 
1803
              log_info ("TLS network write failed: %s\n",
 
1804
                        gnutls_strerror (nwritten));
 
1805
              errno = EIO;
 
1806
              return -1;
 
1807
            }
 
1808
          nleft -= nwritten;
 
1809
          buffer += nwritten;
 
1810
        }
 
1811
    }
 
1812
  else
 
1813
#endif /*HTTP_USE_GNUTLS*/
 
1814
    {
 
1815
      if ( write_server (c->fd, buffer, size) )
 
1816
        {
 
1817
          errno = EIO;
 
1818
          nwritten = -1;
 
1819
        }
 
1820
      else
 
1821
        nwritten = size;
 
1822
    }
 
1823
 
 
1824
  return nwritten;
 
1825
}
 
1826
 
 
1827
/* Close handler for estream.  */
 
1828
static int
 
1829
cookie_close (void *cookie)
 
1830
{
 
1831
  cookie_t c = cookie;
 
1832
 
 
1833
  if (!c)
 
1834
    return 0;
 
1835
 
 
1836
#ifdef HTTP_USE_GNUTLS
 
1837
  if (c->tls_session && !c->keep_socket)
 
1838
    {
 
1839
      gnutls_bye (c->tls_session, GNUTLS_SHUT_RDWR);
 
1840
    }
 
1841
#endif /*HTTP_USE_GNUTLS*/
 
1842
  if (c->fd != -1 && !c->keep_socket)
 
1843
    sock_close (c->fd);
 
1844
 
 
1845
  xfree (c);
 
1846
  return 0;
 
1847
}
 
1848
#endif /*HTTP_USE_ESTREAM*/
 
1849
 
 
1850
 
 
1851
 
 
1852
 
 
1853
/**** Test code ****/
 
1854
#ifdef TEST
 
1855
 
 
1856
static gpg_error_t
 
1857
verify_callback (http_t hd, void *tls_context, int reserved)
 
1858
{
 
1859
  log_info ("verification of certificates skipped\n");
 
1860
  return 0;
 
1861
}
 
1862
 
 
1863
 
 
1864
 
 
1865
/* static void */
 
1866
/* my_gnutls_log (int level, const char *text) */
 
1867
/* { */
 
1868
/*   fprintf (stderr, "gnutls:L%d: %s", level, text); */
 
1869
/* } */
 
1870
 
 
1871
int
 
1872
main (int argc, char **argv)
 
1873
{
 
1874
  int rc;
 
1875
  parsed_uri_t uri;
 
1876
  uri_tuple_t r;
 
1877
  http_t hd;
 
1878
  int c;
 
1879
  gnutls_session_t tls_session = NULL;
 
1880
#ifdef HTTP_USE_GNUTLS
 
1881
  gnutls_certificate_credentials certcred;
 
1882
  const int certprio[] = { GNUTLS_CRT_X509, 0 };
 
1883
#endif /*HTTP_USE_GNUTLS*/
 
1884
  header_t hdr;
 
1885
 
 
1886
#ifdef HTTP_USE_ESTREAM
 
1887
  es_init ();
 
1888
#endif
 
1889
  log_set_prefix ("http-test", 1 | 4);
 
1890
  if (argc == 1)
 
1891
    {
 
1892
      /*start_server (); */
 
1893
      return 0;
 
1894
    }
 
1895
 
 
1896
  if (argc != 2)
 
1897
    {
 
1898
      fprintf (stderr, "usage: http-test uri\n");
 
1899
      return 1;
 
1900
    }
 
1901
  argc--;
 
1902
  argv++;
 
1903
 
 
1904
#ifdef HTTP_USE_GNUTLS
 
1905
  rc = gnutls_global_init ();
 
1906
  if (rc)
 
1907
    log_error ("gnutls_global_init failed: %s\n", gnutls_strerror (rc));
 
1908
  rc = gnutls_certificate_allocate_credentials (&certcred);
 
1909
  if (rc)
 
1910
    log_error ("gnutls_certificate_allocate_credentials failed: %s\n",
 
1911
               gnutls_strerror (rc));
 
1912
/*   rc = gnutls_certificate_set_x509_trust_file */
 
1913
/*     (certcred, "ca.pem", GNUTLS_X509_FMT_PEM); */
 
1914
/*   if (rc) */
 
1915
/*     log_error ("gnutls_certificate_set_x509_trust_file failed: %s\n", */
 
1916
/*                gnutls_strerror (rc)); */
 
1917
  rc = gnutls_init (&tls_session, GNUTLS_CLIENT);
 
1918
  if (rc)
 
1919
    log_error ("gnutls_init failed: %s\n", gnutls_strerror (rc));
 
1920
  rc = gnutls_set_default_priority (tls_session);
 
1921
  if (rc)
 
1922
    log_error ("gnutls_set_default_priority failed: %s\n",
 
1923
               gnutls_strerror (rc));
 
1924
  rc = gnutls_certificate_type_set_priority (tls_session, certprio);
 
1925
  if (rc)
 
1926
    log_error ("gnutls_certificate_type_set_priority failed: %s\n",
 
1927
               gnutls_strerror (rc));
 
1928
  rc = gnutls_credentials_set (tls_session, GNUTLS_CRD_CERTIFICATE, certcred);
 
1929
  if (rc)
 
1930
    log_error ("gnutls_credentials_set failed: %s\n", gnutls_strerror (rc));
 
1931
/*   gnutls_global_set_log_function (my_gnutls_log); */
 
1932
/*   gnutls_global_set_log_level (4); */
 
1933
 
 
1934
  http_register_tls_callback (verify_callback);
 
1935
#endif /*HTTP_USE_GNUTLS*/
 
1936
 
 
1937
  rc = http_parse_uri (&uri, *argv);
 
1938
  if (rc)
 
1939
    {
 
1940
      log_error ("`%s': %s\n", *argv, gpg_strerror (rc));
 
1941
      http_release_parsed_uri (uri);
 
1942
      return 1;
 
1943
    }
 
1944
 
 
1945
  printf ("Scheme: %s\n", uri->scheme);
 
1946
  printf ("Host  : %s\n", uri->host);
 
1947
  printf ("Port  : %u\n", uri->port);
 
1948
  printf ("Path  : %s\n", uri->path);
 
1949
  for (r = uri->params; r; r = r->next)
 
1950
    {
 
1951
      printf ("Params: %s", r->name);
 
1952
      if (!r->no_value)
 
1953
        {
 
1954
          printf ("=%s", r->value);
 
1955
          if (strlen (r->value) != r->valuelen)
 
1956
            printf (" [real length=%d]", (int) r->valuelen);
 
1957
        }
 
1958
      putchar ('\n');
 
1959
    }
 
1960
  for (r = uri->query; r; r = r->next)
 
1961
    {
 
1962
      printf ("Query : %s", r->name);
 
1963
      if (!r->no_value)
 
1964
        {
 
1965
          printf ("=%s", r->value);
 
1966
          if (strlen (r->value) != r->valuelen)
 
1967
            printf (" [real length=%d]", (int) r->valuelen);
 
1968
        }
 
1969
      putchar ('\n');
 
1970
    }
 
1971
  http_release_parsed_uri (uri);
 
1972
  uri = NULL;
 
1973
 
 
1974
  rc = http_open_document (&hd, *argv, NULL, 
 
1975
                           HTTP_FLAG_NO_SHUTDOWN | HTTP_FLAG_NEED_HEADER,
 
1976
                           NULL, tls_session);
 
1977
  if (rc)
 
1978
    {
 
1979
      log_error ("can't get `%s': %s\n", *argv, gpg_strerror (rc));
 
1980
      return 1;
 
1981
    }
 
1982
  log_info ("open_http_document succeeded; status=%u\n",
 
1983
            http_get_status_code (hd));
 
1984
  for (hdr = hd->headers; hdr; hdr = hdr->next)
 
1985
    printf ("HDR: %s: %s\n", hdr->name, hdr->value);
 
1986
  switch (http_get_status_code (hd))
 
1987
    {
 
1988
    case 200:
 
1989
      while ((c = P_ES(getc) (http_get_read_ptr (hd))) != EOF)
 
1990
        putchar (c);
 
1991
      break;
 
1992
    case 301:
 
1993
    case 302:
 
1994
      printf ("Redirected to `%s'\n", http_get_header (hd, "Location"));
 
1995
      break;
 
1996
    }
 
1997
  http_close (hd, 0);
 
1998
 
 
1999
#ifdef HTTP_USE_GNUTLS
 
2000
  gnutls_deinit (tls_session);
 
2001
  gnutls_certificate_free_credentials (certcred);
 
2002
  gnutls_global_deinit ();
 
2003
#endif /*HTTP_USE_GNUTLS*/
 
2004
 
 
2005
  return 0;
 
2006
}
 
2007
#endif /*TEST*/
 
2008
 
 
2009
 
 
2010
/*
 
2011
Local Variables:
 
2012
compile-command: "gcc -I.. -I../gl -DTEST -DHAVE_CONFIG_H -Wall -O2 -g -o http-test http.c -L. -lcommon -L../jnlib -ljnlib -lgcrypt -lpth -lgnutls"
 
2013
End:
 
2014
*/