00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "klone_conf.h"
00012 #include <sys/types.h>
00013 #include <stdlib.h>
00014 #include <unistd.h>
00015 #ifdef HAVE_LIBOPENSSL
00016 #include <openssl/ssl.h>
00017 #include <openssl/err.h>
00018 #endif
00019 #include <u/libu.h>
00020 #include <klone/utils.h>
00021 #include <klone/os.h>
00022 #include <klone/server.h>
00023 #include <klone/context.h>
00024 #include <klone/broker.h>
00025 #include <klone/request.h>
00026 #include <klone/ses_prv.h>
00027 #include <klone/response.h>
00028 #include <klone/backend.h>
00029 #include <klone/io.h>
00030 #include <klone/timer.h>
00031 #include <klone/tls.h>
00032 #include <klone/ses_prv.h>
00033 #include <klone/hook.h>
00034 #include <klone/hookprv.h>
00035 #include "http_s.h"
00036
00037 struct http_status_map_s
00038 {
00039 int status;
00040 const char *desc;
00041 } http_status_map[] = {
00042 { HTTP_STATUS_OK , "OK" },
00043 { HTTP_STATUS_NOT_MODIFIED , "Not Modified" },
00044 { HTTP_STATUS_NOT_FOUND , "Not Found" },
00045 { HTTP_STATUS_INTERNAL_SERVER_ERROR , "Internal Server Error" },
00046 { HTTP_STATUS_MOVED_PERMANENTLY , "Moved Permanently" },
00047 { HTTP_STATUS_MOVED_TEMPORARILY , "Moved Temporarily" },
00048 { HTTP_STATUS_CREATED , "Created" },
00049 { HTTP_STATUS_ACCEPTED , "Accepted" },
00050 { HTTP_STATUS_NO_CONTENT , "No Content" },
00051 { HTTP_STATUS_BAD_REQUEST , "Bad Request" },
00052 { HTTP_STATUS_UNAUTHORIZED , "Unauthorized" },
00053 { HTTP_STATUS_FORBIDDEN , "Forbidden" },
00054 { HTTP_STATUS_LENGTH_REQUIRED , "Content-Length required" },
00055 { HTTP_STATUS_REQUEST_TOO_LARGE , "Request data too big" },
00056 { HTTP_STATUS_NOT_IMPLEMENTED , "Not Implemented" },
00057 { HTTP_STATUS_BAD_GATEWAY , "Bad Gateway" },
00058 { HTTP_STATUS_SERVICE_UNAVAILABLE , "Service Unavailable" },
00059 { 0 , NULL }
00060 };
00061
00062
00063 int cgi_set_request(request_t *rq);
00064
00065 session_opt_t *http_get_session_opt(http_t *http)
00066 {
00067 dbg_return_if (http == NULL, NULL);
00068
00069 return http->sess_opt;
00070 }
00071
00072 u_config_t *http_get_config(http_t* http)
00073 {
00074 dbg_return_if (http == NULL, NULL);
00075
00076 return http->config;
00077 }
00078
00079 const char *http_get_status_desc(int status)
00080 {
00081 struct http_status_map_s *map = http_status_map;
00082 const char *msg = "Unknown Status Code";
00083
00084 for( ; map->status; ++map)
00085 if(map->status == status)
00086 {
00087 msg = map->desc;
00088 break;
00089 }
00090
00091 return msg;
00092 }
00093
00094 static int http_try_resolv(const char *alias, char *dst, const char *uri,
00095 size_t sz)
00096 {
00097 static const char *WP = " \t";
00098 char *src, *res, *v = NULL, *pp = NULL;
00099
00100 dbg_err_if(dst == NULL);
00101 dbg_err_if(uri == NULL);
00102 dbg_err_if(alias == NULL);
00103
00104
00105 v = u_strdup(alias);
00106 dbg_err_if(v == NULL);
00107
00108
00109 src = strtok_r(v, WP, &pp);
00110 dbg_err_if(src == NULL);
00111
00112
00113 nop_err_if(strncmp(src, uri, strlen(src)));
00114
00115
00116 if(src[strlen(src)-1] != '/')
00117 nop_err_if(uri[strlen(src)] != '/');
00118
00119
00120 res = strtok_r(NULL, WP, &pp);
00121 dbg_err_if(res == NULL);
00122
00123
00124 dbg_err_if(u_path_snprintf(dst, sz, '/', "%s/%s", res, uri + strlen(src)));
00125
00126 U_FREE(v);
00127
00128 return 0;
00129 err:
00130 U_FREE(v);
00131 return ~0;
00132 }
00133
00134 const char *http_vhost_config_value(http_t *h, request_t *rq, const char *key)
00135 {
00136 u_config_t *config;
00137
00138 if(http_get_vhost_config(h, rq, &config))
00139 return NULL;
00140
00141 return u_config_get_subkey_value(config, key);
00142 }
00143
00144 int http_get_vhost_config(http_t *h, request_t *rq, u_config_t **pc)
00145 {
00146 u_config_t *config = NULL;;
00147 const char *host;
00148 char *p, hostcp[128];
00149
00150 dbg_err_if (h == NULL);
00151 dbg_err_if (rq == NULL);
00152 dbg_err_if (pc == NULL);
00153
00154
00155
00156 nop_err_if((host = request_get_field_value(rq, "Host")) == NULL);
00157
00158 strlcpy(hostcp, host, sizeof(hostcp));
00159
00160
00161 if((p = strrchr(hostcp, ':')) != NULL)
00162 *p = 0;
00163
00164
00165 nop_err_if((config = u_config_get_child(h->config, hostcp)) == NULL);
00166
00167 *pc = config;
00168
00169 return 0;
00170 err:
00171 return ~0;
00172 }
00173
00174 int http_alias_resolv(http_t *h, request_t *rq, char *dst, const char *uri,
00175 size_t sz)
00176 {
00177 u_config_t *config, *cgi, *base = NULL;
00178 const char *host, *dir_root = NULL;
00179 char *p, hostcp[128];
00180 int i;
00181
00182 dbg_err_if (h == NULL);
00183 dbg_err_if (dst == NULL);
00184 dbg_err_if (uri == NULL);
00185
00186
00187 base = h->config;
00188 dir_root = h->dir_root;
00189
00190
00191 if(!http_get_vhost_config(h, rq, &base))
00192 dir_root = u_config_get_subkey_value(base, "dir_root");
00193
00194
00195 for(i = 0; !u_config_get_subkey_nth(base, "dir_alias", i, &config);
00196 ++i)
00197 {
00198 if(!http_try_resolv(u_config_get_value(config), dst, uri, sz))
00199 return 0;
00200 }
00201
00202
00203 if(!u_config_get_subkey(base, "cgi", &cgi))
00204 {
00205 for(i = 0; !u_config_get_subkey_nth(cgi, "script_alias", i, &config);
00206 ++i)
00207 {
00208 if(!http_try_resolv(u_config_get_value(config), dst, uri, sz))
00209 return 0;
00210 }
00211 }
00212
00213
00214 dbg_err_if(u_path_snprintf(dst, sz, '/', "%s/%s", dir_root, uri));
00215
00216 return 0;
00217 err:
00218 return ~0;
00219 }
00220
00221 static int http_is_valid_uri(void *arg, const char *buf, size_t len)
00222 {
00223 enum { URI_MAX = 2048 };
00224 char resolved[U_FILENAME_MAX], uri[URI_MAX];
00225 request_t *rq = (request_t*)arg;
00226 http_t *h = NULL;
00227
00228 dbg_err_if (arg == NULL);
00229 dbg_err_if (buf == NULL);
00230
00231 h = request_get_http(rq);
00232 dbg_err_if (h == NULL);
00233
00234 strncpy(uri, buf, len);
00235 uri[len] = 0;
00236
00237 dbg_err_if(http_alias_resolv(h, rq, resolved, uri, URI_MAX));
00238
00239 return broker_is_valid_uri(h->broker, h, rq, resolved, strlen(resolved));
00240 err:
00241 return ~0;
00242 }
00243
00244 static void http_resolv_request(http_t *h, request_t *rq)
00245 {
00246 const char *cstr;
00247 char resolved[U_FILENAME_MAX];
00248
00249 dbg_ifb(h == NULL) return;
00250 dbg_ifb(rq == NULL) return;
00251
00252
00253 cstr = request_get_filename(rq);
00254 if(cstr && !http_alias_resolv(h, rq, resolved, cstr, U_FILENAME_MAX))
00255 request_set_resolved_filename(rq, resolved);
00256
00257
00258 cstr = request_get_path_info(rq);
00259 if(cstr && !http_alias_resolv(h, rq, resolved, cstr, U_FILENAME_MAX))
00260 request_set_resolved_path_info(rq, resolved);
00261 }
00262
00263 static int http_is_valid_index(http_t *h, request_t *rq, const char *uri)
00264 {
00265 char resolved[U_FILENAME_MAX] = { 0 };
00266
00267 dbg_err_if(u_path_snprintf(resolved, U_FILENAME_MAX, '/', "%s/%s",
00268 request_get_resolved_filename(rq), uri));
00269
00270 if(broker_is_valid_uri(h->broker, h, rq, resolved, strlen(resolved)))
00271 return 1;
00272
00273 err:
00274 return 0;
00275 }
00276
00277 static int http_get_config_index(http_t *h, request_t *rq, char *idx, size_t sz)
00278 {
00279 char buf[256], *tok, *src, *pp = NULL;
00280 const char *index = NULL;
00281 u_config_t *config;
00282
00283 dbg_err_if (h == NULL);
00284 dbg_err_if (rq == NULL);
00285
00286 if((index = http_vhost_config_value(h, rq, "index")) == NULL)
00287 index = h->index;
00288
00289 if(!index)
00290 return ~0;
00291
00292
00293 dbg_err_if(strlcpy(buf, index, sizeof(buf)) >= sizeof(buf));
00294
00295 for(src = buf; (tok = strtok_r(src, " \t", &pp)) != NULL; src = NULL)
00296 {
00297 if(!strcmp(tok, ""))
00298 continue;
00299
00300 if(http_is_valid_index(h, rq, tok))
00301 {
00302 dbg_err_if(strlcpy(idx, tok, sz) >= sz);
00303 return 0;
00304 }
00305 }
00306
00307
00308 err:
00309 return ~0;
00310 }
00311
00312 static int http_get_default_index(http_t *h, request_t *rq, char *index,
00313 size_t sz)
00314 {
00315 static const char *indexes[] = { "/index.klone", "/index.kl1",
00316 "/index.html", "/index.htm", NULL };
00317 const char **pg;
00318
00319 dbg_err_if (h == NULL);
00320 dbg_err_if (rq == NULL);
00321
00322
00323 for(pg = indexes; *pg; ++pg)
00324 {
00325 if(http_is_valid_index(h, rq, *pg))
00326 {
00327 dbg_err_if(strlcpy(index, *pg, sz) >= sz);
00328 return 0;
00329 }
00330 }
00331
00332
00333 err:
00334 return ~0;
00335 }
00336
00337 static int http_set_index_request(http_t *h, request_t *rq)
00338 {
00339 char idx[128], uri[1024];
00340
00341 dbg_err_if (h == NULL);
00342 dbg_err_if (rq == NULL);
00343
00344
00345 if(!http_get_config_index(h, rq, idx, sizeof(idx)) ||
00346 !http_get_default_index(h, rq, idx, sizeof(idx)))
00347 {
00348 dbg_err_if(u_snprintf(uri, sizeof(uri), "%s%s",
00349 request_get_filename(rq), idx));
00350
00351 dbg_if(request_set_filename(rq, uri));
00352 }
00353
00354 http_resolv_request(h, rq);
00355
00356 return 0;
00357 err:
00358 return ~0;
00359 }
00360
00361 static int http_add_default_header(http_t *h, response_t *rs)
00362 {
00363 time_t now;
00364
00365 dbg_err_if (h == NULL);
00366 dbg_err_if (rs == NULL);
00367
00368
00369 dbg_err_if(response_set_field(rs, "Server", h->server_sig));
00370
00371 now = time(NULL);
00372 dbg_err_if(response_set_date(rs, now));
00373
00374 return 0;
00375 err:
00376 return ~0;
00377 }
00378
00379 static int http_print_error_page(http_t *h, request_t *rq, response_t *rs,
00380 int http_status)
00381 {
00382 enum { BUFSZ = 64 };
00383 const char *err_page;
00384 char buf[BUFSZ];
00385 int rc;
00386
00387 dbg_err_if (h == NULL);
00388 dbg_err_if (rq == NULL);
00389 dbg_err_if (rs == NULL);
00390 dbg_err_if (http_status == 0);
00391
00392
00393 if(http_status != 302)
00394 dbg_err_if(header_clear(response_get_header(rs)));
00395
00396
00397 dbg_err_if(http_add_default_header(h, rs));
00398
00399
00400 dbg_err_if(response_disable_caching(rs));
00401
00402
00403 dbg_err_if(u_snprintf(buf, BUFSZ, "error.%d", http_status));
00404 err_page = u_config_get_subkey_value(h->config, buf);
00405
00406 if(err_page && !request_set_uri(rq, err_page, NULL, NULL))
00407 {
00408 http_resolv_request(h, rq);
00409 if((rc = broker_serve(h->broker, h, rq, rs)) == 0)
00410 return 0;
00411 else {
00412
00413 http_status = rc;
00414 }
00415 }
00416
00417
00418 response_set_status(rs, http_status);
00419
00420 response_print_header(rs);
00421
00422 if(request_get_method(rq) == HM_HEAD)
00423 return 0;
00424
00425
00426 dbg_err_if(io_printf(response_io(rs),
00427 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">"
00428 "<html><head><title>%d %s</title></head>\n"
00429 "<body><h1>%s</h1><p>URL: %s</p><hr>"
00430 "<address>KLone/%s web server - www.koanlogic.com</address>"
00431 "</body></html>",
00432 http_status, http_get_status_desc(http_status),
00433 http_get_status_desc(http_status),
00434 (request_get_uri(rq) ? request_get_uri(rq) : ""),
00435 KLONE_VERSION
00436 ) < 0);
00437
00438 return 0;
00439 err:
00440 return ~0;
00441 }
00442
00443 static int http_serve(http_t *h, int fd)
00444 {
00445 request_t *rq = NULL;
00446 response_t *rs = NULL;
00447 io_t *in = NULL, *out = NULL;
00448 int cgi = 0, port, rc = HTTP_STATUS_INTERNAL_SERVER_ERROR;
00449 const char *gwi = NULL, *cstr;
00450 talarm_t *al = NULL;
00451 addr_t *addr;
00452 struct sockaddr sa;
00453 size_t sasz;
00454
00455 u_unused_args(al);
00456
00457 dbg_err_if (h == NULL);
00458 dbg_err_if (fd < 0);
00459
00460 if(fd == 0 && (gwi = getenv("GATEWAY_INTERFACE")) != NULL)
00461 cgi++;
00462
00463
00464 dbg_err_if(request_create(h, &rq));
00465 request_set_cgi(rq, cgi);
00466
00467
00468 dbg_err_if(addr_create(&addr));
00469
00470 if(cgi)
00471 {
00472 if(getenv("REMOTE_ADDR") && getenv("REMOTE_PORT"))
00473 {
00474 port = atoi(getenv("REMOTE_PORT"));
00475 dbg_err_if(addr_set(addr, getenv("REMOTE_ADDR"), port));
00476 dbg_err_if(request_set_addr(rq, addr));
00477 }
00478
00479 if(getenv("SERVER_ADDR"))
00480 {
00481 if(getenv("SERVER_PORT"))
00482 port = atoi(getenv("SERVER_PORT"));
00483 else
00484 port = 80;
00485 dbg_err_if(addr_set(addr, getenv("SERVER_ADDR"), port));
00486 dbg_err_if(request_set_peer_addr(rq, addr));
00487 }
00488 } else {
00489
00490 sasz = sizeof(struct sockaddr);
00491 dbg_err_if(getsockname(fd, &sa, &sasz));
00492 dbg_err_if(addr_set_from_sa(addr, &sa, sasz));
00493 dbg_err_if(request_set_addr(rq, addr));
00494
00495
00496 sasz = sizeof(struct sockaddr);
00497 dbg_err_if(getpeername(fd, &sa, &sasz));
00498 dbg_err_if(addr_set_from_sa(addr, &sa, sasz));
00499 dbg_err_if(request_set_peer_addr(rq, addr));
00500 }
00501
00502 addr_free(addr);
00503 addr = NULL;
00504
00505 #ifdef HAVE_LIBOPENSSL
00506
00507
00508 if(h->ssl && !cgi)
00509 dbg_err_if(io_ssl_create(fd, IO_FD_CLOSE, h->ssl_ctx, &in));
00510 else
00511 dbg_err_if(io_fd_create(fd, IO_FD_CLOSE, &in));
00512 #else
00513
00514 dbg_err_if(io_fd_create(fd, IO_FD_CLOSE, &in));
00515 #endif
00516
00517
00518 dbg_err_if(request_bind(rq, in));
00519 in = NULL;
00520
00521
00522 dbg_err_if(response_create(h, &rs));
00523
00524 response_set_cgi(rs, cgi);
00525
00526 if(cgi)
00527 dbg_err_if(cgi_set_request(rq));
00528
00529
00530 if(cgi)
00531 dbg_err_if(io_fd_create((cgi ? 1 : fd), IO_FD_CLOSE, &out));
00532 else
00533
00534 dbg_err_if(io_dup(request_io(rq), &out));
00535
00536
00537 response_set_method(rs, HM_GET);
00538
00539
00540 dbg_err_if(response_bind(rs, out));
00541 out = NULL;
00542
00543 dbg_err_if(response_set_status(rs, HTTP_STATUS_BAD_REQUEST));
00544
00545
00546 dbg_err_if(rc = request_parse_header(rq, http_is_valid_uri, rq));
00547
00548 response_set_method(rs, request_get_method(rq));
00549
00550
00551 http_resolv_request(h, rq);
00552
00553
00554 if((cstr = request_get_filename(rq)) != NULL && cstr[strlen(cstr)-1] == '/')
00555 dbg_err_if(http_set_index_request(h, rq));
00556
00557
00558 dbg_err_if(http_add_default_header(h, rs));
00559
00560
00561 dbg_err_if(response_set_status(rs, HTTP_STATUS_OK));
00562
00563
00564 nop_err_if((rc = broker_serve(h->broker, h, rq, rs)) != 0);
00565
00566
00567 hook_call(request, rq, rs);
00568
00569
00570
00571 request_free(rq);
00572 response_free(rs);
00573
00574
00575
00576 return 0;
00577 err:
00578
00579 hook_call(request, rq, rs);
00580
00581 if(rc && rq && rs && response_io(rs))
00582 http_print_error_page(h, rq, rs, rc);
00583 if(in)
00584 io_free(in);
00585 if(out)
00586 io_free(out);
00587 if(rq)
00588 request_free(rq);
00589 if(rs)
00590 response_free(rs);
00591 return ~0;
00592 }
00593
00594 static int http_free(http_t *h)
00595 {
00596 dbg_return_if (h == NULL, 0);
00597
00598 if(h->broker)
00599 broker_free(h->broker);
00600
00601 U_FREE(h);
00602
00603 return 0;
00604 }
00605
00606 static int http_set_config_opt(http_t *http)
00607 {
00608 u_config_t *c = http->config;
00609 const char *v;
00610
00611 dbg_err_if (http == NULL);
00612
00613
00614 http->server_sig = "klone/" KLONE_VERSION;
00615 http->dir_root = "";
00616 http->index = NULL;
00617 http->send_enc_deflate = 0;
00618
00619
00620 dbg_err_if(u_config_get_subkey_value_b(c, "send_enc_deflate", 0,
00621 &http->send_enc_deflate));
00622
00623
00624 if((v = u_config_get_subkey_value(c, "server_sig")) != NULL)
00625 http->server_sig = v;
00626
00627
00628 if((v = u_config_get_subkey_value(c, "dir_root")) != NULL)
00629 http->dir_root = v;
00630 else
00631 crit_err("dir_root must be set");
00632
00633
00634 if((v = u_config_get_subkey_value(c, "index")) != NULL)
00635 http->index = v;
00636
00637 return 0;
00638 err:
00639 return ~0;
00640 }
00641
00642
00643 static int http_create(u_config_t *config, http_t **ph)
00644 {
00645 http_t *h = NULL;
00646
00647 dbg_err_if (config == NULL);
00648 dbg_err_if (ph == NULL);
00649
00650 h = u_zalloc(sizeof(http_t));
00651 dbg_err_if(h == NULL);
00652
00653 h->config = config;
00654
00655
00656 dbg_err_if(broker_create(&h->broker));
00657
00658
00659 dbg_err_if(http_set_config_opt(h));
00660
00661 *ph = h;
00662
00663 return 0;
00664 err:
00665 if(h)
00666 http_free(h);
00667 return ~0;
00668 }
00669
00670 static int http_backend_serve(struct backend_s *be, int fd)
00671 {
00672 http_t *h;
00673 int rc;
00674
00675 dbg_err_if (be == NULL);
00676 dbg_err_if (be->arg == NULL);
00677 dbg_err_if (fd < 0);
00678
00679 h = (http_t *) be->arg;
00680
00681
00682 rc = http_serve(h, fd);
00683
00684 return rc;
00685 err:
00686 return ~0;
00687 }
00688
00689 static int http_backend_term(struct backend_s *be)
00690 {
00691 http_t *http;
00692
00693 dbg_return_if (be == NULL, 0);
00694 dbg_return_if (be->arg == NULL, 0);
00695
00696 http = (http_t *) be->arg;
00697
00698 dbg_err_if(session_module_term(http->sess_opt));
00699
00700 http_free(http);
00701
00702 return 0;
00703 err:
00704 return ~0;
00705 }
00706
00707 static int http_backend_init(struct backend_s *be)
00708 {
00709 http_t *http = NULL;
00710 broker_t *broker = NULL;
00711
00712 dbg_err_if (be == NULL);
00713
00714 dbg_err_if(http_create(be->config, &http));
00715
00716 be->arg = http;
00717
00718 dbg_err_if(session_module_init(http->config, &http->sess_opt));
00719
00720 return 0;
00721 err:
00722 if(http)
00723 http_free(http);
00724 if(broker)
00725 broker_free(broker);
00726 return ~0;
00727 }
00728
00729 #ifdef HAVE_LIBOPENSSL
00730 static int https_backend_init(struct backend_s *be)
00731 {
00732 http_t *https;
00733
00734 dbg_err_if (be == NULL);
00735
00736 dbg_err_if(http_backend_init(be));
00737
00738 https = (http_t *) be->arg;
00739
00740
00741 https->ssl = 1;
00742
00743
00744 https->ssl_ctx = tls_load_init_ctx(http_get_config(https));
00745 warn_err_ifm (https->ssl_ctx == NULL, "bad or missing HTTPS credentials");
00746
00747 dbg_err_if(session_module_init(https->config, &https->sess_opt));
00748
00749 return 0;
00750 err:
00751 return ~0;
00752 }
00753
00754 static int https_backend_term(struct backend_s *be)
00755 {
00756 http_t *https;
00757
00758 dbg_err_if (be == NULL);
00759
00760 https = (http_t *) be->arg;
00761 if (https == NULL)
00762 return 0;
00763
00764 SSL_CTX_free(https->ssl_ctx);
00765
00766 return http_backend_term(be);
00767 err:
00768 return ~0;
00769 }
00770
00771
00772 backend_t be_https =
00773 BACKEND_STATIC_INITIALIZER( "https",
00774 https_backend_init,
00775 http_backend_serve,
00776 https_backend_term );
00777 #endif
00778
00779 backend_t be_http =
00780 BACKEND_STATIC_INITIALIZER( "http",
00781 http_backend_init,
00782 http_backend_serve,
00783 http_backend_term );
00784