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

sup_emb.c

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

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