nanohttp-client.c

Go to the documentation of this file.
00001 /******************************************************************
00002 *  $Id: nanohttp-client.c,v 1.53 2007/01/01 22:54:46 m0gg Exp $
00003 *
00004 * CSOAP Project:  A http client/server library in C
00005 * Copyright (C) 2003  Ferhat Ayaz
00006 *
00007 * This library is free software; you can redistribute it and/or
00008 * modify it under the terms of the GNU Library General Public
00009 * License as published by the Free Software Foundation; either
00010 * version 2 of the License, or (at your option) any later version.
00011 *
00012 * This library is distributed in the hope that it will be useful,
00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015 * Library General Public License for more details.
00016 *
00017 * You should have received a copy of the GNU Library General Public
00018 * License along with this library; if not, write to the
00019 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00020 * Boston, MA  02111-1307, USA.
00021 *
00022 * Email: ferhatayaz@yahoo.com
00023 ******************************************************************/
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 
00028 #ifdef HAVE_SYS_TIME_H
00029 #include <sys/time.h>
00030 #endif
00031 
00032 #ifdef HAVE_STDLIB_H
00033 #include <stdlib.h>
00034 #endif
00035 
00036 #ifdef HAVE_STDIO_H
00037 #include <stdio.h>
00038 #endif
00039 
00040 #ifdef HAVE_STDLIB_H
00041 #include <stdlib.h>
00042 #endif
00043 
00044 #ifdef HAVE_STDARG_H
00045 #include <stdarg.h>
00046 #endif
00047 
00048 #ifdef HAVE_ERRNO_H
00049 #include <errno.h>
00050 #endif
00051 
00052 #ifdef HAVE_STRING_H
00053 #include <string.h>
00054 #endif
00055 
00056 #ifdef HAVE_TIME_H
00057 #include <time.h>
00058 #endif
00059 
00060 #ifdef HAVE_NETINET_IN_H
00061 #include <netinet/in.h>
00062 #endif
00063 
00064 #ifdef WIN32
00065 #define snprintf(buffer, num, s1, s2) sprintf(buffer, s1,s2)
00066 #endif
00067 
00068 #include "nanohttp-logging.h"
00069 #include "nanohttp-error.h"
00070 #include "nanohttp-common.h"
00071 #include "nanohttp-socket.h"
00072 #include "nanohttp-stream.h"
00073 #include "nanohttp-request.h"
00074 #include "nanohttp-response.h"
00075 #include "nanohttp-base64.h"
00076 #include "nanohttp-url.h"
00077 #include "nanohttp-client.h"
00078 
00079 herror_t
00080 httpc_init(int argc, char **argv)
00081 {
00082   return hsocket_module_init(argc, argv);
00083 }
00084 
00085 void
00086 httpc_destroy(void)
00087 {
00088   hsocket_module_destroy();
00089 
00090   return;
00091 }
00092 
00093 httpc_conn_t *
00094 httpc_new(void)
00095 {
00096   static int counter = 10000;
00097   herror_t status;
00098   httpc_conn_t *res;
00099  
00100   if (!(res = (httpc_conn_t *) malloc(sizeof(httpc_conn_t))))
00101   {
00102     log_error2("malloc failed (%s)", strerror(errno));
00103     return NULL;
00104   }
00105 
00106   if (!(res->sock = (struct hsocket_t *)malloc(sizeof(struct hsocket_t))))
00107   {
00108     log_error2("malloc failed (%s)", strerror(errno));
00109     free(res);
00110     return NULL;
00111   }
00112 
00113   if (!(res->url = (struct hurl_t *)malloc(sizeof(struct hurl_t))))
00114   {
00115     log_error2("malloc failed (%s)", strerror(errno));
00116     free(res->sock);
00117     free(res);
00118     return NULL;
00119   }
00120 
00121   if ((status = hsocket_init(res->sock)) != H_OK)
00122   {
00123     log_warn2("hsocket_init failed (%s)", herror_message(status));
00124     hurl_free(res->url);
00125     free(res->sock);
00126     free(res);
00127     return NULL;
00128   }
00129 
00130   res->header = NULL;
00131   res->version = HTTP_1_1;
00132   res->out = NULL;
00133   res->id = counter++;
00134 
00135   return res;
00136 }
00137 
00138 void
00139 httpc_free(httpc_conn_t * conn)
00140 {
00141   hpair_t *tmp;
00142 
00143   if (conn == NULL)
00144     return;
00145 
00146   while (conn->header != NULL)
00147   {
00148     tmp = conn->header;
00149     conn->header = conn->header->next;
00150     hpairnode_free(tmp);
00151   }
00152 
00153   if (conn->out != NULL)
00154   {
00155     http_output_stream_free(conn->out);
00156     conn->out = NULL;
00157   }
00158 
00159   hsocket_free(conn->sock);
00160   hurl_free(conn->url);
00161 
00162   if (conn->sock)
00163     free(conn->sock);
00164   free(conn);
00165 
00166   return;
00167 }
00168 
00169 void
00170 httpc_close_free(httpc_conn_t * conn)
00171 {
00172   if (conn == NULL)
00173     return;
00174 
00175   hsocket_close(conn->sock);
00176   httpc_free(conn);
00177 
00178   return;
00179 }
00180 
00181 int
00182 httpc_add_header(httpc_conn_t *conn, const char *key, const char *value)
00183 {
00184   if (!conn)
00185   {
00186     log_warn1("Connection object is NULL");
00187     return -1;
00188   }
00189 
00190   conn->header = hpairnode_new(key, value, conn->header);
00191 
00192   return 0;
00193 }
00194 
00195 void
00196 httpc_add_headers(httpc_conn_t *conn, const hpair_t *values)
00197 {
00198   if (conn == NULL)
00199   {
00200     log_warn1("Connection object is NULL");
00201     return;
00202   }
00203 
00204   for ( ;values; values=values->next)
00205     httpc_add_header(conn, values->key, values->value);
00206 
00207   return;
00208 }
00209  
00210 /*--------------------------------------------------
00211 FUNCTION: httpc_set_header
00212 DESC: Adds a new (key, value) pair to the header
00213 or modifies the old pair if this function will
00214 finds another pair with the same 'key' value.
00215 ----------------------------------------------------*/
00216 int
00217 httpc_set_header(httpc_conn_t *conn, const char *key, const char *value)
00218 {
00219   hpair_t *p;
00220 
00221   if (conn == NULL)
00222   {
00223     log_warn1("Connection object is NULL");
00224     return 0;
00225   }
00226 
00227   for (p = conn->header; p; p = p->next)
00228   {
00229     if (p->key && !strcmp(p->key, key))
00230     {
00231       free(p->value);
00232       p->value = strdup(value);
00233       return 1;
00234     }
00235   }
00236 
00237   conn->header = hpairnode_new(key, value, conn->header);
00238 
00239   return 0;
00240 }
00241 
00242 static int
00243 _httpc_set_basic_authorization_header(httpc_conn_t *conn, const char *key, const char *user, const char *password)
00244 {
00245   /* XXX: use malloc/free */
00246   char in[64], out[64];
00247 
00248   if (!user)
00249     user = "";
00250 
00251   if (!password)
00252     password = "";
00253 
00254   /* XXX: do we need this really? */
00255   memset(in, 0, 64);
00256   memset(out, 0, 64);
00257 
00258   sprintf(in, "%s:%s", user, password);
00259 
00260   base64_encode_string(in, out);
00261 
00262   sprintf(in, "Basic %s", out);
00263 
00264   return httpc_set_header(conn, key, in);
00265 }
00266 
00267 int
00268 httpc_set_basic_authorization(httpc_conn_t *conn, const char *user, const char *password)
00269 {
00270   return _httpc_set_basic_authorization_header(conn, HEADER_AUTHORIZATION, user, password);
00271 }
00272 
00273 int
00274 httpc_set_basic_proxy_authorization(httpc_conn_t *conn, const char *user, const char *password)
00275 {
00276   return _httpc_set_basic_authorization_header(conn, HEADER_PROXY_AUTHORIZATION, user, password);
00277 }
00278 
00279 static void
00280 httpc_header_set_date(httpc_conn_t * conn)
00281 {
00282   char buffer[32];
00283   time_t ts;
00284   struct tm stm;
00285 
00286   ts = time(NULL);
00287   localtime_r(&ts, &stm);
00288   strftime(buffer, 32, "%a, %d %b %Y %H:%M:%S GMT", &stm);
00289 
00290   httpc_set_header(conn, HEADER_DATE, buffer);
00291 
00292   return;
00293 }
00294 
00295 /*--------------------------------------------------
00296 FUNCTION: httpc_send_header
00297 DESC: Sends the current header information stored
00298 in conn through conn->sock.
00299 ----------------------------------------------------*/
00300 herror_t
00301 httpc_send_header(httpc_conn_t * conn)
00302 {
00303   hpair_t *walker;
00304   herror_t status;
00305   char buffer[1024];
00306   int len;
00307 
00308   for (walker = conn->header; walker; walker = walker->next)
00309   {
00310     if (walker->key && walker->value)
00311     {
00312       len = snprintf(buffer, 1024, "%s: %s\r\n", walker->key, walker->value);
00313       if ((status = hsocket_send(conn->sock, buffer, len)) != H_OK)
00314         return status;
00315     }
00316   }
00317 
00318   return hsocket_send_string(conn->sock, "\r\n");
00319 }
00320 
00321 /*--------------------------------------------------
00322 FUNCTION: httpc_talk_to_server
00323 DESC: This function is the heart of the httpc
00324 module. It will send the request and process the
00325 response.
00326 
00327 Here the parameters:
00328 
00329 method:
00330 the request method. This can be HTTP_REQUEST_POST and
00331 HTTP_REQUEST_GET.
00332 
00333 conn:
00334 the connection object (created with httpc_new())
00335 
00336 urlstr:
00337 the complete url in string format.
00338 http://<host>:<port>/<context>
00339 where <port> is not mendatory.
00340 
00341 start_cb:
00342 a callback function, which will be called when
00343 the response header is completely arrives.
00344 
00345 cb:
00346 a callback function, which will be called everytime
00347 when data arrives.
00348 
00349 content_size:
00350 size of content to send.
00351 (only if method is HTTP_REQUEST_POST)
00352 
00353 content:
00354 the content data to send.
00355 (only if method is HTTP_REQUEST_POST)
00356 
00357 userdata:
00358 a user define data, which will be passed to the
00359 start_cb and cb callbacks as a parameter. This
00360 can also be NULL.
00361 
00362 
00363 If success, this function will return 0.
00364 >0 otherwise.
00365 ----------------------------------------------------*/
00366 static herror_t
00367 _httpc_talk_to_server(hreq_method_t method, httpc_conn_t * conn, const char *urlstr)
00368 {
00369   char buffer[4096];
00370   herror_t status;
00371   int len;
00372   int ssl;
00373 
00374   if (conn == NULL)
00375   {
00376     return herror_new("httpc_talk_to_server", GENERAL_INVALID_PARAM, "httpc_conn_t param is NULL");
00377   }
00378 
00379   /* Build request header */
00380   httpc_header_set_date(conn);
00381 
00382   if ((status = hurl_parse(conn->url, urlstr)) != H_OK)
00383   {
00384     log_error2("Cannot parse URL \"%s\"", SAVE_STR(urlstr));
00385     return status;
00386   }
00387 /* TODO (#1#): Check for HTTP protocol in URL */
00388 
00389   /* Set hostname */
00390   httpc_set_header(conn, HEADER_HOST, conn->url->host);
00391 
00392   ssl = conn->url->protocol == PROTOCOL_HTTPS ? 1 : 0;
00393   log_verbose4("ssl = %i (%i %i)", ssl, conn->url->protocol, PROTOCOL_HTTPS);
00394 
00395   /* Open connection */
00396   if ((status = hsocket_open(conn->sock, conn->url->host, conn->url->port, ssl)) != H_OK)
00397   {
00398     log_error2("hsocket_open failed (%s)", herror_message(status));
00399     return status;
00400   }
00401 
00402   switch(method)
00403   {
00404     case HTTP_REQUEST_GET:
00405 
00406       len = sprintf(buffer, "GET %s HTTP/%s\r\n",
00407           (conn->url->context[0] != '\0') ? conn->url->context : ("/"),
00408           (conn->version == HTTP_1_0) ? "1.0" : "1.1");
00409       break;
00410 
00411     case HTTP_REQUEST_POST:
00412 
00413       len = sprintf(buffer, "POST %s HTTP/%s\r\n",
00414           (conn->url->context[0] != '\0') ? conn->url->context : ("/"),
00415           (conn->version == HTTP_1_0) ? "1.0" : "1.1");
00416       break;
00417 
00418     default:
00419       log_error1("Unknown method type!");
00420       return herror_new("httpc_talk_to_server",
00421         GENERAL_INVALID_PARAM,
00422         "hreq_method_t must be  HTTP_REQUEST_GET or HTTP_REQUEST_POST");
00423   }
00424 
00425   log_verbose1("Sending request...");
00426   if ((status = hsocket_send(conn->sock, buffer, len)) != H_OK)
00427   {
00428     log_error2("Cannot send request (%s)", herror_message(status));
00429     hsocket_close(conn->sock);
00430     return status;
00431   }
00432 
00433   log_verbose1("Sending header...");
00434   if ((status = httpc_send_header(conn)) != H_OK)
00435   {
00436     log_error2("Cannot send header (%s)", herror_message(status));
00437     hsocket_close(conn->sock);
00438     return status;
00439   }
00440 
00441   return H_OK;
00442 }
00443 
00444 herror_t
00445 httpc_get(httpc_conn_t *conn, hresponse_t **out, const char *urlstr)
00446 {
00447   herror_t status;
00448 
00449   if ((status = _httpc_talk_to_server(HTTP_REQUEST_GET, conn, urlstr)) != H_OK)
00450   {
00451     log_error2("_httpc_talk_to_server failed (%s)", herror_message(status));
00452     return status;
00453   }
00454 
00455   if ((status = hresponse_new_from_socket(conn->sock, out)) != H_OK)
00456   {
00457     log_error2("hresponse_new_from_socket failed (%s)", herror_message(status));
00458     return status;
00459   }
00460 
00461   return H_OK;
00462 }
00463 
00464 herror_t
00465 httpc_post_begin(httpc_conn_t * conn, const char *url)
00466 {
00467   herror_t status;
00468 
00469   if ((status = _httpc_talk_to_server(HTTP_REQUEST_POST, conn, url)) != H_OK)
00470   {
00471     log_error2("_httpc_talk_to_server failed (%s)", herror_message(status));
00472     return status;
00473   }
00474 
00475   conn->out = http_output_stream_new(conn->sock, conn->header);
00476 
00477   return H_OK;
00478 }
00479 
00480 /*--------------------------------------------------
00481 FUNCTION: httpc_post_begin
00482 DESC: End a "POST" method and receive the response.
00483   You MUST call httpc_post_end() before!
00484 ----------------------------------------------------*/
00485 herror_t
00486 httpc_post_end(httpc_conn_t * conn, hresponse_t ** out)
00487 {
00488   herror_t status;
00489 
00490   if ((status = http_output_stream_flush(conn->out)) != H_OK)
00491     return status;
00492 
00493   if ((status = hresponse_new_from_socket(conn->sock, out)) != H_OK)
00494     return status;
00495 
00496   return H_OK;
00497 }
00498 
00499 /* ---------------------------------------------------
00500   MIME support functions httpc_mime_* function set
00501 -----------------------------------------------------*/
00502 
00503 static void
00504 _httpc_mime_get_boundary(httpc_conn_t * conn, char *dest)
00505 {
00506   sprintf(dest, "---=.Part_NH_%d", conn->id);
00507   log_verbose2("boundary= \"%s\"", dest);
00508 
00509   return;
00510 }
00511 
00512 herror_t
00513 httpc_mime_begin(httpc_conn_t * conn, const char *url, const char *related_start, const char *related_start_info, const char *related_type)
00514 {
00515   herror_t status;
00516   char buffer[300];
00517   char temp[75];
00518   char boundary[75];
00519 
00520   /* 
00521      Set Content-type Set multipart/related parameter type=..; start=.. ;
00522      start-info= ..; boundary=...
00523 
00524    */
00525   sprintf(buffer, "multipart/related;");
00526 
00527   if (related_type)
00528   {
00529     snprintf(temp, 75, " type=\"%s\";", related_type);
00530     strcat(buffer, temp);
00531   }
00532 
00533   if (related_start)
00534   {
00535     snprintf(temp, 75, " start=\"%s\";", related_start);
00536     strcat(buffer, temp);
00537   }
00538 
00539   if (related_start_info)
00540   {
00541     snprintf(temp, 75, " start-info=\"%s\";", related_start_info);
00542     strcat(buffer, temp);
00543   }
00544 
00545   _httpc_mime_get_boundary(conn, boundary);
00546   snprintf(temp, 75, " boundary=\"%s\"", boundary);
00547   strcat(buffer, temp);
00548 
00549   httpc_set_header(conn, HEADER_CONTENT_TYPE, buffer);
00550 
00551   status = httpc_post_begin(conn, url);
00552   return status;
00553 }
00554 
00555 herror_t
00556 httpc_mime_next(httpc_conn_t * conn, const char *content_id, const char *content_type, const char *transfer_encoding)
00557 {
00558   herror_t status;
00559   char buffer[512];
00560   char boundary[75];
00561   int len;
00562 
00563   /* Get the boundary string */
00564   _httpc_mime_get_boundary(conn, boundary);
00565   len = sprintf(buffer, "\r\n--%s\r\n", boundary);
00566 
00567   /* Send boundary */
00568   if ((status = http_output_stream_write(conn->out, buffer, len)) != H_OK)
00569     return status;
00570 
00571   /* Send Content header */
00572   len = sprintf(buffer, "%s: %s\r\n%s: %s\r\n%s: %s\r\n\r\n",
00573             HEADER_CONTENT_TYPE, content_type,
00574             HEADER_CONTENT_TRANSFER_ENCODING, transfer_encoding,
00575             HEADER_CONTENT_ID, content_id);
00576 
00577   return http_output_stream_write(conn->out, buffer, len);
00578 }
00579 
00580 herror_t
00581 httpc_mime_end(httpc_conn_t * conn, hresponse_t ** out)
00582 {
00583   herror_t status;
00584   char buffer[512];
00585   char boundary[75];
00586   int len;
00587 
00588   /* Get the boundary string */
00589   _httpc_mime_get_boundary(conn, boundary);
00590   len = sprintf(buffer, "\r\n--%s--\r\n\r\n", boundary);
00591 
00592   /* Send boundary */
00593   if ((status = http_output_stream_write(conn->out, buffer, len)) != H_OK)
00594     return status;
00595 
00596   if ((status = http_output_stream_flush(conn->out)) != H_OK)
00597     return status;
00598 
00599   if ((status = hresponse_new_from_socket(conn->sock, out)) != H_OK)
00600     return status;
00601 
00602   return H_OK;
00603 }
00604 
00605 
00610 herror_t
00611 httpc_mime_send_file(httpc_conn_t * conn, const char *content_id, const char *content_type, const char *transfer_encoding, const char *filename)
00612 {
00613   herror_t status;
00614   FILE *fd;
00615   unsigned char buffer[MAX_FILE_BUFFER_SIZE];
00616   size_t size;
00617 
00618   if ((fd = fopen(filename, "rb")) == NULL)
00619   {
00620     log_error2("fopen failed (%s)", strerror(errno));
00621     return herror_new("httpc_mime_send_file", FILE_ERROR_OPEN,
00622                       "Can not open file \"%s\" (%s)", filename, strerror(errno));
00623   }
00624 
00625   status = httpc_mime_next(conn, content_id, content_type, transfer_encoding);
00626   if (status != H_OK)
00627   {
00628     fclose(fd);
00629     return status;
00630   }
00631 
00632   while (!feof(fd))
00633   {
00634     size = fread(buffer, 1, MAX_FILE_BUFFER_SIZE, fd);
00635     if (size == -1)
00636     {
00637       fclose(fd);
00638       return herror_new("httpc_mime_send_file", FILE_ERROR_READ,
00639                         "Can not read from file '%s'", filename);
00640     }
00641 
00642     if (size > 0)
00643     {
00644       /* DEBUG: fwrite(buffer, 1, size, stdout); */
00645       status = http_output_stream_write(conn->out, buffer, size);
00646       if (status != H_OK)
00647       {
00648         fclose(fd);
00649         return status;
00650       }
00651     }
00652   }
00653 
00654   fclose(fd);
00655   log_verbose1("file sent!");
00656 
00657   return H_OK;
00658 }

Generated on Thu Jan 25 23:36:02 2007 for csoap by  doxygen 1.4.6