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

« back to all changes in this revision

Viewing changes to util/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 Free Software Foundation, Inc.
3
 
 *
4
 
 * This file is part of GnuPG.
5
 
 *
6
 
 * GnuPG is free software; you can redistribute it and/or modify
7
 
 * it under the terms of the GNU General Public License as published by
8
 
 * the Free Software Foundation; either version 2 of the License, or
9
 
 * (at your option) any later version.
10
 
 *
11
 
 * GnuPG is distributed in the hope that it will be useful,
12
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 * GNU General Public License for more details.
15
 
 *
16
 
 * You should have received a copy of the GNU General Public License
17
 
 * along with this program; if not, write to the Free Software
18
 
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19
 
 */
20
 
 
21
 
#include <config.h>
22
 
#include <stdio.h>
23
 
#include <stdlib.h>
24
 
#include <stdarg.h>
25
 
#include <string.h>
26
 
#include <ctype.h>
27
 
#include <errno.h>
28
 
 
29
 
#ifdef _WIN32
30
 
#include <windows.h>
31
 
#else
32
 
#include <unistd.h>
33
 
#include <sys/types.h>
34
 
#include <sys/socket.h>
35
 
#include <sys/time.h>
36
 
#include <time.h>
37
 
#include <netinet/in.h>
38
 
#include <arpa/inet.h>
39
 
#include <netdb.h>
40
 
#endif
41
 
 
42
 
#include "util.h"
43
 
#include "iobuf.h"
44
 
#include "i18n.h"
45
 
#include "http.h"
46
 
#include "srv.h"
47
 
 
48
 
#ifdef _WIN32
49
 
#define sock_close(a)  closesocket(a)
50
 
#else
51
 
#define sock_close(a)  close(a)
52
 
#endif
53
 
 
54
 
#define MAX_LINELEN 20000  /* max. length of a HTTP line */
55
 
#define VALID_URI_CHARS "abcdefghijklmnopqrstuvwxyz"   \
56
 
                        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"   \
57
 
                        "01234567890@"                 \
58
 
                        "!\"#$%&'()*+,-./:;<=>?[\\]^_{|}~"
59
 
 
60
 
#ifndef EAGAIN
61
 
#define EAGAIN  EWOULDBLOCK
62
 
#endif
63
 
 
64
 
static int parse_uri( PARSED_URI *ret_uri, const char *uri );
65
 
static void release_parsed_uri( PARSED_URI uri );
66
 
static int do_parse_uri( PARSED_URI uri, int only_local_part );
67
 
static int remove_escapes( byte *string );
68
 
static int insert_escapes( byte *buffer, const byte *string,
69
 
                                         const byte *special );
70
 
static URI_TUPLE parse_tuple( byte *string );
71
 
static int send_request( HTTP_HD hd, const char *proxy );
72
 
static byte *build_rel_path( PARSED_URI uri );
73
 
static int parse_response( HTTP_HD hd );
74
 
 
75
 
static int connect_server( const char *server, ushort port, unsigned int flags,
76
 
                           const char *srvtag );
77
 
static int write_server( int sock, const char *data, size_t length );
78
 
 
79
 
#ifdef _WIN32
80
 
static void
81
 
deinit_sockets (void)
82
 
{
83
 
    WSACleanup();
84
 
}
85
 
 
86
 
static void
87
 
init_sockets (void)
88
 
{
89
 
    static int initialized;
90
 
    static WSADATA wsdata;
91
 
 
92
 
    if (initialized)
93
 
        return;
94
 
 
95
 
    if( WSAStartup( 0x0101, &wsdata ) ) {
96
 
        log_error ("error initializing socket library: ec=%d\n", 
97
 
                    (int)WSAGetLastError () );
98
 
        return;
99
 
    }
100
 
    if( wsdata.wVersion < 0x0001 ) {
101
 
        log_error ("socket library version is %x.%x - but 1.1 needed\n",
102
 
                   LOBYTE(wsdata.wVersion), HIBYTE(wsdata.wVersion));
103
 
        WSACleanup();
104
 
        return;
105
 
    }
106
 
    atexit ( deinit_sockets );
107
 
    initialized = 1;
108
 
}
109
 
#endif /*_WIN32*/
110
 
 
111
 
static byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
112
 
                         "abcdefghijklmnopqrstuvwxyz"
113
 
                         "0123456789+/";
114
 
 
115
 
/****************
116
 
 * create a radix64 encoded string.
117
 
 */
118
 
 
119
 
/* TODO: This is a duplicate of code in g10/armor.c.  Better to use a
120
 
   single copy in strgutil.c */
121
 
static char *
122
 
make_radix64_string( const byte *data, size_t len )
123
 
{
124
 
    char *buffer, *p;
125
 
 
126
 
    buffer = p = m_alloc( (len+2)/3*4 + 1 );
127
 
    for( ; len >= 3 ; len -= 3, data += 3 ) {
128
 
        *p++ = bintoasc[(data[0] >> 2) & 077];
129
 
        *p++ = bintoasc[(((data[0] <<4)&060)|((data[1] >> 4)&017))&077];
130
 
        *p++ = bintoasc[(((data[1]<<2)&074)|((data[2]>>6)&03))&077];
131
 
        *p++ = bintoasc[data[2]&077];
132
 
    }
133
 
    if( len == 2 ) {
134
 
        *p++ = bintoasc[(data[0] >> 2) & 077];
135
 
        *p++ = bintoasc[(((data[0] <<4)&060)|((data[1] >> 4)&017))&077];
136
 
        *p++ = bintoasc[((data[1]<<2)&074)];
137
 
    }
138
 
    else if( len == 1 ) {
139
 
        *p++ = bintoasc[(data[0] >> 2) & 077];
140
 
        *p++ = bintoasc[(data[0] <<4)&060];
141
 
    }
142
 
    *p = 0;
143
 
    return buffer;
144
 
}
145
 
 
146
 
int
147
 
http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url,
148
 
           unsigned int flags, const char *proxy )
149
 
{
150
 
    int rc;
151
 
 
152
 
    if( !(reqtype == HTTP_REQ_GET || reqtype == HTTP_REQ_POST) )
153
 
        return G10ERR_INV_ARG;
154
 
 
155
 
    /* initialize the handle */
156
 
    memset( hd, 0, sizeof *hd );
157
 
    hd->sock = -1;
158
 
    hd->initialized = 1;
159
 
    hd->req_type = reqtype;
160
 
    hd->flags = flags;
161
 
 
162
 
    rc = parse_uri( &hd->uri, url );
163
 
    if( !rc ) {
164
 
        rc = send_request( hd, proxy );
165
 
        if( !rc ) {
166
 
            hd->fp_write = iobuf_sockopen( hd->sock , "w" );
167
 
            if( hd->fp_write )
168
 
                return 0;
169
 
            rc = G10ERR_GENERAL;
170
 
        }
171
 
    }
172
 
 
173
 
    if( !hd->fp_read && !hd->fp_write && hd->sock != -1 )
174
 
        sock_close( hd->sock );
175
 
    iobuf_close( hd->fp_read );
176
 
    iobuf_close( hd->fp_write);
177
 
    release_parsed_uri( hd->uri );
178
 
    hd->initialized = 0;
179
 
 
180
 
    return rc;
181
 
}
182
 
 
183
 
 
184
 
void
185
 
http_start_data( HTTP_HD hd )
186
 
{
187
 
    iobuf_flush ( hd->fp_write );
188
 
    if( !hd->in_data ) {
189
 
        write_server (hd->sock, "\r\n", 2);
190
 
        hd->in_data = 1;
191
 
    }
192
 
}
193
 
 
194
 
 
195
 
int
196
 
http_wait_response( HTTP_HD hd, unsigned int *ret_status )
197
 
{
198
 
    int rc;
199
 
 
200
 
    http_start_data( hd ); /* make sure that we are in the data */
201
 
 
202
 
#if 0
203
 
    hd->sock = dup( hd->sock ); 
204
 
    if( hd->sock == -1 )
205
 
        return G10ERR_GENERAL;
206
 
#endif
207
 
    iobuf_ioctl (hd->fp_write, 1, 1, NULL); /* keep the socket open */
208
 
    iobuf_close (hd->fp_write);
209
 
    hd->fp_write = NULL;
210
 
    if ( !(hd->flags & HTTP_FLAG_NO_SHUTDOWN) )
211
 
        shutdown( hd->sock, 1 );
212
 
    hd->in_data = 0;
213
 
 
214
 
    hd->fp_read = iobuf_sockopen( hd->sock , "r" );
215
 
    if( !hd->fp_read )
216
 
        return G10ERR_GENERAL;
217
 
 
218
 
    rc = parse_response( hd );
219
 
    if( !rc && ret_status )
220
 
        *ret_status = hd->status_code;
221
 
 
222
 
    return rc;
223
 
}
224
 
 
225
 
 
226
 
int
227
 
http_open_document( HTTP_HD hd, const char *document,
228
 
                    unsigned int flags, const char *proxy )
229
 
{
230
 
    int rc;
231
 
 
232
 
    rc = http_open( hd, HTTP_REQ_GET, document, flags, proxy );
233
 
    if( rc )
234
 
        return rc;
235
 
 
236
 
    rc = http_wait_response( hd, NULL );
237
 
    if( rc )
238
 
        http_close( hd );
239
 
 
240
 
    return rc;
241
 
}
242
 
 
243
 
 
244
 
void
245
 
http_close( HTTP_HD hd )
246
 
{
247
 
    if( !hd || !hd->initialized )
248
 
        return;
249
 
    if( !hd->fp_read && !hd->fp_write && hd->sock != -1 )
250
 
        sock_close( hd->sock );
251
 
    iobuf_close( hd->fp_read );
252
 
    iobuf_close( hd->fp_write );
253
 
    release_parsed_uri( hd->uri );
254
 
    m_free( hd->buffer );
255
 
    hd->initialized = 0;
256
 
}
257
 
 
258
 
 
259
 
 
260
 
/****************
261
 
 * Parse an URI and put the result into the newly allocated ret_uri.
262
 
 * The caller must always use release_parsed_uri to releases the
263
 
 * resources (even on an error).
264
 
 */
265
 
static int
266
 
parse_uri( PARSED_URI *ret_uri, const char *uri )
267
 
{
268
 
   *ret_uri = m_alloc_clear( sizeof(**ret_uri) + strlen(uri) );
269
 
   strcpy( (*ret_uri)->buffer, uri );
270
 
   return do_parse_uri( *ret_uri, 0 );
271
 
}
272
 
 
273
 
static void
274
 
release_parsed_uri( PARSED_URI uri )
275
 
{
276
 
    if( uri )
277
 
    {
278
 
        URI_TUPLE r, r2;
279
 
 
280
 
        for( r = uri->query; r; r = r2 ) {
281
 
            r2 = r->next;
282
 
            m_free( r );
283
 
        }
284
 
        m_free( uri );
285
 
    }
286
 
}
287
 
 
288
 
static int
289
 
do_parse_uri( PARSED_URI uri, int only_local_part )
290
 
{
291
 
    URI_TUPLE *tail;
292
 
    char *p, *p2, *p3;
293
 
    int n;
294
 
 
295
 
    p = uri->buffer;
296
 
    n = strlen( uri->buffer );
297
 
    /* initialize all fields to an empty string or an empty list */
298
 
    uri->scheme = uri->host = uri->path = p + n;
299
 
    uri->port = 0;
300
 
    uri->params = uri->query = NULL;
301
 
 
302
 
    /* a quick validity check */
303
 
    if( strspn( p, VALID_URI_CHARS) != n )
304
 
        return G10ERR_BAD_URI; /* invalid characters found */
305
 
 
306
 
    if( !only_local_part ) {
307
 
        /* find the scheme */
308
 
        if( !(p2 = strchr( p, ':' ) ) || p2 == p )
309
 
           return G10ERR_BAD_URI; /* No scheme */
310
 
        *p2++ = 0;
311
 
        strlwr( p );
312
 
        uri->scheme = p;
313
 
        if(strcmp(uri->scheme,"http")==0)
314
 
          uri->port = 80;
315
 
        else if(strcmp(uri->scheme,"hkp")==0)
316
 
          uri->port = 11371;
317
 
        else
318
 
          return G10ERR_INVALID_URI; /* Unsupported scheme */
319
 
 
320
 
        p = p2;
321
 
 
322
 
        /* find the hostname */
323
 
        if( *p != '/' )
324
 
            return G10ERR_INVALID_URI; /* does not start with a slash */
325
 
 
326
 
        p++;
327
 
        if( *p == '/' ) {  /* there seems to be a hostname */
328
 
            p++;
329
 
            if( (p2 = strchr(p, '/')) )
330
 
                *p2++ = 0;
331
 
 
332
 
            /* Check for username/password encoding */
333
 
            if((p3=strchr(p,'@')))
334
 
              {
335
 
                uri->auth=p;
336
 
                *p3++='\0';
337
 
                p=p3;
338
 
              }
339
 
 
340
 
            strlwr( p );
341
 
            uri->host = p;
342
 
            if( (p3=strchr( p, ':' )) ) {
343
 
                *p3++ = 0;
344
 
                uri->port = atoi( p3 );
345
 
            }
346
 
 
347
 
            uri->host = p;
348
 
            if( (n = remove_escapes( uri->host )) < 0 )
349
 
                return G10ERR_BAD_URI;
350
 
            if( n != strlen( p ) )
351
 
                return G10ERR_BAD_URI; /* hostname with a Nul in it */
352
 
            p = p2 ? p2 : NULL;
353
 
        }
354
 
    } /* end global URI part */
355
 
 
356
 
    /* parse the pathname part */
357
 
    if( !p || !*p ) /* we don't have a path */
358
 
        return 0; /* and this is okay */
359
 
 
360
 
    /* todo: here we have to check params */
361
 
 
362
 
    /* do we have a query part */
363
 
    if( (p2 = strchr( p, '?' )) )
364
 
        *p2++ = 0;
365
 
 
366
 
    uri->path = p;
367
 
    if( (n = remove_escapes( p )) < 0 )
368
 
        return G10ERR_BAD_URI;
369
 
    if( n != strlen( p ) )
370
 
        return G10ERR_BAD_URI; /* path with a Nul in it */
371
 
    p = p2 ? p2 : NULL;
372
 
 
373
 
    if( !p || !*p ) /* we don't have a query string */
374
 
        return 0;   /* okay */
375
 
 
376
 
    /* now parse the query string */
377
 
    tail = &uri->query;
378
 
    for(;;) {
379
 
        URI_TUPLE elem;
380
 
 
381
 
        if( (p2 = strchr( p, '&' )) )
382
 
            *p2++ = 0;
383
 
        if( !(elem = parse_tuple( p )) )
384
 
            return G10ERR_BAD_URI;
385
 
        *tail = elem;
386
 
        tail = &elem->next;
387
 
 
388
 
        if( !p2 )
389
 
           break; /* ready */
390
 
        p = p2;
391
 
    }
392
 
 
393
 
    return 0;
394
 
}
395
 
 
396
 
 
397
 
 
398
 
/****************
399
 
 * Remove all %xx escapes; this is done inplace.
400
 
 * Returns: new length of the string.
401
 
 */
402
 
static int
403
 
remove_escapes( byte *string )
404
 
{
405
 
    int n = 0;
406
 
    byte *p, *s;
407
 
 
408
 
    for(p=s=string; *s ; s++ ) {
409
 
        if( *s == '%' ) {
410
 
            if( s[1] && s[2] && isxdigit(s[1]) && isxdigit(s[2]) ) {
411
 
                s++;
412
 
                *p  = *s >= '0' && *s <= '9' ? *s - '0' :
413
 
                      *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10 ;
414
 
                *p <<= 4;
415
 
                s++;
416
 
                *p |= *s >= '0' && *s <= '9' ? *s - '0' :
417
 
                      *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10 ;
418
 
                p++;
419
 
                n++;
420
 
            }
421
 
            else {
422
 
                *p++ = *s++;
423
 
                if( *s )
424
 
                   *p++ = *s++;
425
 
                if( *s )
426
 
                   *p++ = *s++;
427
 
                if( *s )
428
 
                   *p = 0;
429
 
                return -1; /* bad URI */
430
 
            }
431
 
        }
432
 
        else
433
 
        {
434
 
            *p++ = *s;
435
 
            n++;
436
 
        }
437
 
    }
438
 
    *p = 0; /* always keep a string terminator */
439
 
    return n;
440
 
}
441
 
 
442
 
 
443
 
static int
444
 
insert_escapes( byte *buffer, const byte *string, const byte *special )
445
 
{
446
 
    int n = 0;
447
 
 
448
 
    for( ; *string; string++ ) {
449
 
        if( strchr( VALID_URI_CHARS, *string )
450
 
            && !strchr( special, *string ) )  {
451
 
            if( buffer )
452
 
                *buffer++ = *string;
453
 
            n++;
454
 
        }
455
 
        else {
456
 
            if( buffer ) {
457
 
                sprintf( buffer, "%%%02X", *string );
458
 
                buffer += 3;
459
 
            }
460
 
            n += 3;
461
 
        }
462
 
    }
463
 
    return n;
464
 
}
465
 
 
466
 
 
467
 
static URI_TUPLE
468
 
parse_tuple( byte *string )
469
 
{
470
 
    byte *p = string;
471
 
    byte *p2;
472
 
    int n;
473
 
    URI_TUPLE tuple;
474
 
 
475
 
    if( (p2 = strchr( p, '=' )) )
476
 
        *p2++ = 0;
477
 
    if( (n = remove_escapes( p )) < 0 )
478
 
        return NULL; /* bad URI */
479
 
    if( n != strlen( p ) )
480
 
       return NULL; /* name with a Nul in it */
481
 
    tuple = m_alloc_clear( sizeof *tuple );
482
 
    tuple->name = p;
483
 
    if( !p2 )  {
484
 
        /* we have only the name, so we assume an empty value string */
485
 
        tuple->value = p + strlen(p);
486
 
        tuple->valuelen = 0;
487
 
    }
488
 
    else { /* name and value */
489
 
        if( (n = remove_escapes( p2 )) < 0 ) {
490
 
            m_free( tuple );
491
 
            return NULL; /* bad URI */
492
 
        }
493
 
        tuple->value = p2;
494
 
        tuple->valuelen = n;
495
 
    }
496
 
    return tuple;
497
 
}
498
 
 
499
 
 
500
 
/****************
501
 
 * Send a HTTP request to the server
502
 
 * Returns 0 if the request was successful
503
 
 */
504
 
static int
505
 
send_request( HTTP_HD hd, const char *proxy )
506
 
{
507
 
    const byte *server;
508
 
    byte *request, *p;
509
 
    ushort port;
510
 
    int rc;
511
 
    char *auth=NULL;
512
 
 
513
 
    server = *hd->uri->host? hd->uri->host : "localhost";
514
 
    port   = hd->uri->port?  hd->uri->port : 80;
515
 
 
516
 
    if(proxy)
517
 
      {
518
 
        PARSED_URI uri;
519
 
 
520
 
        rc = parse_uri( &uri, proxy );
521
 
        if (rc)
522
 
          {
523
 
            log_error("invalid HTTP proxy (%s): %s\n",proxy,g10_errstr(rc));
524
 
            release_parsed_uri( uri );
525
 
            return G10ERR_NETWORK;
526
 
          }
527
 
        hd->sock = connect_server( *uri->host? uri->host : "localhost",
528
 
                                   uri->port? uri->port : 80, 0, NULL );
529
 
        if(uri->auth)
530
 
          {
531
 
            char *x=make_radix64_string(uri->auth,strlen(uri->auth));
532
 
            auth=m_alloc(50+strlen(x));
533
 
            sprintf(auth,"Proxy-Authorization: Basic %s\r\n",x);
534
 
            m_free(x);
535
 
          }
536
 
 
537
 
        release_parsed_uri( uri );
538
 
      }
539
 
    else
540
 
      {
541
 
        hd->sock = connect_server( server, port, hd->flags, hd->uri->scheme );
542
 
        if(hd->uri->auth)
543
 
          {
544
 
            char *x=make_radix64_string(hd->uri->auth,strlen(hd->uri->auth));
545
 
            auth=m_alloc(50+strlen(x));
546
 
            sprintf(auth,"Authorization: Basic %s\r\n",x);
547
 
            m_free(x);
548
 
          }
549
 
      }
550
 
 
551
 
    if( hd->sock == -1 )
552
 
        return G10ERR_NETWORK;
553
 
 
554
 
    p = build_rel_path( hd->uri );
555
 
 
556
 
    request=m_alloc(strlen(server)*2 + strlen(p) + (auth?strlen(auth):0) + 65);
557
 
    if( proxy )
558
 
      sprintf( request, "%s http://%s:%hu%s%s HTTP/1.0\r\n%s",
559
 
               hd->req_type == HTTP_REQ_GET ? "GET" :
560
 
               hd->req_type == HTTP_REQ_HEAD? "HEAD":
561
 
               hd->req_type == HTTP_REQ_POST? "POST": "OOPS",
562
 
               server, port,  *p == '/'? "":"/", p, auth?auth:"" );
563
 
    else
564
 
      {
565
 
        char portstr[15];
566
 
 
567
 
        if(port!=80)
568
 
          sprintf(portstr,":%u",port);
569
 
 
570
 
        sprintf( request, "%s %s%s HTTP/1.0\r\nHost: %s%s\r\n%s",
571
 
                 hd->req_type == HTTP_REQ_GET ? "GET" :
572
 
                 hd->req_type == HTTP_REQ_HEAD? "HEAD":
573
 
                 hd->req_type == HTTP_REQ_POST? "POST": "OOPS",
574
 
                 *p == '/'? "":"/", p, server, (port!=80)?portstr:"",
575
 
                 auth?auth:"");
576
 
      }
577
 
 
578
 
    m_free(p);
579
 
 
580
 
    rc = write_server( hd->sock, request, strlen(request) );
581
 
    m_free( request );
582
 
    m_free(auth);
583
 
 
584
 
    return rc;
585
 
}
586
 
 
587
 
 
588
 
/****************
589
 
 * Build the relative path from the parsed URI.
590
 
 * Minimal implementation.
591
 
 */
592
 
static byte*
593
 
build_rel_path( PARSED_URI uri )
594
 
{
595
 
    URI_TUPLE r;
596
 
    byte *rel_path, *p;
597
 
    int n;
598
 
 
599
 
    /* count the needed space */
600
 
    n = insert_escapes( NULL, uri->path, "%;?&" );
601
 
    /* todo: build params */
602
 
    for( r=uri->query; r; r = r->next ) {
603
 
        n++; /* '?'/'&' */
604
 
        n += insert_escapes( NULL, r->name, "%;?&=" );
605
 
        n++; /* '='*/
606
 
        n += insert_escapes( NULL, r->value, "%;?&=" );
607
 
    }
608
 
    n++;
609
 
 
610
 
    /* now  allocate and copy */
611
 
    p = rel_path = m_alloc( n );
612
 
    n = insert_escapes( p, uri->path, "%;?&" );
613
 
    p += n;
614
 
    /* todo: add params */
615
 
    for( r=uri->query; r; r = r->next ) {
616
 
        *p++ = r == uri->query? '?':'&';
617
 
        n = insert_escapes( p, r->name, "%;?&=" );
618
 
        p += n;
619
 
        *p++ = '=';
620
 
        /* todo: use valuelen */
621
 
        n = insert_escapes( p, r->value, "%;?&=" );
622
 
        p += n;
623
 
    }
624
 
    *p = 0;
625
 
    return rel_path;
626
 
}
627
 
 
628
 
 
629
 
 
630
 
/***********************
631
 
 * Parse the response from a server.
632
 
 * Returns: errorcode and sets some fileds in the handle
633
 
 */
634
 
static int
635
 
parse_response( HTTP_HD hd )
636
 
{
637
 
    byte *line, *p, *p2;
638
 
    unsigned maxlen, len;
639
 
 
640
 
    /* Wait for the status line */
641
 
    do {
642
 
        maxlen = MAX_LINELEN;
643
 
        len = iobuf_read_line( hd->fp_read, &hd->buffer,
644
 
                                            &hd->buffer_size, &maxlen );
645
 
        line = hd->buffer;
646
 
        if( !maxlen )
647
 
            return -1; /* line has been truncated */
648
 
        if( !len )
649
 
            return -1; /* eof */
650
 
    } while( !*line  );
651
 
 
652
 
    if( (p = strchr( line, '/')) )
653
 
        *p++ = 0;
654
 
    if( !p || strcmp( line, "HTTP" ) )
655
 
        return 0; /* assume http 0.9 */
656
 
 
657
 
    if( (p2 = strpbrk( p, " \t" ) ) ) {
658
 
        *p2++ = 0;
659
 
        p2 += strspn( p2, " \t" );
660
 
    }
661
 
    if( !p2 )
662
 
        return 0; /* assume http 0.9 */
663
 
    p = p2;
664
 
    /* todo: add HTTP version number check here */
665
 
    if( (p2 = strpbrk( p, " \t" ) ) )
666
 
        *p2++ = 0;
667
 
    if( !isdigit(p[0]) || !isdigit(p[1]) || !isdigit(p[2]) || p[3] ) {
668
 
         /* malformed HTTP statuscode - assume HTTP 0.9 */
669
 
        hd->is_http_0_9 = 1;
670
 
        hd->status_code = 200;
671
 
        return 0;
672
 
    }
673
 
    hd->status_code = atoi( p );
674
 
 
675
 
    /* skip all the header lines and wait for the empty line */
676
 
    do {
677
 
        maxlen = MAX_LINELEN;
678
 
        len = iobuf_read_line( hd->fp_read, &hd->buffer,
679
 
                               &hd->buffer_size, &maxlen );
680
 
        line = hd->buffer;
681
 
        /* we ignore truncated lines */
682
 
        if( !len )
683
 
            return -1; /* eof */
684
 
        /* time lineendings */
685
 
        if( (*line == '\r' && line[1] == '\n') || *line == '\n' )
686
 
            *line = 0;
687
 
    } while( len && *line  );
688
 
 
689
 
    return 0;
690
 
}
691
 
 
692
 
#ifdef TEST
693
 
static int
694
 
start_server()
695
 
{
696
 
    struct sockaddr_in mya;
697
 
    struct sockaddr_in peer;
698
 
    int fd, client;
699
 
    fd_set rfds;
700
 
    int addrlen;
701
 
    int i;
702
 
 
703
 
    if( (fd=socket(AF_INET,SOCK_STREAM, 0)) == -1 ) {
704
 
        log_error("socket() failed: %s\n", strerror(errno));
705
 
        return -1;
706
 
    }
707
 
    i = 1;
708
 
    if( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (byte*)&i, sizeof(i) ) )
709
 
        log_info("setsockopt(SO_REUSEADDR) failed: %s\n", strerror(errno) );
710
 
 
711
 
    mya.sin_family=AF_INET;
712
 
    memset(&mya.sin_addr, 0, sizeof(mya.sin_addr));
713
 
    mya.sin_port=htons(11371);
714
 
 
715
 
    if( bind( fd, (struct sockaddr *)&mya, sizeof(mya)) ) {
716
 
        log_error("bind to port 11371 failed: %s\n", strerror(errno) );
717
 
        sock_close( fd );
718
 
        return -1;
719
 
    }
720
 
 
721
 
    if( listen( fd, 5 ) ) {
722
 
        log_error("listen failed: %s\n", strerror(errno) );
723
 
        sock_close( fd );
724
 
        return -1;
725
 
    }
726
 
 
727
 
    for(;;) {
728
 
        FD_ZERO(&rfds);
729
 
        FD_SET( fd, &rfds );
730
 
 
731
 
        if( select( fd+1, &rfds, NULL, NULL, NULL) <= 0 )
732
 
            continue; /* ignore any errors */
733
 
 
734
 
        if( !FD_ISSET( fd, &rfds ) )
735
 
            continue;
736
 
 
737
 
        addrlen = sizeof peer;
738
 
        client = accept( fd, (struct sockaddr *)&peer, &addrlen);
739
 
        if( client == -1 )
740
 
            continue; /* oops */
741
 
 
742
 
        log_info("connect from %s\n", inet_ntoa( peer.sin_addr ) );
743
 
 
744
 
        fflush(stdout);
745
 
        fflush(stderr);
746
 
        if( !fork() ) {
747
 
            int c;
748
 
            FILE *fp;
749
 
 
750
 
            fp = fdopen( client , "r" );
751
 
            while( (c=getc(fp)) != EOF )
752
 
                putchar(c);
753
 
            fclose(fp);
754
 
            exit(0);
755
 
        }
756
 
        sock_close( client );
757
 
    }
758
 
 
759
 
 
760
 
    return 0;
761
 
}
762
 
#endif
763
 
 
764
 
 
765
 
static int
766
 
connect_server( const char *server, ushort port, unsigned int flags,
767
 
                const char *srvtag )
768
 
{
769
 
  int sock=-1,srv,srvcount=0,connected=0,hostfound=0;
770
 
  struct srventry *srvlist=NULL;
771
 
 
772
 
#ifdef _WIN32
773
 
  unsigned long inaddr;
774
 
 
775
 
  init_sockets();
776
 
  /* Win32 gethostbyname doesn't handle IP addresses internally, so we
777
 
     try inet_addr first on that platform only. */
778
 
  if((inaddr=inet_addr(server))!=SOCKET_ERROR)
779
 
    {
780
 
      struct sockaddr_in addr;
781
 
 
782
 
      memset(&addr,0,sizeof(addr));
783
 
 
784
 
      if((sock=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET)
785
 
        {
786
 
          log_error("error creating socket: ec=%d\n",(int)WSAGetLastError());
787
 
          return -1;
788
 
        }
789
 
 
790
 
      addr.sin_family=AF_INET; 
791
 
      addr.sin_port=htons(port);
792
 
      memcpy(&addr.sin_addr,&inaddr,sizeof(inaddr));      
793
 
 
794
 
      if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0)
795
 
        return sock;
796
 
      else
797
 
        {
798
 
          sock_close(sock);
799
 
          return -1;
800
 
        }
801
 
    }
802
 
#endif
803
 
 
804
 
#ifdef USE_DNS_SRV
805
 
  /* Do the SRV thing */
806
 
  if(flags&HTTP_FLAG_TRY_SRV && srvtag)
807
 
    {
808
 
      /* We're using SRV, so append the tags */
809
 
      if(1+strlen(srvtag)+6+strlen(server)+1<=MAXDNAME)
810
 
        {
811
 
          char srvname[MAXDNAME];
812
 
 
813
 
          strcpy(srvname,"_");
814
 
          strcat(srvname,srvtag);
815
 
          strcat(srvname,"._tcp.");
816
 
          strcat(srvname,server);
817
 
          srvcount=getsrv(srvname,&srvlist);
818
 
        }
819
 
    }
820
 
#endif
821
 
 
822
 
  if(srvlist==NULL)
823
 
    {
824
 
      /* Either we're not using SRV, or the SRV lookup failed.  Make
825
 
         up a fake SRV record. */
826
 
      srvlist=m_alloc_clear(sizeof(struct srventry));
827
 
      srvlist->port=port;
828
 
      strncpy(srvlist->target,server,MAXDNAME);
829
 
      srvlist->target[MAXDNAME-1]='\0';
830
 
      srvcount=1;
831
 
    }
832
 
 
833
 
#ifdef HAVE_GETADDRINFO
834
 
 
835
 
  for(srv=0;srv<srvcount;srv++)
836
 
    {
837
 
      struct addrinfo hints,*res,*ai;
838
 
      char portstr[6];
839
 
 
840
 
      sprintf(portstr,"%u",srvlist[srv].port);
841
 
      memset(&hints,0,sizeof(hints));
842
 
      hints.ai_socktype=SOCK_STREAM;
843
 
      if(getaddrinfo(srvlist[srv].target,portstr,&hints,&res)==0)
844
 
        hostfound=1;
845
 
      else
846
 
        continue;
847
 
 
848
 
      for(ai=res;ai;ai=ai->ai_next)
849
 
        {
850
 
          if((sock=socket(ai->ai_family,ai->ai_socktype,ai->ai_protocol))==-1)
851
 
            {
852
 
              log_error("error creating socket: %s\n",strerror(errno));
853
 
              freeaddrinfo(res);
854
 
              return -1;
855
 
            }
856
 
 
857
 
          if(connect(sock,ai->ai_addr,ai->ai_addrlen)==0)
858
 
            {
859
 
              connected=1;
860
 
              break;
861
 
            }
862
 
        }
863
 
 
864
 
      freeaddrinfo(res);
865
 
 
866
 
      if(ai)
867
 
        break;
868
 
    }
869
 
 
870
 
#else /* !HAVE_GETADDRINFO */
871
 
 
872
 
  for(srv=0;srv<srvcount;srv++)
873
 
    {
874
 
      int i=0;
875
 
      struct hostent *host=NULL;
876
 
      struct sockaddr_in addr;
877
 
 
878
 
      memset(&addr,0,sizeof(addr));
879
 
 
880
 
      if((host=gethostbyname(srvlist[srv].target))==NULL)
881
 
        continue;
882
 
 
883
 
      if((sock=socket(host->h_addrtype,SOCK_STREAM,0))==-1)
884
 
        {
885
 
          log_error("error creating socket: %s\n",strerror(errno));
886
 
          return -1;
887
 
        }
888
 
 
889
 
      addr.sin_family=host->h_addrtype;
890
 
      if(addr.sin_family!=AF_INET)
891
 
        {
892
 
          log_error("%s: unknown address family\n",srvlist[srv].target);
893
 
          return -1;
894
 
        }
895
 
 
896
 
      addr.sin_port=htons(srvlist[srv].port);
897
 
 
898
 
      /* Try all A records until one responds. */
899
 
      while(host->h_addr_list[i])
900
 
        {
901
 
          if(host->h_length!=4)
902
 
            {
903
 
              log_error("%s: illegal address length\n",srvlist[srv].target);
904
 
              return -1;
905
 
            }
906
 
 
907
 
          memcpy(&addr.sin_addr,host->h_addr_list[i],host->h_length);
908
 
 
909
 
          if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0)
910
 
            {
911
 
              connected=1;
912
 
              break;
913
 
            }
914
 
 
915
 
          i++;
916
 
        }
917
 
 
918
 
      if(host->h_addr_list[i])
919
 
        break;
920
 
    }
921
 
#endif /* !HAVE_GETADDRINFO */
922
 
 
923
 
  m_free(srvlist);
924
 
 
925
 
  if(!connected)
926
 
    {
927
 
#ifdef _WIN32
928
 
      if(hostfound)
929
 
        log_error("%s: Unable to connect: ec=%d\n",server,(int)WSAGetLastError());
930
 
      else
931
 
        log_error("%s: Host not found: ec=%d\n",server,(int)WSAGetLastError());
932
 
#else
933
 
      if(hostfound)
934
 
        log_error("%s: %s\n",server,strerror(errno));
935
 
      else
936
 
        log_error("%s: Host not found\n",server);
937
 
#endif
938
 
      if(sock!=-1)
939
 
        sock_close(sock);
940
 
      return -1;
941
 
    }
942
 
 
943
 
  return sock;
944
 
}
945
 
 
946
 
 
947
 
static int
948
 
write_server( int sock, const char *data, size_t length )
949
 
{
950
 
    int nleft;
951
 
 
952
 
    nleft = length;
953
 
    while( nleft > 0 ) {
954
 
#ifdef _WIN32  
955
 
        int nwritten;
956
 
 
957
 
        nwritten = send (sock, data, nleft, 0);
958
 
        if ( nwritten == SOCKET_ERROR ) {
959
 
            log_info ("write failed: ec=%d\n", (int)WSAGetLastError ());
960
 
            return G10ERR_NETWORK;
961
 
        }
962
 
#else
963
 
        int nwritten = write( sock, data, nleft );
964
 
        if( nwritten == -1 ) {
965
 
            if( errno == EINTR )
966
 
                continue;
967
 
            if( errno == EAGAIN ) {
968
 
                struct timeval tv;
969
 
 
970
 
                tv.tv_sec =  0;
971
 
                tv.tv_usec = 50000;
972
 
                select(0, NULL, NULL, NULL, &tv);
973
 
                continue;
974
 
            }
975
 
            log_info("write failed: %s\n", strerror(errno));
976
 
            return G10ERR_NETWORK;
977
 
        }
978
 
#endif
979
 
        nleft -=nwritten;
980
 
        data += nwritten;
981
 
    }
982
 
 
983
 
    return 0;
984
 
}
985
 
 
986
 
/**** Test code ****/
987
 
#ifdef TEST
988
 
 
989
 
int
990
 
main(int argc, char **argv)
991
 
{
992
 
    int rc;
993
 
    PARSED_URI uri;
994
 
    URI_TUPLE r;
995
 
    struct http_context hd;
996
 
    int c;
997
 
 
998
 
    log_set_name("http-test");
999
 
    if( argc == 1 ) {
1000
 
        start_server();
1001
 
        return 0;
1002
 
    }
1003
 
 
1004
 
    if( argc != 2 ) {
1005
 
        fprintf(stderr,"usage: http-test uri\n");
1006
 
        return 1;
1007
 
    }
1008
 
    argc--; argv++;
1009
 
 
1010
 
    rc = parse_uri( &uri, *argv );
1011
 
    if( rc ) {
1012
 
        log_error("`%s': %s\n", *argv, g10_errstr(rc));
1013
 
        release_parsed_uri( uri );
1014
 
        return 1;
1015
 
    }
1016
 
 
1017
 
    printf("Scheme: %s\n", uri->scheme );
1018
 
    printf("Host  : %s\n", uri->host );
1019
 
    printf("Port  : %u\n", uri->port );
1020
 
    printf("Path  : %s\n", uri->path );
1021
 
    for( r=uri->params; r; r = r->next ) {
1022
 
        printf("Params: %s=%s", r->name, r->value );
1023
 
        if( strlen( r->value ) != r->valuelen )
1024
 
            printf(" [real length=%d]", (int)r->valuelen );
1025
 
        putchar('\n');
1026
 
    }
1027
 
    for( r=uri->query; r; r = r->next ) {
1028
 
        printf("Query : %s=%s", r->name, r->value );
1029
 
        if( strlen( r->value ) != r->valuelen )
1030
 
            printf(" [real length=%d]", (int)r->valuelen );
1031
 
        putchar('\n');
1032
 
    }
1033
 
    release_parsed_uri( uri ); uri = NULL;
1034
 
 
1035
 
    rc = http_open_document( &hd, *argv, 0, NULL );
1036
 
    if( rc ) {
1037
 
        log_error("can't get `%s': %s\n", *argv, g10_errstr(rc));
1038
 
        return 1;
1039
 
    }
1040
 
    log_info("open_http_document succeeded; status=%u\n", hd.status_code );
1041
 
    while( (c=iobuf_get( hd.fp_read)) != -1 )
1042
 
        putchar(c);
1043
 
    http_close( &hd );
1044
 
    return 0;
1045
 
}
1046
 
#endif /*TEST*/