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

response.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: response.c,v 1.28 2007/10/26 11:21:51 tho Exp $
00009  */
00010 
00011 #include "klone_conf.h"
00012 #include <time.h>
00013 #include <u/libu.h>
00014 #include <klone/response.h>
00015 #include <klone/utils.h>
00016 #include <klone/io.h>
00017 #include <klone/codec.h>
00018 #include <klone/http.h>
00019 #include <klone/rsfilter.h>
00020 
00021 struct response_s
00022 {
00023     http_t *http;           /* http server handle               */
00024     header_t *header;       /* output header                    */
00025     io_t *io;               /* output stream                    */
00026     int status;             /* http status code                 */
00027     int method;             /* HTTP request method              */
00028     int cgi;                /* if we're running in cgi context  */
00029 };
00030 
00044 int response_set_content_encoding(response_t *rs, const char *encoding)
00045 {
00046     dbg_err_if(encoding == NULL);
00047 
00048     dbg_err_if(header_set_field(rs->header, "Content-Encoding", encoding));
00049 
00050     return 0;
00051 err:
00052     return ~0;
00053 }
00054 
00074 int response_disable_caching(response_t *rs)
00075 {
00076     dbg_err_if(response_set_field(rs, "Cache-Control", 
00077         "no-cache, must-revalidate"));
00078 
00079     dbg_err_if(response_set_field(rs, "Expires", 
00080         "Mon, 1 Jan 1990 05:00:00 GMT"));
00081 
00082     dbg_err_if(response_set_field(rs, "Pragma", "no-cache"));
00083 
00084     return 0;
00085 err:
00086     return ~0;
00087 }
00088 
00108 int response_enable_caching(response_t *rs)
00109 {
00110     dbg_err_if(response_del_field(rs, "Cache-Control"));
00111 
00112     dbg_err_if(response_del_field(rs, "Expires"));
00113 
00114     dbg_err_if(response_del_field(rs, "Pragma"));
00115 
00116     return 0;
00117 err:
00118     return ~0;
00119 }
00120 
00140 int response_set_cookie(response_t *rs, const char *name, const char *value,
00141     time_t expire, const char *path, const char *domain, int secure)
00142 {
00143     enum { BUFSZ = 4096, DATESZ = 64 };
00144     field_t *field = NULL;
00145     char buf[BUFSZ], date[DATESZ];
00146 
00147     if(value == NULL)
00148     {   /* delete this cookie */
00149         dbg_err_if(u_snprintf(buf, BUFSZ, 
00150             "%s=; expires=Wed, 01-Jan-1990 10:10:10 GMT", name));
00151     } else {
00152         /* name */
00153         dbg_err_if(u_snprintf(buf, BUFSZ, "%s=", name));
00154 
00155         /* encoded value */
00156         // FIXME buf may be too small....
00157         dbg_err_if(u_urlncpy(buf + strlen(buf), value, strlen(value), 
00158             URLCPY_ENCODE) <= 0);
00159 
00160         /* expiration date */
00161         if(expire)
00162         {
00163             dbg_err_if(u_tt_to_rfc822(date, expire));
00164 
00165             dbg_err_if(u_snprintf(buf + strlen(buf), BUFSZ - strlen(buf), 
00166                         "; expire=%s", date));
00167         }
00168 
00169         /* path */
00170         if(path)
00171             dbg_err_if(u_snprintf(buf + strlen(buf), 
00172                         BUFSZ - strlen(buf), "; path=%s", path));
00173 
00174         /* domain */
00175         if(domain)
00176             dbg_err_if(u_snprintf(buf + strlen(buf), 
00177                         BUFSZ - strlen(buf), "; domain=%s", domain));
00178         /* secure flag */
00179         if(secure)
00180             dbg_err_if(u_snprintf(buf + strlen(buf), 
00181                         BUFSZ - strlen(buf), "; secure"));
00182 
00183     }
00184 
00185     dbg_err_if(field_create("Set-Cookie", buf, &field));
00186 
00187     dbg_err_if(header_add_field(rs->header, field));
00188 
00189     return 0;
00190 err:
00191     if(field)
00192         field_free(field);
00193     return ~0;
00194 }
00195 
00196 /*
00197  * \ingroup response
00198  * \brief   Print the status of a response object.
00199  *
00200  * A string representing the status of a response object \p rs is printed to \p
00201  * io. 
00202  *
00203  * \param rs      response object
00204  * \param io      output I/O object
00205  *
00206  * \return
00207  *  - \c 0 if successful
00208  *  - \c ~0 on error
00209  */
00210 static int response_print_status(response_t *rs, io_t *io)
00211 {
00212     dbg_err_if(io_printf(io, "HTTP/1.0 %d %s\r\n", rs->status, 
00213         http_get_status_desc(rs->status)) < 0);
00214 
00215     return 0;
00216 err:
00217     return ~0;
00218 }
00219 
00220 /*
00221  * \ingroup response
00222  * \brief   Print a response field.
00223  *
00224  * Print the name and value of a \p field of \p response to \p io.
00225  *
00226  * \param rs      response object
00227  * \param io      output I/O object
00228  * \param field   field to be printed
00229  *
00230  * \return
00231  *  - \c 0 if successful
00232  *  - \c ~0 on error
00233  */
00234 static int response_print_field(response_t *rs, io_t *io, field_t *field)
00235 {
00236     u_unused_args(rs);
00237 
00238     dbg_err_if(io_printf(io, "%s: %s\r\n", field->name, field->value) < 0);
00239     
00240     return 0;
00241 err:
00242     return ~0;
00243 }
00244 
00258 void response_set_method(response_t *rs, int method)
00259 {
00260     rs->method = method;
00261 }
00262 
00275 int response_get_method(response_t *rs)
00276 {
00277     return rs->method;
00278 }
00279 
00280 
00281 /* set is-cgi flag */
00282 void response_set_cgi(response_t *rs, int cgi)
00283 {
00284     rs->cgi = cgi;
00285     return ;
00286 }
00287 
00288 /* calculate the approx max value of the current header (useful to alloc a
00289  * buffer big enough) */
00290 size_t response_get_max_header_size(response_t *rs)
00291 {
00292     field_t *field;
00293     int i, n;
00294     size_t sz = 0;
00295 
00296     /* calc status line length */
00297     sz += 16; /* http/x.y nnn[n] \r\n */
00298     sz += strlen(http_get_status_desc(rs->status));
00299 
00300     n = header_field_count(rs->header);
00301     for(i = 0; i < n; ++i)
00302     {
00303         field =  header_get_fieldn(rs->header, i);
00304         sz += strlen(field_get_name(field));
00305         sz += strlen(field_get_value(field));
00306         sz += 4; /* blanks and new lines */
00307     }
00308 
00309     sz += 2; /* final \r\n */
00310     sz += 64; /* guard bytes */
00311 
00312     return sz;
00313 }
00314 
00315 /* 
00316  * \ingroup response
00317  * \brief   Output a response header 
00318  *
00319  * Print the header of \p rs to \p io.
00320  *
00321  * \param rs        response object
00322  * \param io        output I/O object
00323  * 
00324  * \return
00325  *  - \c 0 if successful
00326  *  - \c ~0 on error
00327  */
00328 int response_print_header_to_io(response_t *rs, io_t *io)
00329 {
00330     int i, n;
00331 
00332     dbg_err_if(io == NULL);
00333 
00334     /* print status line */
00335     if(!rs->cgi)
00336         dbg_err_if(response_print_status(rs, io));
00337 
00338     /* print field list */
00339     n = header_field_count(rs->header);
00340     for(i = 0; i < n; ++i)
00341         dbg_err_if(response_print_field(rs, io,
00342             header_get_fieldn(rs->header, i)));
00343 
00344     dbg_err_if(io_printf(io, "\r\n") < 0);
00345 
00346     return 0;
00347 err:
00348     return ~0;
00349 }
00350 
00363 int response_print_header(response_t *rs)
00364 {
00365     return response_print_header_to_io(rs, rs->io);
00366 }
00367 
00368 
00383 int response_set_field(response_t *rs, const char *name, const char *value)
00384 {
00385     return header_set_field(rs->header, name, value);
00386 }
00387 
00388 
00402 int response_del_field(response_t *rs, const char *name)
00403 {
00404     field_t *f = NULL;
00405     
00406     f = header_get_field(rs->header, name);
00407     dbg_err_if(f == NULL);
00408 
00409     /* field found, delete it */
00410     dbg_err_if(header_del_field(rs->header, f));
00411 
00412     field_free(f);
00413 
00414     return 0;
00415 err:
00416     return ~0;
00417 }
00418 
00432 int response_set_content_type(response_t *rs, const char *mime_type)
00433 {
00434     dbg_err_if(mime_type == NULL);
00435 
00436     dbg_err_if(header_set_field(rs->header, "Content-Type", mime_type));
00437 
00438     return 0;
00439 err:
00440     return ~0;
00441 }
00442 
00456 int response_set_date(response_t *rs, time_t date)
00457 {
00458     enum { BUFSZ = 64 };
00459     char buf[BUFSZ];
00460 
00461     dbg_err_if(u_tt_to_rfc822(buf, date));
00462 
00463     dbg_err_if(header_set_field(rs->header, "Date", buf));
00464 
00465     return 0;
00466 err:
00467     return ~0;
00468 }
00469 
00483 int response_set_last_modified(response_t *rs, time_t mtime)
00484 {
00485     enum { BUFSZ = 64 };
00486     char buf[BUFSZ];
00487 
00488     dbg_err_if(u_tt_to_rfc822(buf, mtime));
00489 
00490     dbg_err_if(header_set_field(rs->header, "Last-Modified", buf));
00491 
00492     return 0;
00493 err:
00494     return ~0;
00495 }
00496 
00510 int response_set_content_length(response_t *rs, size_t sz)
00511 {
00512     enum { BUFSZ = 64 };
00513     char buf[BUFSZ];
00514 
00515     dbg_err_if(u_snprintf(buf, BUFSZ, "%u", sz));
00516 
00517     dbg_err_if(header_set_field(rs->header, "Content-Length", buf));
00518 
00519     return 0;
00520 err:
00521     return ~0;
00522 }
00523 
00536 int response_get_status(response_t *rs)
00537 {
00538     return rs->status;
00539 }
00540 
00552 header_t* response_get_header(response_t *rs)
00553 {
00554     return rs->header;
00555 }
00556 
00568 io_t* response_io(response_t *rs)
00569 {
00570     return rs->io;
00571 }
00572 
00586 int response_redirect(response_t *rs, const char *url)
00587 {
00588     field_t *field;
00589 
00590     /* send Location: with redirect status code */
00591     response_set_status(rs, HTTP_STATUS_MOVED_TEMPORARILY);
00592 
00593     dbg_err_if(field_create("Location", url, &field));
00594 
00595     header_add_field(rs->header, field); 
00596 
00597     return 0;
00598 err:
00599     return ~0;
00600 }
00601 
00615 int response_set_status(response_t *rs, int status)
00616 {
00617     rs->status = status;
00618 
00619     return 0;
00620 }
00621 
00622 /*
00623  * \ingroup response
00624  * \brief   Bind the response to a given I/O object
00625  *  
00626  * Bind response \p rs to I/O object \p out.
00627  *
00628  * \param rs     
00629  * \param out  output I/O object
00630  *  
00631  * \return
00632  *  - \c 0  always
00633  */
00634 int response_bind(response_t *rs, io_t *out)
00635 {
00636     rs->io = out;
00637 
00638     return 0;
00639 }
00640 
00641 /*
00642  * \ingroup response
00643  * \brief   Create a response object
00644  *  
00645  * \param http  parameter \p http description
00646  * \param prs   parameter \p prs description
00647  *  
00648  * \return
00649  *  - \c 0  if successful
00650  *  - \c ~0 on error
00651  */
00652 int response_create(http_t *http, response_t **prs)
00653 {
00654     response_t *rs = NULL;
00655 
00656     rs = u_zalloc(sizeof(response_t));
00657     dbg_err_if(rs == NULL);
00658 
00659     dbg_err_if(header_create(&rs->header));
00660 
00661     rs->http = http;
00662 
00663     *prs = rs;
00664 
00665     return 0;
00666 err:
00667     if(rs->header)
00668         header_free(rs->header);
00669     if(rs)
00670         response_free(rs);
00671     return ~0;
00672 }
00673 
00674 /*
00675  * \ingroup response
00676  * \brief   Free a response object
00677  *  
00678  * \param rs response object
00679  *  
00680  * \return
00681  *  - \c 0  always
00682  */
00683 int response_free(response_t *rs)
00684 {
00685     if(rs->io)
00686         io_free(rs->io);
00687 
00688     if(rs->header)
00689         header_free(rs->header);
00690 
00691     U_FREE(rs);
00692 
00693     return 0;
00694 }
00695 
00696 
00697 /* return a field obj of the field named 'name' or NULL if the field does not 
00698    exist */
00699 field_t* response_get_field(response_t *rs, const char *name)
00700 {
00701     dbg_return_if (rs == NULL, NULL);
00702     dbg_return_if (name == NULL, NULL);
00703 
00704     return header_get_field(rs->header, name);
00705 }
00706 
00707 /* return the string value of the field named 'name' or NULL if the field does
00708    not exist */
00709 const char* response_get_field_value(response_t *rs, const char *name)
00710 {
00711     dbg_return_if (rs == NULL, NULL);
00712     dbg_return_if (name == NULL, NULL);
00713 
00714     return header_get_field_value(rs->header, name);
00715 }