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_SELECT_H
00029 #include <sys/select.h>
00030 #endif
00031
00032 #ifdef HAVE_SOCKET_H
00033 #include <sys/socket.h>
00034 #endif
00035
00036 #ifdef HAVE_SYS_TIME_H
00037 #include <sys/time.h>
00038 #endif
00039
00040 #ifdef HAVE_SYS_TYPES_H
00041 #include <sys/types.h>
00042 #endif
00043
00044 #ifdef HAVE_NETINET_IN_H
00045 #include <netinet/in.h>
00046 #endif
00047
00048 #ifdef HAVE_STDIO_H
00049 #include <stdio.h>
00050 #endif
00051
00052 #ifdef HAVE_STDLIB_H
00053 #include <stdlib.h>
00054 #endif
00055
00056 #ifdef HAVE_SIGNAL_H
00057 #include <signal.h>
00058 #endif
00059
00060 #ifdef HAVE_STRING_H
00061 #include <string.h>
00062 #endif
00063
00064 #ifdef HAVE_UNISTD_H
00065 #include <unistd.h>
00066 #endif
00067
00068 #ifdef HAVE_ERRNO_H
00069 #include <errno.h>
00070 #endif
00071
00072 #ifdef HAVE_PTHREAD_H
00073 #include <pthread.h>
00074 #endif
00075
00076 #ifdef HAVE_PROCESS_H
00077 #include <process.h>
00078 #endif
00079
00080 #include "nanohttp-logging.h"
00081 #include "nanohttp-error.h"
00082 #include "nanohttp-common.h"
00083 #include "nanohttp-socket.h"
00084 #include "nanohttp-stream.h"
00085 #include "nanohttp-request.h"
00086 #include "nanohttp-response.h"
00087 #include "nanohttp-server.h"
00088 #include "nanohttp-base64.h"
00089 #ifdef HAVE_SSL
00090 #ifdef HAVE_OPENSSL_SSL_H
00091 #include <openssl/ssl.h>
00092 #endif
00093 #include "nanohttp-ssl.h"
00094 #else
00095 static inline int hssl_enabled(void) { return 0; }
00096 #endif
00097 #include "nanohttp-admin.h"
00098
00099 #ifndef timeradd
00100 #define timeradd(tvp, uvp, vvp) \
00101 do { \
00102 (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \
00103 (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \
00104 if ((vvp)->tv_usec >= 1000000) { \
00105 (vvp)->tv_sec++; \
00106 (vvp)->tv_usec -= 1000000; \
00107 } \
00108 } while (0)
00109 #endif
00110
00111 #ifndef timersub
00112 #define timersub(tvp, uvp, vvp) \
00113 do { \
00114 (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
00115 (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
00116 if ((vvp)->tv_usec < 0) { \
00117 (vvp)->tv_sec--; \
00118 (vvp)->tv_usec += 1000000; \
00119 } \
00120 } while (0)
00121 #endif
00122
00123 typedef struct _conndata
00124 {
00125 volatile int flag;
00126 struct hsocket_t sock;
00127 #ifdef WIN32
00128 HANDLE tid;
00129 #else
00130 pthread_t tid;
00131 pthread_attr_t attr;
00132 #endif
00133 }
00134 conndata_t;
00135
00136 #define CONNECTION_FREE 0
00137 #define CONNECTION_IN_USE 1
00138
00144 static volatile int _httpd_run = 1;
00145
00146 static struct hsocket_t _httpd_socket;
00147 static int _httpd_port = 10000;
00148 static int _httpd_max_connections = 20;
00149
00150 static hservice_t *_httpd_services_default = NULL;
00151 static hservice_t *_httpd_services_head = NULL;
00152 static hservice_t *_httpd_services_tail = NULL;
00153
00154 static conndata_t *_httpd_connection;
00155
00156 #ifdef WIN32
00157 static DWORD _httpd_terminate_signal = CTRL_C_EVENT;
00158 static int _httpd_max_idle = 120;
00159 HANDLE _httpd_connection_lock;
00160 LPCTSTR _httpd_connection_lock_str;
00161 #define strncasecmp(s1, s2, num) strncmp(s1, s2, num)
00162 #define snprintf(buffer, num, s1, s2) sprintf(buffer, s1,s2)
00163 #else
00164 static int _httpd_terminate_signal = SIGINT;
00165 static sigset_t thrsigset;
00166 static pthread_mutex_t _httpd_connection_lock;
00167 #endif
00168
00169 #ifdef WIN32
00170 BOOL WINAPI
00171 _httpd_term(DWORD sig)
00172 {
00173
00174 if (sig == _httpd_terminate_signal)
00175 _httpd_run = 0;
00176
00177 return TRUE;
00178 }
00179
00180 static void _httpd_sys_sleep(int secs)
00181 {
00182 Sleep(secs*1000);
00183
00184 return;
00185 }
00186 #else
00187 static void
00188 _httpd_term(int sig)
00189 {
00190 log_debug2("Got signal %d", sig);
00191
00192 if (sig == _httpd_terminate_signal)
00193 _httpd_run = 0;
00194
00195 return;
00196 }
00197
00198 static inline void _httpd_sys_sleep(int secs)
00199 {
00200 sleep(secs);
00201
00202 return;
00203 }
00204 #endif
00205
00206 static void
00207 _httpd_parse_arguments(int argc, char **argv)
00208 {
00209 int i;
00210
00211 for (i = 1; i < argc; i++)
00212 {
00213 if (!strcmp(argv[i - 1], NHTTPD_ARG_PORT))
00214 {
00215 _httpd_port = atoi(argv[i]);
00216 }
00217 else if (!strcmp(argv[i - 1], NHTTPD_ARG_TERMSIG))
00218 {
00219 _httpd_terminate_signal = atoi(argv[i]);
00220 }
00221 else if (!strcmp(argv[i - 1], NHTTPD_ARG_MAXCONN))
00222 {
00223 _httpd_max_connections = atoi(argv[i]);
00224 }
00225 else if (!strcmp(argv[i - 1], NHTTPD_ARG_TIMEOUT))
00226 {
00227 hsocket_set_timeout(atoi(argv[i]));
00228 }
00229 }
00230
00231 log_verbose2("socket bind to port '%d'", _httpd_port);
00232
00233 return;
00234 }
00235
00236
00237 static void
00238 _httpd_connection_slots_init(void)
00239 {
00240 int i;
00241
00242 #ifdef WIN32
00243 _httpd_connection_lock = CreateMutex( NULL, TRUE, _httpd_connection_lock_str );
00244 #else
00245 pthread_mutex_init(&_httpd_connection_lock, NULL);
00246 #endif
00247
00248 _httpd_connection = calloc(_httpd_max_connections, sizeof(conndata_t));
00249 for (i = 0; i < _httpd_max_connections; i++)
00250 hsocket_init(&(_httpd_connection[i].sock));
00251
00252 return;
00253 }
00254
00255 static herror_t
00256 _httpd_register_builtin_services(int argc, char **argv)
00257 {
00258 herror_t status;
00259
00260 if ((status = httpd_admin_init_args(argc, argv)) != H_OK)
00261 {
00262 log_error2("httpd_admin_init_args failed (%s)", herror_message(status));
00263 return status;
00264 }
00265
00266 return H_OK;
00267 }
00268
00269 herror_t
00270 httpd_init(int argc, char **argv)
00271 {
00272 herror_t status;
00273
00274 _httpd_parse_arguments(argc, argv);
00275
00276 if ((status = hsocket_module_init(argc, argv)) != H_OK)
00277 {
00278 log_error2("hsocket_modeule_init failed (%s)", herror_message(status));
00279 return status;
00280 }
00281
00282 _httpd_connection_slots_init();
00283
00284 if ((status = _httpd_register_builtin_services(argc, argv)) != H_OK)
00285 {
00286 log_error2("_httpd_register_builtin_services failed (%s)", herror_message(status));
00287 return status;
00288 }
00289
00290 if ((status = hsocket_init(&_httpd_socket)) != H_OK)
00291 {
00292 log_error2("hsocket_init failed (%s)", herror_message(status));
00293 return status;
00294 }
00295
00296 if ((status = hsocket_bind(&_httpd_socket, _httpd_port)) != H_OK)
00297 {
00298 log_error2("hsocket_bind failed (%s)", herror_message(status));
00299 return status;
00300 }
00301
00302 return H_OK;
00303 }
00304
00305 herror_t
00306 httpd_register_secure(const char *context, httpd_service func, httpd_auth auth)
00307 {
00308 hservice_t *service;
00309
00310 if (!(service = (hservice_t *) malloc(sizeof(hservice_t))))
00311 {
00312 log_error2("malloc failed (%s)", strerror(errno));
00313 return herror_new("httpd_register_secure", 0, "malloc failed (%s)", strerror(errno));
00314 }
00315
00316 if (!(service->statistics = (struct service_statistics *)malloc(sizeof(struct service_statistics))))
00317 {
00318 log_error2("malloc failed (%s)", strerror(errno));
00319 free(service);
00320 return herror_new("httpd_register_secure", 0, "malloc failed (%s)", strerror(errno));
00321 }
00322 memset(service->statistics, 0, sizeof(struct service_statistics));
00323 service->statistics->time.tv_sec = 0;
00324 service->statistics->time.tv_usec = 0;
00325 pthread_rwlock_init(&(service->statistics->lock), NULL);
00326
00327 service->next = NULL;
00328 service->auth = auth;
00329 service->func = func;
00330 service->status = NHTTPD_SERVICE_UP;
00331 service->context = strdup(context);
00332
00333 log_verbose3("register service (%p) for \"%s\"", service, context);
00334 if (_httpd_services_head == NULL)
00335 {
00336 _httpd_services_head = _httpd_services_tail = service;
00337 }
00338 else
00339 {
00340 _httpd_services_tail->next = service;
00341 _httpd_services_tail = service;
00342 }
00343
00344 return H_OK;
00345 }
00346
00347 herror_t
00348 httpd_register(const char *context, httpd_service service)
00349 {
00350 return httpd_register_secure(context, service, NULL);
00351 }
00352
00353 herror_t
00354 httpd_register_default_secure(const char *context, httpd_service service, httpd_auth auth)
00355 {
00356 herror_t ret;
00357
00358 ret = httpd_register_secure(context, service, auth);
00359
00360
00361 _httpd_services_default = _httpd_services_tail;
00362
00363 return ret;
00364 }
00365
00366 herror_t
00367 httpd_register_default(const char *context, httpd_service service)
00368 {
00369 return httpd_register_default_secure(context, service, NULL);
00370 }
00371
00372 short
00373 httpd_get_port(void)
00374 {
00375 return _httpd_port;
00376 }
00377
00378 int
00379 httpd_get_timeout(void)
00380 {
00381 return hsocket_get_timeout();
00382 }
00383
00384 void
00385 httpd_set_timeout(int secs)
00386 {
00387 hsocket_set_timeout(secs);
00388
00389 return;
00390 }
00391
00392 const char *
00393 httpd_get_protocol(void)
00394 {
00395 return hssl_enabled() ? "https" : "http";
00396 }
00397
00398 int
00399 httpd_get_conncount(void)
00400 {
00401 int i, ret;
00402
00403 for (ret = i = 0; i<_httpd_max_connections; i++)
00404 {
00405 if (_httpd_connection[i].flag == CONNECTION_IN_USE)
00406 ret++;
00407 }
00408
00409 return ret;
00410 }
00411
00412 hservice_t *
00413 httpd_get_services(void)
00414 {
00415 return _httpd_services_head;
00416 }
00417
00418 static void
00419 hservice_free(hservice_t * service)
00420 {
00421 if (!service)
00422 return;
00423
00424 if (service->statistics)
00425 free(service->statistics);
00426
00427 free(service);
00428
00429 return;
00430 }
00431
00432 int httpd_enable_service(hservice_t *service)
00433 {
00434 int ret;
00435
00436 ret = service->status;
00437 service->status = NHTTPD_SERVICE_UP;
00438
00439 return ret;
00440 }
00441
00442 int httpd_disable_service(hservice_t *service)
00443 {
00444 int ret;
00445
00446 ret = service->status;
00447 service->status = NHTTPD_SERVICE_DOWN;
00448
00449 return ret;
00450 }
00451
00452 hservice_t *
00453 httpd_find_service(const char *context)
00454 {
00455 hservice_t *cur;
00456
00457 for (cur = _httpd_services_head; cur; cur = cur->next)
00458 {
00459 if (!strcmp(cur->context, context))
00460 return cur;
00461 }
00462
00463 return _httpd_services_default;
00464 }
00465
00466 void
00467 httpd_response_set_content_type(httpd_conn_t * res, const char *content_type)
00468 {
00469 strncpy(res->content_type, content_type, 25);
00470
00471 return;
00472 }
00473
00474 herror_t
00475 httpd_send_header(httpd_conn_t * res, int code, const char *text)
00476 {
00477 struct tm stm;
00478 time_t nw;
00479 char buffer[255];
00480 char header[1024];
00481 hpair_t *cur;
00482 herror_t status;
00483
00484
00485 sprintf(header, "HTTP/1.1 %d %s\r\n", code, text);
00486
00487
00488 nw = time(NULL);
00489 localtime_r(&nw, &stm);
00490 strftime(buffer, 255, "Date: %a, %d %b %Y %H:%M:%S GMT\r\n", &stm);
00491 strcat(header, buffer);
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501 strcat(header, "Server: nanoHTTP library\r\n");
00502
00503
00504
00505
00506
00507 for (cur = res->header; cur; cur = cur->next)
00508 {
00509 sprintf(buffer, "%s: %s\r\n", cur->key, cur->value);
00510 strcat(header, buffer);
00511 }
00512
00513
00514 strcat(header, "\r\n");
00515
00516
00517 if ((status = hsocket_send(res->sock, header, strlen(header))) != H_OK)
00518 return status;
00519
00520 res->out = http_output_stream_new(res->sock, res->header);
00521 return H_OK;
00522 }
00523
00524 static herror_t
00525 _httpd_send_html_message(httpd_conn_t *conn, int reason, const char *phrase, const char *msg)
00526 {
00527 const char const *tmpl =
00528 "<html>"
00529 "<head>"
00530 "<title>%s</title>"
00531 "</head>"
00532 "<body>"
00533 "<h3>%s</h3>"
00534 "<hr/>"
00535 "<div>Message: '%s'</div>"
00536 "</body>"
00537 "</html>";
00538 char buf[4096];
00539 char slen[5];
00540 int len;
00541
00542 len = snprintf(buf, 4096, tmpl, phrase, phrase, msg);
00543 snprintf(slen, 5, "%d", len);
00544
00545 httpd_set_header(conn, HEADER_CONTENT_LENGTH, slen);
00546 httpd_send_header(conn, reason, phrase);
00547
00548 return http_output_stream_write(conn->out, buf, len);
00549 }
00550
00551 herror_t
00552 httpd_send_bad_request(httpd_conn_t *conn, const char *msg)
00553 {
00554 return _httpd_send_html_message(conn, 400, HTTP_STATUS_400_REASON_PHRASE, msg);
00555 }
00556
00557 herror_t
00558 httpd_send_unauthorized(httpd_conn_t *conn, const char *realm)
00559 {
00560 char buf[128];
00561
00562 snprintf(buf, 128, "Basic realm=\"%s\"", realm);
00563 httpd_set_header(conn, HEADER_WWW_AUTHENTICATE, buf);
00564
00565 return _httpd_send_html_message(conn, 401, HTTP_STATUS_401_REASON_PHRASE, "Unauthorized request logged");
00566 }
00567
00568 herror_t
00569 httpd_send_not_found(httpd_conn_t *conn, const char *msg)
00570 {
00571 return _httpd_send_html_message(conn, 404, HTTP_STATUS_404_REASON_PHRASE, msg);
00572 }
00573
00574 herror_t
00575 httpd_send_internal_error(httpd_conn_t *conn, const char *msg)
00576 {
00577 return _httpd_send_html_message(conn, 500, HTTP_STATUS_500_REASON_PHRASE, msg);
00578 }
00579
00580 herror_t
00581 httpd_send_not_implemented(httpd_conn_t *conn, const char *msg)
00582 {
00583 return _httpd_send_html_message(conn, 501, HTTP_STATUS_501_REASON_PHRASE, msg);
00584 }
00585
00586 static void
00587 _httpd_request_print(struct hrequest_t * req)
00588 {
00589 hpair_t *pair;
00590
00591 log_verbose1("++++++ Request +++++++++");
00592 log_verbose2(" Method : '%s'",
00593 (req->method == HTTP_REQUEST_POST) ? "POST" : "GET");
00594 log_verbose2(" Path : '%s'", req->path);
00595 log_verbose2(" Spec : '%s'",
00596 (req->version == HTTP_1_0) ? "HTTP/1.0" : "HTTP/1.1");
00597 log_verbose1(" Parsed query string :");
00598
00599 for (pair = req->query; pair; pair = pair->next)
00600 log_verbose3(" %s = '%s'", pair->key, pair->value);
00601
00602 log_verbose1(" Parsed header :");
00603 for (pair = req->header; pair; pair = pair->next)
00604 log_verbose3(" %s = '%s'", pair->key, pair->value);
00605
00606 log_verbose1("++++++++++++++++++++++++");
00607
00608 return;
00609 }
00610
00611 httpd_conn_t *
00612 httpd_new(struct hsocket_t * sock)
00613 {
00614 httpd_conn_t *conn;
00615
00616 if (!(conn = (httpd_conn_t *) malloc(sizeof(httpd_conn_t))))
00617 {
00618 log_error2("malloc failed (%s)", strerror(errno));
00619 return NULL;
00620 }
00621 conn->sock = sock;
00622 conn->out = NULL;
00623 conn->content_type[0] = '\0';
00624 conn->header = NULL;
00625
00626 return conn;
00627 }
00628
00629 void
00630 httpd_free(httpd_conn_t * conn)
00631 {
00632 if (!conn)
00633 return;
00634
00635 if (conn->out)
00636 http_output_stream_free(conn->out);
00637
00638 if (conn->header)
00639 hpairnode_free_deep(conn->header);
00640
00641 free(conn);
00642
00643 return;
00644 }
00645
00646 static int
00647 _httpd_decode_authorization(const char *value, char **user, char **pass)
00648 {
00649 unsigned char *tmp, *tmp2;
00650 size_t len;
00651
00652 len = strlen(value) * 2;
00653 if (!(tmp = (char *) calloc(1, len)))
00654 {
00655 log_error2("calloc failed (%s)", strerror(errno));
00656 return -1;
00657 }
00658
00659 value = strstr(value, " ") + 1;
00660
00661 log_verbose2("Authorization (base64) = \"%s\"", value);
00662
00663 base64_decode_string(value, tmp);
00664
00665 log_verbose2("Authorization (ascii) = \"%s\"", tmp);
00666
00667 if ((tmp2 = strstr(tmp, ":")))
00668 {
00669 *tmp2++ = '\0';
00670 *pass = strdup(tmp2);
00671 }
00672 else
00673 {
00674 *pass = strdup("");
00675 }
00676 *user = strdup(tmp);
00677
00678 free(tmp);
00679
00680 return 0;
00681 }
00682
00683 static int
00684 _httpd_authenticate_request(struct hrequest_t * req, httpd_auth auth)
00685 {
00686 char *user, *pass;
00687 char *authorization;
00688 int ret;
00689
00690 if (!auth)
00691 return 1;
00692
00693 if (!(authorization = hpairnode_get_ignore_case(req->header, HEADER_AUTHORIZATION)))
00694 {
00695 log_debug2("\"%s\" header not set", HEADER_AUTHORIZATION);
00696 return 0;
00697 }
00698
00699 if (_httpd_decode_authorization(authorization, &user, &pass))
00700 {
00701 log_error1("httpd_base64_decode_failed");
00702 return 0;
00703 }
00704
00705 if ((ret = auth(req, user, pass)))
00706 log_debug2("Access granted for user=\"%s\"", user);
00707 else
00708 log_info2("Authentication failed for user=\"%s\"", user);
00709
00710 free(user);
00711 free(pass);
00712
00713 return ret;
00714 }
00715
00716 #ifdef WIN32
00717 static unsigned _stdcall
00718 httpd_session_main(void *data)
00719 #else
00720 static void *
00721 httpd_session_main(void *data)
00722 #endif
00723 {
00724 struct hrequest_t *req;
00725 conndata_t *conn;
00726 httpd_conn_t *rconn;
00727 hservice_t *service;
00728 herror_t status;
00729 struct timeval start, end, duration;
00730 int done;
00731
00732 if (gettimeofday(&start, NULL) == -1)
00733 log_error2("gettimeofday failed (%s)", strerror(errno));
00734
00735 conn = (conndata_t *) data;
00736
00737 log_verbose2("starting new httpd session on socket %d", conn->sock);
00738
00739 rconn = httpd_new(&(conn->sock));
00740
00741 done = 0;
00742 while (!done)
00743 {
00744 log_verbose3("starting HTTP request on socket %d (%p)", conn->sock, conn->sock.sock);
00745
00746 if ((status = hrequest_new_from_socket(&(conn->sock), &req)) != H_OK)
00747 {
00748 int code;
00749
00750 switch ((code = herror_code(status)))
00751 {
00752 case HSOCKET_ERROR_SSLCLOSE:
00753 case HSOCKET_ERROR_RECEIVE:
00754 log_error2("hrequest_new_from_socket failed (%s)", herror_message(status));
00755 break;
00756 default:
00757 httpd_send_bad_request(rconn, herror_message(status));
00758 break;
00759 }
00760 herror_release(status);
00761 done = 1;
00762 }
00763 else
00764 {
00765 char *conn_str;
00766
00767 _httpd_request_print(req);
00768
00769 conn_str = hpairnode_get_ignore_case(req->header, HEADER_CONNECTION);
00770 if (conn_str && strncasecmp(conn_str, "close", 6) == 0)
00771 done = 1;
00772
00773 if (!done)
00774 done = req->version == HTTP_1_0 ? 1 : 0;
00775
00776 if ((service = httpd_find_service(req->path)))
00777 {
00778 log_verbose3("service '%s' for '%s' found", service->context, req->path);
00779
00780 if (service->status == NHTTPD_SERVICE_UP)
00781 {
00782 pthread_rwlock_wrlock(&(service->statistics->lock));
00783 service->statistics->requests++;
00784 pthread_rwlock_unlock(&(service->statistics->lock));
00785
00786 if (_httpd_authenticate_request(req, service->auth))
00787 {
00788 if (service->func != NULL)
00789 {
00790 service->func(rconn, req);
00791
00792 if (gettimeofday(&end, NULL) == -1)
00793 log_error2("gettimeofday failed (%s)", strerror(errno));
00794 timersub(&end, &start, &duration);
00795
00796 pthread_rwlock_wrlock(&(service->statistics->lock));
00797 service->statistics->bytes_received += rconn->sock->bytes_received;
00798 service->statistics->bytes_transmitted += rconn->sock->bytes_transmitted;
00799 timeradd(&(service->statistics->time), &duration, &(service->statistics->time));
00800 pthread_rwlock_unlock(&(service->statistics->lock));
00801
00802 if (rconn->out && rconn->out->type == HTTP_TRANSFER_CONNECTION_CLOSE)
00803 {
00804 log_verbose1("Connection close requested");
00805 done = 1;
00806 }
00807 }
00808 else
00809 {
00810 char buffer[256];
00811
00812 snprintf(buffer, 256, "service '%s' is not registered properly (service function is NULL)", req->path);
00813 log_verbose1(buffer);
00814 httpd_send_not_implemented(rconn, buffer);
00815 }
00816 }
00817 else
00818 {
00819 httpd_send_unauthorized(rconn, req->path);
00820 done = 1;
00821 }
00822 }
00823 else
00824 {
00825 char buffer[256];
00826
00827 sprintf(buffer, "service for '%s' is disabled", req->path);
00828 log_verbose1(buffer);
00829 httpd_send_internal_error(rconn, buffer);
00830 }
00831 }
00832 else
00833 {
00834 char buffer[256];
00835 sprintf(buffer, "no service for '%s' found", req->path);
00836 log_verbose1(buffer);
00837 httpd_send_not_implemented(rconn, buffer);
00838 done = 1;
00839 }
00840 hrequest_free(req);
00841 }
00842 }
00843
00844 httpd_free(rconn);
00845
00846 hsocket_close(&(conn->sock));
00847
00848 #ifdef WIN32
00849 CloseHandle((HANDLE) conn->tid);
00850 #else
00851 pthread_attr_destroy(&(conn->attr));
00852 #endif
00853
00854 conn->flag = CONNECTION_FREE;
00855
00856 #ifdef WIN32
00857 _endthread();
00858 return 0;
00859 #else
00860
00861 return NULL;
00862 #endif
00863 }
00864
00865 int
00866 httpd_set_header(httpd_conn_t * conn, const char *key, const char *value)
00867 {
00868 hpair_t *p;
00869
00870 if (conn == NULL)
00871 {
00872 log_warn1("Connection object is NULL");
00873 return 0;
00874 }
00875
00876 for (p = conn->header; p; p = p->next)
00877 {
00878 if (p->key && !strcmp(p->key, key))
00879 {
00880 free(p->value);
00881 p->value = strdup(value);
00882 return 1;
00883 }
00884 }
00885
00886 conn->header = hpairnode_new(key, value, conn->header);
00887
00888 return 0;
00889 }
00890
00891 void
00892 httpd_set_headers(httpd_conn_t * conn, hpair_t * header)
00893 {
00894 while (header)
00895 {
00896 httpd_set_header(conn, header->key, header->value);
00897 header = header->next;
00898 }
00899 return;
00900 }
00901
00902 int
00903 httpd_add_header(httpd_conn_t * conn, const char *key, const char *value)
00904 {
00905 if (!conn)
00906 {
00907 log_warn1("Connection object is NULL");
00908 return 0;
00909 }
00910
00911 conn->header = hpairnode_new(key, value, conn->header);
00912
00913 return 1;
00914 }
00915
00916 void
00917 httpd_add_headers(httpd_conn_t * conn, const hpair_t * values)
00918 {
00919 if (!conn)
00920 {
00921 log_warn1("Connection object is NULL");
00922 return;
00923 }
00924
00925 while (values)
00926 {
00927 httpd_add_header(conn, values->key, values->value);
00928 values = values->next;
00929 }
00930 return;
00931 }
00932
00933
00934
00935
00936
00937
00938 static void
00939 _httpd_register_signal_handler(void)
00940 {
00941
00942 #ifndef WIN32
00943 sigemptyset(&thrsigset);
00944 sigaddset(&thrsigset, SIGALRM);
00945 #endif
00946
00947 log_verbose2("registering termination signal handler (SIGNAL:%d)",
00948 _httpd_terminate_signal);
00949 #ifdef WIN32
00950 if (SetConsoleCtrlHandler((PHANDLER_ROUTINE) _httpd_term, TRUE) == FALSE)
00951 {
00952 log_error1("Unable to install console event handler!");
00953 }
00954
00955 #else
00956 signal(_httpd_terminate_signal, _httpd_term);
00957 #endif
00958
00959 return;
00960 }
00961
00962 static conndata_t *
00963 _httpd_wait_for_empty_conn(void)
00964 {
00965 int i;
00966
00967 #ifdef WIN32
00968 WaitForSingleObject(_httpd_connection_lock, INFINITE);
00969 #else
00970 pthread_mutex_lock(&_httpd_connection_lock);
00971 #endif
00972
00973 for (i = 0;; i++)
00974 {
00975 if (!_httpd_run)
00976 {
00977 #ifdef WIN32
00978 ReleaseMutex(_httpd_connection_lock);
00979 #else
00980 pthread_mutex_unlock(&_httpd_connection_lock);
00981 #endif
00982 return NULL;
00983 }
00984
00985 if (i >= _httpd_max_connections)
00986 {
00987 _httpd_sys_sleep(1);
00988 i = -1;
00989 }
00990 else if (_httpd_connection[i].flag == CONNECTION_FREE)
00991 {
00992 _httpd_connection[i].flag = CONNECTION_IN_USE;
00993 break;
00994 }
00995 }
00996
00997 #ifdef WIN32
00998 ReleaseMutex(_httpd_connection_lock);
00999 #else
01000 pthread_mutex_unlock(&_httpd_connection_lock);
01001 #endif
01002
01003 return &_httpd_connection[i];
01004 }
01005
01006 static void
01007 _httpd_start_thread(conndata_t * conn)
01008 {
01009 int err;
01010
01011 #ifdef WIN32
01012 conn->tid =
01013 (HANDLE) _beginthreadex(NULL, 65535, httpd_session_main, conn, 0, &err);
01014 #else
01015 pthread_attr_init(&(conn->attr));
01016
01017 #ifdef PTHREAD_CREATE_DETACHED
01018 pthread_attr_setdetachstate(&(conn->attr), PTHREAD_CREATE_DETACHED);
01019 #endif
01020
01021 pthread_sigmask(SIG_BLOCK, &thrsigset, NULL);
01022 if ((err =
01023 pthread_create(&(conn->tid), &(conn->attr), httpd_session_main, conn)))
01024 log_error2("pthread_create failed (%s)", strerror(err));
01025 #endif
01026
01027 return;
01028 }
01029
01030 herror_t
01031 httpd_run(void)
01032 {
01033 struct timeval timeout;
01034 conndata_t *conn;
01035 herror_t err;
01036 fd_set fds;
01037
01038 log_verbose1("starting run routine");
01039
01040 _httpd_register_signal_handler();
01041
01042 if ((err = hsocket_listen(&_httpd_socket)) != H_OK)
01043 {
01044 log_error2("hsocket_listen failed (%s)", herror_message(err));
01045 return err;
01046 }
01047
01048 while (_httpd_run)
01049 {
01050 conn = _httpd_wait_for_empty_conn();
01051 if (!_httpd_run)
01052 break;
01053
01054
01055 while (_httpd_run)
01056 {
01057
01058
01059 timeout.tv_sec = 1;
01060 timeout.tv_usec = 0;
01061
01062
01063 FD_ZERO(&fds);
01064 FD_SET(_httpd_socket.sock, &fds);
01065
01066
01067 switch (select(_httpd_socket.sock + 1, &fds, NULL, NULL, &timeout))
01068 {
01069 case 0:
01070
01071 continue;
01072 case -1:
01073
01074 continue;
01075 default:
01076
01077 break;
01078 }
01079 if (FD_ISSET(_httpd_socket.sock, &fds))
01080 {
01081 break;
01082 }
01083 }
01084
01085
01086 if (!_httpd_run)
01087 break;
01088
01089 if ((err = hsocket_accept(&_httpd_socket, &(conn->sock))) != H_OK)
01090 {
01091 log_error2("hsocket_accept failed (%s)", herror_message(err));
01092
01093 hsocket_close(&(conn->sock));
01094
01095 continue;
01096 }
01097
01098 _httpd_start_thread(conn);
01099 }
01100
01101 return 0;
01102 }
01103
01104 void
01105 httpd_destroy(void)
01106 {
01107 hservice_t *tmp, *cur = _httpd_services_head;
01108
01109 while (cur != NULL)
01110 {
01111 tmp = cur->next;
01112 hservice_free(cur);
01113 cur = tmp;
01114 }
01115
01116 hsocket_module_destroy();
01117
01118 free(_httpd_connection);
01119
01120 return;
01121 }
01122
01123 unsigned char *
01124 httpd_get_postdata(httpd_conn_t * conn, struct hrequest_t * req, long *received, long max)
01125 {
01126 char *content_length_str;
01127 long content_length = 0;
01128 unsigned char *postdata = NULL;
01129
01130 if (req->method == HTTP_REQUEST_POST)
01131 {
01132
01133 content_length_str =
01134 hpairnode_get_ignore_case(req->header, HEADER_CONTENT_LENGTH);
01135
01136 if (content_length_str != NULL)
01137 content_length = atol(content_length_str);
01138
01139 }
01140 else
01141 {
01142 log_warn1("Not a POST method");
01143 return NULL;
01144 }
01145
01146 if (content_length > max && max != -1)
01147 return NULL;
01148
01149 if (content_length == 0)
01150 {
01151 *received = 0;
01152 if (!(postdata = (char *) malloc(1)))
01153 {
01154
01155 log_error2("malloc failed (%s)", strerror(errno));
01156 return NULL;
01157 }
01158 postdata[0] = '\0';
01159 return postdata;
01160 }
01161 if (!(postdata = (unsigned char *) malloc(content_length + 1)))
01162 {
01163 log_error2("malloc failed (%)", strerror(errno));
01164 return NULL;
01165 }
01166 if (http_input_stream_read(req->in, postdata, (int) content_length) > 0)
01167 {
01168 *received = content_length;
01169 postdata[content_length] = '\0';
01170 return postdata;
01171 }
01172 free(postdata);
01173 return NULL;
01174 }
01175
01176
01177
01178
01179
01180
01181 static void
01182 _httpd_mime_get_boundary(httpd_conn_t * conn, char *dest)
01183 {
01184 sprintf(dest, "---=.Part_NH_%p", conn);
01185 log_verbose2("boundary= \"%s\"", dest);
01186
01187 return;
01188 }
01189
01190
01195 herror_t
01196 httpd_mime_send_header(httpd_conn_t * conn, const char *related_start,
01197 const char *related_start_info,
01198 const char *related_type, int code, const char *text)
01199 {
01200 char buffer[300];
01201 char temp[250];
01202 char boundary[250];
01203
01204
01205
01206
01207
01208 sprintf(buffer, "multipart/related;");
01209
01210 if (related_type)
01211 {
01212 snprintf(temp, 75, " type=\"%s\";", related_type);
01213 strcat(buffer, temp);
01214 }
01215
01216 if (related_start)
01217 {
01218 snprintf(temp, 250, " start=\"%s\";", related_start);
01219 strcat(buffer, temp);
01220 }
01221
01222 if (related_start_info)
01223 {
01224 snprintf(temp, 250, " start-info=\"%s\";", related_start_info);
01225 strcat(buffer, temp);
01226 }
01227
01228 _httpd_mime_get_boundary(conn, boundary);
01229 snprintf(temp, 250, " boundary=\"%s\"", boundary);
01230 strcat(buffer, temp);
01231
01232 httpd_set_header(conn, HEADER_CONTENT_TYPE, buffer);
01233
01234 return httpd_send_header(conn, code, text);
01235 }
01236
01237
01242 herror_t
01243 httpd_mime_next(httpd_conn_t * conn, const char *content_id,
01244 const char *content_type, const char *transfer_encoding)
01245 {
01246 herror_t status;
01247 char buffer[512];
01248 char boundary[75];
01249 int len;
01250
01251
01252 _httpd_mime_get_boundary(conn, boundary);
01253 len = sprintf(buffer, "\r\n--%s\r\n", boundary);
01254
01255
01256 if ((status = http_output_stream_write(conn->out, buffer, len)) != H_OK)
01257 return status;
01258
01259
01260 len = sprintf(buffer, "%s: %s\r\n%s: %s\r\n%s: %s\r\n\r\n",
01261 HEADER_CONTENT_TYPE, content_type ? content_type : "text/plain",
01262 HEADER_CONTENT_TRANSFER_ENCODING,
01263 transfer_encoding ? transfer_encoding : "binary",
01264 HEADER_CONTENT_ID,
01265 content_id ? content_id : "<content-id-not-set>");
01266
01267 return http_output_stream_write(conn->out, buffer, len);
01268 }
01269
01274 herror_t
01275 httpd_mime_send_file(httpd_conn_t * conn, const char *content_id,
01276 const char *content_type, const char *transfer_encoding,
01277 const char *filename)
01278 {
01279 unsigned char buffer[MAX_FILE_BUFFER_SIZE];
01280 herror_t status;
01281 FILE *fd;
01282 size_t size;
01283
01284 if ((fd = fopen(filename, "rb")) == NULL)
01285 return herror_new("httpd_mime_send_file", FILE_ERROR_OPEN,
01286 "Can not open file '%d'", filename);
01287
01288 status = httpd_mime_next(conn, content_id, content_type, transfer_encoding);
01289 if (status != H_OK)
01290 {
01291 fclose(fd);
01292 return status;
01293 }
01294
01295 while (!feof(fd))
01296 {
01297 size = fread(buffer, 1, MAX_FILE_BUFFER_SIZE, fd);
01298 if (size == -1)
01299 {
01300 fclose(fd);
01301 return herror_new("httpd_mime_send_file", FILE_ERROR_READ,
01302 "Can not read from file '%d'", filename);
01303 }
01304
01305 if ((status = http_output_stream_write(conn->out, buffer, size)) != H_OK)
01306 {
01307 fclose(fd);
01308 return status;
01309 }
01310 }
01311
01312 fclose(fd);
01313 return H_OK;
01314 }
01315
01320 herror_t
01321 httpd_mime_end(httpd_conn_t * conn)
01322 {
01323 herror_t status;
01324 char buffer[512];
01325 char boundary[75];
01326 int len;
01327
01328
01329 _httpd_mime_get_boundary(conn, boundary);
01330 len = sprintf(buffer, "\r\n--%s--\r\n\r\n", boundary);
01331
01332
01333 if ((status = http_output_stream_write(conn->out, buffer, len)) != H_OK)
01334 return status;
01335
01336 return http_output_stream_flush(conn->out);
01337 }