http.c

00001 /*
00002  * Copyright (c) 2005-2012 by KoanLogic s.r.l. <http://www.koanlogic.com>
00003  * All rights reserved.
00004  *
00005  * This file is part of KLone, and as such it is subject to the license stated
00006  * in the LICENSE file which you have received as part of this distribution.
00007  *
00008  * $Id: http.c,v 1.69 2010/05/30 12:51:13 stewy Exp $
00009  */
00010 
00011 #include "klone_conf.h"
00012 #include <sys/types.h>
00013 #include <stdlib.h>
00014 #include <unistd.h>
00015 #ifdef SSL_ON
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 <klone/access.h>
00036 #include <klone/vhost.h>
00037 #include <klone/supplier.h>
00038 #include "http_s.h"
00039 
00040 struct http_status_map_s
00041 {
00042     int status;
00043     const char *desc;
00044 } http_status_map[] = {
00045     { HTTP_STATUS_OK                    , "OK"                      },
00046     { HTTP_STATUS_NOT_MODIFIED          , "Not Modified"            },
00047     { HTTP_STATUS_NOT_FOUND             , "Not Found"               },
00048     { HTTP_STATUS_INTERNAL_SERVER_ERROR , "Internal Server Error"   },
00049     { HTTP_STATUS_MOVED_PERMANENTLY     , "Moved Permanently"       },
00050     { HTTP_STATUS_MOVED_TEMPORARILY     , "Moved Temporarily"       },
00051     { HTTP_STATUS_CREATED               , "Created"                 },
00052     { HTTP_STATUS_ACCEPTED              , "Accepted"                },
00053     { HTTP_STATUS_NO_CONTENT            , "No Content"              },
00054     { HTTP_STATUS_BAD_REQUEST           , "Bad Request"             },
00055     { HTTP_STATUS_UNAUTHORIZED          , "Unauthorized"            },
00056     { HTTP_STATUS_FORBIDDEN             , "Forbidden"               },
00057     { HTTP_STATUS_LENGTH_REQUIRED       , "Content-Length required" },
00058     { HTTP_STATUS_REQUEST_TOO_LARGE     , "Request data too big"    },
00059     { HTTP_STATUS_EXT_KEY_NEEDED        , "Key needed"              },
00060     { HTTP_STATUS_NOT_IMPLEMENTED       , "Not Implemented"         },
00061     { HTTP_STATUS_BAD_GATEWAY           , "Bad Gateway"             },
00062     { HTTP_STATUS_SERVICE_UNAVAILABLE   , "Service Unavailable"     },
00063     { 0                                 , NULL                      }
00064 };
00065 
00066 enum { URI_MAX = 2048 };
00067 
00068 /* in cgi.c */
00069 int cgi_set_request(request_t *rq);
00070 
00071 session_opt_t *http_get_session_opt(http_t *http)
00072 {
00073     dbg_return_if (http == NULL, NULL);
00074 
00075     return http->sess_opt;
00076 }
00077 
00078 u_config_t *http_get_config(http_t* http)
00079 {
00080     dbg_return_if (http == NULL, NULL);
00081 
00082     return http->config;
00083 }
00084 
00085 const char *http_get_status_desc(int status)
00086 {
00087     struct http_status_map_s *map = http_status_map;
00088     const char *msg = "Unknown Status Code";
00089 
00090     for( ; map->status; ++map)
00091         if(map->status == status)
00092         {
00093             msg = map->desc;
00094             break;
00095         }
00096 
00097     return msg;
00098 }
00099 
00100 static int http_try_resolv(const char *alias, char *dst, const char *uri, 
00101         size_t sz)
00102 {
00103     static const char *WP = " \t";
00104     char *src, *res, *pp = NULL;
00105     char v[1024];
00106 
00107     dbg_err_if(dst == NULL);
00108     dbg_err_if(uri == NULL);
00109     dbg_err_if(alias == NULL);
00110 
00111     /* copy the alias in a buffer, strtok_r modifies it */
00112     dbg_err_if(u_strlcpy(v, alias, sizeof(v)));
00113 
00114     /* src is the source directory */
00115     src = strtok_r(v, WP, &pp); 
00116     dbg_err_if(src == NULL);
00117 
00118     /* exit if the URI doesn't match this alias */
00119     nop_err_if(strncmp(src, uri, strlen(src)));
00120 
00121     /* if src doesn't end with a slash check that the next char in uri is a / */
00122     if(src[strlen(src)-1] != '/')
00123         nop_err_if(uri[strlen(src)] != '/');
00124 
00125     /* alias found, get the resolved prefix */
00126     res = strtok_r(NULL, WP, &pp);
00127     dbg_err_if(res == NULL);
00128 
00129     /* copy-out the resolved uri to dst */
00130     dbg_err_if(u_path_snprintf(dst, sz, '/', "%s/%s", res, uri + strlen(src)));
00131 
00132     return 0;
00133 err:
00134     return ~0;
00135 }
00136 
00137 vhost_list_t* http_get_vhost_list(http_t *http)
00138 {
00139     dbg_err_if(http == NULL);
00140 
00141     return http->vhosts;
00142 err:
00143     return NULL;
00144 }
00145 
00146 vhost_t* http_get_vhost(http_t *h, request_t *rq)
00147 {
00148     const char *host;
00149     char *p, hostcp[128];
00150     vhost_t *vh = NULL;
00151 
00152     dbg_err_if (h == NULL);
00153     dbg_err_if (rq == NULL);
00154 
00155     if((vh = request_get_vhost(rq)) != NULL)
00156         return vh; /* cached */
00157 
00158     if((host = request_get_field_value(rq, "Host")) != NULL)
00159     {
00160         dbg_err_if(u_strlcpy(hostcp, host, sizeof(hostcp)));
00161 
00162         /* remove :port part */   
00163         if((p = strrchr(hostcp, ':')) != NULL)
00164             *p = 0;
00165 
00166         vh = vhost_list_get(h->vhosts, hostcp);
00167     }
00168 
00169     if(vh == NULL)
00170     {
00171         /* get the default vhost */
00172         vh = vhost_list_get_n(h->vhosts, 0);
00173         dbg_err_if(vh == NULL);
00174     }
00175 
00176     return vh;
00177 err:
00178     return NULL;
00179 }
00180 
00181 int http_alias_resolv(http_t *h, request_t *rq, char *dst, const char *uri, 
00182         size_t sz)
00183 {
00184     u_config_t *config, *cgi;
00185     vhost_t *vhost;
00186     int i;
00187 
00188     dbg_err_if (h == NULL);
00189     dbg_err_if (dst == NULL);
00190     dbg_err_if (uri == NULL);
00191 
00192     dbg_err_if((vhost = http_get_vhost(h, rq)) == NULL);
00193 
00194     /* for each dir_alias config item */
00195     for(i = 0; !u_config_get_subkey_nth(vhost->config,"dir_alias", i, &config); 
00196         ++i)
00197     {
00198         if(!http_try_resolv(u_config_get_value(config), dst, uri, sz))
00199             return 0;   /* alias found, uri resolved */
00200     }
00201 
00202     /* if there's a cgi tree also try to resolv script_alias rules */
00203     if(!u_config_get_subkey(vhost->config, "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;   /* alias found, uri resolved */
00210         }
00211     }
00212 
00213     /* alias not found, prepend dir_root to the uri */
00214     dbg_err_if(u_path_snprintf(dst, sz, '/', "%s/%s", vhost->dir_root, uri));
00215 
00216     return 0;
00217 err:
00218     return ~0;
00219 }
00220 
00221 static int http_is_valid_uri(request_t *rq, const char *buf, size_t len)
00222 {
00223     char resolved[U_FILENAME_MAX], uri[URI_MAX];
00224     http_t *h = NULL;
00225 
00226     dbg_err_if (rq == NULL);
00227     dbg_err_if (buf == NULL);
00228     dbg_err_if (len + 1 > URI_MAX);
00229 
00230     dbg_err_if ((h = request_get_http(rq)) == NULL);
00231 
00232     memcpy(uri, buf, len);
00233     uri[len] = '\0';
00234     
00235     /* try the url itself */
00236     if(broker_is_valid_uri(h->broker, h, rq, uri, strlen(uri)))
00237         return 1;
00238 
00239     /* try the path-resolved url */
00240     dbg_err_if(http_alias_resolv(h, rq, resolved, uri, sizeof resolved));
00241 
00242     return broker_is_valid_uri(h->broker, h, rq, resolved, strlen(resolved));
00243 err:
00244     return 0; /* error, not a valid uri */
00245 }
00246 
00247 static int http_resolv_request(http_t *h, request_t *rq)
00248 {
00249     const char *cstr;
00250     char resolved[U_FILENAME_MAX];
00251 
00252     dbg_err_if(h == NULL);
00253     dbg_err_if(rq == NULL);
00254     
00255     /* unalias rq->filename */
00256     if((cstr = request_get_filename(rq)) != NULL)
00257     {
00258         dbg_err_if(http_alias_resolv(h, rq, resolved, cstr, U_FILENAME_MAX));
00259 
00260         dbg_err_if(request_set_resolved_filename(rq, resolved));
00261     }
00262 
00263     /* unalias rq->path_info */
00264     if((cstr = request_get_path_info(rq)) != NULL)
00265     {
00266         dbg_err_if(http_alias_resolv(h, rq, resolved, cstr, U_FILENAME_MAX));
00267 
00268         dbg_err_if(request_set_resolved_path_info(rq, resolved));
00269     }
00270 
00271     return 0;
00272 err:
00273     return ~0;
00274 }
00275 
00276 static int http_is_valid_index(http_t *h, request_t *rq, const char *uri)
00277 {
00278     char resolved[U_FILENAME_MAX] = { 0 };
00279 
00280     dbg_err_if(u_path_snprintf(resolved, U_FILENAME_MAX, '/', "%s/%s", 
00281             request_get_resolved_filename(rq), uri));
00282 
00283     if(broker_is_valid_uri(h->broker, h, rq, resolved, strlen(resolved)))
00284         return 1; /* index found */
00285 
00286 err:
00287     return 0; /* index not found */
00288 }
00289 
00290 static int http_get_config_index(http_t *h, request_t *rq, char *idx, size_t sz)
00291 {
00292     vhost_t *vhost;
00293     char buf[256], *tok, *src, *pp = NULL;
00294     const char *cindex = NULL;
00295 
00296     dbg_err_if (h == NULL);
00297     dbg_err_if (rq == NULL);
00298 
00299     dbg_err_if((vhost = http_get_vhost(h, rq)) == NULL);
00300 
00301     if((cindex = u_config_get_subkey_value(vhost->config, "index")) == NULL)
00302         return ~0; /* index config key missing */
00303 
00304     /* copy the string (u_tokenize will modify it) */
00305     dbg_err_if(u_strlcpy(buf, cindex, sizeof(buf)));
00306 
00307     for(src = buf; (tok = strtok_r(src, " \t", &pp)) != NULL; src = NULL)
00308     {
00309         if(!strcmp(tok, ""))
00310             continue; 
00311 
00312         if(http_is_valid_index(h, rq, tok))
00313         {
00314             dbg_err_if(u_strlcpy(idx, tok, sz));
00315             return 0; /* index page found */
00316         }
00317     }
00318 
00319     /* fall through */
00320 err:
00321     return ~0;
00322 }
00323 
00324 static int http_get_default_index(http_t *h, request_t *rq, char *cindex, 
00325         size_t sz)
00326 {
00327     const char **pg;
00328     static const char *indexes[] = 
00329     { 
00330         "/index.kl1",
00331         "/index.html", 
00332         "/index.htm", 
00333         "/index.klx", 
00334         "/index.klone", 
00335         "/index.klc", 
00336         NULL 
00337     };
00338 
00339     dbg_err_if (h == NULL);
00340     dbg_err_if (rq == NULL);
00341     dbg_err_if (cindex == NULL);
00342 
00343     /* try to find an index page between default index uris */
00344     for(pg = indexes; *pg; ++pg)
00345     {
00346         if(http_is_valid_index(h, rq, *pg))
00347         {
00348             dbg_err_if(u_strlcpy(cindex, *pg, sz));
00349             return 0; /* index page found */
00350         }
00351     }
00352 
00353     /* fall through */
00354 err:
00355     return ~0;
00356 }
00357 
00358 static int http_set_index_request(http_t *h, request_t *rq)
00359 {
00360     char idx[128], uri[1024];
00361 
00362     dbg_err_if (h == NULL);
00363     dbg_err_if (rq == NULL);
00364 
00365     /* find an index page; try first config options then static index names */
00366     nop_err_if(http_get_config_index(h, rq, idx, sizeof(idx)) &&
00367             http_get_default_index(h, rq, idx, sizeof(idx)));
00368 
00369     dbg_err_if(u_snprintf(uri, sizeof(uri), "%s%s", 
00370                 request_get_filename(rq), idx));
00371 
00372     dbg_if(request_set_filename(rq, uri));
00373 
00374     dbg_err_if(http_resolv_request(h, rq));
00375 
00376     return 0;
00377 err:
00378     return ~0;
00379 }
00380 
00381 static int http_add_default_header(http_t *h, request_t *rq, response_t *rs)
00382 {
00383     vhost_t *vhost;
00384     time_t now;
00385 
00386     dbg_err_if (h == NULL);
00387     dbg_err_if (rs == NULL);
00388     
00389     dbg_err_if((vhost = http_get_vhost(h, rq)) == NULL);
00390 
00391     /* set server signature */
00392     dbg_err_if(response_set_field(rs, "Server", vhost->server_sig));
00393 
00394     now = time(NULL);
00395     dbg_err_if(response_set_date(rs, now));
00396 
00397     return 0;
00398 err:
00399     return ~0;
00400 }
00401 
00402 static int http_print_error_page(http_t *h, request_t *rq, response_t *rs, 
00403     int http_status)
00404 {
00405     enum { BUFSZ = 64 };
00406     const char *err_page;
00407     char s[URI_MAX], *sp = NULL;
00408     char buf[BUFSZ], *pp = NULL;
00409     vhost_t *vhost;
00410 
00411     dbg_err_if (h == NULL);
00412     dbg_err_if (rq == NULL);
00413     dbg_err_if (rs == NULL);
00414     dbg_err_if (http_status == 0);
00415     
00416     /* clean dirty header fields (not for redirects) */
00417     if(http_status != 302)
00418         dbg_err_if(header_clear(response_get_header(rs)));
00419 
00420     /* add default header fields */
00421     dbg_err_if(http_add_default_header(h, rq, rs));
00422 
00423     /* disable page caching */
00424     dbg_err_if(response_disable_caching(rs));
00425 
00426     /* looking for user provided error page */
00427     dbg_err_if(u_snprintf(buf, BUFSZ, "error.%d", http_status));
00428     if((vhost = http_get_vhost(h, rq)) == NULL)
00429         err_page = u_config_get_subkey_value(h->config, buf);
00430     else
00431         err_page = u_config_get_subkey_value(vhost->config, buf);
00432 
00433     if(err_page && !request_set_uri(rq, err_page, NULL, NULL))
00434     {
00435         dbg_err_if(http_resolv_request(h, rq));
00436 
00437         /* http_is_valid_uri() expects uri without parameters */
00438         dbg_err_if (u_strlcpy(s, err_page, sizeof s));
00439 
00440         sp = strtok_r(s, "?", &pp);
00441         dbg_err_if (sp == NULL);
00442 
00443         if(http_is_valid_uri(rq, sp, strlen(sp)))
00444         {
00445             /* user provided error page found */
00446             broker_serve(h->broker, h, rq, rs);
00447             return 0;
00448         }
00449 
00450         /* page not found */
00451         warn("%d handler page (%s) not found", http_status, sp);
00452     }
00453 
00454     /* be sure that the status code is properly set */
00455     response_set_status(rs, http_status);
00456 
00457     response_print_header(rs);
00458 
00459     if(request_get_method(rq) == HM_HEAD)
00460         return 0; /* just the header is requested */
00461 
00462     /* print default error page */
00463     dbg_err_if(io_printf(response_io(rs), 
00464         "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">"
00465         "<html><head><title>%d %s</title></head>\n"
00466         "<body><h1>%s</h1><p>URL: %s</p><hr>"
00467         "<address>KLone/%s web server - www.koanlogic.com</address>"
00468         "</body></html>", 
00469         http_status, http_get_status_desc(http_status), 
00470         http_get_status_desc(http_status), 
00471         (request_get_uri(rq) ? request_get_uri(rq) : ""),
00472         KLONE_VERSION
00473         ) < 0);
00474 
00475     return 0;
00476 err:
00477     return ~0;
00478 }
00479 
00480 static int http_serve(http_t *h, int fd)
00481 {
00482     request_t *rq = NULL;
00483     response_t *rs = NULL;
00484     io_t *in = NULL, *out = NULL;
00485     int cgi = 0, rc = HTTP_STATUS_INTERNAL_SERVER_ERROR;
00486     const char *gwi = NULL, *cstr;
00487     talarm_t *al = NULL;
00488     char addr[128] = { '\0' };
00489     vhost_t *vhost;
00490     struct sockaddr_storage ss;
00491     socklen_t slen;
00492     char *uri, nuri[URI_MAX];
00493     const char *port;
00494     supplier_t *sup;
00495 
00496     u_unused_args(al);
00497 
00498     dbg_err_if (h == NULL);
00499     dbg_err_if (fd < 0);
00500     
00501     if(fd == 0 && (gwi = getenv("GATEWAY_INTERFACE")) != NULL)
00502         cgi++; /* klone is being used as a CGI */
00503 
00504     /* create a request object */
00505     dbg_err_if(request_create(h, &rq));
00506     request_set_cgi(rq, cgi);
00507 
00508     /* save local and peer address into the request object */
00509     if (cgi)
00510     {
00511         if (getenv("REMOTE_ADDR") && getenv("REMOTE_PORT"))
00512         {
00513             (void) u_addr_fmt(getenv("REMOTE_ADDR"), getenv("REMOTE_PORT"), 
00514                     addr, sizeof addr);
00515 
00516             dbg_err_if(request_set_addr(rq, addr));
00517         }
00518 
00519         if (getenv("SERVER_ADDR"))
00520         {
00521             if ((port = getenv("SERVER_PORT")) == NULL)
00522                 port = "80";
00523 
00524             (void) u_addr_fmt(getenv("SERVER_ADDR"), port, addr, sizeof addr);
00525 
00526             dbg_err_if(request_set_peer_addr(rq, addr));
00527         }
00528     }
00529     else 
00530     {
00531         slen = sizeof ss;
00532 
00533         /* set local addr */
00534         dbg_err_if(getsockname(fd, (struct sockaddr *) &ss, &slen) == -1);
00535         dbg_err_if(request_set_addr(rq, 
00536                     u_sa_ntop((struct sockaddr *) &ss, addr, sizeof addr)));
00537 
00538         /* set peer addr */
00539         dbg_err_if(getpeername(fd, (struct sockaddr *) &ss, &slen) == -1);
00540         dbg_err_if(request_set_peer_addr(rq, 
00541                     u_sa_ntop((struct sockaddr *) &ss, addr, sizeof addr)));
00542     }
00543 
00544 #ifdef SSL_ON
00545     /* create input io buffer */
00546     if(h->ssl && !cgi)
00547         dbg_err_if(io_ssl_create(fd, IO_FD_CLOSE, 0, h->ssl_ctx, &in));
00548     else
00549         dbg_err_if(io_fd_create(fd, IO_FD_CLOSE, &in));
00550 #else
00551     /* create input io buffer */
00552     dbg_err_if(io_fd_create(fd, IO_FD_CLOSE, &in));
00553 #endif
00554 
00555     /* bind the request object to the 'in' io_t */
00556     dbg_err_if(request_bind(rq, in));
00557     in = NULL; 
00558 
00559     /* create a response object */
00560     dbg_err_if(response_create(h, &rs));
00561 
00562     response_set_cgi(rs, cgi);
00563 
00564     if(cgi)
00565         dbg_err_if(cgi_set_request(rq));
00566 
00567     /* create the output io_t */
00568     if(cgi)
00569         dbg_err_if(io_fd_create((cgi ? 1 : dup(fd)), IO_FD_CLOSE, &out));
00570     else {
00571         /* create the response io_t dup'ping the request io_t object */
00572         dbg_err_if(io_dup(request_io(rq), &out));
00573     }
00574 
00575     /* default method used if we cannot parse the request (bad request) */
00576     response_set_method(rs, HM_GET);
00577 
00578     /* bind the response to the connection c */
00579     dbg_err_if(response_bind(rs, out));
00580     out = NULL;
00581 
00582     /* server ready, parse the request */
00583     dbg_err_if(response_set_status(rs, HTTP_STATUS_BAD_REQUEST));
00584     rc = HTTP_STATUS_BAD_REQUEST;
00585 
00586     /* parse request. may fail on timeout */
00587     dbg_err_if(request_parse_header(rq, http_is_valid_uri, rq));
00588 
00589     response_set_method(rs, request_get_method(rq));
00590 
00591     /* get and cache the vhost ptr to speed up next lookups */
00592     dbg_err_if((vhost = http_get_vhost(h, rq)) == NULL);
00593     request_set_vhost(rq, vhost);
00594 
00595     /* if we're running in server mode then resolv aliases and dir_root */
00596     dbg_err_if(http_resolv_request(h, rq));
00597 
00598     /* if the uri end with a slash then return an index page */
00599     request_get_sup_info(rq, &sup, NULL, NULL);
00600     if(sup == NULL && (cstr = request_get_filename(rq)) != NULL && 
00601             cstr[strlen(cstr)-1] == '/')
00602         dbg_if(http_set_index_request(h, rq)); /* set the index page */
00603 
00604     /* add default header fields */
00605     dbg_err_if(http_add_default_header(h, rq, rs));
00606 
00607     /* set default successfull status code */
00608     dbg_err_if(response_set_status(rs, HTTP_STATUS_OK));
00609 
00610     /* serve the page; on error write out a simple error page */
00611     rc = broker_serve(h->broker, h, rq, rs);
00612 
00613     /* on 404 (file not found) try to find out if this is a directory request 
00614        i.e. http://site:port/dir redirects to /dir/ */
00615     if(response_get_status(rs) == 404 && (uri = request_get_uri(rq)) != NULL &&
00616             uri[strlen(uri)-1] != '/')
00617     {
00618         if(!http_set_index_request(h, rq))
00619         {
00620             (void) u_strlcpy(nuri, request_get_uri(rq), sizeof(nuri));
00621             (void) u_strlcat(nuri, "/", sizeof(nuri));
00622 
00623             if(request_get_path_info(rq))
00624                 (void) u_strlcat(nuri, request_get_path_info(rq), sizeof(nuri));
00625 
00626             if(request_get_query_string(rq))
00627             {
00628                 (void) u_strlcat(nuri, "?", sizeof(nuri));
00629                 (void) u_strlcat(nuri, request_get_query_string(rq), 
00630                         sizeof(nuri));
00631             }
00632 
00633             response_redirect(rs, nuri);
00634             rc = HTTP_STATUS_MOVED_TEMPORARILY;
00635         }
00636     }
00637 
00638     /* log the request */
00639     if(vhost->klog)
00640         dbg_if(access_log(h, vhost->al_config, rq, rs));
00641 
00642     /* call the hook that fires on each request */
00643     hook_call(request, rq, rs);
00644 
00645     /* on broker_serve error jump to err */
00646     nop_err_if(rc != 0);
00647 
00648     /* page successfully served */
00649 
00650     request_free(rq);
00651     response_free(rs); /* must be free'd after the request object because
00652                           the rsfilter references the response object during
00653                           the flush of the codec (so the response object must
00654                           not be free'd) that happens during the io_free call */
00655     return 0;
00656 err:
00657     /* hook get fired also on error */
00658     if(rq && rs)
00659         hook_call(request, rq, rs);
00660 
00661     if(rc && rq && rs && response_io(rs))
00662         http_print_error_page(h, rq, rs, rc); /* print the error page */
00663     if(in)
00664         io_free(in);
00665     if(out)
00666         io_free(out);
00667     if(rq)
00668         request_free(rq);
00669     if(rs)
00670         response_free(rs);
00671     return ~0;
00672 }
00673 
00674 static int http_free(http_t *h)
00675 {
00676     dbg_return_if (h == NULL, 0);   /* it's ok */
00677 
00678     if(h->broker)
00679         broker_free(h->broker);
00680 
00681     if(h->vhosts)
00682         vhost_list_free(h->vhosts);
00683 
00684     U_FREE(h);
00685 
00686     return 0;
00687 }
00688 
00689 static int http_add_vhost(http_t *http, const char *host, u_config_t *c)
00690 {
00691     vhost_t *top, *vhost = NULL;
00692     u_config_t *child;
00693     const char *v;
00694 
00695     dbg_err_if (http == NULL);
00696     dbg_err_if (host == NULL);
00697     dbg_err_if (c == NULL);
00698 
00699     dbg_err_if(vhost_create(&vhost));
00700     
00701     vhost->host = host;
00702     vhost->config = c;
00703     vhost->http = http;
00704 
00705     /* set defaults */
00706     vhost->server_sig = "klone/" KLONE_VERSION;
00707     vhost->dir_root = "";
00708     vhost->index = NULL;
00709     vhost->send_enc_deflate = 0; 
00710 
00711     /* if there's a per-vhost access_log open it, otherwise inherit from the
00712        main server configuration */
00713     if((child = u_config_get_child(c, "access_log")) != NULL)
00714     {
00715         v = u_config_get_value(child);
00716 
00717         /* if the access_log key is not "no" then load the log configuration */
00718         if(v == NULL || strcasecmp(v, "no"))
00719             dbg_err_if(klog_open_from_config(child, &vhost->klog));
00720 
00721         vhost->al_config = child;
00722     } else {
00723         /* if there's a global access log use it */
00724         if((top = vhost_list_get_n(http->vhosts, 0)) != NULL)
00725         {
00726             /* inherit from the main config (may be NULL) */
00727             vhost->klog = top->klog;
00728             vhost->al_config = top->al_config;
00729         }
00730     }
00731 
00732     /* send_enc_deflate (disable if not configured) */
00733     dbg_err_if(u_config_get_subkey_value_b(c, "send_enc_deflate", 0, 
00734         &vhost->send_enc_deflate));
00735 
00736     /* server signature */
00737     if((v = u_config_get_subkey_value(c, "server_sig")) != NULL)
00738         vhost->server_sig = v;
00739 
00740     /* html dir root */
00741     if((v = u_config_get_subkey_value(c, "dir_root")) != NULL)
00742         vhost->dir_root = v;
00743     else
00744         crit_err("dir_root must be set (vhost: %s)", vhost->host);
00745 
00746     /* index page */
00747     if((v = u_config_get_subkey_value(c, "index")) != NULL)
00748         vhost->index = v;
00749 
00750     dbg_err_if(vhost_list_add(http->vhosts, vhost));
00751 
00752     return 0;
00753 err:
00754     if(vhost)
00755         vhost_free(vhost);
00756     return ~0;
00757 }
00758 
00759 static int config_inherit(u_config_t *dst, u_config_t *from)
00760 {
00761     static const char *dont_inherit[] = {
00762         "addr", "model", "type", "dir_root", "dir_alias", "script_alias", 
00763         "access_log", NULL
00764     };
00765     u_config_t *config, *child = NULL;
00766     const char **di, *key, *value;
00767     int n;
00768 
00769     dbg_err_if (dst == NULL);
00770     dbg_err_if (from == NULL);
00771 
00772     for(n = 0; (config = u_config_get_child_n(from, NULL, n)); ++n)
00773     {
00774         if(u_config_get_child(config, "dir_root"))
00775             continue; /* skip vhost config subtree */
00776         
00777         key = u_config_get_key(config);
00778         value = u_config_get_value(config);
00779 
00780         /* don't inherit keys listed in dont_inherit array */
00781         for(di = dont_inherit; *di; ++di)
00782             if(strcasecmp(*di, key) == 0)
00783                 goto next;
00784 
00785         dbg_err_if(u_config_add_child(dst, key, &child));
00786         dbg_err_if(u_config_set_value(child, value));
00787 
00788         dbg_err_if(config_inherit(child, config));
00789 
00790     next:;
00791     }
00792 
00793     return 0;
00794 err:
00795     return ~0;
00796 }
00797 
00798 static int http_set_vhost_list(http_t *http)
00799 {
00800     u_config_t *config;
00801     int n;
00802 
00803     dbg_err_if (http == NULL);
00804 
00805     /* virtual vhost that stores the main server config */
00806     dbg_err_if(http_add_vhost(http, "", http->config));
00807 
00808     /* look for vhosts (any key that contain a dir_root subkey is a vhost) */
00809     for(n = 0; (config = u_config_get_child_n(http->config, NULL, n)); ++n)
00810     {
00811         if(u_config_get_child(config, "dir_root") == NULL)
00812             continue; /* it's not a vhost config branch */
00813 
00814         dbg_err_if(u_config_get_key(config) == NULL);
00815 
00816         u_info("configuring virtual host [%s]", u_config_get_key(config));
00817 
00818         /* inherit top-level values */
00819         dbg_err_if(config_inherit(config, http->config));
00820 
00821         dbg_err_if(http_add_vhost(http, u_config_get_key(config), config));
00822     }
00823 
00824     return 0;
00825 err:
00826     return ~0;
00827 }
00828 
00829 static int http_create(u_config_t *config, http_t **ph)
00830 {
00831     http_t *h = NULL;
00832 
00833     dbg_err_if (config == NULL);
00834     dbg_err_if (ph == NULL);
00835 
00836     h = u_zalloc(sizeof(http_t));
00837     dbg_err_if(h == NULL);
00838 
00839     h->config = config;
00840 
00841     dbg_err_if(vhost_list_create(&h->vhosts));
00842 
00843     /* init page broker (and page suppliers) */
00844     dbg_err_if(broker_create(&h->broker));
00845 
00846     /* load main server and vhosts config */
00847     dbg_err_if(http_set_vhost_list(h));
00848 
00849     /* print-out config with inherited values */
00850     if(ctx->debug > 1)
00851         u_config_print(ctx->config, 0);
00852 
00853     *ph = h;
00854 
00855     return 0;
00856 err:
00857     if(h)
00858         http_free(h);
00859     return ~0;
00860 }
00861 
00862 static int http_backend_serve(struct backend_s *be, int fd)
00863 {
00864     http_t *h;
00865     int rc;
00866 
00867     dbg_err_if (be == NULL);
00868     dbg_err_if (be->arg == NULL);
00869     dbg_err_if (fd < 0);
00870     
00871     h = (http_t *) be->arg;
00872     
00873     /* new connection accepted on http listening socket, handle it */
00874     rc = http_serve(h, fd);
00875 
00876     return rc;
00877 err:
00878     return ~0;
00879 }
00880 
00881 static int http_backend_term(struct backend_s *be)
00882 {
00883     http_t *http;
00884 
00885     dbg_return_if (be == NULL, 0);
00886     dbg_return_if (be->arg == NULL, 0);
00887 
00888     http = (http_t *) be->arg;
00889 
00890     dbg_err_if(session_module_term(http->sess_opt));
00891 
00892     http_free(http);
00893 
00894     return 0;
00895 err:
00896     return ~0;
00897 }
00898 
00899 static int http_backend_init(struct backend_s *be)
00900 {
00901     http_t *http = NULL;
00902     broker_t *broker = NULL;
00903 
00904     dbg_err_if (be == NULL);
00905  
00906     dbg_err_if(http_create(be->config, &http));
00907 
00908     be->arg = http;
00909 
00910     dbg_err_if(session_module_init(http->config, &http->sess_opt));
00911 
00912     return 0;
00913 err:
00914     if(http)
00915         http_free(http);
00916     if(broker)
00917         broker_free(broker);
00918     return ~0;
00919 }
00920 
00921 #ifdef SSL_ON
00922 static int https_backend_init(struct backend_s *be)
00923 {
00924     http_t *https;
00925 
00926     dbg_err_if (be == NULL);
00927 
00928     dbg_err_if(http_backend_init(be));
00929 
00930     https = (http_t *) be->arg;
00931 
00932     /* turn on SSL encryption */
00933     https->ssl = 1;
00934 
00935     /* load config values and set SSL_CTX accordingly */
00936     https->ssl_ctx = tls_load_init_ctx(http_get_config(https));
00937     warn_err_ifm (https->ssl_ctx == NULL, "bad or missing HTTPS credentials");
00938 
00939     dbg_err_if(session_module_init(https->config, &https->sess_opt));
00940 
00941     return 0;
00942 err:
00943     return ~0;
00944 }
00945 
00946 static int https_backend_term(struct backend_s *be)
00947 {
00948     http_t *https;
00949 
00950     dbg_err_if (be == NULL);
00951 
00952     https = (http_t *) be->arg;
00953     if (https == NULL)
00954         return 0;
00955 
00956     SSL_CTX_free(https->ssl_ctx);
00957 
00958     return http_backend_term(be); 
00959 err:
00960     return ~0;
00961 }
00962 
00963 /* same http functions but different '_init' */
00964 backend_t be_https =
00965     BACKEND_STATIC_INITIALIZER( "https", 
00966         https_backend_init, 
00967         http_backend_serve, 
00968         https_backend_term );
00969 #endif /* SSL_ON */
00970 
00971 backend_t be_http =
00972     BACKEND_STATIC_INITIALIZER( "http", 
00973         http_backend_init, 
00974         http_backend_serve, 
00975         http_backend_term );
00976 

←Products
Copyright © 2005-2012 - KoanLogic S.r.l. - All rights reserved