source: trunk/third/libghttp/ghttp.c @ 15592

Revision 15592, 19.2 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r15591, which included commits to RCS files with non-trunk default branches.
RevLine 
[15591]1/*
2 * ghttp.c -- Implementation of the public interface to http functions
3 * Created: Christopher Blizzard <blizzard@appliedtheory.com>, 21-Aug-1998
4 *
5 * Copyright (C) 1998 Free Software Foundation
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library 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 GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include <stdlib.h>
23#include <string.h>
24#include <unistd.h>
25#include "ghttp.h"
26#include "http_uri.h"
27#include "http_hdrs.h"
28#include "http_trans.h"
29#include "http_req.h"
30#include "http_resp.h"
31#include "http_date.h"
32#include "http_global.h"
33#include "http_base64.h"
34
35struct _ghttp_request
36{
37  http_uri           *uri;
38  http_uri           *proxy;
39  http_req           *req;
40  http_resp          *resp;
41  http_trans_conn    *conn;
42  const char         *errstr;
43  int                 connected;
44  ghttp_proc          proc;
45  char               *username;
46  char               *password;
47  char               *authtoken;
48  char               *proxy_username;
49  char               *proxy_password;
50  char               *proxy_authtoken;
51};
52
53static const char *basic_header = "Basic ";
54
55ghttp_request *
56ghttp_request_new(void)
57{
58  struct _ghttp_request *l_return = NULL;
59
60  /* create everything */
61  l_return = malloc(sizeof(struct _ghttp_request));
62  memset(l_return, 0, sizeof(struct _ghttp_request));
63  l_return->uri = http_uri_new();
64  l_return->proxy = http_uri_new();
65  l_return->req = http_req_new();
66  l_return->resp = http_resp_new();
67  l_return->conn = http_trans_conn_new();
68  return l_return;
69}
70
71void
72ghttp_request_destroy(ghttp_request *a_request)
73{
74  if (!a_request)
75    return;
76  /* make sure that the socket was shut down. */
77  if (a_request->conn->sock >= 0)
78    {
79      close(a_request->conn->sock);
80      a_request->conn->sock = -1;
81    }
82  /* destroy everything else */
83  if (a_request->uri)
84    http_uri_destroy(a_request->uri);
85  if (a_request->proxy)
86    http_uri_destroy(a_request->proxy);
87  if (a_request->req)
88    http_req_destroy(a_request->req);
89  if (a_request->resp)
90    http_resp_destroy(a_request->resp);
91  if (a_request->conn)
92    http_trans_conn_destroy(a_request->conn);
93  /* destroy username info. */
94  if (a_request->username)
95    {
96      free(a_request->username);
97      a_request->username = NULL;
98    }
99  if (a_request->password)
100    {
101      free(a_request->password);
102      a_request->password = NULL;
103    }
104  if (a_request->authtoken)
105    {
106      free(a_request->authtoken);
107      a_request->authtoken = NULL;
108    }
109  /* destroy proxy authentication */
110  if (a_request->proxy_username)
111    {
112      free(a_request->proxy_username);
113      a_request->proxy_username = NULL;
114    }
115  if (a_request->proxy_password)
116    {
117      free(a_request->proxy_password);
118      a_request->proxy_password = NULL;
119    }
120  if (a_request->proxy_authtoken)
121    {
122      free(a_request->proxy_authtoken);
123      a_request->proxy_authtoken = NULL;
124    }
125  if (a_request)
126    free(a_request);
127  return;
128}
129
130int
131ghttp_uri_validate(char *a_uri)
132{
133  if (!a_uri)
134    return -1;
135  /* you can do this... */
136  return(http_uri_parse(a_uri, NULL));
137}
138
139int
140ghttp_set_uri(ghttp_request *a_request, char *a_uri)
141{
142  int l_rv = 0;
143  http_uri *l_new_uri = NULL;
144
145  if ((!a_request) || (!a_uri))
146    return -1;
147  /* set the uri */
148  l_new_uri = http_uri_new();
149  l_rv = http_uri_parse(a_uri, l_new_uri);
150  if (l_rv < 0)
151    {
152      http_uri_destroy(l_new_uri);
153      return -1;
154    }
155  if (a_request->uri)
156    {
157      /* check to see if this has been set yet. */
158      if (a_request->uri->host &&
159          a_request->uri->port &&
160          a_request->uri->resource)
161        {
162          /* check to see if we just need to change the resource */
163          if ((!strcmp(a_request->uri->host, l_new_uri->host)) &&
164              (a_request->uri->port == l_new_uri->port))
165            {
166              free(a_request->uri->resource);
167              /* make a copy since we're about to destroy it */
168              a_request->uri->resource = strdup(l_new_uri->resource);
169              http_uri_destroy(l_new_uri);
170            }
171          else
172            {
173              http_uri_destroy(a_request->uri);
174              a_request->uri = l_new_uri;
175            }
176        }
177      else
178        {
179          http_uri_destroy(a_request->uri);
180          a_request->uri = l_new_uri;
181        }
182    }
183  return 0;
184}
185
186int
187ghttp_set_proxy(ghttp_request *a_request, char *a_uri)
188{
189  int l_rv = 0;
190 
191  if ((!a_request) || (!a_uri))
192    return -1;
193  /* set the uri */
194  l_rv = http_uri_parse(a_uri, a_request->proxy);
195  if (l_rv < 0)
196    return -1;
197  return 0;
198}
199
200int
201ghttp_set_type(ghttp_request *a_request, ghttp_type a_type)
202{
203  int l_return = 0;
204
205  /* check to make sure that the args are ok */
206  if (!a_request)
207    return -1;
208  /* switch on all of the supported types */
209  switch(a_type)
210    {
211    case ghttp_type_get:
212      a_request->req->type = http_req_type_get;
213      break;
214    case ghttp_type_options:
215      a_request->req->type = http_req_type_options;
216      break;
217    case ghttp_type_head:
218      a_request->req->type = http_req_type_head;
219      break;
220    case ghttp_type_post:
221      a_request->req->type = http_req_type_post;
222      break;
223    case ghttp_type_put:
224      a_request->req->type = http_req_type_put;
225      break;
226    case ghttp_type_delete:
227      a_request->req->type = http_req_type_delete;
228      break;
229    case ghttp_type_trace:
230      a_request->req->type = http_req_type_trace;
231      break;
232    case ghttp_type_connect:
233      a_request->req->type = http_req_type_connect;
234      break;
235    case ghttp_type_propfind:
236      a_request->req->type = http_req_type_propfind;
237      break;
238    case ghttp_type_proppatch:
239      a_request->req->type = http_req_type_proppatch;
240      break;
241    case ghttp_type_mkcol:
242      a_request->req->type = http_req_type_mkcol;
243      break;
244    case ghttp_type_copy:
245      a_request->req->type = http_req_type_copy;
246      break;
247    case ghttp_type_move:
248      a_request->req->type = http_req_type_move;
249      break;
250    case ghttp_type_lock:
251      a_request->req->type = http_req_type_lock;
252      break;
253    case ghttp_type_unlock:
254      a_request->req->type = http_req_type_unlock;
255      break;
256    default:
257      l_return = -1;
258      break;
259    }
260  return l_return;
261}
262
263int
264ghttp_set_body(ghttp_request *a_request, char *a_body, int a_len)
265{
266  /* check to make sure the request is there */
267  if (!a_request)
268    return -1;
269  /* check to make sure the body is there */
270  if ((a_len > 0) && (a_body == NULL))
271    return -1;
272  /* check to make sure that it makes sense */
273  if ((a_request->req->type != http_req_type_post) &&
274      (a_request->req->type != http_req_type_put) &&
275      (a_request->req->type != http_req_type_proppatch) &&
276      (a_request->req->type != http_req_type_propfind) &&
277      (a_request->req->type != http_req_type_lock))
278    return -1;
279  /* set the variables */
280  a_request->req->body = a_body;
281  a_request->req->body_len = a_len;
282  return 0;
283}
284
285int
286ghttp_set_sync(ghttp_request *a_request,
287               ghttp_sync_mode a_mode)
288{
289  if (!a_request)
290    return -1;
291  if (a_mode == ghttp_sync)
292    a_request->conn->sync = HTTP_TRANS_SYNC;
293  else if (a_mode == ghttp_async)
294    a_request->conn->sync = HTTP_TRANS_ASYNC;
295  else
296    return -1;
297  return 0;
298}
299
300int
301ghttp_prepare(ghttp_request *a_request)
302{
303  /* only allow http requests if no proxy has been set */
304  if (!a_request->proxy->host && a_request->uri->proto &&
305      strcmp(a_request->uri->proto, "http"))
306    return 1;
307  /* check to see if we have to set up the
308     host information */
309  if ((a_request->conn->host == NULL) ||
310      (a_request->conn->host != a_request->uri->host) ||
311      (a_request->conn->port != a_request->uri->port) ||
312      (a_request->conn->proxy_host != a_request->proxy->host) ||
313      (a_request->conn->proxy_port != a_request->proxy->port))
314    {
315      /* reset everything. */
316      a_request->conn->host = a_request->uri->host;
317      a_request->req->host = a_request->uri->host;
318      a_request->req->full_uri = a_request->uri->full;
319      a_request->conn->port = a_request->uri->port;
320      a_request->conn->proxy_host = a_request->proxy->host;
321      a_request->conn->proxy_port = a_request->proxy->port;
322      a_request->conn->hostinfo = NULL;
323      /* close the socket if it looks open */
324      if (a_request->conn->sock >= 0)
325        {
326          close(a_request->conn->sock);
327          a_request->conn->sock = -1;
328          a_request->connected = 0;
329        }
330    }
331  /* check to see if we need to change the resource. */
332  if ((a_request->req->resource == NULL) ||
333      (a_request->req->resource != a_request->uri->resource))
334    {
335      a_request->req->resource = a_request->uri->resource;
336      a_request->req->host = a_request->uri->host;
337    }
338  /* set the authorization header */
339  if ((a_request->authtoken != NULL) &&
340      (strlen(a_request->authtoken) > 0))
341    {
342      http_hdr_set_value(a_request->req->headers,
343                         http_hdr_Authorization,
344                         a_request->authtoken);
345    }
346  else
347    {
348      http_hdr_set_value(a_request->req->headers,
349                         http_hdr_WWW_Authenticate,
350                         NULL);
351    }
352  /* set the proxy authorization header */
353  if ((a_request->proxy_authtoken != NULL) &&
354      (strlen(a_request->proxy_authtoken) > 0))
355    {
356      http_hdr_set_value(a_request->req->headers,
357                         http_hdr_Proxy_Authorization,
358                         a_request->proxy_authtoken);
359    }
360  http_req_prepare(a_request->req);
361  return 0;
362}
363
364ghttp_status
365ghttp_process(ghttp_request *a_request)
366{
367  int l_rv = 0;
368
369  if (a_request->proc == ghttp_proc_none)
370    a_request->proc = ghttp_proc_request;
371  if (a_request->proc == ghttp_proc_request)
372    {
373      if (a_request->connected == 0)
374        {
375          if (http_trans_connect(a_request->conn) < 0)
376            {
377              if (a_request->conn->error_type == http_trans_err_type_errno)
378                a_request->errstr = strerror(a_request->conn->error);
379              else if(a_request->conn->error_type == http_trans_err_type_host)
380                a_request->errstr = http_trans_get_host_error(h_errno);
381              return ghttp_error;
382            }
383          a_request->connected = 1;
384        }
385      l_rv = http_req_send(a_request->req, a_request->conn);
386      if (l_rv == HTTP_TRANS_ERR)
387        return ghttp_error;
388      if (l_rv == HTTP_TRANS_NOT_DONE)
389        return ghttp_not_done;
390      if (l_rv == HTTP_TRANS_DONE)
391        {
392          a_request->proc = ghttp_proc_response_hdrs;
393          if (a_request->conn->sync == HTTP_TRANS_ASYNC)
394            return ghttp_not_done;
395        }
396    }
397  if (a_request->proc == ghttp_proc_response_hdrs)
398    {
399      l_rv = http_resp_read_headers(a_request->resp, a_request->conn);
400      if (l_rv == HTTP_TRANS_ERR)
401        return ghttp_error;
402      if (l_rv == HTTP_TRANS_NOT_DONE)
403        return ghttp_not_done;
404      if (l_rv == HTTP_TRANS_DONE)
405        {
406          a_request->proc = ghttp_proc_response;
407          if (a_request->conn->sync == HTTP_TRANS_ASYNC)
408            return ghttp_not_done;
409        }
410    }
411  if (a_request->proc == ghttp_proc_response)
412    {
413      l_rv = http_resp_read_body(a_request->resp,
414                                 a_request->req,
415                                 a_request->conn);
416      if (l_rv == HTTP_TRANS_ERR)
417        {
418          /* make sure that the connected flag is fixed and stuff */
419          if (a_request->conn->sock == -1)
420            a_request->connected = 0;
421          return ghttp_error;
422        }
423      if (l_rv == HTTP_TRANS_NOT_DONE)
424        return ghttp_not_done;
425      if (l_rv == HTTP_TRANS_DONE)
426        {
427        /* make sure that the connected flag is fixed and stuff */
428          if (a_request->conn->sock == -1)
429            a_request->connected = 0;
430          a_request->proc = ghttp_proc_none;
431          return ghttp_done;
432        }
433    }
434  return ghttp_error;
435}
436
437ghttp_current_status
438ghttp_get_status(ghttp_request *a_request)
439{
440  ghttp_current_status l_return;
441
442  l_return.proc = a_request->proc;
443  if (a_request->proc == ghttp_proc_request)
444    {
445      l_return.bytes_read = a_request->conn->io_buf_io_done;
446      l_return.bytes_total = a_request->conn->io_buf_alloc;
447    }
448  else if (a_request->proc == ghttp_proc_response_hdrs)
449    {
450      l_return.bytes_read = 0;
451      l_return.bytes_total = 0;
452    }
453  else if (a_request->proc == ghttp_proc_response)
454    {
455      if (a_request->resp->content_length > 0)
456        {
457          l_return.bytes_read = a_request->resp->body_len +
458            a_request->conn->io_buf_alloc +
459            a_request->resp->flushed_length;
460          l_return.bytes_total = a_request->resp->content_length;
461        }
462      else
463        {
464          l_return.bytes_read = a_request->resp->body_len +
465            a_request->conn->io_buf_alloc +
466            a_request->resp->flushed_length;
467          l_return.bytes_total = -1;
468        }
469    }
470  else
471    {
472      l_return.bytes_read = 0;
473      l_return.bytes_total = 0;
474    }
475  return l_return;
476}
477
478void
479ghttp_flush_response_buffer(ghttp_request *a_request)
480{
481  http_resp_flush(a_request->resp, a_request->conn);
482}
483
484int
485ghttp_close(ghttp_request *a_request)
486{
487  if (!a_request)
488    return -1;
489  if (a_request->conn->sock >= 0)
490    {
491      close(a_request->conn->sock);
492      a_request->conn->sock = -1;
493    }
494  a_request->connected = 0;
495  return 0;
496}
497
498void
499ghttp_clean(ghttp_request *a_request)
500{
501  http_resp_destroy(a_request->resp);
502  a_request->resp = http_resp_new();
503  http_req_destroy(a_request->req);
504  a_request->req = http_req_new();
505  http_trans_buf_reset(a_request->conn);
506  a_request->proc = ghttp_proc_none;
507  return;
508}
509
510void
511ghttp_set_chunksize(ghttp_request *a_request, int a_size)
512{
513  if (a_request && (a_size > 0))
514    a_request->conn->io_buf_chunksize = a_size;
515}
516
517void
518ghttp_set_header(ghttp_request *a_request,
519                 const char *a_hdr, const char *a_val)
520{
521  http_hdr_set_value(a_request->req->headers,
522                     a_hdr, a_val);
523}
524
525const char *
526ghttp_get_header(ghttp_request *a_request,
527                 const char *a_hdr)
528{
529  return http_hdr_get_value(a_request->resp->headers,
530                            a_hdr);
531}
532
533int
534ghttp_get_header_names(ghttp_request *a_request,
535                       char ***a_hdrs, int *a_num_hdrs)
536{
537  return http_hdr_get_headers(a_request->resp->headers,
538                              a_hdrs, a_num_hdrs);
539}
540
541const char *
542ghttp_get_error(ghttp_request *a_request)
543{
544  if (a_request->errstr == NULL)
545    return "Unknown Error.";
546  return a_request->errstr;
547}
548
549time_t
550ghttp_parse_date(char *a_date)
551{
552  if (!a_date)
553    return 0;
554  return (http_date_to_time(a_date));
555}
556
557int
558ghttp_status_code(ghttp_request *a_request)
559{
560  if (!a_request)
561    return 0;
562  return(a_request->resp->status_code);
563}
564
565const char *
566ghttp_reason_phrase(ghttp_request *a_request)
567{
568  if (!a_request)
569    return 0;
570  return(a_request->resp->reason_phrase);
571}
572
573int
574ghttp_get_socket(ghttp_request *a_request)
575{
576  if (!a_request)
577    return -1;
578  return(a_request->conn->sock);
579}
580
581char *
582ghttp_get_body(ghttp_request *a_request)
583{
584  if (!a_request)
585    return NULL;
586  if (a_request->proc == ghttp_proc_none)
587    return (a_request->resp->body);
588  if (a_request->proc == ghttp_proc_response)
589    {
590      if (a_request->resp->content_length > 0)
591        {
592          if (a_request->resp->body_len)
593            return a_request->resp->body;
594          else
595            return a_request->conn->io_buf;
596        }
597      else
598        {
599          return a_request->resp->body;
600        }
601    }
602  return NULL;
603}
604
605int
606ghttp_get_body_len(ghttp_request *a_request)
607{
608  if (!a_request)
609    return 0;
610  if (a_request->proc == ghttp_proc_none)
611    return (a_request->resp->body_len);
612  if (a_request->proc == ghttp_proc_response)
613    {
614      if (a_request->resp->content_length > 0)
615        {
616          if (a_request->resp->body_len)
617            return a_request->resp->body_len;
618          else
619            return a_request->conn->io_buf_alloc;
620        }
621      else
622        {
623          return a_request->resp->body_len;
624        }
625    }
626  return 0;
627}
628
629int
630ghttp_set_authinfo(ghttp_request *a_request,
631                   const char *a_user,
632                   const char *a_pass)
633{
634  char *l_authtoken = NULL;
635  char *l_final_auth = NULL;
636  char *l_auth64 = NULL;
637
638  /* check our args */
639  if (!a_request)
640    return -1;
641  /* if we have a NULL or zero length string in the username
642     or password field, blitz the authinfo */
643  if ((!a_user) || (strlen(a_user) < 1) ||
644      (!a_pass) || (strlen(a_pass)< 1))
645    {
646      if (a_request->username)
647        {
648          free(a_request->username);
649          a_request->username = NULL;
650        }
651      if (a_request->password)
652        {
653          free(a_request->password);
654          a_request->password = NULL;
655        }
656      if (a_request->authtoken)
657        {
658          free(a_request->authtoken);
659          a_request->authtoken = NULL;
660        }
661      return 0;
662    }
663  /* encode the string using base64.  Usernames and passwords
664     for basic authentication are encoded like this:
665     username:password
666     That's it.  Easy, huh?
667  */
668  /* enough for the trailing \0 and the : */
669  l_authtoken = malloc(strlen(a_user) + strlen(a_pass) + 2);
670  memset(l_authtoken, 0, (strlen(a_user) + strlen(a_pass) + 2));
671  sprintf(l_authtoken, "%s:%s", a_user, a_pass);
672  l_auth64 = http_base64_encode(l_authtoken);
673  if (!l_auth64)
674    {
675      free(l_authtoken);
676      return -1;
677    }
678  /* build the final header */
679  l_final_auth = malloc(strlen(l_auth64) + strlen(basic_header) + 1);
680  memset(l_final_auth, 0, (strlen(l_auth64) + strlen(basic_header) + 1));
681  strcat(l_final_auth, basic_header);
682  strcat(l_final_auth, l_auth64);
683  free(l_auth64);
684  free(l_authtoken);
685  /* copy the strings into the request */
686
687  if (a_request->username) free(a_request->username);
688  if (a_request->password) free(a_request->password);
689  if (a_request->authtoken) free(a_request->authtoken);
690  a_request->username = strdup(a_user);
691  a_request->password = strdup(a_pass);
692  a_request->authtoken = l_final_auth;
693
694  return 0;
695}
696
697
698int
699ghttp_set_proxy_authinfo(ghttp_request *a_request,
700                         const char *a_user,
701                         const char *a_pass)
702{
703  char *l_authtoken = NULL;
704  char *l_final_auth = NULL;
705  char *l_auth64 = NULL;
706 
707  /* check our args */
708  if (!a_request)
709    return -1;
710  /* if we have a NULL or zero length string in the username
711     or password field, blitz the authinfo */
712  if ((!a_user) || (strlen(a_user) < 1) ||
713      (!a_pass) || (strlen(a_pass)< 1))
714    {
715      if (a_request->proxy_username)
716        {
717          free(a_request->proxy_username);
718          a_request->proxy_username = NULL;
719        }
720      if (a_request->proxy_password)
721        {
722          free(a_request->proxy_password);
723          a_request->proxy_password = NULL;
724        }
725      if (a_request->proxy_authtoken)
726        {
727          free(a_request->proxy_authtoken);
728          a_request->proxy_authtoken = NULL;
729        }
730      return 0;
731    }
732  /* encode the string using base64.  Usernames and passwords
733     for basic authentication are encoded like this:
734     username:password
735     That's it.  Easy, huh?
736  */
737  /* enough for the trailing \0 and the : */
738  l_authtoken = malloc(strlen(a_user) + strlen(a_pass) + 2);
739  memset(l_authtoken, 0, (strlen(a_user) + strlen(a_pass) + 2));
740  sprintf(l_authtoken, "%s:%s", a_user, a_pass);
741  l_auth64 = http_base64_encode(l_authtoken);
742  if (!l_auth64)
743    {
744      free(l_authtoken);
745      return -1;
746    }
747  /* build the final header */
748  l_final_auth = malloc(strlen(l_auth64) + strlen(basic_header) + 1);
749  memset(l_final_auth, 0, (strlen(l_auth64) + strlen(basic_header) + 1));
750  strcat(l_final_auth, basic_header);
751  strcat(l_final_auth, l_auth64);
752  free(l_auth64);
753  free(l_authtoken);
754  /* copy the strings into the request */
755  if (a_request->proxy_username) free(a_request->proxy_username);
756  if (a_request->proxy_password) free(a_request->proxy_password);
757  if (a_request->proxy_authtoken) free(a_request->proxy_authtoken);
758  a_request->proxy_username = strdup(a_user);
759  a_request->proxy_password = strdup(a_pass);
760  a_request->proxy_authtoken = l_final_auth;
761 
762  return 0;
763}
Note: See TracBrowser for help on using the repository browser.