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

response.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: response.c,v 1.22 2006/03/21 15:38:01 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 
00031 
00057 int response_set_content_encoding(response_t *rs, const char *encoding)
00058 {
00059     dbg_err_if(encoding == NULL);
00060 
00061     dbg_err_if(header_set_field(rs->header, "Content-Encoding", encoding));
00062 
00063     return 0;
00064 err:
00065     return ~0;
00066 }
00067 
00086 int response_disable_caching(response_t *rs)
00087 {
00088     dbg_err_if(response_set_field(rs, "Cache-Control", 
00089         "no-cache, must-revalidate"));
00090 
00091     dbg_err_if(response_set_field(rs, "Expires", 
00092         "Mon, 1 Jan 1990 05:00:00 GMT"));
00093 
00094     dbg_err_if(response_set_field(rs, "Pragma", "no-cache"));
00095 
00096     return 0;
00097 err:
00098     return ~0;
00099 }
00100 
00119 int response_enable_caching(response_t *rs)
00120 {
00121     dbg_err_if(response_del_field(rs, "Cache-Control"));
00122 
00123     dbg_err_if(response_del_field(rs, "Expires"));
00124 
00125     dbg_err_if(response_del_field(rs, "Pragma"));
00126 
00127     return 0;
00128 err:
00129     return ~0;
00130 }
00131 
00150 int response_set_cookie(response_t *rs, const char *name, const char *value,
00151     time_t expire, const char *path, const char *domain, int secure)
00152 {
00153     enum { BUFSZ = 4096, DATESZ = 64 };
00154     field_t *field = NULL;
00155     char buf[BUFSZ], date[DATESZ];
00156 
00157     if(value == NULL)
00158     {   /* delete this cookie */
00159         dbg_err_if(u_snprintf(buf, BUFSZ, 
00160             "%s=; expires=Wed, 01-Jan-1990 10:10:10 GMT", name));
00161     } else {
00162         /* name */
00163         dbg_err_if(u_snprintf(buf, BUFSZ, "%s=", name));
00164 
00165         /* encoded value */
00166         // FIXME buf may be too small....
00167         dbg_err_if(u_urlncpy(buf + strlen(buf), value, strlen(value), 
00168             URLCPY_ENCODE) <= 0);
00169 
00170         /* expiration date */
00171         if(expire)
00172         {
00173             dbg_err_if(u_tt_to_rfc822(date, expire));
00174 
00175             dbg_err_if(u_snprintf(buf + strlen(buf), BUFSZ - strlen(buf), 
00176                         "; expire=%s", date));
00177         }
00178 
00179         /* path */
00180         if(path)
00181             dbg_err_if(u_snprintf(buf + strlen(buf), 
00182                         BUFSZ - strlen(buf), "; path=%s", path));
00183 
00184         /* domain */
00185         if(domain)
00186             dbg_err_if(u_snprintf(buf + strlen(buf), 
00187                         BUFSZ - strlen(buf), "; domain=%s", domain));
00188         /* secure flag */
00189         if(secure)
00190             dbg_err_if(u_snprintf(buf + strlen(buf), 
00191                         BUFSZ - strlen(buf), "; secure"));
00192 
00193     }
00194 
00195     dbg_err_if(field_create("Set-Cookie", buf, &field));
00196 
00197     dbg_err_if(header_add_field(rs->header, field));
00198 
00199     return 0;
00200 err:
00201     if(field)
00202         field_free(field);
00203     return ~0;
00204 }
00205 
00206 /*
00207  * \brief   Print the status of a response object.
00208  *
00209  * A string representing the status of a response object \p rs is printed to \p
00210  * io. 
00211  *
00212  * \param rs      response object
00213  * \param io      output I/O object
00214  *
00215  * \return
00216  *  - \c 0 if successful
00217  *  - \c ~0 on error
00218  */
00219 static int response_print_status(response_t *rs, io_t *io)
00220 {
00221     dbg_err_if(io_printf(io, "HTTP/1.0 %d %s\r\n", rs->status, 
00222         http_get_status_desc(rs->status)) < 0);
00223 
00224     return 0;
00225 err:
00226     return ~0;
00227 }
00228 
00229 /*
00230  * \brief   Print a response field.
00231  *
00232  * Print the name and value of a \p field of \p response to \p io.
00233  *
00234  * \param rs      response object
00235  * \param io      output I/O object
00236  * \param field   field to be printed
00237  *
00238  * \return
00239  *  - \c 0 if successful
00240  *  - \c ~0 on error
00241  */
00242 static int response_print_field(response_t *rs, io_t *io, field_t *field)
00243 {
00244     u_unused_args(rs);
00245 
00246     dbg_err_if(io_printf(io, "%s: %s\r\n", field->name, field->value) < 0);
00247     
00248     return 0;
00249 err:
00250     return ~0;
00251 }
00252 
00265 void response_set_method(response_t *rs, int method)
00266 {
00267     rs->method = method;
00268 }
00269 
00281 int response_get_method(response_t *rs)
00282 {
00283     return rs->method;
00284 }
00285 
00286 
00287 /* set is-cgi flag */
00288 void response_set_cgi(response_t *rs, int cgi)
00289 {
00290     rs->cgi = cgi;
00291     return ;
00292 }
00293 
00294 /* calculate the approx max value of the current header (useful to alloc a
00295  * buffer big enough) */
00296 size_t response_get_max_header_size(response_t *rs)
00297 {
00298     field_t *field;
00299     int i, n;
00300     size_t sz = 0;
00301 
00302     /* calc status line length */
00303     sz += 16; /* http/x.y nnn[n] \r\n */
00304     sz += strlen(http_get_status_desc(rs->status));
00305 
00306     n = header_field_count(rs->header);
00307     for(i = 0; i < n; ++i)
00308     {
00309         field =  header_get_fieldn(rs->header, i);
00310         sz += strlen(field_get_name(field));
00311         sz += strlen(field_get_value(field));
00312         sz += 4; /* blanks and new lines */
00313     }
00314 
00315     sz += 2; /* final \r\n */
00316     sz += 64; /* guard bytes */
00317 
00318     return sz;
00319 }
00320 
00321 /* 
00322  * \brief   Output a response header 
00323  *
00324  * Print the header of \p rs to \p io.
00325  *
00326  * \param rs        response object
00327  * \param io        output I/O object
00328  * 
00329  * \return
00330  *  - \c 0 if successful
00331  *  - \c ~0 on error
00332  */
00333 int response_print_header_to_io(response_t *rs, io_t *io)
00334 {
00335     int i, n;
00336 
00337     dbg_err_if(io == NULL);
00338 
00339     /* print status line */
00340     if(!rs->cgi)
00341         dbg_err_if(response_print_status(rs, io));
00342 
00343     /* print field list */
00344     n = header_field_count(rs->header);
00345     for(i = 0; i < n; ++i)
00346         dbg_err_if(response_print_field(rs, io,
00347             header_get_fieldn(rs->header, i)));
00348 
00349     dbg_err_if(io_printf(io, "\r\n") < 0);
00350 
00351     return 0;
00352 err:
00353     return ~0;
00354 }
00355 
00367 int response_print_header(response_t *rs)
00368 {
00369     return response_print_header_to_io(rs, rs->io);
00370 }
00371 
00372 
00386 int response_set_field(response_t *rs, const char *name, const char *value)
00387 {
00388     return header_set_field(rs->header, name, value);
00389 }
00390 
00391 
00404 int response_del_field(response_t *rs, const char *name)
00405 {
00406     field_t *f = NULL;
00407     
00408     f = header_get_field(rs->header, name);
00409     dbg_err_if(f == NULL);
00410 
00411     /* field found, delete it */
00412     dbg_err_if(header_del_field(rs->header, f));
00413 
00414     field_free(f);
00415 
00416     return 0;
00417 err:
00418     return ~0;
00419 }
00420 
00433 int response_set_content_type(response_t *rs, const char *mime_type)
00434 {
00435     dbg_err_if(mime_type == NULL);
00436 
00437     dbg_err_if(header_set_field(rs->header, "Content-Type", mime_type));
00438 
00439     return 0;
00440 err:
00441     return ~0;
00442 }
00443 
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 
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 
00508 int response_set_content_length(response_t *rs, size_t sz)
00509 {
00510     enum { BUFSZ = 64 };
00511     char buf[BUFSZ];
00512 
00513     dbg_err_if(u_snprintf(buf, BUFSZ, "%u", sz));
00514 
00515     dbg_err_if(header_set_field(rs->header, "Content-Length", buf));
00516 
00517     return 0;
00518 err:
00519     return ~0;
00520 }
00521 
00533 int response_get_status(response_t *rs)
00534 {
00535     return rs->status;
00536 }
00537 
00548 header_t* response_get_header(response_t *rs)
00549 {
00550     return rs->header;
00551 }
00552 
00563 io_t* response_io(response_t *rs)
00564 {
00565     return rs->io;
00566 }
00567 
00580 int response_redirect(response_t *rs, const char *url)
00581 {
00582     field_t *field;
00583 
00584     /* send Location: with redirect status code */
00585     response_set_status(rs, HTTP_STATUS_MOVED_TEMPORARILY);
00586 
00587     dbg_err_if(field_create("Location", url, &field));
00588 
00589     header_add_field(rs->header, field); 
00590 
00591     return 0;
00592 err:
00593     return ~0;
00594 }
00595 
00608 int response_set_status(response_t *rs, int status)
00609 {
00610     rs->status = status;
00611 
00612     return 0;
00613 }
00614 
00615 /*
00616  * \brief   Bind the response to a given I/O object
00617  *  
00618  * Bind response \p rs to I/O object \p out.
00619  *
00620  * \param rs     
00621  * \param out  output I/O object
00622  *  
00623  * \return
00624  *  - \c 0  always
00625  */
00626 int response_bind(response_t *rs, io_t *out)
00627 {
00628     rs->io = out;
00629 
00630     return 0;
00631 }
00632 
00633 /*
00634  * \brief   Create a response object
00635  *  
00636  * \param http  parameter \p http description
00637  * \param prs   parameter \p prs description
00638  *  
00639  * \return
00640  *  - \c 0  if successful
00641  *  - \c ~0 on error
00642  */
00643 int response_create(http_t *http, response_t **prs)
00644 {
00645     response_t *rs = NULL;
00646 
00647     rs = u_zalloc(sizeof(response_t));
00648     dbg_err_if(rs == NULL);
00649 
00650     dbg_err_if(header_create(&rs->header));
00651 
00652     rs->http = http;
00653 
00654     *prs = rs;
00655 
00656     return 0;
00657 err:
00658     if(rs->header)
00659         header_free(rs->header);
00660     if(rs)
00661         response_free(rs);
00662     return ~0;
00663 }
00664 
00665 /*
00666  * \brief   Free a response object
00667  *  
00668  * \param rs response object
00669  *  
00670  * \return
00671  *  - \c 0  always
00672  */
00673 int response_free(response_t *rs)
00674 {
00675     if(rs->io)
00676         io_free(rs->io);
00677 
00678     if(rs->header)
00679         header_free(rs->header);
00680 
00681     U_FREE(rs);
00682 
00683     return 0;
00684 }
00685 

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