Main Page | Modules | File List | 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.29 2008/04/16 14:02:59 tat 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         dbg_err_if(u_urlncpy(buf + strlen(buf), value, strlen(value), 
00157             URLCPY_ENCODE) <= 0);
00158 
00159         /* expiration date */
00160         if(expire)
00161         {
00162             dbg_err_if(u_tt_to_rfc822(date, expire));
00163 
00164             dbg_err_if(u_snprintf(buf + strlen(buf), BUFSZ - strlen(buf), 
00165                         "; expires=%s", date));
00166         }
00167 
00168         /* path */
00169         if(path)
00170             dbg_err_if(u_snprintf(buf + strlen(buf), 
00171                         BUFSZ - strlen(buf), "; path=%s", path));
00172 
00173         /* domain */
00174         if(domain)
00175             dbg_err_if(u_snprintf(buf + strlen(buf), 
00176                         BUFSZ - strlen(buf), "; domain=%s", domain));
00177         /* secure flag */
00178         if(secure)
00179             dbg_err_if(u_snprintf(buf + strlen(buf), 
00180                         BUFSZ - strlen(buf), "; secure"));
00181 
00182     }
00183 
00184     dbg_err_if(field_create("Set-Cookie", buf, &field));
00185 
00186     dbg_err_if(header_add_field(rs->header, field));
00187 
00188     return 0;
00189 err:
00190     if(field)
00191         field_free(field);
00192     return ~0;
00193 }
00194 
00195 /*
00196  * \ingroup response
00197  * \brief   Print the status of a response object.
00198  *
00199  * A string representing the status of a response object \p rs is printed to \p
00200  * io. 
00201  *
00202  * \param rs      response object
00203  * \param io      output I/O object
00204  *
00205  * \return
00206  *  - \c 0 if successful
00207  *  - \c ~0 on error
00208  */
00209 static int response_print_status(response_t *rs, io_t *io)
00210 {
00211     dbg_err_if(io_printf(io, "HTTP/1.0 %d %s\r\n", rs->status, 
00212         http_get_status_desc(rs->status)) < 0);
00213 
00214     return 0;
00215 err:
00216     return ~0;
00217 }
00218 
00219 /*
00220  * \ingroup response
00221  * \brief   Print a response field.
00222  *
00223  * Print the name and value of a \p field of \p response to \p io.
00224  *
00225  * \param rs      response object
00226  * \param io      output I/O object
00227  * \param field   field to be printed
00228  *
00229  * \return
00230  *  - \c 0 if successful
00231  *  - \c ~0 on error
00232  */
00233 static int response_print_field(response_t *rs, io_t *io, field_t *field)
00234 {
00235     u_unused_args(rs);
00236 
00237     dbg_err_if(io_printf(io, "%s: %s\r\n", field->name, field->value) < 0);
00238     
00239     return 0;
00240 err:
00241     return ~0;
00242 }
00243 
00257 void response_set_method(response_t *rs, int method)
00258 {
00259     rs->method = method;
00260 }
00261 
00274 int response_get_method(response_t *rs)
00275 {
00276     return rs->method;
00277 }
00278 
00279 
00280 /* set is-cgi flag */
00281 void response_set_cgi(response_t *rs, int cgi)
00282 {
00283     rs->cgi = cgi;
00284     return ;
00285 }
00286 
00287 /* calculate the approx max value of the current header (useful to alloc a
00288  * buffer big enough) */
00289 size_t response_get_max_header_size(response_t *rs)
00290 {
00291     field_t *field;
00292     int i, n;
00293     size_t sz = 0;
00294 
00295     /* calc status line length */
00296     sz += 16; /* http/x.y nnn[n] \r\n */
00297     sz += strlen(http_get_status_desc(rs->status));
00298 
00299     n = header_field_count(rs->header);
00300     for(i = 0; i < n; ++i)
00301     {
00302         field =  header_get_fieldn(rs->header, i);
00303         sz += strlen(field_get_name(field));
00304         sz += strlen(field_get_value(field));
00305         sz += 4; /* blanks and new lines */
00306     }
00307 
00308     sz += 2; /* final \r\n */
00309     sz += 64; /* guard bytes */
00310 
00311     return sz;
00312 }
00313 
00314 /* 
00315  * \ingroup response
00316  * \brief   Output a response header 
00317  *
00318  * Print the header of \p rs to \p io.
00319  *
00320  * \param rs        response object
00321  * \param io        output I/O object
00322  * 
00323  * \return
00324  *  - \c 0 if successful
00325  *  - \c ~0 on error
00326  */
00327 int response_print_header_to_io(response_t *rs, io_t *io)
00328 {
00329     int i, n;
00330 
00331     dbg_err_if(io == NULL);
00332 
00333     /* print status line */
00334     if(!rs->cgi)
00335         dbg_err_if(response_print_status(rs, io));
00336 
00337     /* print field list */
00338     n = header_field_count(rs->header);
00339     for(i = 0; i < n; ++i)
00340         dbg_err_if(response_print_field(rs, io,
00341             header_get_fieldn(rs->header, i)));
00342 
00343     dbg_err_if(io_printf(io, "\r\n") < 0);
00344 
00345     return 0;
00346 err:
00347     return ~0;
00348 }
00349 
00362 int response_print_header(response_t *rs)
00363 {
00364     return response_print_header_to_io(rs, rs->io);
00365 }
00366 
00367 
00382 int response_set_field(response_t *rs, const char *name, const char *value)
00383 {
00384     return header_set_field(rs->header, name, value);
00385 }
00386 
00387 
00401 int response_del_field(response_t *rs, const char *name)
00402 {
00403     field_t *f = NULL;
00404     
00405     f = header_get_field(rs->header, name);
00406     dbg_err_if(f == NULL);
00407 
00408     /* field found, delete it */
00409     dbg_err_if(header_del_field(rs->header, f));
00410 
00411     field_free(f);
00412 
00413     return 0;
00414 err:
00415     return ~0;
00416 }
00417 
00431 int response_set_content_type(response_t *rs, const char *mime_type)
00432 {
00433     dbg_err_if(mime_type == NULL);
00434 
00435     dbg_err_if(header_set_field(rs->header, "Content-Type", mime_type));
00436 
00437     return 0;
00438 err:
00439     return ~0;
00440 }
00441 
00455 int response_set_date(response_t *rs, time_t date)
00456 {
00457     enum { BUFSZ = 64 };
00458     char buf[BUFSZ];
00459 
00460     dbg_err_if(u_tt_to_rfc822(buf, date));
00461 
00462     dbg_err_if(header_set_field(rs->header, "Date", buf));
00463 
00464     return 0;
00465 err:
00466     return ~0;
00467 }
00468 
00482 int response_set_last_modified(response_t *rs, time_t mtime)
00483 {
00484     enum { BUFSZ = 64 };
00485     char buf[BUFSZ];
00486 
00487     dbg_err_if(u_tt_to_rfc822(buf, mtime));
00488 
00489     dbg_err_if(header_set_field(rs->header, "Last-Modified", buf));
00490 
00491     return 0;
00492 err:
00493     return ~0;
00494 }
00495 
00509 int response_set_content_length(response_t *rs, size_t sz)
00510 {
00511     enum { BUFSZ = 64 };
00512     char buf[BUFSZ];
00513 
00514     dbg_err_if(u_snprintf(buf, BUFSZ, "%u", sz));
00515 
00516     dbg_err_if(header_set_field(rs->header, "Content-Length", buf));
00517 
00518     return 0;
00519 err:
00520     return ~0;
00521 }
00522 
00535 int response_get_status(response_t *rs)
00536 {
00537     return rs->status;
00538 }
00539 
00551 header_t* response_get_header(response_t *rs)
00552 {
00553     return rs->header;
00554 }
00555 
00567 io_t* response_io(response_t *rs)
00568 {
00569     return rs->io;
00570 }
00571 
00585 int response_redirect(response_t *rs, const char *url)
00586 {
00587     field_t *field;
00588 
00589     /* send Location: with redirect status code */
00590     response_set_status(rs, HTTP_STATUS_MOVED_TEMPORARILY);
00591 
00592     dbg_err_if(field_create("Location", url, &field));
00593 
00594     header_add_field(rs->header, field); 
00595 
00596     return 0;
00597 err:
00598     return ~0;
00599 }
00600 
00614 int response_set_status(response_t *rs, int status)
00615 {
00616     rs->status = status;
00617 
00618     return 0;
00619 }
00620 
00621 /*
00622  * \ingroup response
00623  * \brief   Bind the response to a given I/O object
00624  *  
00625  * Bind response \p rs to I/O object \p out.
00626  *
00627  * \param rs     
00628  * \param out  output I/O object
00629  *  
00630  * \return
00631  *  - \c 0  always
00632  */
00633 int response_bind(response_t *rs, io_t *out)
00634 {
00635     rs->io = out;
00636 
00637     return 0;
00638 }
00639 
00640 /*
00641  * \ingroup response
00642  * \brief   Create a response object
00643  *  
00644  * \param http  parameter \p http description
00645  * \param prs   parameter \p prs description
00646  *  
00647  * \return
00648  *  - \c 0  if successful
00649  *  - \c ~0 on error
00650  */
00651 int response_create(http_t *http, response_t **prs)
00652 {
00653     response_t *rs = NULL;
00654 
00655     rs = u_zalloc(sizeof(response_t));
00656     dbg_err_if(rs == NULL);
00657 
00658     dbg_err_if(header_create(&rs->header));
00659 
00660     rs->http = http;
00661 
00662     *prs = rs;
00663 
00664     return 0;
00665 err:
00666     if(rs->header)
00667         header_free(rs->header);
00668     if(rs)
00669         response_free(rs);
00670     return ~0;
00671 }
00672 
00673 /*
00674  * \ingroup response
00675  * \brief   Free a response object
00676  *  
00677  * \param rs response object
00678  *  
00679  * \return
00680  *  - \c 0  always
00681  */
00682 int response_free(response_t *rs)
00683 {
00684     if(rs->io)
00685         io_free(rs->io);
00686 
00687     if(rs->header)
00688         header_free(rs->header);
00689 
00690     U_FREE(rs);
00691 
00692     return 0;
00693 }
00694 
00695 
00696 /* return a field obj of the field named 'name' or NULL if the field does not 
00697    exist */
00698 field_t* response_get_field(response_t *rs, const char *name)
00699 {
00700     dbg_return_if (rs == NULL, NULL);
00701     dbg_return_if (name == NULL, NULL);
00702 
00703     return header_get_field(rs->header, name);
00704 }
00705 
00706 /* return the string value of the field named 'name' or NULL if the field does
00707    not exist */
00708 const char* response_get_field_value(response_t *rs, const char *name)
00709 {
00710     dbg_return_if (rs == NULL, NULL);
00711     dbg_return_if (name == NULL, NULL);
00712 
00713     return header_get_field_value(rs->header, name);
00714 }