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

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