LTP GCOV extension - code coverage report
Current view: directory - and-httpd/src - httpd_req.c
Test: And-httpd coverage
Date: 2006-09-11 Instrumented lines: 517
Code covered: 90.1 % Executed lines: 466

       1                 : /*
       2                 :  *  Copyright (C) 2004, 2005, 2006  James Antill
       3                 :  *
       4                 :  *  This library is free software; you can redistribute it and/or
       5                 :  *  modify it under the terms of the GNU Lesser General Public
       6                 :  *  License as published by the Free Software Foundation; either
       7                 :  *  version 2 of the License, or (at your option) any later version.
       8                 :  *
       9                 :  *  This library is distributed in the hope that it will be useful,
      10                 :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      11                 :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12                 :  *  Lesser General Public License for more details.
      13                 :  *
      14                 :  *  You should have received a copy of the GNU Lesser General Public
      15                 :  *  License along with this library; if not, write to the Free Software
      16                 :  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17                 :  *
      18                 :  *  email: james@and.org
      19                 :  */
      20                 : /* main HTTP server request processing */
      21                 : 
      22                 : #define EX_UTILS_NO_FUNCS 1
      23                 : #include "ex_utils.h"
      24                 : 
      25                 : #include "mk.h"
      26                 : 
      27                 : #include "vlg.h"
      28                 : 
      29                 : #define HTTPD_HAVE_GLOBAL_OPTS 1
      30                 : #include "httpd.h"
      31                 : #include "httpd_policy.h"
      32                 : 
      33                 : #include <syslog.h>
      34                 : 
      35                 : #if ! HTTPD_CONF_USE_MIME_XATTR
      36                 : # define getxattr(w, x, y, z) (errno = ENOSYS, -1)
      37                 : #else
      38                 : # include <sys/xattr.h>
      39                 : #endif
      40                 : 
      41                 : #if ! COMPILE_DEBUG
      42                 : # define HTTP_CONF_MMAP_LIMIT_MIN (16 * 1024) /* a couple of pages */
      43                 : # define HTTP_CONF_SAFE_PRINT_REQ TRUE
      44                 : #else
      45                 : # define HTTP_CONF_MMAP_LIMIT_MIN 8 /* debug... */
      46                 : # define HTTP_CONF_SAFE_PRINT_REQ FALSE
      47                 : #endif
      48                 : #define HTTP_CONF_MMAP_LIMIT_MAX (50 * 1024 * 1024)
      49                 : 
      50                 : #define HTTPD_CONF_ZIP_LIMIT_MIN 8
      51                 : 
      52                 : #define CLEN COMPILE_STRLEN
      53                 : 
      54                 : /* is the cstr a prefix of the vstr */
      55                 : #define VPREFIX(vstr, p, l, cstr)                                       \
      56                 :     (((l) >= CLEN(cstr)) &&                                             \
      57                 :      vstr_cmp_buf_eq(vstr, p, CLEN(cstr), cstr, CLEN(cstr)))
      58                 : /* is the cstr a suffix of the vstr */
      59                 : #define VSUFFIX(vstr, p, l, cstr)                                       \
      60                 :     (((l) >= CLEN(cstr)) &&                                             \
      61                 :      vstr_cmp_eod_buf_eq(vstr, p, l, cstr, CLEN(cstr)))
      62                 : 
      63                 : /* is the cstr a prefix of the vstr, no case */
      64                 : #define VIPREFIX(vstr, p, l, cstr)                                      \
      65                 :     (((l) >= CLEN(cstr)) &&                                             \
      66                 :      vstr_cmp_case_buf_eq(vstr, p, CLEN(cstr), cstr, CLEN(cstr)))
      67                 : 
      68                 : /* for simplicity */
      69                 : #define VEQ(vstr, p, l, cstr)  vstr_cmp_cstr_eq(vstr, p, l, cstr)
      70                 : #define VIEQ(vstr, p, l, cstr) vstr_cmp_case_cstr_eq(vstr, p, l, cstr)
      71                 : 
      72                 : #define HTTP__HDR_SET(req, h, p, l) do {               \
      73                 :       (req)-> http_hdrs -> hdr_ ## h ->pos = (p);          \
      74                 :       (req)-> http_hdrs -> hdr_ ## h ->len = (l);          \
      75                 :     } while (FALSE)
      76                 : #define HTTP__HDR_MULTI_SET(req, h, p, l) do {         \
      77                 :       (req)-> http_hdrs -> multi -> hdr_ ## h ->pos = (p); \
      78                 :       (req)-> http_hdrs -> multi -> hdr_ ## h ->len = (l); \
      79                 :     } while (FALSE)
      80                 : 
      81                 : #define HTTP__XTRA_HDR_INIT(x) do {             \
      82                 :       req-> x ## _vs1 = NULL;                   \
      83                 :       req-> x ## _pos = 0;                      \
      84                 :       req-> x ## _len = 0;                      \
      85                 :     } while (FALSE)
      86                 : 
      87                 : static Vlg *vlg = NULL;
      88                 : 
      89                 : void httpd_req_init(Vlg *passed_vlg)
      90              64 : {
      91              32 :   ASSERT(passed_vlg && !vlg);
      92              64 :   vlg = passed_vlg;
      93              64 : }
      94                 : 
      95                 : void httpd_req_exit(void)
      96              44 : {
      97              22 :   ASSERT(vlg);
      98              44 :   vlg = NULL;
      99              44 : }
     100                 : 
     101                 : Httpd_req_data *http_req_make(struct Con *con)
     102           59398 : {
     103                 :   static Httpd_req_data real_req[1];
     104           59398 :   Httpd_req_data *req = real_req;
     105           59398 :   const Httpd_policy_opts *policy = NULL;
     106                 :   
     107           29028 :   ASSERT(!req->using_req);
     108                 : 
     109           59398 :   if (!req->done_once)
     110                 :   {
     111              44 :     Vstr_conf *conf = NULL;
     112                 : 
     113              44 :     if (con)
     114              44 :       conf = con->evnt->io_w->conf;
     115                 :       
     116              44 :     if (!(req->fname                            = vstr_make_base(conf)) ||
     117                 :         !(req->http_hdrs->multi->combiner_store = vstr_make_base(conf)) ||
     118                 :         !(req->sects                            = vstr_sects_make(8)) ||
     119                 :         !(req->tag                              = vstr_make_base(conf)))
     120               0 :       return (NULL);
     121                 :     
     122              44 :     req->f_mmap       = NULL;
     123              44 :     req->xtra_content = NULL;
     124                 :   }
     125                 : 
     126           59398 :   http_parse_clear_hdrs(req);
     127                 :   
     128           59398 :   req->http_hdrs->multi->comb = con ? con->evnt->io_r : NULL;
     129                 : 
     130           59398 :   vstr_del(req->fname, 1, req->fname->len);
     131                 : 
     132           59398 :   req->now = evnt_sc_time();
     133                 :   
     134           59398 :   req->len = 0;
     135                 : 
     136           59398 :   req->path_pos = 0;
     137           59398 :   req->path_len = 0;
     138                 : 
     139           59398 :   req->error_code = 0;
     140           59398 :   req->error_line = "";
     141           59398 :   req->error_msg  = "";
     142           59398 :   req->error_xmsg = "";
     143           59398 :   req->error_len  = 0;
     144                 : 
     145           59398 :   req->fs_len     = 0;
     146                 : 
     147           59398 :   req->f_stat_st_size = 0;
     148                 : 
     149           59398 :   req->sects->num = 0;
     150                 :   /* f_stat */
     151           59398 :   if (con)
     152           59354 :     req->orig_io_w_len = con->evnt->io_w->len;
     153                 : 
     154                 :   /* NOTE: These should probably be allocated at init time, depending on the
     155                 :    * option flags given */
     156           29028 :   ASSERT(!req->f_mmap || !req->f_mmap->len);
     157           59398 :   if (req->f_mmap)
     158            4291 :     vstr_del(req->f_mmap, 1, req->f_mmap->len);
     159           29028 :   ASSERT(!req->xtra_content || !req->xtra_content->len);
     160           59398 :   if (req->xtra_content)
     161           57548 :     vstr_del(req->xtra_content, 1, req->xtra_content->len);
     162                 :   
     163           59398 :   req->vhost_prefix_len = 0;
     164                 :   
     165           59398 :   req->sects->malloc_bad = FALSE;
     166                 : 
     167           59398 :   req->parsed_content_encoding   = FALSE;
     168           59398 :   req->content_encoding_identity = TRUE;
     169           59398 :   req->content_encoding_gzip     = FALSE;
     170           59398 :   req->content_encoding_bzip2    = FALSE;
     171           59398 :   req->content_encoding_xgzip    = FALSE;
     172                 : 
     173           59398 :   req->user_return_error_code = FALSE;
     174                 : 
     175           59398 :   req->vary_star = con ? con->vary_star : FALSE;
     176           59398 :   req->vary_a    = FALSE;
     177           59398 :   req->vary_ac   = FALSE;
     178           59398 :   req->vary_ae   = FALSE;
     179           59398 :   req->vary_al   = FALSE;
     180           59398 :   req->vary_rf   = FALSE;
     181           59398 :   req->vary_ua   = FALSE;
     182           59398 :   req->vary_ims  = FALSE;
     183           59398 :   req->vary_ius  = FALSE;
     184           59398 :   req->vary_ir   = FALSE;
     185           59398 :   req->vary_im   = FALSE;
     186           59398 :   req->vary_inm  = FALSE;
     187           59398 :   req->vary_xm   = FALSE;
     188                 : 
     189           59398 :   req->direct_uri         = FALSE;
     190           59398 :   req->direct_filename    = FALSE;
     191           59398 :   req->skip_document_root = FALSE;
     192                 :   
     193           59398 :   req->ver_0_9    = FALSE;
     194           59398 :   req->ver_1_1    = FALSE;
     195           59398 :   req->ver_1_x    = FALSE;
     196           59398 :   req->head_op    = FALSE;
     197                 : 
     198           59398 :   req->chked_encoded_path = FALSE;
     199                 :   
     200           59398 :   req->neg_content_type_done = FALSE;
     201           59398 :   req->neg_content_lang_done = FALSE;
     202                 :       
     203           59398 :   req->conf_secure_dirs   = FALSE;
     204           59398 :   req->conf_friendly_file = FALSE;
     205           59398 :   req->conf_friendly_dirs = FALSE;
     206                 :   
     207           59398 :   req->done_once  = TRUE;
     208           59398 :   req->using_req  = TRUE;
     209                 : 
     210           59398 :   req->malloc_bad = FALSE;
     211                 : 
     212           59398 :   if (con && !vstr_sub_vstr(req->tag, 1, req->tag->len,
     213                 :                             con->tag, 1, con->tag->len, VSTR_TYPE_SUB_BUF_REF))
     214               0 :     return (NULL);
     215                 :   
     216           59398 :   if (!con)
     217              44 :     req->policy = NULL;
     218                 :   else
     219                 :   {
     220           59354 :     policy = con->policy;
     221           59354 :     httpd_policy_change_req(con, req, policy);
     222                 :   }
     223                 :   
     224           59398 :   return (req);
     225                 : }
     226                 : 
     227                 : void http_req_free(Httpd_req_data *req)
     228           59354 : {
     229           59354 :   if (!req) /* for if/when move to malloc/free */
     230               0 :     return;
     231                 : 
     232           29006 :   ASSERT(req->done_once && req->using_req);
     233                 : 
     234                 :   /* we do vstr deletes here to return the nodes back to the pool */
     235           59354 :   vstr_del(req->fname, 1, req->fname->len);
     236           29006 :   ASSERT(!req->http_hdrs->multi->combiner_store->len);
     237           59354 :   if (req->f_mmap)
     238            4291 :     vstr_del(req->f_mmap, 1, req->f_mmap->len);
     239                 : 
     240           59354 :   req->http_hdrs->multi->comb = NULL;
     241                 : 
     242           59354 :   req->using_req = FALSE;
     243                 : }
     244                 : 
     245                 : void http_req_exit(void)
     246              44 : {
     247              44 :   Httpd_req_data *req = http_req_make(NULL);
     248              44 :   struct Http_hdrs__multi *tmp = NULL;
     249                 :   
     250              44 :   if (!req)
     251               0 :     return;
     252                 : 
     253              44 :   tmp = req->http_hdrs->multi;
     254                 :   
     255              44 :   vstr_free_base(req->fname);          req->fname          = NULL;
     256              44 :   vstr_free_base(tmp->combiner_store); tmp->combiner_store = NULL;
     257              44 :   vstr_free_base(req->f_mmap);         req->f_mmap         = NULL;
     258              44 :   vstr_free_base(req->xtra_content);   req->xtra_content   = NULL;
     259              44 :   vstr_sects_free(req->sects);         req->sects          = NULL;
     260              44 :   vstr_free_base(req->tag);            req->tag            = NULL;
     261                 :   
     262              44 :   req->done_once = FALSE;
     263              44 :   req->using_req = FALSE;
     264                 : }
     265                 : 
     266                 : 
     267                 : void httpd_req_absolute_uri(struct Con *con, Httpd_req_data *req,
     268                 :                             Vstr_base *lfn, size_t pos, size_t len)
     269            4672 : {
     270            4672 :   Vstr_base *data = con->evnt->io_r;
     271            4672 :   size_t apos = pos - 1;
     272            4672 :   size_t alen = lfn->len;
     273            4672 :   int has_schema   = TRUE;
     274            4672 :   int has_abs_path = TRUE;
     275            4672 :   int has_data     = TRUE;
     276            4672 :   unsigned int prev_num = 0;
     277                 :   
     278            4672 :   if (!VPREFIX(lfn, pos, len, "http://"))
     279                 :   {
     280            3424 :     has_schema = FALSE;
     281            3424 :     if (!VPREFIX(lfn, pos, len, "/")) /* relative pathname */
     282                 :     {
     283            1280 :       if (VPREFIX(lfn, pos, len, "./"))
     284                 :       {
     285              64 :         has_data = TRUE;
     286              64 :         vstr_del(lfn, pos, CLEN("./")); len -= CLEN("./");
     287              64 :         alen = lfn->len;
     288                 :       }
     289                 :       else
     290                 :       {
     291            1728 :         while (VPREFIX(lfn, pos, len, "../"))
     292                 :         {
     293               0 :           ++prev_num;
     294               0 :           vstr_del(lfn, pos, CLEN("../")); len -= CLEN("../");
     295                 :         }
     296            1152 :         if (prev_num)
     297               0 :           alen = lfn->len;
     298                 :         else
     299            1152 :           has_data = !!lfn->len;
     300                 :       }
     301                 :       
     302            1216 :       has_abs_path = FALSE;
     303                 :     }
     304                 :   }
     305                 : 
     306            4672 :   if (!has_schema)
     307                 :   {
     308            3424 :     vstr_add_cstr_buf(lfn, apos, "http://");
     309            3424 :     apos += lfn->len - alen;
     310            3424 :     alen = lfn->len;
     311            3424 :     httpd_sc_add_hostname(con, req, lfn, apos);
     312            3424 :     apos += lfn->len - alen;
     313                 :   }
     314                 :     
     315            4672 :   if (!has_abs_path)
     316                 :   {
     317            1216 :     size_t path_len = req->path_len;
     318                 : 
     319            1216 :     if (has_data || prev_num)
     320                 :     {
     321             608 :       path_len -= vstr_cspn_cstr_chrs_rev(data, req->path_pos, path_len, "/");
     322                 :       
     323            1216 :       while (path_len && prev_num--)
     324                 :       {
     325               0 :         path_len -= vstr_spn_cstr_chrs_rev(data,  req->path_pos, path_len, "/");
     326               0 :         path_len -= vstr_cspn_cstr_chrs_rev(data, req->path_pos, path_len, "/");
     327                 :       }
     328             608 :       if (!path_len) path_len = 1; /* make sure there is a / at the end */
     329                 :     }
     330                 : 
     331            1216 :     vstr_add_vstr(lfn, apos, data, req->path_pos, path_len, VSTR_TYPE_ADD_DEF);
     332                 :   }
     333            4672 : }
     334                 : 
     335                 : /* doing http://www.example.com/foo/bar where bar is a dir is bad
     336                 :    because all relative links will be relative to foo, not bar.
     337                 :    Also note that location must be "http://www.example.com/foo/bar/" or maybe
     338                 :    "http:/foo/bar/" (but we don't use the later anymore)
     339                 : */
     340                 : int http_req_chk_dir(struct Con *con, Httpd_req_data *req, const char *xmsg)
     341             608 : {
     342             608 :   Vstr_base *fname = req->fname;
     343                 :   
     344                 :   /* fname == what was just passed to open() */
     345             304 :   ASSERT(fname->len);
     346                 : 
     347             608 :   if (req->policy->use_secure_dirs && !req->conf_secure_dirs)
     348                 :   { /* check if file exists before redirecting without leaking info. */
     349               0 :     const char *fname_cstr = NULL;
     350                 :     struct stat64 d_stat[1];
     351                 :   
     352               0 :     vstr_add_cstr_buf(fname, fname->len, "/");
     353               0 :     HTTPD_APP_REF_ALLVSTR(fname, req->policy->dir_filename);
     354                 :     
     355               0 :     fname_cstr = vstr_export_cstr_ptr(fname, 1, fname->len);
     356               0 :     if (fname->conf->malloc_bad)
     357               0 :       return (http_fin_errmem_req(con, req));
     358                 : 
     359               0 :     if ((stat64(fname_cstr, d_stat) == -1) || !S_ISREG(d_stat->st_mode))
     360               0 :       HTTPD_ERR_MSG_RET(req, 404, xmsg, http_fin_err_req(con, req));
     361                 :   }
     362                 :   
     363             608 :   vstr_del(fname, 1, fname->len);
     364             608 :   httpd_req_absolute_uri(con, req, fname, 1, fname->len);
     365                 :   
     366                 :   /* we got:       http://foo/bar/
     367                 :    * and so tried: http://foo/bar/index.html
     368                 :    *
     369                 :    * but foo/bar/index.html is a directory (fun), so redirect to:
     370                 :    *               http://foo/bar/index.html/
     371                 :    */
     372             608 :   if (fname->len && (vstr_export_chr(fname, fname->len) == '/'))
     373             144 :     HTTPD_APP_REF_ALLVSTR(fname, req->policy->dir_filename);
     374                 :   
     375             608 :   vstr_add_cstr_buf(fname, fname->len, "/");
     376                 :   
     377             608 :   HTTPD_REDIR_MSG(req, 301, "dir -> filename");
     378                 :   
     379             608 :   if (fname->conf->malloc_bad)
     380               0 :     return (http_fin_errmem_req(con, req));
     381                 :   
     382             608 :   return (http_fin_err_req(con, req));
     383                 : }
     384                 : 
     385                 : /* doing http://www.example.com/foo/bar/ when url is really
     386                 :    http://www.example.com/foo/bar is a very simple mistake, so we almost
     387                 :    certainly don't want a 404 */
     388                 : int http_req_chk_file(struct Con *con, Httpd_req_data *req, const char *xmsg)
     389              64 : {
     390              64 :   Vstr_base *fname = req->fname;
     391              64 :   size_t len = 0;
     392                 :   
     393                 :   /* fname == what was just passed to open() */
     394              32 :   ASSERT(fname->len);
     395                 : 
     396              64 :   if (!req->policy->use_friendly_dirs)
     397               0 :     HTTPD_ERR_MSG_RET(req, 404, xmsg, http_fin_err_req(con, req));
     398              64 :   else if (!req->conf_friendly_dirs)
     399                 :   { /* check if file exists before redirecting without leaking info. */
     400              64 :     const char *fname_cstr = NULL;
     401                 :     struct stat64 d_stat[1];
     402              64 :     len = vstr_cspn_cstr_chrs_rev(fname, 1, fname->len, "/") + 1;
     403                 : 
     404                 :     /* must be a filename, can't be toplevel */
     405              64 :     if ((len <= 1) || (len >= (fname->len - req->vhost_prefix_len)))
     406               0 :       HTTPD_ERR_MSG_RET(req, 404, xmsg, http_fin_err_req(con, req));
     407                 : 
     408              64 :     vstr_sc_reduce(fname, 1, fname->len, len);
     409                 :     
     410              64 :     fname_cstr = vstr_export_cstr_ptr(fname, 1, fname->len);
     411              64 :     if (fname->conf->malloc_bad)
     412               0 :       return (http_fin_errmem_req(con, req));    
     413              64 :     if ((stat64(fname_cstr, d_stat) == -1) && !S_ISREG(d_stat->st_mode))
     414               0 :       HTTPD_ERR_MSG_RET(req, 404, xmsg, http_fin_err_req(con, req));
     415                 :   }
     416                 :   
     417              64 :   vstr_sub_cstr_ptr(fname, 1, fname->len, "./");
     418              64 :   httpd_req_absolute_uri(con, req, fname, 1, fname->len);
     419              32 :   assert(VSUFFIX(fname, 1, fname->len, "/"));
     420              64 :   vstr_sc_reduce(fname, 1, fname->len, strlen("/"));
     421                 : 
     422              64 :   HTTPD_REDIR_MSG(req, 301, "filename -> dir");
     423                 :   
     424              64 :   if (fname->conf->malloc_bad)
     425               0 :     return (http_fin_errmem_req(con, req));
     426                 :   
     427              64 :   return (http_fin_err_req(con, req));
     428                 : }
     429                 : 
     430                 : /* FIXME: maybe should be in the parse section...? */
     431                 : void http_req_split_method(struct Con *con, struct Httpd_req_data *req)
     432           41761 : {
     433           41761 :   Vstr_base *s1 = con->evnt->io_r;
     434           41761 :   size_t pos = 1;
     435           41761 :   size_t len = req->len;
     436           41761 :   size_t el = 0;
     437           41761 :   size_t skip_len = 0;
     438           41761 :   unsigned int orig_num = req->sects->num;
     439                 :   
     440           41761 :   el = vstr_srch_cstr_buf_fwd(s1, pos, len, HTTP_EOL);
     441           20825 :   ASSERT(el >= pos);
     442           41761 :   len = el - pos; /* only parse the first line */
     443                 : 
     444                 :   /* split request */
     445           41761 :   if (!(el = vstr_srch_cstr_chrs_fwd(s1, pos, len, HTTP_LWS)))
     446             144 :     return;
     447           41617 :   vstr_sects_add(req->sects, pos, el - pos);
     448           41617 :   len -= (el - pos); pos += (el - pos);
     449                 : 
     450                 :   /* just skip whitespace on method call... */
     451           41617 :   if ((skip_len = vstr_spn_cstr_chrs_fwd(s1, pos, len, HTTP_LWS)))
     452           41617 :   { len -= skip_len; pos += skip_len; }
     453                 : 
     454           41617 :   if (!len)
     455             144 :     goto req_line_parse_err;
     456                 :   
     457           41473 :   if (!(el = vstr_srch_cstr_chrs_fwd(s1, pos, len, HTTP_LWS)))
     458                 :   {
     459             672 :     vstr_sects_add(req->sects, pos, len);
     460             672 :     len = 0;
     461                 :   }
     462                 :   else
     463                 :   {
     464           40801 :     vstr_sects_add(req->sects, pos, el - pos);
     465           40801 :     len -= (el - pos); pos += (el - pos);
     466                 :     
     467                 :     /* just skip whitespace on method call... */
     468           40801 :     if ((skip_len = vstr_spn_cstr_chrs_fwd(s1, pos, len, HTTP_LWS)))
     469           40801 :     { len -= skip_len; pos += skip_len; }
     470                 :   }
     471                 : 
     472           41473 :   if (len)
     473           40801 :     vstr_sects_add(req->sects, pos, len);
     474             672 :   else if (!req->policy->allow_http_0_9)
     475               0 :     return; /* we keep it, for logging */
     476                 :   else
     477             672 :     req->ver_0_9 = TRUE;
     478                 : 
     479           41473 :   if (req->sects->malloc_bad)
     480               0 :     goto req_line_parse_err;
     481                 :   
     482           20792 :   return;
     483                 :   
     484             144 :  req_line_parse_err:
     485             144 :   req->sects->num = orig_num;
     486                 : }
     487                 : 
     488                 : void http_req_split_hdrs(struct Con *con, struct Httpd_req_data *req)
     489           39241 : {
     490           39241 :   Vstr_base *s1 = con->evnt->io_r;
     491           39241 :   size_t pos = 1;
     492           39241 :   size_t len = req->len;
     493           39241 :   size_t el = 0;
     494           39241 :   size_t hpos = 0;
     495                 : 
     496           19628 :   ASSERT(req->sects->num >= 3);  
     497                 :     
     498                 :   /* skip first line */
     499           39241 :   el = (VSTR_SECTS_NUM(req->sects, req->sects->num)->pos +
     500                 :         VSTR_SECTS_NUM(req->sects, req->sects->num)->len);
     501                 :   
     502           19628 :   assert(VEQ(s1, el, CLEN(HTTP_EOL), HTTP_EOL));
     503           39241 :   len -= (el - pos) + CLEN(HTTP_EOL); pos += (el - pos) + CLEN(HTTP_EOL);
     504                 :   
     505           39241 :   if (VPREFIX(s1, pos, len, HTTP_EOL))
     506            3648 :     return; /* end of headers */
     507                 : 
     508           17804 :   ASSERT(vstr_srch_cstr_buf_fwd(s1, pos, len, HTTP_END_OF_REQUEST));
     509                 :   /* split headers */
     510           35593 :   hpos = pos;
     511          146475 :   while ((el = vstr_srch_cstr_buf_fwd(s1, pos, len, HTTP_EOL)) != pos)
     512                 :   {
     513           75289 :     char chr = 0;
     514                 :     
     515           75289 :     len -= (el - pos) + CLEN(HTTP_EOL); pos += (el - pos) + CLEN(HTTP_EOL);
     516                 : 
     517           75289 :     chr = vstr_export_chr(s1, pos);
     518           75289 :     if (chr == ' ' || chr == '\t') /* header continues to next line */
     519            2620 :       continue;
     520                 : 
     521           70049 :     vstr_sects_add(req->sects, hpos, el - hpos);
     522                 :     
     523           70049 :     hpos = pos;
     524                 :   }
     525                 : }
     526                 : 
     527                 : /* try to set the content-type,
     528                 :  * . first if it's manually set leave it,
     529                 :  * . next try looking it up in the xattr for the file.
     530                 :  * . next do a real "lookup" based on the filename
     531                 :  * NOTE: If this lookup "fails" it still returns
     532                 :  * the default content-type. So we just have to determine if we want to use
     533                 :  * it or not. Can also return "content-types" like /404/ which returns a 404
     534                 :  * error for the request */
     535                 : int http_req_content_type(Httpd_req_data *req)
     536           27649 : {
     537           27649 :   const Vstr_base *vs1 = NULL;
     538           27649 :   size_t     pos = 0;
     539           27649 :   size_t     len = 0;
     540                 : 
     541           27649 :   if (req->content_type_vs1) /* manually set */
     542            1344 :     return (TRUE);
     543                 : 
     544           26305 :   if (req->policy->use_mime_xattr)
     545                 :   { /* lookup mime/type in the xattr of the filename -- this is racey
     546                 :      * but we want to parse the accept line before, open(), so we can't use
     547                 :      * fgetxattr() anyway. */
     548                 :     static const char key[] = "user.mime_type";
     549                 :     char buf[1024]; /* guess */
     550           26305 :     ssize_t ret = -1;
     551           26305 :     const char *fname_cstr = NULL;
     552                 :     
     553           26305 :     if (!req->xtra_content && !(req->xtra_content = vstr_make_base(NULL)))
     554               0 :       return (FALSE);
     555                 : 
     556           26305 :     fname_cstr = vstr_export_cstr_ptr(req->fname, 1, req->fname->len);
     557           13160 :     ASSERT(fname_cstr); /* must have been done before call */
     558                 : 
     559                 :     /* don't use lgetxattr() as it does nothing on Linux */
     560           26305 :     if ((ret = getxattr(fname_cstr, key, buf, sizeof(buf))) != -1)
     561                 :     {
     562               0 :       pos = req->xtra_content->len + 1;
     563               0 :       len = ret;
     564               0 :       if (!vstr_add_buf(req->xtra_content, req->xtra_content->len, buf, len))
     565               0 :         return (FALSE);
     566                 : 
     567               0 :       req->content_type_vs1 = req->xtra_content;
     568               0 :       req->content_type_pos = pos;
     569               0 :       req->content_type_len = len;
     570                 :       
     571               0 :       HTTP_REQ__X_CONTENT_HDR_CHK(content_type);
     572                 :       
     573               0 :       return (TRUE);
     574                 :     }
     575           26305 :     else if (errno == ENOSYS)
     576               0 :       httpd_disable_getxattr();
     577           26305 :     else if ((errno == EOPNOTSUPP) || (errno == EPERM))
     578                 :     { /* time limit the warn messages... */
     579                 :       static time_t last = -1;
     580             144 :       time_t now = evnt_sc_time();
     581                 : 
     582             144 :       if ((last == -1) || (difftime(last, now) > (10 * 60)))
     583                 :       {
     584              12 :         vlg_warn(vlg, "getxattr($<vstr.all:%p>, %s): %m\n", req->fname, key);
     585              12 :         last = now;
     586                 :       }
     587                 :     }
     588                 :   }
     589                 :   
     590           26305 :   mime_types_match(req->policy->mime_types,
     591                 :                    req->fname, 1, req->fname->len, &vs1, &pos, &len);
     592           26305 :   if (!len)
     593                 :   {
     594            3665 :     req->parse_accept = FALSE;
     595            3665 :     return (TRUE);
     596                 :   }
     597                 :   
     598           22640 :   if ((vstr_export_chr(vs1, pos) == '/') && (len > 2) &&
     599                 :       (vstr_export_chr(vs1, vstr_sc_poslast(pos, len)) == '/'))
     600                 :   {
     601             432 :     size_t num_len = 1;
     602                 :     static const char xmsg[] = "Mime/Type";
     603                 :     
     604             432 :     len -= 2;
     605             432 :     ++pos;
     606             432 :     req->user_return_error_code = TRUE;
     607             432 :     req->direct_filename = FALSE;
     608             432 :     switch (vstr_parse_uint(vs1, pos, len, 0, &num_len, NULL))
     609                 :     {
     610              48 :       case 400: if (num_len == len) HTTPD_ERR_MSG_RET(req, 400, xmsg, FALSE);
     611             144 :       case 403: if (num_len == len) HTTPD_ERR_MSG_RET(req, 403, xmsg, FALSE);
     612              48 :       case 404: if (num_len == len) HTTPD_ERR_MSG_RET(req, 404, xmsg, FALSE);
     613              48 :       case 410: if (num_len == len) HTTPD_ERR_MSG_RET(req, 410, xmsg, FALSE);
     614              48 :       case 500: if (num_len == len) HTTPD_ERR_MSG_RET(req, 500, xmsg, FALSE);
     615              48 :       case 503: if (num_len == len) HTTPD_ERR_MSG_RET(req, 503, xmsg, FALSE);
     616                 :         
     617                 :       default: /* just ignore any other content */
     618              48 :         req->user_return_error_code = FALSE;
     619              48 :         return (TRUE);
     620                 :     }
     621                 :   }
     622                 : 
     623           22208 :   req->content_type_vs1 = vs1;
     624           22208 :   req->content_type_pos = pos;
     625           22208 :   req->content_type_len = len;
     626                 : 
     627           22208 :   return (TRUE);
     628                 : }
     629                 : 
     630                 : static void httpd__req_etag_hex_num(Vstr_base *vs1, uintmax_t val, int more)
     631            2688 : {
     632                 :   char buf[(sizeof(uintmax_t) * CHAR_BIT) + 1];
     633            2688 :   size_t len = 0;
     634                 : 
     635            2688 :   len = vstr_sc_conv_num_uintmax(buf, sizeof(buf), val, "0123456789abcdef", 16);
     636            2688 :   vstr_add_buf(vs1, vs1->len, buf, len);
     637            2688 :   if (more)
     638            1344 :     vstr_add_cstr_buf(vs1, vs1->len, "-");
     639            2688 : }
     640                 : 
     641                 : static int httpd__req_etag_auto(struct Httpd_req_data *req)
     642            1344 : {
     643            1344 :   size_t xpos = 0;
     644            1344 :   Vstr_base *vs1 = NULL;
     645                 :   
     646             672 :   ASSERT(!req->etag_vs1 && req->policy->etag_auto_type);
     647                 :   
     648            1344 :   if (!(xpos = http_req_xtra_content(req, NULL, 0, &req->etag_len)))
     649               0 :     return (FALSE);
     650            1344 :   vs1 = req->xtra_content;
     651                 : 
     652                 :   /* If it's too soon, make it weak */
     653            1344 :   if (difftime(req->now, req->f_stat->st_mtime) <= 1)
     654               0 :     vstr_add_cstr_buf(vs1, vs1->len, "W/");
     655                 :   
     656            1344 :   vstr_add_cstr_buf(vs1, vs1->len, "\"");
     657            1344 :   switch (req->policy->etag_auto_type)
     658                 :   {
     659                 :     case HTTPD_ETAG_TYPE_AUTO_DISM:
     660               0 :       httpd__req_etag_hex_num(vs1, req->f_stat->st_dev,   TRUE);
     661                 :       /* FALL THROUGH */
     662                 :     case HTTPD_ETAG_TYPE_AUTO_ISM:
     663               0 :       httpd__req_etag_hex_num(vs1, req->f_stat->st_ino,   TRUE);
     664                 :       /* FALL THROUGH */      
     665                 :     case HTTPD_ETAG_TYPE_AUTO_SM:
     666            1344 :       httpd__req_etag_hex_num(vs1, req->f_stat->st_size,  TRUE);
     667            1344 :       httpd__req_etag_hex_num(vs1, req->f_stat->st_mtime, FALSE);
     668                 :       /* Use st_mtime.tv_nsec ? */
     669                 :       
     670               0 :       ASSERT_NO_SWITCH_DEF();
     671                 :   }
     672            1344 :   vstr_add_cstr_buf(vs1, vs1->len, "\"");
     673                 : 
     674            1344 :   req->etag_vs1 = vs1;
     675            1344 :   req->etag_pos = xpos;
     676            1344 :   req->etag_len = (req->xtra_content->len - xpos) + 1;
     677                 : 
     678            1344 :   return (!vs1->conf->malloc_bad);
     679                 : }
     680                 : 
     681                 : #define HTTPD__HD_EQ(x)                                 \
     682                 :     VEQ(hdrs, h_ ## x ->pos,  h_ ## x ->len,  date)
     683                 : 
     684                 : /* gets here if the GET/HEAD response is ok, we test for caching etc. using the
     685                 :  * if-* headers */
     686                 : /* FALSE = 412 Precondition Failed */
     687                 : static int http_response_ok(struct Con *con, struct Httpd_req_data *req,
     688                 :                             unsigned int *http_ret_code,
     689                 :                             const char ** http_ret_line)
     690           22089 : {
     691           22089 :   const Vstr_base *hdrs = con->evnt->io_r;
     692           22089 :   time_t mtime = req->f_stat->st_mtime;
     693           22089 :   Vstr_sect_node *h_ims  = req->http_hdrs->hdr_if_modified_since;
     694           22089 :   Vstr_sect_node *h_ir   = req->http_hdrs->hdr_if_range;
     695           22089 :   Vstr_sect_node *h_iums = req->http_hdrs->hdr_if_unmodified_since;
     696           22089 :   Vstr_sect_node *h_r    = req->http_hdrs->hdr_range;
     697           22089 :   Vstr_base *comb = req->http_hdrs->multi->comb;
     698           22089 :   Vstr_sect_node *h_im   = req->http_hdrs->multi->hdr_if_match;
     699           22089 :   Vstr_sect_node *h_inm  = req->http_hdrs->multi->hdr_if_none_match;
     700           22089 :   int h_ir_tst      = FALSE;
     701           22089 :   int h_iums_tst    = FALSE;
     702           22089 :   int req_if_range  = FALSE;
     703           22089 :   int cached_output = FALSE;
     704           22089 :   const char *date = NULL;
     705                 :   
     706           22089 :   if (HTTPD_VER_GE_1_1(req) && h_iums->pos)
     707             432 :     h_iums_tst = TRUE;
     708                 : 
     709           22089 :   if (HTTPD_VER_GE_1_1(req) && h_ir->pos && h_r->pos)
     710             936 :     h_ir_tst = TRUE;
     711                 :   
     712                 :   /* assumes time doesn't go backwards ... From rfc2616:
     713                 :    *
     714                 :    * Note: When handling an If-Modified-Since header field, some
     715                 :    * servers will use an exact date comparison function, rather than a
     716                 :    * less-than function, for deciding whether to send a 304 (Not
     717                 :    * Modified) response. To get best results when sending an If-
     718                 :    * Modified-Since header field for cache validation, clients are
     719                 :    * advised to use the exact date string received in a previous Last-
     720                 :    * Modified header field whenever possible.
     721                 :    */
     722           22089 :   if (difftime(req->now, mtime) > 0)
     723                 :   { /* if mtime in future, or now ... don't allow checking */
     724           22088 :     Date_store *ds = httpd_opts->date;
     725                 : 
     726           22088 :     date = date_rfc1123(ds, mtime);
     727           22088 :     if (h_ims->pos && !cached_output && HTTPD__HD_EQ(ims))
     728             312 :       cached_output = TRUE;
     729           22088 :     if (h_iums_tst &&                   HTTPD__HD_EQ(iums))
     730             144 :       return (FALSE);
     731           21944 :     if (h_ir_tst   && !req_if_range  && HTTPD__HD_EQ(ir))
     732             312 :       req_if_range = TRUE;
     733                 :   
     734           21944 :     date = date_rfc850(ds, mtime);
     735           21944 :     if (h_ims->pos && !cached_output && HTTPD__HD_EQ(ims))
     736             144 :       cached_output = TRUE;
     737           21944 :     if (h_iums_tst &&                   HTTPD__HD_EQ(iums))
     738             144 :       return (FALSE);
     739           21800 :     if (h_ir_tst   && !req_if_range  && HTTPD__HD_EQ(ir))
     740             144 :       req_if_range = TRUE;
     741                 :   
     742           21800 :     date = date_asctime(ds, mtime);
     743           21800 :     if (h_ims->pos && !cached_output && HTTPD__HD_EQ(ims))
     744             144 :       cached_output = TRUE;
     745           21800 :     if (h_iums_tst &&                   HTTPD__HD_EQ(iums))
     746             144 :       return (FALSE);
     747           21656 :     if (h_ir_tst   && !req_if_range  && HTTPD__HD_EQ(ir))
     748             144 :       req_if_range = TRUE;
     749                 :   }
     750                 : 
     751           30862 :   if (HTTPD_VER_GE_1_1(req))
     752                 :   {
     753           19017 :     const Vstr_base *vs1 = NULL;
     754           19017 :     size_t pos = 0;
     755           19017 :     size_t len = 0;
     756                 : 
     757           19017 :     if (req->policy->etag_auto_type && !req->etag_vs1)
     758                 :     {
     759            1344 :       if (!httpd__req_etag_auto(req))
     760                 :       {
     761               0 :         con->evnt->io_w->conf->malloc_bad = TRUE;
     762               0 :         return (TRUE); /* dealt with in http_req_op_get, can't continue */
     763                 :       }
     764                 : 
     765            1344 :       req->etag_time = mtime;
     766                 :     }
     767           19017 :     if (req->etag_vs1 && (req->etag_time >= mtime))
     768                 :     {
     769            2912 :       vs1 = req->etag_vs1;
     770            2912 :       pos = req->etag_pos;
     771            2912 :       len = req->etag_len;
     772                 :     }
     773                 : 
     774           19017 :     if (h_ir_tst   && !req_if_range &&
     775                 :         httpd_match_etags(req,
     776                 :                           hdrs, h_ir->pos, h_ir->len, vs1, pos, len, FALSE))
     777             192 :       req_if_range = TRUE;
     778                 :   
     779           19017 :     if (h_ir_tst && !req_if_range)
     780             144 :       h_r->pos = 0;
     781                 : 
     782                 :     /* #13.3.3 says: don't trust weak for "complex" queries, ie. byteranges */
     783           19017 :     if (h_inm->pos && (VEQ(hdrs, h_inm->pos, h_inm->len, "*") ||
     784                 :                        httpd_match_etags(req, comb, h_inm->pos, h_inm->len,
     785                 :                                          vs1, pos, len, !h_r->pos)))
     786            1000 :       cached_output = TRUE; /* Note: should return 412 for POST/PUT */
     787                 : 
     788                 :     /* #14.24 says: must use strong comparison, and also...
     789                 :        If the request would, without the If-Match header field, result in
     790                 :        anything other than a 2xx or 412 status, then the If-Match header
     791                 :        MUST be ignored. */
     792           19017 :     if (!cached_output &&
     793                 :         h_im->pos  && !(VEQ(hdrs, h_im->pos, h_im->len, "*") ||
     794                 :                         httpd_match_etags(req, comb, h_im->pos, h_im->len,
     795                 :                                           vs1, pos, len, FALSE)))
     796             592 :       return (FALSE);
     797                 :   }
     798            2640 :   else if (h_ir_tst && !req_if_range)
     799               0 :     h_r->pos = 0;
     800                 :   
     801           21065 :   if (cached_output)
     802                 :   {
     803            1600 :     req->head_op = TRUE;
     804            1600 :     *http_ret_code = 304;
     805            1600 :     *http_ret_line = "Not Modified";
     806                 :   }
     807           19465 :   else if (h_r->pos)
     808                 :   {
     809            3288 :     *http_ret_code = 206;
     810            3288 :     *http_ret_line = "Partial content";
     811                 :   }
     812                 : 
     813           21065 :   return (TRUE);
     814                 : }
     815                 : 
     816                 : int http_req_1_x(struct Con *con, Httpd_req_data *req,
     817                 :                  unsigned int *http_ret_code,
     818                 :                  const char **http_ret_line)
     819           22665 : {
     820           22665 :   Vstr_base *out = con->evnt->io_w;
     821           22665 :   Vstr_sect_node *h_r = req->http_hdrs->hdr_range;
     822           22665 :   time_t mtime = -1;
     823                 :   
     824           22665 :   if (HTTPD_VER_GE_1_1(req) && req->http_hdrs->hdr_expect->len)
     825                 :     /* I'm pretty sure we can ignore 100-continue, as no request will
     826                 :      * have a body */
     827             144 :     HTTPD_ERR_RET(req, 417, FALSE);
     828                 :           
     829           22521 :   httpd_parse_sc_try_fd_encoding(con, req, req->f_stat, &req->f_stat_st_size,
     830                 :                                  req->fname);
     831                 :   
     832           22521 :   if (req->policy->use_err_406 &&
     833                 :       !req->content_encoding_identity &&
     834                 :       !req->content_encoding_bzip2 && !req->content_encoding_gzip)
     835             144 :     HTTPD_ERR_MSG_RET(req, 406, "Encoding", FALSE);
     836                 : 
     837           22377 :   if (h_r->pos)
     838                 :   {
     839            5336 :     int ret_code = 0;
     840                 : 
     841            5384 :     if (!(req->policy->use_range &&
     842                 :           (HTTPD_VER_GE_1_1(req) || req->policy->use_range_1_0)))
     843              48 :       h_r->pos = 0;
     844            5288 :     else if (!(ret_code = http_parse_range(con, req)))
     845            1424 :       h_r->pos = 0;
     846            2668 :     ASSERT(!ret_code || (ret_code == 200) || (ret_code == 416));
     847            5336 :     if (ret_code == 416)
     848                 :     {
     849             432 :       if (!req->http_hdrs->hdr_if_range->pos)
     850             288 :         HTTPD_ERR_RET(req, 416, FALSE);
     851             144 :       h_r->pos = 0;
     852                 :     }
     853                 :   }
     854                 :   
     855           22089 :   if (!http_response_ok(con, req, http_ret_code, http_ret_line))
     856            1024 :     HTTPD_ERR_RET(req, 412, FALSE);
     857                 : 
     858           21065 :   if (!h_r->pos)
     859           17777 :     httpd_serv_file_sects_none(con, req, req->f_stat_st_size);
     860                 :   
     861           21065 :   httpd_serv_call_file_init(con, req, http_ret_code, http_ret_line);
     862                 : 
     863           10540 :   ASSERT(con->fs && (con->fs_off < con->fs_num) && (con->fs_num <= con->fs_sz));
     864           10540 :   ASSERT(!con->fs_off);
     865                 : 
     866           21065 :   mtime = req->f_stat->st_mtime;
     867           21065 :   http_app_def_hdrs(con, req, *http_ret_code, *http_ret_line,
     868                 :                     mtime, NULL, TRUE, http_serv_file_len(con, req));
     869           21065 :   if (h_r->pos && !con->use_mpbr)
     870            3096 :     http_app_hdr_fmt(out, "Content-Range", "%s %ju-%ju/%ju", "bytes",
     871                 :                      con->fs->off, con->fs->off + (con->fs->len - 1),
     872                 :                      (uintmax_t)req->f_stat_st_size);
     873           21065 :   if (req->content_location_vs1)
     874               0 :     http_app_hdr_vstr_def(out, "Content-Location",
     875                 :                           HTTP__XTRA_HDR_PARAMS(req, content_location));
     876           21065 :   http_app_hdrs_url(con, req);
     877           21065 :   http_app_hdrs_file(con, req);  
     878                 :   
     879           21065 :   http_app_end_hdrs(out);
     880                 : 
     881           21065 :   if (!req->head_op && h_r->pos && con->use_mpbr)
     882                 :   {
     883             128 :     con->mpbr_fs_len = req->f_stat_st_size;
     884             128 :     http_app_hdrs_mpbr(con, con->fs);
     885                 :   }
     886                 :   
     887           21065 :   return (TRUE);
     888                 : }
     889                 : 
     890                 : static int httpd_req_add_vhost(struct Con *con, struct Httpd_req_data *req)
     891           33505 : {
     892           33505 :   Vstr_base *data = con->evnt->io_r;
     893           33505 :   Vstr_base *fname = req->fname;
     894           33505 :   Vstr_sect_node *h_h = req->http_hdrs->hdr_host;
     895           33505 :   size_t h_h_pos = h_h->pos;
     896           33505 :   size_t h_h_len = h_h->len;
     897           33505 :   size_t orig_len = 0;
     898           33505 :   size_t dots = 0;  
     899                 :   
     900                 :   /* a lot of clients will pass example.com. for example.com ... fix them
     901                 :    * this can happen more than one time Eg. "wget www.and.org.." */
     902           33505 :   if (h_h_len)
     903                 :   {
     904           23249 :     dots = vstr_spn_cstr_chrs_rev(data, h_h_pos, h_h_len, ".");
     905           23249 :     if (dots == h_h_len)
     906             352 :       h_h_len = 1; /* give 400s to hostname "." */
     907                 :     else
     908                 :     {
     909           11456 :       ASSERT(dots < h_h_len);
     910                 :       
     911           22897 :       h_h_len -= dots;
     912                 :   
     913           22897 :       if (req->policy->use_canonize_host)
     914                 :       {
     915             288 :         if (VIPREFIX(data, h_h_pos, h_h_len, "www."))
     916             144 :         { h_h_len -= CLEN("www."); h_h_pos += CLEN("www."); }
     917                 :       }
     918                 :     }
     919                 :     
     920           23249 :     h_h->pos = h_h_pos;
     921           23249 :     h_h->len = h_h_len;
     922                 :   }
     923                 :   
     924           33505 :   if (!req->policy->use_vhosts_name)
     925             929 :     return (TRUE);
     926                 : 
     927           32576 :   orig_len = fname->len;
     928           32576 :   if (!http_serv_add_vhost(con, req, fname, 0, TRUE))
     929             608 :     return (FALSE);
     930                 : 
     931           31968 :   vstr_add_cstr_ptr(fname, 0, "/");
     932                 : 
     933           31968 :   req->vhost_prefix_len = (fname->len - orig_len);
     934                 : 
     935           31968 :   return (TRUE);
     936                 : }
     937                 : 
     938                 : /* Decode url-path,
     939                 :    check url-path for a bunch of problems,
     940                 :    if vhosts is on add vhost prefix,
     941                 :    Note we don't do dir_filename additions yet */
     942                 : int http_req_make_path(struct Con *con, Httpd_req_data *req)
     943           34657 : {
     944           34657 :   Vstr_base *data = con->evnt->io_r;
     945           34657 :   Vstr_base *fname = req->fname;
     946                 :   
     947           17336 :   ASSERT(!fname->len);
     948                 : 
     949           17336 :   assert(VPREFIX(data, req->path_pos, req->path_len, "/") ||
     950                 :          VEQ(data, req->path_pos, req->path_len, "*"));
     951                 : 
     952           34657 :   if (req->chk_encoded_slash &&
     953                 :       vstr_srch_case_cstr_buf_fwd(data, req->path_pos, req->path_len, "%2f"))
     954            1152 :     HTTPD_ERR_MSG_RET(req, 403, "Path has encoded /", FALSE);
     955           33505 :   if (req->chk_encoded_dot &&
     956                 :       vstr_srch_case_cstr_buf_fwd(data, req->path_pos, req->path_len, "%2e"))
     957               0 :     HTTPD_ERR_MSG_RET(req, 403, "Path has encoded .", FALSE);
     958           33505 :   req->chked_encoded_path = TRUE;
     959                 : 
     960           33505 :   vstr_add_vstr(fname, 0,
     961                 :                 data, req->path_pos, req->path_len, VSTR_TYPE_ADD_BUF_PTR);
     962           33505 :   vstr_conv_decode_uri(fname, 1, fname->len);
     963                 : 
     964           33505 :   if (fname->conf->malloc_bad) /* dealt with as errmem_req() later */
     965               0 :     return (TRUE);
     966                 : 
     967                 :   /* NOTE: need to split function here so we can more efficently alter the
     968                 :    * path. */
     969           33505 :   if (!httpd_req_add_vhost(con, req))
     970             608 :     return (FALSE);
     971                 :   
     972                 :   /* check posix path ... including hostname, for NIL and path escapes */
     973           32897 :   if (vstr_srch_chr_fwd(fname, 1, fname->len, 0))
     974             144 :     HTTPD_ERR_MSG_RET(req, 403, "Path has NIL", FALSE);
     975                 : 
     976                 :   /* web servers don't have relative paths, so /./ and /../ aren't "special" */
     977           32753 :   if (vstr_srch_cstr_buf_fwd(fname, 1, fname->len, "/../") ||
     978                 :       VSUFFIX(req->fname, 1, req->fname->len, "/.."))
     979             432 :     HTTPD_ERR_MSG_RET(req, 403, "Path has /../", FALSE);
     980           32321 :   if (req->policy->chk_dot_dir &&
     981                 :       (vstr_srch_cstr_buf_fwd(fname, 1, fname->len, "/./") ||
     982                 :        VSUFFIX(req->fname, 1, req->fname->len, "/.")))
     983               0 :     HTTPD_ERR_MSG_RET(req, 403, "Path has /./", FALSE);
     984                 : 
     985           16168 :   ASSERT(fname->len);
     986           16168 :   assert(VPREFIX(fname, 1, fname->len, "/") ||
     987                 :          VEQ(fname, 1, fname->len, "*") ||
     988                 :          fname->conf->malloc_bad);
     989                 : 
     990           32321 :   if (fname->conf->malloc_bad)
     991               0 :     return (TRUE);
     992                 :   
     993           32321 :   return (TRUE);
     994                 : }
     995                 : 
     996                 : size_t http_req_xtra_content(Httpd_req_data *req, const Vstr_base *s1,
     997                 :                              size_t pos, size_t *len)
     998           13376 : {
     999           13376 :   Vstr_base *xs1 = req->xtra_content;
    1000           13376 :   size_t ret = 0;
    1001                 :   
    1002            6688 :   ASSERT(len);
    1003            6688 :   ASSERT((s1 == xs1) || !s1);
    1004            6688 :   ASSERT(s1 || !*len);
    1005                 :   
    1006           13376 :   if (!req->xtra_content && !(req->xtra_content = vstr_make_base(NULL)))
    1007               0 :     return (0);
    1008           13376 :   xs1 = req->xtra_content;
    1009                 : 
    1010           13376 :   if (!s1 || !*len)
    1011           11008 :     return (xs1->len + 1);
    1012                 :   
    1013            2368 :   if (vstr_sc_poslast(pos, *len) == xs1->len)
    1014             640 :     return (pos); /* we are last, so just overwrite */
    1015                 : 
    1016                 :   /* we aren't, so copy to last place */
    1017            1728 :   ret = xs1->len + 1;
    1018            1728 :   if (!vstr_add_vstr(xs1, xs1->len, s1, pos, *len, VSTR_TYPE_ADD_BUF_REF))
    1019               0 :     return (0);
    1020                 : 
    1021            1728 :   return (ret);
    1022                 : }

Generated by: LTP GCOV extension version 1.4