00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
00212
00213
00214
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
00246 char in[64], out[64];
00247
00248 if (!user)
00249 user = "";
00250
00251 if (!password)
00252 password = "";
00253
00254
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
00297
00298
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
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
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
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
00388
00389
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
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
00482
00483
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
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
00522
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
00564 _httpc_mime_get_boundary(conn, boundary);
00565 len = sprintf(buffer, "\r\n--%s\r\n", boundary);
00566
00567
00568 if ((status = http_output_stream_write(conn->out, buffer, len)) != H_OK)
00569 return status;
00570
00571
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
00589 _httpc_mime_get_boundary(conn, boundary);
00590 len = sprintf(buffer, "\r\n--%s--\r\n\r\n", boundary);
00591
00592
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
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 }