Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals

sup_emb.c

00001 /*
00002  * Copyright (c) 2005, 2006 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: sup_emb.c,v 1.29 2007/10/25 20:26:56 tat Exp $
00009  */
00010 
00011 #include "klone_conf.h"
00012 #include <sys/stat.h>
00013 #include <sys/types.h>
00014 #include <unistd.h>
00015 #include <u/libu.h>
00016 #include <klone/supplier.h>
00017 #include <klone/io.h>
00018 #include <klone/ioprv.h>
00019 #include <klone/page.h>
00020 #include <klone/http.h>
00021 #include <klone/emb.h>
00022 #include <klone/codecs.h>
00023 #include <klone/ses_prv.h>
00024 #include <klone/rsfilter.h>
00025 #include "http_s.h"
00026 
00027 static int supemb_is_valid_uri(http_t *h, request_t *rq, const char *uri, 
00028         size_t len, time_t *mtime)
00029 {
00030     embres_t *e;
00031     char filename[U_FILENAME_MAX] = { 0 };
00032 
00033     dbg_err_if (uri == NULL);
00034     dbg_err_if (mtime == NULL);
00035     dbg_err_if (len >= U_FILENAME_MAX);
00036 
00037     u_unused_args(h);
00038 
00039     strncpy(filename, uri, len);
00040 
00041     if(emb_lookup(filename, &e) == 0)
00042     {   /* resource found */
00043 
00044         if(e->type == ET_FILE)
00045             *mtime = ((embfile_t*)e)->mtime;
00046         else
00047             *mtime = 0; /* dynamic pages cannot be cached */
00048 
00049         return 1;
00050     }
00051 
00052 err:
00053     return 0; /* not found */
00054 }
00055 
00056 static int supemb_get_cipher_key(request_t *rq, response_t *rs, char *key, 
00057     size_t keysz)
00058 {
00059     session_t *ss = NULL;
00060     http_t *http = NULL;
00061     session_opt_t *so;
00062     vars_t *vars;
00063     var_t *v;
00064 
00065     dbg_err_if (rq == NULL);
00066     dbg_err_if (rs == NULL);
00067     dbg_err_if (key == NULL);
00068 
00069     /* get session options */
00070     dbg_err_if((http = request_get_http(rq)) == NULL);
00071     dbg_err_if((so = http_get_session_opt(http)) == NULL);
00072 
00073     /* create/get the session */
00074     dbg_err_if(session_create(so, rq, rs, &ss));
00075 
00076     /* get variables list */
00077     vars = session_get_vars(ss);
00078     dbg_err_if(vars == NULL);
00079 
00080     v = vars_geti(vars,"KLONE_CIPHER_KEY", 0); 
00081     dbg_err_if(v == NULL); /* no such variable */
00082 
00083     dbg_err_if(var_get_value_size(v) > keysz);
00084 
00085     /* zero-out key array */
00086     memset(key, 0, keysz);
00087 
00088     /* set the key */
00089     memcpy(key, var_get_value(v), var_get_value_size(v));
00090 
00091     session_free(ss);
00092 
00093     return 0;
00094 err:
00095     if(ss)
00096         session_free(ss);
00097     return ~0;
00098 }
00099 
00100 static int supemb_static_set_header_fields(request_t *rq, response_t *rs, 
00101     embfile_t *e, int *sai)
00102 {
00103     http_t *http;
00104 
00105     dbg_err_if (rq == NULL);
00106     dbg_err_if (rs == NULL);
00107     dbg_err_if (e == NULL);
00108     dbg_err_if (sai == NULL);
00109 
00110     dbg_err_if((http = request_get_http(rq)) == NULL);
00111 
00112     /* set header fields based on embfile_t struct */
00113 
00114     /* set content-type, last-modified and content-length*/
00115     dbg_err_if(response_set_content_type(rs, e->mime_type));
00116     dbg_err_if(response_set_last_modified(rs, e->mtime));
00117     dbg_err_if(response_set_content_length(rs, e->file_size));
00118 
00119     /* if the client can accept deflated content don't uncompress the 
00120        resource but send as it is (if enabled by config) */
00121     if(http->send_enc_deflate)
00122     {
00123         if(e->comp && (*sai = request_is_encoding_accepted(rq, "deflate")) != 0)
00124         {   /* we can send compressed responses */
00125             dbg_err_if(response_set_content_encoding(rs, "deflate"));
00126             dbg_err_if(response_set_content_length(rs, e->size));
00127             /*  dbg("sending deflated content"); */
00128         } 
00129     }
00130 
00131     return 0;
00132 err:
00133     return ~0;
00134 }
00135 
00136 static int supemb_serve_static(request_t *rq, response_t *rs, embfile_t *e)
00137 {
00138     codec_t *gzip = NULL, *decrypt = NULL;
00139     int sai = 0; /* send as is */
00140     int decrypting = 0;
00141     char key[CODEC_CIPHER_KEY_SIZE];
00142     codec_t *rsf = NULL;
00143 
00144     dbg_return_if (rq == NULL, ~0);
00145     dbg_return_if (rs == NULL, ~0);
00146     dbg_return_if (e == NULL, 0);
00147     
00148     /* create a response filter and attach it to the response io */
00149     dbg_err_if(response_filter_create(rq, rs, NULL, &rsf));
00150     dbg_err_if(io_codec_add_tail(response_io(rs), rsf));
00151     rsf = NULL;
00152 
00153     /* set HTTP header based on 'e' (we have the cipher key here) */
00154     dbg_err_if(supemb_static_set_header_fields(rq, rs, e, &sai));
00155 
00156     /* if this is a HEAD request print the header and exit */
00157     if(request_get_method(rq) == HM_HEAD)
00158         return 0; /* just the header is requested */
00159 
00160 #ifdef HAVE_LIBZ
00161     /* if needed apply a gzip codec to uncompress content data */
00162     if(e->comp && !sai)
00163         dbg_err_if(codec_gzip_create(GZIP_UNCOMPRESS, &gzip));
00164 #endif
00165 
00166 #ifdef HAVE_LIBOPENSSL
00167     /* if the resource is encrypted unencrypt using the key stored in 
00168        KLONE_CIPHER_KEY session variable */
00169     if(e->encrypted)
00170     {
00171         if(supemb_get_cipher_key(rq, rs, key, CODEC_CIPHER_KEY_SIZE))
00172         {   /* if the content is encrypted and there's no key then exit */
00173             dbg_err_if(response_set_status(rs, 401));
00174             dbg_err("cipher key not found, aborting");
00175         }
00176         dbg_err_if(codec_cipher_create(CIPHER_DECRYPT, EVP_aes_256_cbc(),
00177                     key, NULL, &decrypt));
00178         /* delete the key from the stack */
00179         memset(key, 0, CODEC_CIPHER_KEY_SIZE);
00180     } 
00181 #endif
00182 
00183     if(gzip)
00184     {   /* set gzip filter */
00185         dbg_err_if(io_codec_add_head(response_io(rs), gzip));
00186         gzip = NULL; /* io_t owns it after io_codec_add_tail */
00187     }
00188 
00189     if(decrypt)
00190     {   /* set decrypt filter */
00191         dbg_err_if(io_codec_add_head(response_io(rs), decrypt));
00192         decrypt = NULL; /* io_t owns it after io_codec_add_tail */
00193         decrypting = 1;
00194     }
00195 
00196     /* print out page content (the header will be autoprinted by the 
00197        response io filter) */
00198     dbg_err_if(!io_write(response_io(rs), (const char*)e->data, e->size));
00199 
00200     /* remove and free the gzip codec (if it has been set) */
00201     dbg_err_if(io_codecs_remove(response_io(rs))); 
00202 
00203     return 0;
00204 err:
00205     if(decrypting)
00206         dbg_if(response_set_status(rs, 401)); /* usually wrong key given */
00207     /* remove codecs and rs filter */
00208     dbg_if(io_codecs_remove(response_io(rs))); 
00209     if(decrypt)
00210         codec_free(decrypt);
00211     if(gzip)
00212         codec_free(gzip);
00213     return ~0;
00214 }
00215 
00216 static int supemb_serve_dynamic(request_t *rq, response_t *rs, embpage_t *e)
00217 {
00218     session_t *ss = NULL;
00219     http_t *http = NULL;
00220     codec_t *filter = NULL;
00221     session_opt_t *so;
00222     io_t *oio;
00223 
00224     dbg_return_if (rq == NULL, ~0);
00225     dbg_return_if (rs == NULL, ~0);
00226     dbg_return_if (e == NULL, ~0);
00227 
00228     /* output io object */
00229     oio = response_io(rs);
00230 
00231     /* get session options */
00232     dbg_err_if((http = request_get_http(rq)) == NULL);
00233     dbg_err_if((so = http_get_session_opt(http)) == NULL);
00234 
00235     /* parse URL encoded or POSTed data (POST must be read before) */
00236     dbg_err_if(request_parse_data(rq));
00237 
00238     /* create/get the session */
00239     dbg_err_if(session_create(so, rq, rs, &ss));
00240 
00241     /* set some default values */
00242     dbg_err_if(response_set_content_type(rs, "text/html"));
00243 
00244     /* by default disable caching */
00245     response_disable_caching(rs);
00246 
00247     /* create a response filter (used to automatically print all header fields 
00248      * when the header buffer fills up) and attach it to the response io */
00249     dbg_err_if(response_filter_create(rq, rs, ss, &filter));
00250     io_codec_add_tail(oio, filter);
00251 
00252     /* run the page code */
00253     e->run(rq, rs, ss);
00254 
00255     /* flush the output buffer */
00256     io_flush(oio);
00257 
00258     /* if nothing has been printed by the sciprt then write a dummy byte so 
00259      * the io_t calls the filter function that, in turn, will print out the 
00260      * HTTP header (rsfilter will handle it) */
00261     if(oio->wcount == 0)
00262         io_write(oio, "\n", 1);
00263 
00264     /* save and destroy the session */
00265     session_free(ss);
00266 
00267     return 0;
00268 err:
00269     io_flush(response_io(rs));
00270     if(ss)
00271         session_free(ss);
00272     return ~0;
00273 }
00274 
00275 static int supemb_serve(request_t *rq, response_t *rs)
00276 {
00277     const char *file_name;
00278     embres_t *e;
00279 
00280     dbg_err_if (rq == NULL);
00281     dbg_err_if (rs == NULL);
00282     
00283     file_name = request_get_resolved_filename(rq);
00284     dbg_ifb(file_name == NULL || emb_lookup(file_name, &e))
00285     {
00286         response_set_status(rs, HTTP_STATUS_NOT_FOUND); 
00287         return 0;
00288     }
00289 
00290     /* dbg("serving %s", e->filename); */
00291 
00292     switch(e->type)
00293     {
00294     case ET_FILE:
00295         dbg_err_if(supemb_serve_static(rq, rs, (embfile_t*)e));
00296         break;
00297     case ET_PAGE:
00298         dbg_err_if(supemb_serve_dynamic(rq, rs, (embpage_t*)e));
00299         break;
00300     default:
00301         dbg_err_if("unknown res type");
00302     }
00303 
00304     return 0;
00305 err:
00306     return ~0;
00307 }
00308 
00309 static int supemb_init(void)
00310 {
00311     return 0;
00312 }
00313 
00314 static void supemb_term(void)
00315 {
00316     return;
00317 }
00318 
00319 supplier_t sup_emb = {
00320     "embedded content supplier",
00321     supemb_init,
00322     supemb_term,
00323     supemb_is_valid_uri,
00324     supemb_serve
00325 };
00326