rsfilter.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: rsfilter.c,v 1.14 2007/12/03 16:05:55 tat Exp $
00009  */
00010 
00011 #include "klone_conf.h"
00012 #include <time.h>
00013 #include <u/libu.h>
00014 #include <klone/request.h>
00015 #include <klone/response.h>
00016 #include <klone/session.h>
00017 #include <klone/utils.h>
00018 #include <klone/io.h>
00019 #include <klone/codec.h>
00020 #include <klone/http.h>
00021 #include <klone/response.h>
00022 #include <klone/rsfilter.h>
00023 #include <klone/ses_prv.h>
00024 
00025 /* this filter prints the HTTP header before any body part of the web page. 
00026  * the first RFBUFSZ bytes (at most) of the response will be buffered to 
00027  * postpone the header printing (the header can be modified until filter flush)
00028  */
00029 
00030 enum { 
00031     RFS_BUFFERING,
00032     RFS_FLUSHING
00033 };
00034 
00035 struct response_filter_s
00036 {
00037     codec_t codec;          /* must be the first item in the struct */
00038     request_t *rq;
00039     response_t *rs;
00040     session_t *ss;
00041     int state, feeded;
00042     char buf[RFBUFSZ], *ptr;
00043     size_t off;
00044     io_t *iob;
00045 };
00046 
00047 static int rf_init_iob(response_filter_t *rf)
00048 {
00049     char *h;
00050     size_t hsz, htell;
00051 
00052     dbg_err_if (rf == NULL);
00053     
00054     hsz = response_get_max_header_size(rf->rs) + rf->off;
00055 
00056     h = (char *)u_zalloc(hsz);
00057     dbg_err_if(h == NULL);
00058 
00059     dbg_err_if(io_mem_create(h, hsz, 0, &rf->iob));
00060 
00061     /* write the header to the memory io_t */
00062     response_print_header_to_io(rf->rs, rf->iob);
00063 
00064     if(response_get_method(rf->rs) != HM_HEAD)
00065     {
00066         /* append the rf->buf to the iob */
00067         dbg_err_if(io_write(rf->iob, rf->buf, rf->off) < 0);
00068     }
00069     dbg_err_if(io_flush(rf->iob));
00070 
00071     htell = io_tell(rf->iob);
00072 
00073     dbg_if(io_free(rf->iob));
00074     rf->iob = NULL;
00075 
00076     /* create another in-memory io to read from it */
00077     dbg_err_if(io_mem_create(h, htell, IO_MEM_FREE_BUF, &rf->iob));
00078 
00079     return 0;
00080 err:
00081     return ~0;
00082 }
00083 
00084 static int rf_flush(codec_t *codec, char *dst, size_t *dcount)
00085 {
00086     response_filter_t *rf = (response_filter_t*)codec;
00087     ssize_t c;
00088 
00089 
00090     dbg_err_if (codec == NULL);
00091     dbg_err_if (dst == NULL);
00092     dbg_err_if (dcount == NULL);
00093 
00094     if(rf->state == RFS_BUFFERING)
00095     {
00096         rf->state = RFS_FLUSHING;
00097 
00098         /* create a in-memory io_t and fill it with header and rf->buf */
00099         dbg_err_if(rf_init_iob(rf));
00100     }
00101 
00102     if(rf->iob)
00103     {
00104         dbg_err_if((c = io_read(rf->iob, dst, *dcount)) < 0);
00105         if(c == 0)
00106         { /* eof */
00107             io_free(rf->iob);
00108             rf->iob = NULL;
00109         } else {
00110             *dcount = c;
00111             return CODEC_FLUSH_CHUNK;
00112         }
00113     }
00114 
00115     return CODEC_FLUSH_COMPLETE;
00116 err:
00117     return -1;
00118 }
00119 
00120 static ssize_t rf_transform(codec_t *codec, 
00121         char *dst, size_t *dcount, 
00122         const char *src, size_t src_sz)
00123 {
00124     response_filter_t *rf = (response_filter_t*)codec;
00125     size_t max;
00126     ssize_t c;
00127 
00128     dbg_err_if (codec == NULL);
00129     dbg_err_if (dst == NULL);
00130     dbg_err_if (dcount == NULL);
00131     dbg_err_if (src == NULL);
00132 
00133     rf->feeded = 1;
00134 
00135     /* if this's a HEAD request don't print the body of the page */
00136     if(response_get_method(rf->rs) == HM_HEAD)
00137     {
00138         *dcount = 0;    /* zero output byte written */
00139         return src_sz;  /* all input bytes consumed */
00140     }
00141 
00142     if(rf->state == RFS_BUFFERING)
00143     {
00144         if(rf->off + src_sz < RFBUFSZ)
00145         {
00146             memcpy(rf->buf + rf->off, src, src_sz);
00147             rf->off += src_sz;
00148             *dcount = 0;    /* zero output byte written */
00149             return src_sz;  /* src_sz input byte consumed */
00150         } else {
00151             /* the buffer is full, print the header and flush the buffer */
00152             rf->state = RFS_FLUSHING;
00153 
00154             /* here's the last chance to modify HTTP header so, if not already
00155                set, add a session ID to the cookie list */
00156             if(rf->ss && strlen(rf->ss->id) == 0)
00157                 dbg_err_if(session_priv_set_id(rf->ss, NULL));
00158 
00159             /* create a in-memory io_t and fill it with header and rf->buf */
00160             dbg_err_if(rf_init_iob(rf));
00161         }
00162     }
00163 
00164     if(rf->iob)
00165     {
00166         dbg_err_if((c = io_read(rf->iob, dst, *dcount)) < 0);
00167         if(c == 0)
00168         { /* eof */
00169             io_free(rf->iob);
00170             rf->iob = NULL;
00171         } else {
00172             *dcount = c;
00173             return 0;
00174         }
00175     }
00176 
00177     /* copyout the next data block */
00178     max = U_MIN(*dcount, src_sz);
00179     memcpy(dst, src, max);
00180     *dcount = max;
00181     return max;
00182 err:
00183     return -1;
00184 }
00185 
00186 static int rf_free(codec_t *codec)
00187 {
00188     response_filter_t *rf;
00189 
00190     dbg_return_if (codec == NULL, 0);   /* it's ok */
00191 
00192     rf = (response_filter_t*)codec;
00193  
00194     if(rf->iob)
00195         io_free(rf->iob);
00196 
00197     U_FREE(rf);
00198 
00199     return 0;
00200 }
00201 
00202 int response_filter_feeded(codec_t *codec)
00203 {
00204     response_filter_t *rf;
00205 
00206     dbg_return_if (codec == NULL, 0);   /* it's ok */
00207 
00208     rf = (response_filter_t*)codec;
00209 
00210     return rf->feeded; /* 1 if at least 1 byte has been written */
00211 }
00212 
00213 int response_filter_create(request_t *rq, response_t *rs, session_t *ss,
00214     codec_t **prf)
00215 {
00216     response_filter_t *rf = NULL;
00217 
00218     dbg_err_if (rs == NULL);
00219     dbg_err_if (prf == NULL);
00220     
00221     rf = u_zalloc(sizeof(response_filter_t));
00222     dbg_err_if(rf == NULL);
00223 
00224     rf->rq = rq;
00225     rf->rs = rs;
00226     rf->ss = ss;
00227     rf->codec.transform = rf_transform;
00228     rf->codec.flush = rf_flush;
00229     rf->codec.free = rf_free;
00230     rf->ptr = rf->buf;
00231     rf->iob = NULL;
00232 
00233     *prf = (codec_t*)rf;
00234 
00235     return 0;
00236 err:
00237     U_FREE(rf);
00238     return ~0;
00239 }

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