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/klone.h>
00022 #include <klone/server.h>
00023 #include <klone/broker.h>
00024 #include <klone/request.h>
00025 #include <klone/ses_prv.h>
00026 #include <klone/response.h>
00027 #include <klone/backend.h>
00028 #include <klone/io.h>
00029 #include <klone/timer.h>
00030 #include <klone/tls.h>
00031 #include <klone/ses_prv.h>
00032 #include "http_s.h"
00033
00034 struct http_status_map_s
00035 {
00036 int status;
00037 const char *desc;
00038 } http_status_map[] = {
00039 { HTTP_STATUS_OK , "OK" },
00040 { HTTP_STATUS_NOT_MODIFIED , "Not Modified" },
00041 { HTTP_STATUS_NOT_FOUND , "Not Found" },
00042 { HTTP_STATUS_INTERNAL_SERVER_ERROR , "Internal Server Error" },
00043 { HTTP_STATUS_MOVED_PERMANENTLY , "Moved Permanently" },
00044 { HTTP_STATUS_MOVED_TEMPORARILY , "Moved Temporarily" },
00045 { HTTP_STATUS_CREATED , "Created" },
00046 { HTTP_STATUS_ACCEPTED , "Accepted" },
00047 { HTTP_STATUS_NO_CONTENT , "No Content" },
00048 { HTTP_STATUS_BAD_REQUEST , "Bad Request" },
00049 { HTTP_STATUS_UNAUTHORIZED , "Unauthorized" },
00050 { HTTP_STATUS_FORBIDDEN , "Forbidden" },
00051 { HTTP_STATUS_LENGTH_REQUIRED , "Content-Length required" },
00052 { HTTP_STATUS_REQUEST_TOO_LARGE , "Request data too big" },
00053 { HTTP_STATUS_NOT_IMPLEMENTED , "Not Implemented" },
00054 { HTTP_STATUS_BAD_GATEWAY , "Bad Gateway" },
00055 { HTTP_STATUS_SERVICE_UNAVAILABLE , "Service Unavailable" },
00056 { 0 , NULL }
00057 };
00058
00059
00060 int cgi_set_request(request_t *rq);
00061
00062 session_opt_t *http_get_session_opt(http_t *http)
00063 {
00064 dbg_return_if (http == NULL, NULL);
00065
00066 return http->sess_opt;
00067 }
00068
00069 u_config_t *http_get_config(http_t* http)
00070 {
00071 dbg_return_if (http == NULL, NULL);
00072
00073 return http->config;
00074 }
00075
00076 const char *http_get_status_desc(int status)
00077 {
00078 struct http_status_map_s *map = http_status_map;
00079 const char *msg = "Unknown Status Code";
00080
00081 for( ; map->status; ++map)
00082 if(map->status == status)
00083 {
00084 msg = map->desc;
00085 break;
00086 }
00087
00088 return msg;
00089 }
00090
00091 int http_alias_resolv(http_t *h, char *dst, const char *filename, size_t sz)
00092 {
00093 static const char *WP = " \t";
00094 u_config_t *config;
00095 int i;
00096 const char *value;
00097 char *src, *res, *v = NULL,*pp = NULL;
00098
00099 dbg_err_if (h == NULL);
00100 dbg_err_if (dst == NULL);
00101 dbg_err_if (filename == NULL);
00102
00103
00104 for(i = 0; !u_config_get_subkey_nth(h->config, "dir_alias", i, &config);
00105 ++i)
00106 {
00107 if((value = u_config_get_value(config)) == NULL)
00108 continue;
00109
00110
00111 v = u_strdup(value);
00112 dbg_err_if(v == NULL);
00113
00114 src = strtok_r(v, WP, &pp);
00115 dbg_err_if(src == NULL);
00116
00117 if(strncmp(src, filename, strlen(src)) == 0)
00118 {
00119
00120 res = strtok_r(NULL, WP, &pp);
00121 dbg_err_if(res == NULL);
00122
00123 dbg_err_if(u_path_snprintf(dst, sz, '/', "%s/%s", res,
00124 filename + strlen(src)));
00125
00126 U_FREE(v);
00127 return 0;
00128 }
00129
00130 U_FREE(v);
00131 }
00132
00133
00134 dbg_err_if(u_path_snprintf(dst, sz, '/', "%s/%s", h->dir_root, filename));
00135
00136 return 0;
00137 err:
00138 U_FREE(v);
00139 return ~0;
00140 }
00141
00142 static int http_is_valid_uri(void *arg, const char *buf, size_t len)
00143 {
00144 enum { URI_MAX = 2048 };
00145 char resolved[U_FILENAME_MAX], uri[URI_MAX];
00146 http_t *h = (http_t*)arg;
00147
00148 dbg_err_if (arg == NULL);
00149 dbg_err_if (buf == NULL);
00150
00151 strncpy(uri, buf, len);
00152 uri[len] = 0;
00153
00154 dbg_err_if(http_alias_resolv(h, resolved, uri, URI_MAX));
00155
00156 return broker_is_valid_uri(h->broker, resolved, strlen(resolved));
00157 err:
00158 return ~0;
00159 }
00160
00161 static void http_resolv_request(http_t *h, request_t *rq)
00162 {
00163 const char *cstr;
00164 char resolved[U_FILENAME_MAX];
00165
00166 dbg_ifb(h == NULL) return;
00167 dbg_ifb(rq == NULL) return;
00168
00169
00170 cstr = request_get_filename(rq);
00171 if(cstr && !http_alias_resolv(h, resolved, cstr, U_FILENAME_MAX))
00172 request_set_resolved_filename(rq, resolved);
00173
00174
00175 cstr = request_get_path_info(rq);
00176 if(cstr && !http_alias_resolv(h, resolved, cstr, U_FILENAME_MAX))
00177 request_set_resolved_path_info(rq, resolved);
00178 }
00179
00180 static int http_set_index_request(http_t *h, request_t *rq)
00181 {
00182 static const char *indexes[] = { "/index.klone", "/index.kl1",
00183 "/index.html", "/index.htm", NULL };
00184 const char **pg;
00185 char resolved[U_FILENAME_MAX];
00186
00187 dbg_err_if (h == NULL);
00188 dbg_err_if (rq == NULL);
00189
00190
00191 if(h->index == NULL)
00192 {
00193
00194 for(pg = indexes; *pg; ++pg)
00195 {
00196 resolved[0] = 0;
00197 dbg_err_if(u_path_snprintf(resolved, U_FILENAME_MAX, '/', "%s/%s",
00198 request_get_resolved_filename(rq), *pg));
00199
00200 if(broker_is_valid_uri(h->broker, resolved, strlen(resolved)))
00201 {
00202
00203 request_set_filename(rq, *pg);
00204 break;
00205 }
00206 }
00207 if(*pg == NULL)
00208 dbg_if(request_set_filename(rq, "/index.html"));
00209 } else
00210 dbg_if(request_set_filename(rq, h->index));
00211
00212 http_resolv_request(h, rq);
00213
00214 return 0;
00215 err:
00216 return ~0;
00217 }
00218
00219 static int http_add_default_header(http_t *h, response_t *rs)
00220 {
00221 time_t now;
00222
00223 dbg_err_if (h == NULL);
00224 dbg_err_if (rs == NULL);
00225
00226
00227 dbg_err_if(response_set_field(rs, "Server", h->server_sig));
00228
00229 now = time(NULL);
00230 dbg_err_if(response_set_date(rs, now));
00231
00232 return 0;
00233 err:
00234 return ~0;
00235 }
00236
00237 static int http_print_error_page(http_t *h, request_t *rq, response_t *rs,
00238 int http_status)
00239 {
00240 enum { BUFSZ = 64 };
00241 const char *err_page;
00242 char buf[BUFSZ];
00243 int rc;
00244
00245 dbg_err_if (h == NULL);
00246 dbg_err_if (rq == NULL);
00247 dbg_err_if (rs == NULL);
00248 dbg_err_if (http_status == 0);
00249
00250
00251 if(http_status != 302)
00252 dbg_err_if(header_clear(response_get_header(rs)));
00253
00254
00255 dbg_err_if(http_add_default_header(h, rs));
00256
00257
00258 dbg_err_if(response_disable_caching(rs));
00259
00260
00261 dbg_err_if(u_snprintf(buf, BUFSZ, "error.%d", http_status));
00262 err_page = u_config_get_subkey_value(h->config, buf);
00263
00264 if(err_page && !request_set_uri(rq, err_page, NULL, NULL))
00265 {
00266 http_resolv_request(h, rq);
00267 if((rc = broker_serve(h->broker, rq, rs)) == 0)
00268 return 0;
00269 else {
00270
00271 http_status = rc;
00272 }
00273 }
00274
00275
00276 response_set_status(rs, http_status);
00277
00278 response_print_header(rs);
00279
00280 if(request_get_method(rq) == HM_HEAD)
00281 return 0;
00282
00283
00284 dbg_err_if(io_printf(response_io(rs),
00285 "<html><head><title>%d %s</title></head>\n"
00286 "<body><h1>%s</h1><p>URL: %s</body></html>",
00287 http_status, http_get_status_desc(http_status),
00288 http_get_status_desc(http_status),
00289 (request_get_uri(rq) ? request_get_uri(rq) : "") ) < 0);
00290
00291 return 0;
00292 err:
00293 return ~0;
00294 }
00295
00296 static int http_serve(http_t *h, int fd)
00297 {
00298 request_t *rq = NULL;
00299 response_t *rs = NULL;
00300 io_t *in = NULL, *out = NULL;
00301 int cgi = 0, port;
00302 const char *gwi = NULL;
00303 talarm_t *al = NULL;
00304 addr_t *addr;
00305 struct sockaddr sa;
00306 int sasz, rc = HTTP_STATUS_INTERNAL_SERVER_ERROR;
00307
00308 dbg_err_if (h == NULL);
00309 dbg_err_if (fd < 0);
00310
00311 if(fd == 0 && (gwi = getenv("GATEWAY_INTERFACE")) != NULL)
00312 cgi++;
00313
00314
00315 dbg_err_if(request_create(h, &rq));
00316 request_set_cgi(rq, cgi);
00317
00318
00319 dbg_err_if(addr_create(&addr));
00320
00321 if(cgi)
00322 {
00323 if(getenv("REMOTE_ADDR") && getenv("REMOTE_PORT"))
00324 {
00325 port = atoi(getenv("REMOTE_PORT"));
00326 dbg_err_if(addr_set(addr, getenv("REMOTE_ADDR"), port));
00327 dbg_err_if(request_set_addr(rq, addr));
00328 }
00329
00330 if(getenv("SERVER_ADDR"))
00331 {
00332 if(getenv("SERVER_PORT"))
00333 port = atoi(getenv("SERVER_PORT"));
00334 else
00335 port = 80;
00336 dbg_err_if(addr_set(addr, getenv("SERVER_ADDR"), port));
00337 dbg_err_if(request_set_peer_addr(rq, addr));
00338 }
00339 } else {
00340
00341 sasz = sizeof(struct sockaddr);
00342 dbg_err_if(getsockname(fd, &sa, &sasz));
00343 dbg_err_if(addr_set_from_sa(addr, &sa, sasz));
00344 dbg_err_if(request_set_addr(rq, addr));
00345
00346
00347 sasz = sizeof(struct sockaddr);
00348 dbg_err_if(getpeername(fd, &sa, &sasz));
00349 dbg_err_if(addr_set_from_sa(addr, &sa, sasz));
00350 dbg_err_if(request_set_peer_addr(rq, addr));
00351 }
00352
00353 addr_free(addr);
00354 addr = NULL;
00355
00356 #ifdef HAVE_LIBOPENSSL
00357
00358
00359 if(h->ssl && !cgi)
00360 dbg_err_if(io_ssl_create(fd, IO_FD_CLOSE, h->ssl_ctx, &in));
00361 else
00362 dbg_err_if(io_fd_create(fd, IO_FD_CLOSE, &in));
00363 #else
00364
00365 dbg_err_if(io_fd_create(fd, IO_FD_CLOSE, &in));
00366 #endif
00367
00368
00369 dbg_err_if(request_bind(rq, in));
00370 in = NULL;
00371
00372
00373 dbg_err_if(response_create(h, &rs));
00374
00375 response_set_cgi(rs, cgi);
00376
00377 if(cgi)
00378 dbg_err_if(cgi_set_request(rq));
00379
00380
00381 if(cgi)
00382 dbg_err_if(io_fd_create((cgi ? 1 : fd), IO_FD_CLOSE, &out));
00383 else
00384
00385 dbg_err_if(io_dup(request_io(rq), &out));
00386
00387
00388 response_set_method(rs, HM_GET);
00389
00390
00391 dbg_err_if(response_bind(rs, out));
00392 out = NULL;
00393
00394 dbg_err_if(rc = request_parse_header(rq, http_is_valid_uri, h));
00395
00396 response_set_method(rs, request_get_method(rq));
00397
00398
00399 http_resolv_request(h, rq);
00400
00401
00402 if(strcmp(request_get_filename(rq), "/") == 0)
00403 dbg_err_if(http_set_index_request(h, rq));
00404
00405
00406 dbg_err_if(http_add_default_header(h, rs));
00407
00408
00409 dbg_err_if(response_set_status(rs, HTTP_STATUS_OK));
00410
00411
00412 dbg_err_if(rc = broker_serve(h->broker, rq, rs));
00413
00414
00415
00416 request_free(rq);
00417 response_free(rs);
00418
00419
00420
00421 return 0;
00422 err:
00423 if(rc && rq && rs && response_io(rs))
00424 http_print_error_page(h, rq, rs, rc);
00425 if(in)
00426 io_free(in);
00427 if(out)
00428 io_free(out);
00429 if(rq)
00430 request_free(rq);
00431 if(rs)
00432 response_free(rs);
00433 return ~0;
00434 }
00435
00436 static int http_free(http_t *h)
00437 {
00438 dbg_return_if (h == NULL, 0);
00439
00440 if(h->broker)
00441 broker_free(h->broker);
00442
00443 U_FREE(h);
00444
00445 return 0;
00446 }
00447
00448 static int http_set_config_opt(http_t *http)
00449 {
00450 u_config_t *c = http->config;
00451 const char *v;
00452
00453 dbg_err_if (http == NULL);
00454
00455
00456 http->server_sig = "klone/" KLONE_VERSION;
00457 http->dir_root = "";
00458 http->index = NULL;
00459 http->send_enc_deflate = 0;
00460
00461
00462 dbg_err_if(u_config_get_subkey_value_b(c, "send_enc_deflate", 0,
00463 &http->send_enc_deflate));
00464
00465
00466 if((v = u_config_get_subkey_value(c, "server_sig")) != NULL)
00467 http->server_sig = v;
00468
00469
00470 if((v = u_config_get_subkey_value(c, "dir_root")) != NULL)
00471 http->dir_root = v;
00472
00473
00474 if((v = u_config_get_subkey_value(c, "index")) != NULL)
00475 http->index = v;
00476
00477 return 0;
00478 err:
00479 return ~0;
00480 }
00481
00482
00483 static int http_create(u_config_t *config, http_t **ph)
00484 {
00485 http_t *h = NULL;
00486
00487 dbg_err_if (config == NULL);
00488 dbg_err_if (ph == NULL);
00489
00490 h = u_zalloc(sizeof(http_t));
00491 dbg_err_if(h == NULL);
00492
00493 h->config = config;
00494
00495
00496 dbg_err_if(broker_create(&h->broker));
00497
00498
00499 dbg_err_if(http_set_config_opt(h));
00500
00501 *ph = h;
00502
00503 return 0;
00504 err:
00505 if(h)
00506 http_free(h);
00507 return ~0;
00508 }
00509
00510 int http_backend_serve(struct backend_s *be, int fd)
00511 {
00512 http_t *h;
00513 int rc;
00514
00515 dbg_err_if (be == NULL);
00516 dbg_err_if (be->arg == NULL);
00517 dbg_err_if (fd < 0);
00518
00519 h = (http_t *) be->arg;
00520
00521
00522 dbg_if((rc = http_serve(h, fd)) != 0);
00523
00524 return rc;
00525 err:
00526 return ~0;
00527 }
00528
00529 int http_backend_term(struct backend_s *be)
00530 {
00531 http_t *http;
00532
00533 dbg_return_if (be == NULL, 0);
00534 dbg_return_if (be->arg == NULL, 0);
00535
00536 http = (http_t *) be->arg;
00537
00538 dbg_err_if(session_module_term(http->sess_opt));
00539
00540 http_free(http);
00541
00542 return 0;
00543 err:
00544 return ~0;
00545 }
00546
00547 int http_backend_init(struct backend_s *be)
00548 {
00549 http_t *http = NULL;
00550 broker_t *broker = NULL;
00551
00552 dbg_err_if (be == NULL);
00553
00554 dbg_err_if(http_create(be->config, &http));
00555
00556 be->arg = http;
00557
00558 dbg_err_if(session_module_init(http->config, &http->sess_opt));
00559
00560 return 0;
00561 err:
00562 if(http)
00563 http_free(http);
00564 if(broker)
00565 broker_free(broker);
00566 return ~0;
00567 }
00568
00569 #ifdef HAVE_LIBOPENSSL
00570 int https_backend_init(struct backend_s *be)
00571 {
00572 http_t *https;
00573 tls_ctx_args_t *cargs;
00574
00575 dbg_err_if (be == NULL);
00576
00577 dbg_err_if(http_backend_init(be));
00578
00579 https = (http_t *) be->arg;
00580
00581
00582 https->ssl = 1;
00583
00584
00585 dbg_err_if (tls_load_ctx_args(http_get_config(https), &cargs));
00586 warn_err_ifm (!(https->ssl_ctx = tls_init_ctx(cargs)),
00587 "bad or missing HTTPS credentials");
00588
00589 dbg_err_if(session_module_init(https->config, &https->sess_opt));
00590
00591 return 0;
00592 err:
00593 return ~0;
00594 }
00595
00596 int https_backend_term(struct backend_s *be)
00597 {
00598 http_t *https;
00599
00600 dbg_err_if (be == NULL);
00601
00602 https = (http_t *) be->arg;
00603 if (https == NULL)
00604 return 0;
00605
00606 SSL_CTX_free(https->ssl_ctx);
00607
00608 return http_backend_term(be);
00609 err:
00610 return ~0;
00611 }
00612
00613
00614 backend_t be_https =
00615 BACKEND_STATIC_INITIALIZER( "https",
00616 https_backend_init,
00617 http_backend_serve,
00618 https_backend_term );
00619 #endif
00620
00621 backend_t be_http =
00622 BACKEND_STATIC_INITIALIZER( "http",
00623 http_backend_init,
00624 http_backend_serve,
00625 http_backend_term );
00626