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

       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 HTTPD APIs, only really implements server portions */
      21                 : 
      22                 : #define EX_UTILS_NO_USE_INIT  1
      23                 : #define EX_UTILS_NO_USE_EXIT  1
      24                 : #define EX_UTILS_NO_USE_LIMIT 1
      25                 : #define EX_UTILS_NO_USE_BLOCK 1
      26                 : #define EX_UTILS_NO_USE_GET   1
      27                 : #define EX_UTILS_NO_USE_PUT   1
      28                 : #define EX_UTILS_RET_FAIL     1
      29                 : #include "ex_utils.h"
      30                 : 
      31                 : #include "mk.h"
      32                 : 
      33                 : #include "vlg.h"
      34                 : 
      35                 : #define HTTPD_HAVE_GLOBAL_OPTS 1
      36                 : #include "httpd.h"
      37                 : #include "httpd_policy.h"
      38                 : 
      39                 : #ifndef POSIX_FADV_SEQUENTIAL
      40                 : # define posix_fadvise64(x1, x2, x3, x4) (errno = ENOSYS, -1)
      41                 : #endif
      42                 : 
      43                 : #if ! COMPILE_DEBUG
      44                 : # define HTTP_CONF_MMAP_LIMIT_MIN (16 * 1024) /* a couple of pages */
      45                 : # define HTTP_CONF_SAFE_PRINT_REQ TRUE
      46                 : #else
      47                 : # define HTTP_CONF_MMAP_LIMIT_MIN 8 /* debug... */
      48                 : # define HTTP_CONF_SAFE_PRINT_REQ FALSE
      49                 : #endif
      50                 : #define HTTP_CONF_MMAP_LIMIT_MAX (50 * 1024 * 1024)
      51                 : 
      52                 : #define HTTPD_CONF_ZIP_LIMIT_MIN 8
      53                 : 
      54                 : #define CLEN COMPILE_STRLEN
      55                 : 
      56                 : /* is the cstr a prefix of the vstr */
      57                 : #define VPREFIX(vstr, p, l, cstr)                                       \
      58                 :     (((l) >= CLEN(cstr)) &&                                             \
      59                 :      vstr_cmp_buf_eq(vstr, p, CLEN(cstr), cstr, CLEN(cstr)))
      60                 : /* is the cstr a suffix of the vstr */
      61                 : #define VSUFFIX(vstr, p, l, cstr)                                       \
      62                 :     (((l) >= CLEN(cstr)) &&                                             \
      63                 :      vstr_cmp_eod_buf_eq(vstr, p, l, cstr, CLEN(cstr)))
      64                 : 
      65                 : /* is the cstr a prefix of the vstr, no case */
      66                 : #define VIPREFIX(vstr, p, l, cstr)                                      \
      67                 :     (((l) >= CLEN(cstr)) &&                                             \
      68                 :      vstr_cmp_case_buf_eq(vstr, p, CLEN(cstr), cstr, CLEN(cstr)))
      69                 : 
      70                 : /* for simplicity */
      71                 : #define VEQ(vstr, p, l, cstr)  vstr_cmp_cstr_eq(vstr, p, l, cstr)
      72                 : #define VIEQ(vstr, p, l, cstr) vstr_cmp_case_cstr_eq(vstr, p, l, cstr)
      73                 : 
      74                 : #define HTTP__HDR_SET(req, h, p, l) do {               \
      75                 :       (req)-> http_hdrs -> hdr_ ## h ->pos = (p);          \
      76                 :       (req)-> http_hdrs -> hdr_ ## h ->len = (l);          \
      77                 :     } while (FALSE)
      78                 : #define HTTP__HDR_MULTI_SET(req, h, p, l) do {         \
      79                 :       (req)-> http_hdrs -> multi -> hdr_ ## h ->pos = (p); \
      80                 :       (req)-> http_hdrs -> multi -> hdr_ ## h ->len = (l); \
      81                 :     } while (FALSE)
      82                 : 
      83                 : #define HTTP__XTRA_HDR_INIT(x) do {             \
      84                 :       req-> x ## _vs1 = NULL;                   \
      85                 :       req-> x ## _pos = 0;                      \
      86                 :       req-> x ## _len = 0;                      \
      87                 :     } while (FALSE)
      88                 : 
      89                 : #include <syslog.h>
      90                 : 
      91                 : HTTPD_CONF_MAIN_DECL_OPTS(httpd_opts);
      92                 : 
      93                 : static Vlg *vlg = NULL;
      94                 : 
      95                 : 
      96                 : void httpd_init(Vlg *passed_vlg)
      97              64 : {
      98              32 :   ASSERT(passed_vlg && !vlg);
      99              64 :   vlg = passed_vlg;
     100              64 :   httpd_app_init(vlg);
     101              64 :   httpd_parse_init(vlg);
     102              64 :   httpd_req_init(vlg);
     103              64 : }
     104                 : 
     105                 : void httpd_exit(void)
     106              44 : {
     107              22 :   ASSERT(vlg);
     108              44 :   vlg = NULL;
     109              44 :   httpd_parse_exit();
     110              44 :   httpd_req_exit();
     111              44 :   httpd_app_exit();
     112              44 : }
     113                 : 
     114                 : /* prints out headers in human friedly way for log files */
     115                 : #define PCUR (pos + (base->len - orig_len))
     116                 : static int http_app_vstr_escape(Vstr_base *base, size_t pos,
     117                 :                                 Vstr_base *sf, size_t sf_pos, size_t sf_len)
     118          178076 : {
     119          178076 :   unsigned int sf_flags = VSTR_TYPE_ADD_BUF_PTR;
     120                 :   Vstr_iter iter[1];
     121          178076 :   size_t orig_len = base->len;
     122          178076 :   int saved_malloc_bad = FALSE;
     123          178076 :   size_t norm_chr = 0;
     124                 : 
     125          178076 :   if (!sf_len) /* hack around !sf_pos */
     126           93570 :     return (TRUE);
     127                 :   
     128           84506 :   if (!vstr_iter_fwd_beg(sf, sf_pos, sf_len, iter))
     129               0 :     return (FALSE);
     130                 : 
     131           84506 :   saved_malloc_bad = base->conf->malloc_bad;
     132           84506 :   base->conf->malloc_bad = FALSE;
     133          771418 :   while (sf_len)
     134                 :   { /* assumes ASCII */
     135          602406 :     char scan = vstr_iter_fwd_chr(iter, NULL);
     136                 : 
     137         1204412 :     if ((scan >= ' ') && (scan <= '~') && (scan != '"') && (scan != '\\'))
     138          602006 :       ++norm_chr;
     139                 :     else
     140                 :     {
     141             400 :       vstr_add_vstr(base, PCUR, sf, sf_pos, norm_chr, sf_flags);
     142             400 :       sf_pos += norm_chr;
     143             400 :       norm_chr = 0;
     144                 :       
     145                 :       if (0) {}
     146             400 :       else if (scan == '"')  vstr_add_cstr_buf(base, PCUR, "\\\"");
     147             144 :       else if (scan == '\\') vstr_add_cstr_buf(base, PCUR, "\\\\");
     148             144 :       else if (scan == '\t') vstr_add_cstr_buf(base, PCUR, "\\t");
     149             144 :       else if (scan == '\v') vstr_add_cstr_buf(base, PCUR, "\\v");
     150             144 :       else if (scan == '\r') vstr_add_cstr_buf(base, PCUR, "\\r");
     151             144 :       else if (scan == '\n') vstr_add_cstr_buf(base, PCUR, "\\n");
     152             144 :       else if (scan == '\b') vstr_add_cstr_buf(base, PCUR, "\\b");
     153                 :       else
     154             144 :         vstr_add_sysfmt(base, PCUR, "\\x%02hhx", scan);
     155             400 :       ++sf_pos;
     156                 :     }
     157                 :     
     158          602406 :     --sf_len;
     159                 :   }
     160                 : 
     161           84506 :   vstr_add_vstr(base, PCUR, sf, sf_pos, norm_chr, sf_flags);
     162                 :   
     163           84506 :   if (base->conf->malloc_bad)
     164               0 :     return (FALSE);
     165                 :   
     166           84506 :   base->conf->malloc_bad = saved_malloc_bad;
     167           84506 :   return (TRUE);
     168                 : }
     169                 : #undef PCUR
     170                 : 
     171                 : static int http__fmt__add_vstr_add_vstr(Vstr_base *base, size_t pos,
     172                 :                                         Vstr_fmt_spec *spec)
     173          159524 : {
     174          159524 :   Vstr_base *sf = VSTR_FMT_CB_ARG_PTR(spec, 0);
     175          159524 :   size_t sf_pos = VSTR_FMT_CB_ARG_VAL(spec, size_t, 1);
     176          159524 :   size_t sf_len = VSTR_FMT_CB_ARG_VAL(spec, size_t, 2);
     177                 :   
     178          159524 :   return (http_app_vstr_escape(base, pos, sf, sf_pos, sf_len));
     179                 : }
     180                 : int http_fmt_add_vstr_add_vstr(Vstr_conf *conf, const char *name)
     181            1344 : {
     182            1344 :   return (vstr_fmt_add(conf, name, http__fmt__add_vstr_add_vstr,
     183                 :                        VSTR_TYPE_FMT_PTR_VOID,
     184                 :                        VSTR_TYPE_FMT_SIZE_T,
     185                 :                        VSTR_TYPE_FMT_SIZE_T,
     186                 :                        VSTR_TYPE_FMT_END));
     187                 : }
     188                 : static int http__fmt__add_vstr_add_sect_vstr(Vstr_base *base, size_t pos,
     189                 :                                              Vstr_fmt_spec *spec)
     190           18552 : {
     191           18552 :   Vstr_base *sf     = VSTR_FMT_CB_ARG_PTR(spec, 0);
     192           18552 :   Vstr_sects *sects = VSTR_FMT_CB_ARG_PTR(spec, 1);
     193           18552 :   unsigned int num  = VSTR_FMT_CB_ARG_VAL(spec, unsigned int, 2);
     194           18552 :   size_t sf_pos     = VSTR_SECTS_NUM(sects, num)->pos;
     195           18552 :   size_t sf_len     = VSTR_SECTS_NUM(sects, num)->len;
     196                 :   
     197           18552 :   return (http_app_vstr_escape(base, pos, sf, sf_pos, sf_len));
     198                 : }
     199                 : int http_fmt_add_vstr_add_sect_vstr(Vstr_conf *conf, const char *name)
     200            1344 : {
     201            1344 :   return (vstr_fmt_add(conf, name, http__fmt__add_vstr_add_sect_vstr,
     202                 :                        VSTR_TYPE_FMT_PTR_VOID,
     203                 :                        VSTR_TYPE_FMT_PTR_VOID,
     204                 :                        VSTR_TYPE_FMT_UINT,
     205                 :                        VSTR_TYPE_FMT_END));
     206                 : }
     207                 : 
     208                 : static void http_vlg_def(struct Con *con, struct Httpd_req_data *req, int meth)
     209           39881 : {
     210           39881 :   Vstr_base *data = con->evnt->io_r;
     211           39881 :   Vstr_sect_node *h_h  = req->http_hdrs->hdr_host;
     212           39881 :   Vstr_sect_node *h_ua = req->http_hdrs->hdr_ua;
     213           39881 :   Vstr_sect_node *h_r  = req->http_hdrs->hdr_referer;
     214                 : 
     215           39881 :   vlg_info(vlg, (" host[\"$<http-esc.vstr:%p%zu%zu>\"]"
     216                 :                  " UA[\"$<http-esc.vstr:%p%zu%zu>\"]"
     217                 :                  " ref[\"$<http-esc.vstr:%p%zu%zu>\"]"),
     218                 :            data, h_h->pos, h_h->len,    
     219                 :            data, h_ua->pos, h_ua->len,
     220                 :            data, h_r->pos, h_r->len);
     221                 : 
     222           39881 :   if (meth && (req->sects->num >= 1))
     223           17784 :     vlg_info(vlg, " meth[\"$<http-esc.vstr.sect:%p%p%u>\"]",
     224                 :              data, req->sects, 1U);
     225                 : 
     226           39881 :   if (req->ver_0_9)
     227             672 :     vlg_info(vlg, " ver[\"HTTP/0.9\"]");
     228                 :   else
     229                 :   {
     230           19612 :     ASSERT(req->sects->num >= 3);
     231           39209 :     vlg_info(vlg, " ver[\"$<vstr.sect:%p%p%u>\"]", data, req->sects, 3);
     232                 :   }
     233                 : 
     234           39881 :   vlg_info(vlg, ": $<http-esc.vstr:%p%zu%zu>\n",
     235                 :            data, req->path_pos, req->path_len);
     236           39881 : }
     237                 : 
     238                 : static struct File_sect *httpd__fd_next(struct Con *con)
     239           47125 : {
     240           47125 :   struct File_sect *fs = NULL;
     241                 :   
     242           23570 :   ASSERT(con->fs &&
     243                 :          (con->fs_off <= con->fs_num) && (con->fs_num <= con->fs_sz));
     244                 :   
     245           47125 :   if (++con->fs_off >= con->fs_num)
     246                 :   {
     247           46741 :     fs = &con->fs[con->fs_off - 1];
     248           46741 :     fs->len = 0;
     249           46741 :     if (fs->fd != -1)
     250           25641 :       close(fs->fd);
     251           46741 :     fs->fd = -1;
     252                 : 
     253           46741 :     fs = con->fs;
     254           46741 :     fs->fd = -1;
     255           46741 :     fs->len = 0;
     256                 :     
     257           46741 :     con->fs_off = 0;
     258           46741 :     con->fs_num = 0;
     259                 : 
     260           46741 :     con->use_mpbr = FALSE;
     261           23378 :     ASSERT(!(con->mpbr_fs_len = 0));
     262                 :   
     263           46741 :     if (con->mpbr_ct)
     264             448 :       vstr_del(con->mpbr_ct, 1, con->mpbr_ct->len);
     265                 : 
     266           46741 :     return (NULL);
     267                 :   }
     268                 : 
     269                 :   /* only allow multipart/byterange atm. where all fd's are the same */
     270             192 :   ASSERT(con->fs[con->fs_off - 1].fd == con->fs[con->fs_off].fd);
     271                 :   
     272             384 :   fs = &con->fs[con->fs_off];
     273             384 :   if (con->use_posix_fadvise)
     274             288 :     posix_fadvise64(fs->fd, fs->off, fs->len, POSIX_FADV_SEQUENTIAL);
     275                 :   
     276             384 :   return (fs);
     277                 : }
     278                 : 
     279                 : void httpd_fin_fd_close(struct Con *con)
     280           46613 : {
     281           46613 :   con->use_posix_fadvise = FALSE;
     282           46709 :   while (httpd__fd_next(con))
     283                 :   { /* do nothing */ }
     284           46613 : }
     285                 : 
     286                 : static int http_fin_req(struct Con *con, Httpd_req_data *req)
     287           40231 : {
     288           40231 :   Vstr_base *out = con->evnt->io_w;
     289                 :   
     290           20123 :   ASSERT(!out->conf->malloc_bad);
     291           40231 :   http_parse_clear_hdrs(req);
     292                 : 
     293                 :   /* Note: Not resetting con->parsed_method_ver_1_0,
     294                 :    * if it's non-0.9 now it should continue to be */
     295                 :   
     296           40231 :   if (!con->keep_alive) /* all input is here */
     297                 :   {
     298           11870 :     evnt_wait_cntl_del(con->evnt, POLLIN);
     299           11870 :     req->len = con->evnt->io_r->len; /* delete it all */
     300                 :   }
     301                 :   
     302           40231 :   vstr_del(con->evnt->io_r, 1, req->len);
     303                 :   
     304           40231 :   evnt_put_pkt(con->evnt);
     305                 : 
     306           40231 :   if (req->policy->use_tcp_cork)
     307           39815 :     evnt_fd_set_cork(con->evnt, TRUE);
     308                 : 
     309           40231 :   http_req_free(req);
     310                 : 
     311           40231 :   return (httpd_serv_send(con));
     312                 : }
     313                 : 
     314                 : static int http_fin_fd_req(struct Con *con, Httpd_req_data *req)
     315           23273 : {
     316           11644 :   ASSERT(con->fs && (con->fs_off < con->fs_num) && (con->fs_num <= con->fs_sz));
     317           11644 :   ASSERT(!con->fs_off);
     318                 :   
     319           35261 :   if (req->head_op || con->use_mmap || !con->fs->len)
     320           11988 :     httpd_fin_fd_close(con);
     321           11285 :   else if ((con->use_posix_fadvise = req->policy->use_posix_fadvise))
     322                 :   {
     323           11285 :     struct File_sect *fs = con->fs;
     324           11285 :     posix_fadvise64(fs->fd, fs->off, fs->len, POSIX_FADV_SEQUENTIAL);
     325                 :   }
     326                 :   
     327           23273 :   return (http_fin_req(con, req));
     328                 : }
     329                 : 
     330                 : static int http_con_cleanup(struct Con *con, Httpd_req_data *req)
     331              32 : {
     332              32 :   con->evnt->io_r->conf->malloc_bad = FALSE;
     333              32 :   con->evnt->io_w->conf->malloc_bad = FALSE;
     334                 :   
     335              32 :   http_parse_clear_hdrs(req);
     336              32 :   http_req_free(req);
     337                 :     
     338              32 :   return (FALSE);
     339                 : }
     340                 : 
     341                 : static int http_con_close_cleanup(struct Con *con, Httpd_req_data *req)
     342               0 : {
     343               0 :   httpd_fin_fd_close(con);
     344               0 :   return (http_con_cleanup(con, req));
     345                 : }
     346                 : 
     347                 : static void httpd__disable_sendfile(void)
     348               0 : {
     349               0 :   Opt_serv_policy_opts *scan = httpd_opts->s->def_policy;
     350                 :   
     351               0 :   while (scan)
     352                 :   {
     353               0 :     Httpd_policy_opts *tmp = (Httpd_policy_opts *)scan;
     354               0 :     tmp->use_sendfile = FALSE;
     355               0 :     scan = scan->next;
     356                 :   }
     357               0 : }
     358                 : 
     359                 : static void httpd__disable_mmap(void)
     360               0 : {
     361               0 :   Opt_serv_policy_opts *scan = httpd_opts->s->def_policy;
     362                 :   
     363               0 :   while (scan)
     364                 :   {
     365               0 :     Httpd_policy_opts *tmp = (Httpd_policy_opts *)scan;
     366               0 :     tmp->use_mmap = FALSE;
     367               0 :     scan = scan->next;
     368                 :   }
     369               0 : }
     370                 : 
     371                 : void httpd_disable_getxattr(void)
     372               0 : {
     373               0 :   Opt_serv_policy_opts *scan = httpd_opts->s->def_policy;
     374                 :   
     375               0 :   while (scan)
     376                 :   {
     377               0 :     Httpd_policy_opts *tmp = (Httpd_policy_opts *)scan;
     378               0 :     tmp->use_mime_xattr = FALSE;
     379               0 :     scan = scan->next;
     380                 :   }
     381               0 : }
     382                 : 
     383                 : static void httpd_serv_call_mmap(struct Con *con, struct Httpd_req_data *req,
     384                 :                                  struct File_sect *fs)
     385           12217 : {
     386                 :   static long pagesz = 0;
     387           12217 :   Vstr_base *data = con->evnt->io_r;
     388           12217 :   uintmax_t mmoff = fs->off;
     389           12217 :   uintmax_t mmlen = fs->len;
     390                 :   
     391            6116 :   ASSERT(!req->f_mmap || !req->f_mmap->len);
     392            6116 :   ASSERT(!con->use_mmap);
     393            6116 :   ASSERT(!req->head_op);
     394                 : 
     395           12217 :   if (con->use_sendfile)
     396            7509 :     return;
     397                 : 
     398            4708 :   if (con->fs_num > 1)
     399               0 :     return;
     400                 :   
     401            4708 :   if (!pagesz)
     402              10 :     pagesz = sysconf(_SC_PAGESIZE);
     403            4708 :   if (pagesz == -1)
     404               0 :     httpd__disable_mmap();
     405                 : 
     406            4708 :   if (!req->policy->use_mmap ||
     407                 :       (mmlen < HTTP_CONF_MMAP_LIMIT_MIN) || (mmlen > HTTP_CONF_MMAP_LIMIT_MAX))
     408            2326 :     return;
     409                 :   
     410                 :   /* mmap offset needs to be aligned - so tweak offset before and after */
     411             388 :   mmoff /= pagesz;
     412             388 :   mmoff *= pagesz;
     413             360 :   ASSERT(mmoff <= fs->off);
     414             388 :   mmlen += fs->off - mmoff;
     415                 : 
     416             388 :   if (!req->f_mmap && !(req->f_mmap = vstr_make_base(data->conf)))
     417               0 :     VLG_WARN_RET_VOID((vlg, /* fall back to read */
     418                 :                        "failed to allocate mmap Vstr.\n"));
     419             360 :   ASSERT(!req->f_mmap->len);
     420                 :   
     421             388 :   if (!vstr_sc_mmap_fd(req->f_mmap, 0, fs->fd, mmoff, mmlen, NULL))
     422                 :   {
     423               0 :     if (errno == ENOSYS) /* also logs it */
     424               0 :       httpd__disable_mmap();
     425                 : 
     426               0 :     VLG_WARN_RET_VOID((vlg, /* fall back to read */
     427                 :                        "mmap($<http-esc.vstr:%p%zu%zu>,"
     428                 :                        "(%ju,%ju)->(%ju,%ju)): %m\n",
     429                 :                        req->fname, (size_t)1, req->fname->len,
     430                 :                        fs->off, fs->len, mmoff, mmlen));
     431                 :   }
     432                 :   
     433             388 :   con->use_mmap = TRUE;  
     434             388 :   vstr_del(req->f_mmap, 1, fs->off - mmoff); /* remove alignment */
     435                 :     
     436             360 :   ASSERT(req->f_mmap->len == fs->len);
     437                 : }
     438                 : 
     439                 : static int httpd_serv_call_seek(struct Con *con, struct File_sect *fs)
     440           10745 : {
     441           10745 :   if (con->use_mmap || con->use_sendfile)
     442            6425 :     return (TRUE);
     443                 : 
     444            4320 :   if (fs->off && fs->len && (lseek64(fs->fd, fs->off, SEEK_SET) == -1))
     445               0 :     return (FALSE);
     446                 :   
     447            4320 :   return (TRUE);
     448                 : }
     449                 : 
     450                 : static void httpd__serv_call_seek(struct Con *con, struct Httpd_req_data *req,
     451                 :                                   struct File_sect *fs,
     452                 :                                   unsigned int *http_ret_code,
     453                 :                                   const char ** http_ret_line)
     454           10457 : {
     455            5236 :   ASSERT(!req->head_op);
     456                 : 
     457           10457 :   if (!httpd_serv_call_seek(con, fs))
     458                 :   { /* this should be impossible for normal files AFAIK */
     459               0 :     vlg_warn(vlg, "lseek($<http-esc.vstr:%p%zu%zu>,off=%ju): %m\n",
     460                 :              req->fname, (size_t)1, req->fname->len, fs->off);
     461                 :     /* opts->use_range - turn off? */
     462               0 :     req->http_hdrs->hdr_range->pos = 0;
     463               0 :     *http_ret_code = 200;
     464               0 :     *http_ret_line = "OK - Range Failed";
     465                 :   }
     466           10457 : }
     467                 : 
     468                 : static int http__conf_req(struct Con *con, Httpd_req_data *req, size_t del_len)
     469           38777 : {
     470           38777 :   Conf_parse *conf = NULL;
     471                 :   
     472           38777 :   if (!(conf = conf_parse_make(NULL)))
     473               0 :     return (FALSE);
     474                 :   
     475           38777 :   if (!httpd_conf_req_parse_file(conf, con, req, del_len))
     476                 :   {
     477             224 :     Vstr_base *s1 = req->policy->s->policy_name;
     478             224 :     Vstr_base *s2 = conf->tmp;
     479                 : 
     480             224 :     if (!req->user_return_error_code)
     481               0 :       vlg_info(vlg, "CONF-REQ-ERR from[$<sa:%p>]: policy $<vstr.all:%p>"
     482                 :                " backtrace: $<vstr.all:%p>\n", CON_CEVNT_SA(con), s1, s2);
     483             224 :     conf_parse_free(conf);
     484             224 :     return (TRUE);
     485                 :   }
     486           38553 :   conf_parse_free(conf);
     487                 :   
     488           38553 :   if (req->direct_uri)
     489                 :   {
     490               0 :     Vstr_base *s1 = req->policy->s->policy_name;
     491               0 :     vlg_info(vlg, "CONF-REQ-ERR from[$<sa:%p>]: policy $<vstr.all:%p>"
     492                 :              " Has URI.\n", CON_CEVNT_SA(con), s1);
     493               0 :     HTTPD_ERR_MSG_RET(req, 503, "Has URI", TRUE);
     494                 :   }
     495                 :   
     496           38553 :   return (TRUE);
     497                 : }
     498                 : 
     499                 : static void http_prepend_doc_root(Vstr_base *fname, Httpd_req_data *req)
     500           27745 : {
     501           27745 :   Vstr_base *dir = req->policy->document_root;
     502                 :   
     503           13880 :   ASSERT((dir->len   >= 1) && vstr_cmp_cstr_eq(dir,   dir->len, 1, "/"));
     504           13880 :   ASSERT((fname->len >= 1) && vstr_cmp_cstr_eq(fname,        1, 1, "/"));
     505           27745 :   vstr_add_vstr(fname, 0, dir, 1, dir->len - 1, VSTR_TYPE_ADD_BUF_REF);
     506           27745 : }
     507                 : 
     508                 : /* characters valid in a hostname -- these are also safe unencoded in a URL */
     509                 : #define HTTPD__VALID_CSTR_CHRS_HOSTNAME     \
     510                 :     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"            \
     511                 :     "abcdefghijklmnopqrstuvwxyz"            \
     512                 :     "0123456789"                            \
     513                 :     ".-_"
     514                 : /* characters that are valid in a part of a URL _and_ in a file basename ...
     515                 :  * without encoding */
     516                 : #define HTTPD__VALID_CSTR_CHRS_URL_FILENAME \
     517                 :     "!$,:=~" HTTPD__VALID_CSTR_CHRS_HOSTNAME
     518                 : 
     519                 : int httpd_valid_url_filename(Vstr_base *s1, size_t pos, size_t len)
     520             138 : {
     521                 :   static const char cstr[] = HTTPD__VALID_CSTR_CHRS_URL_FILENAME;
     522             138 :   return (vstr_spn_cstr_chrs_fwd(s1, pos, len, cstr) == len);
     523                 : }
     524                 : 
     525                 : static unsigned short
     526                 : httpd__valid_hostname(Vstr_base *s1, size_t pos, size_t len, int allow_port)
     527           22338 : {
     528                 :   static const char cstr[] = HTTPD__VALID_CSTR_CHRS_HOSTNAME;
     529           22338 :   size_t tmp = 0;
     530                 :   
     531                 :    /* this is also checked via /./ path checking */
     532           22338 :   if (vstr_cmp_cstr_eq(s1, pos, len, "."))
     533             288 :     return (0);
     534                 :   
     535           22050 :   if (vstr_srch_cstr_buf_fwd(s1, pos, len, ".."))
     536               0 :     return (0); /* example..com */
     537                 : 
     538           22050 :   if (VPREFIX(s1, pos, len, ".")) return (0); /* .example.com  */
     539                 : 
     540                 :   /* this is always removed in httpd_req_add_vhost */
     541           11025 :   assert(!VSUFFIX(s1, pos, len, "."));        /*  example.com. */
     542                 :   
     543           22050 :   tmp = vstr_spn_cstr_chrs_fwd(s1, pos, len, cstr);
     544           22050 :   if (tmp == len)
     545           20466 :     return (80);
     546                 : 
     547            1584 :   if (!allow_port)
     548               0 :     return (0);
     549                 :   
     550            1584 :   len -= tmp; pos += tmp;
     551            1584 :   if (vstr_export_chr(s1, pos) == ':') /* here both before and after port rm */
     552            1584 :     return (httpd_parse_host_port(s1, pos, len));
     553                 :   
     554               0 :   return (0);
     555                 : }
     556                 : 
     557                 : static int httpd__chk_vhost(const Httpd_policy_opts *popts,
     558                 :                             Vstr_base *lfn, size_t pos, size_t len)
     559           22512 : {
     560           22512 :   const char *vhost = NULL;
     561                 :   struct stat64 v_stat[1];
     562           22512 :   const Vstr_base *def_hname = popts->default_hostname;
     563           22512 :   int ret = -1;
     564                 :   
     565           11256 :   ASSERT(pos);
     566                 : 
     567           22512 :   if (popts->use_internal_host_chk)
     568                 :   {
     569           22160 :     if (!httpd__valid_hostname(lfn, pos, len, TRUE))
     570             288 :       return (FALSE);
     571                 :   }
     572                 :   
     573           22224 :   if (!popts->use_host_chk)
     574             192 :     return (TRUE);
     575                 :   
     576           22032 :   if (vstr_cmp_eq(lfn, pos, len, def_hname, 1, def_hname->len))
     577           13544 :     return (TRUE); /* don't do lots of work for nothing */
     578                 : 
     579            8488 :   vstr_add_vstr(lfn, pos - 1, 
     580                 :                 popts->document_root, 1, popts->document_root->len,
     581                 :                 VSTR_TYPE_ADD_BUF_PTR);
     582            8488 :   len += popts->document_root->len;
     583                 :   
     584            8488 :   if (lfn->conf->malloc_bad || !(vhost = vstr_export_cstr_ptr(lfn, pos, len)))
     585               0 :     return (TRUE); /* dealt with as errmem_req() later */
     586                 :   
     587            8488 :   ret = stat64(vhost, v_stat);
     588            8488 :   vstr_del(lfn, pos, popts->document_root->len);
     589                 : 
     590            8488 :   if (ret == -1)
     591             224 :     return (FALSE);
     592                 : 
     593            8264 :   if (!S_ISDIR(v_stat->st_mode))
     594             144 :     return (FALSE);
     595                 :   
     596            8120 :   return (TRUE);
     597                 : }
     598                 : 
     599                 : int http_serv_add_vhost(struct Con *con, Httpd_req_data *req,
     600                 :                         Vstr_base *s1, size_t pos, int chk)
     601           43216 : {
     602           43216 :   size_t tmp = s1->len;
     603                 :   
     604           43216 :   httpd_sc_add_hostname(con, req, s1, pos);
     605                 :   
     606           43216 :   if (!req->http_hdrs->hdr_host->len)
     607           16400 :     return (TRUE); /* don't bother checking valid vhost for default */
     608                 : 
     609           26816 :   tmp = s1->len - tmp; /* length of added data */
     610           26816 :   if (chk && !s1->conf->malloc_bad &&
     611                 :       !httpd__chk_vhost(req->policy, s1, pos + 1, tmp))
     612                 :   {
     613             656 :     if (req->policy->use_host_err_400) /* rfc2616 5.2 */
     614             608 :       HTTPD_ERR_MSG_RET(req, 400, "Hostname not local", FALSE);
     615                 :     else
     616                 :     { /* what everything else does ... *sigh* */
     617              48 :       if (s1->conf->malloc_bad)
     618               0 :         return (TRUE);
     619                 :       
     620              48 :       req->http_hdrs->hdr_host->len = 0;
     621              48 :       vstr_del(s1, pos + 1, tmp);
     622              48 :       httpd_sc_add_default_hostname(con, req, s1, pos);
     623                 :     }
     624                 :   }
     625                 : 
     626           26208 :   return (TRUE);
     627                 : }
     628                 : 
     629                 : static void http_app_err_file(struct Con *con, Httpd_req_data *req,
     630                 :                               Vstr_base *fname, size_t *vhost_prefix_len)
     631           10904 : {
     632           10904 :   Vstr_base *dir = NULL;
     633           10904 :   size_t orig_len = 0;
     634                 : 
     635            5452 :   ASSERT(con && req && fname);
     636            5452 :   ASSERT(vhost_prefix_len && !*vhost_prefix_len);
     637                 : 
     638           10904 :   orig_len = fname->len;
     639           10904 :   dir = req->policy->req_err_dir;
     640            5452 :   ASSERT((dir->len   >= 1) && vstr_cmp_cstr_eq(dir,   dir->len, 1, "/"));
     641           10904 :   HTTPD_APP_REF_ALLVSTR(fname, dir);
     642                 :   
     643           10904 :   if (req->policy->use_vhosts_name)
     644                 :   {
     645           10640 :     http_serv_add_vhost(con, req, fname, fname->len, FALSE);
     646           10640 :     vstr_add_cstr_ptr(fname, fname->len, "/");
     647                 :   }
     648                 :   
     649                 :   /* FIXME: This kind of looks like a hack, we tell the rest of the code that
     650                 :    * the err req dir and any vhost info. is all part of the
     651                 :    * "non-path prefix" basically so = does the right thing with limits.
     652                 :    * Ie. path-eq 404 ... vhost_prefix_len should probably be called
     653                 :    * something else. */
     654           10904 :   *vhost_prefix_len = (fname->len - orig_len);
     655                 :   
     656           10904 :   vstr_add_fmt(fname, fname->len, "%u.html", req->error_code);
     657           10904 : }
     658                 : 
     659                 : uintmax_t http_serv_file_len(struct Con *con, Httpd_req_data *req)
     660           44338 : {
     661                 : #ifndef NDEBUG
     662           22184 :   uintmax_t len = 0;
     663           22184 :   unsigned int num = con->fs_num;
     664                 : 
     665           66936 :   while (num > 0)
     666           22568 :     len += con->fs[--num].len;
     667                 : 
     668           22184 :   ASSERT(len == req->fs_len);
     669                 : #endif
     670                 : 
     671           44338 :   return (req->fs_len);
     672                 : }
     673                 : 
     674                 : static void http__err_vlg_msg(struct Con *con, Httpd_req_data *req)
     675           18134 : {
     676           18134 :   uintmax_t tmp = 0;
     677                 : 
     678           18134 :   if (!req->head_op)
     679           11694 :     tmp = req->error_len;
     680                 :   
     681           18134 :   vlg_info(vlg, "ERREQ from[$<sa:%p>] err[%03u %s%s%s] sz[${BKMG.ju:%ju}:%ju]",
     682                 :            CON_CEVNT_SA(con), req->error_code, req->error_line,
     683                 :            *req->error_xmsg ? " | " : "", req->error_xmsg, tmp, tmp);
     684           35918 :   if ((req->sects->num >= 2) && (req->ver_0_9 || (req->sects->num >= 3)))
     685           17784 :     http_vlg_def(con, req, TRUE);
     686                 :   else
     687             350 :     vlg_info(vlg, "%s", "\n");
     688           18134 : }
     689                 : 
     690                 : void httpd_serv_call_file_init(struct Con *con, Httpd_req_data *req,
     691                 :                                unsigned int *http_ret_code,
     692                 :                                const char ** http_ret_line)
     693           21257 : {
     694           10636 :   ASSERT(req);
     695                 :   
     696           21257 :   con->use_mmap = FALSE;
     697           21257 :   if (!req->head_op)
     698                 :   {
     699           10457 :     httpd_serv_call_mmap(con, req, con->fs);
     700           10457 :     httpd__serv_call_seek(con, req, con->fs, http_ret_code, http_ret_line);
     701                 :   }
     702           21257 : }
     703                 : 
     704                 : void httpd_serv_file_sects_none(struct Con *con, Httpd_req_data *req,
     705                 :                                 off64_t len)
     706           19985 : {
     707           19985 :   con->use_mpbr = FALSE;
     708           19985 :   con->fs_num   = 1;
     709           19985 :   con->fs->off  = 0;
     710           19985 :   con->fs->len  = len;
     711           19985 :   req->fs_len   = len;
     712           19985 : }
     713                 :                                       
     714                 : /* if the attacker gives a user a URL like:
     715                 :    http://example.com/">x</a><script>...</script>
     716                 :  * and we're redirecting everything for example.com to www.example.com
     717                 :  * that'll get output, with html redirects, as:
     718                 :  <a href="http://example.com/">x</a><script>...</script>">here</a>
     719                 :  * ...browsers probably can't be relied upon to not do the stupid thing so
     720                 :  * we escape ' " < > ... ' is just because. None of them mean anything special
     721                 :  * in URLs so we should be fine */
     722                 : static unsigned int http__safe_html_url(Vstr_base *loc)
     723            5632 : {
     724                 :   static const char unsafe[] = "'\"<>"; /* include " " for configs? */
     725            5632 :   size_t pos = 1;
     726            5632 :   size_t len = loc->len;
     727            5632 :   size_t chrs = 0;
     728            5632 :   unsigned int ret = 0;
     729                 :   
     730            2816 :   ASSERT(loc->len);
     731                 :   
     732            9280 :   while ((chrs = vstr_cspn_cstr_chrs_fwd(loc, pos, len, unsafe)) != len)
     733                 :   {
     734             832 :     const char *safe = "...";
     735                 :     
     736             832 :     ++ret;
     737                 :     
     738             832 :     pos += chrs;
     739             832 :     switch (vstr_export_chr(loc, pos))
     740                 :     {
     741               0 :       case ' ':  safe = "%20"; break; /* NOTE: not included above */
     742             128 :       case '"':  safe = "%22"; break;
     743               0 :       case '\'': safe = "%27"; break;
     744             288 :       case '<':  safe = "%3c"; break;
     745             416 :       case '>':  safe = "%3e";
     746             208 :         ASSERT_NO_SWITCH_DEF();
     747                 :     }
     748                 : 
     749             416 :     ASSERT(strlen(safe) == 3);
     750             832 :     if (!vstr_sub_buf(loc, pos, 1, safe, 3))
     751               0 :       return (0);
     752                 : 
     753             832 :     if (pos == len)
     754               0 :       break;
     755                 : 
     756             832 :     pos += 3;
     757             832 :     len = vstr_sc_posdiff(pos, loc->len);
     758                 :   }
     759                 :   
     760            2816 :   ASSERT(vstr_cspn_cstr_chrs_fwd(loc, 1, loc->len, unsafe) == loc->len);
     761                 : 
     762            5632 :   return (ret);
     763                 : }
     764                 : 
     765                 : int http_fin_err_req(struct Con *con, Httpd_req_data *req)
     766           18550 : {
     767           18550 :   Vstr_base *out = con->evnt->io_w;
     768           18550 :   int cust_err_msg = FALSE;
     769           18550 :   int deleted_req_data = FALSE;
     770                 : 
     771            9275 :   ASSERT(req->error_code);
     772                 : 
     773            9275 :   ASSERT(!con->use_mpbr); /* done as part of close() */
     774            9275 :   ASSERT(con->fs && !con->fs_num);
     775                 : 
     776           18550 :   req->content_encoding_gzip  = FALSE;
     777           18550 :   req->content_encoding_bzip2 = FALSE;
     778           18550 :   req->content_encoding_xgzip = FALSE;
     779                 : 
     780                 :   /* These are done before keep-alive parsing is done */
     781            9275 :   ASSERT((req->error_code != 411) || (con->keep_alive == HTTP_NON_KEEP_ALIVE));
     782            9275 :   ASSERT((req->error_code != 413) || (con->keep_alive == HTTP_NON_KEEP_ALIVE));
     783                 :   
     784           18550 :   if ((req->error_code == 400) || (req->error_code == 405) ||
     785                 :       (req->error_code == 411) || (req->error_code == 413) ||
     786                 :       (req->error_code == 500) || (req->error_code == 501))
     787            5614 :     con->keep_alive = HTTP_NON_KEEP_ALIVE;
     788                 :   
     789           18550 :   if (req->malloc_bad)
     790                 :   { /* delete all input to give more room */
     791               0 :     ASSERT(req->error_code == 500);
     792               0 :     http__err_vlg_msg(con, req);
     793               0 :     vstr_del(con->evnt->io_r, 1, con->evnt->io_r->len);
     794               0 :     deleted_req_data = TRUE;
     795                 :   }
     796           18550 :   else if (!HTTPD_ERR_REDIR(req->error_code) && /* don't do as href is passed */
     797                 :            req->policy->req_err_dir->len)
     798                 :   { /* custom err message */
     799           11480 :     Vstr_base *fname = NULL;
     800           11480 :     size_t vhost_prefix_len = 0;
     801           11480 :     const char *fname_cstr = NULL;
     802                 :     struct stat64 f_stat[1];
     803           11480 :     int open_flags = O_NONBLOCK;
     804                 : 
     805           11480 :     if (HTTPD_ERR_MATCH_RESP(req->error_code))
     806                 :     {
     807            8504 :       req->req_user_return_error_code = req->user_return_error_code;
     808            8504 :       req->user_return_error_code     = FALSE;    
     809            8504 :       req->req_error_code             = req->error_code;
     810            8504 :       req->error_code                 = 0;
     811            8504 :       req->req_error_xmsg             = req->error_xmsg;
     812            8504 :       req->error_xmsg                 = "";
     813                 :     
     814            8504 :       if (!httpd_policy_response(con, req,
     815                 :                                  httpd_opts->conf, httpd_opts->match_response))
     816                 :       {
     817             672 :         Vstr_base *s1 = httpd_opts->conf->tmp;
     818             672 :         if (!req->user_return_error_code)
     819               0 :           vlg_info(vlg, "CONF-MATCH-RESP-ERR from[$<sa:%p>]:"
     820                 :                    " backtrace: $<vstr.all:%p>\n", CON_CEVNT_SA(con), s1);
     821                 :         /* fall through */
     822                 :       }
     823                 :       else
     824                 :       {
     825            3916 :         ASSERT(!req->user_return_error_code);
     826            3916 :         ASSERT(!req->error_code);
     827            3916 :         ASSERT(!*req->error_xmsg);
     828            7832 :         req->user_return_error_code = req->req_user_return_error_code;
     829            7832 :         req->error_code             = req->req_error_code;
     830            7832 :         req->error_xmsg             = req->req_error_xmsg;
     831                 :         
     832            7832 :         if (con->evnt->flag_q_closed)
     833                 :         {
     834               0 :           Vstr_base *s1 = req->policy->s->policy_name;
     835                 :           
     836               0 :           vlg_info(vlg, "BLOCKED from[$<sa:%p>]: policy $<vstr.all:%p>\n",
     837                 :                    CON_CEVNT_SA(con), s1);
     838               0 :           return (http_con_cleanup(con, req));
     839                 :         }
     840                 :         
     841            7832 :         if (req->direct_uri)
     842                 :         {
     843               0 :           Vstr_base *s1 = req->policy->s->policy_name;
     844               0 :           vlg_info(vlg, "CONF-MATCH-RESP-ERR from[$<sa:%p>]: "
     845                 :                    "policy $<vstr.all:%p> Has URI.\n", CON_CEVNT_SA(con), s1);
     846               0 :           HTTPD_ERR_MSG_RET(req, 503, "Has URI", TRUE);
     847                 :         }
     848                 :       }
     849                 :     
     850            8504 :       if (!HTTPD_ERR_MATCH_RESP(req->error_code))
     851             416 :         return (http_fin_err_req(con, req)); /* don't loop, just fall through */
     852                 :     }
     853                 :     
     854           11064 :     if (!(fname = vstr_make_base(req->fname->conf)))
     855               0 :       goto fail_custom_err;
     856                 : 
     857                 :     /* NOTE that vary_* is the union of both the req and the resp. processing */
     858                 :     
     859           11064 :     if (!req->user_return_error_code)
     860                 :     {
     861            9688 :       req->cache_control_vs1 = NULL;
     862            9688 :       req->expires_vs1       = NULL;
     863            9688 :       req->p3p_vs1           = NULL;
     864                 :     }
     865                 : 
     866           11144 :     if (req->user_return_error_code && req->direct_filename)
     867                 :     {
     868             160 :       HTTPD_APP_REF_ALLVSTR(fname, req->fname);
     869             160 :       if (!req->skip_document_root)
     870             160 :         http_prepend_doc_root(fname, req);
     871                 :     }
     872                 :     else
     873                 :     {
     874           10904 :       int conf_ret = FALSE;
     875           10904 :       unsigned int code = req->error_code;
     876           10904 :       unsigned int ncode = 0;
     877           10904 :       const char *xmsg = req->error_xmsg;
     878                 :       
     879           10904 :       http_app_err_file(con, req, fname, &vhost_prefix_len);
     880                 : 
     881           10904 :       req->content_type_vs1 = NULL;
     882           10904 :       req->content_type_pos = 0;
     883           10904 :       req->content_type_len = 0;
     884           10904 :       req->error_code = 0;
     885           10904 :       req->skip_document_root = FALSE;
     886           10904 :       req->direct_uri = FALSE;
     887           10904 :       req->neg_content_type_done = FALSE;
     888           10904 :       req->neg_content_lang_done = FALSE;
     889                 :       
     890           10904 :       SWAP_TYPE(fname, req->fname, Vstr_base *);
     891           10904 :       SWAP_TYPE(vhost_prefix_len, req->vhost_prefix_len, size_t);
     892                 :       
     893           10904 :       req->conf_flags = HTTPD_CONF_REQ_FLAGS_PARSE_FILE_UERR;
     894           10904 :       conf_ret = http__conf_req(con, req, CLEN(".html"));
     895                 :       
     896           10904 :       SWAP_TYPE(fname, req->fname, Vstr_base *);
     897           10904 :       SWAP_TYPE(vhost_prefix_len, req->vhost_prefix_len, size_t);
     898                 : 
     899           10904 :       ncode = req->error_code;
     900           10904 :       switch (code)
     901                 :       { /* restore default error info. in case of failure */
     902            2728 :         case 400: HTTPD_ERR(req, 400); break;
     903             640 :         case 401: HTTPD_ERR(req, 401); break;
     904            2176 :         case 403: HTTPD_ERR(req, 403); break;
     905            1680 :         case 404: HTTPD_ERR(req, 404); break;
     906              96 :         case 405: HTTPD_ERR(req, 405); break;
     907            1120 :         case 406: HTTPD_ERR(req, 406); break;
     908             224 :         case 410: HTTPD_ERR(req, 410); break;
     909             288 :         case 411: HTTPD_ERR(req, 411); break;
     910             832 :         case 412: HTTPD_ERR(req, 412); break;
     911              96 :         case 413: HTTPD_ERR(req, 413); break;
     912               0 :         case 414: HTTPD_ERR(req, 414); break;
     913               0 :         case 415: HTTPD_ERR(req, 415); break;
     914             192 :         case 416: HTTPD_ERR(req, 416); break;
     915              96 :         case 417: HTTPD_ERR(req, 417); break;
     916              32 :         case 500: HTTPD_ERR(req, 500); break;
     917             512 :         case 501: HTTPD_ERR(req, 501); break;
     918              96 :         case 503: HTTPD_ERR(req, 503); break;
     919              96 :         case 505: HTTPD_ERR(req, 505);
     920              48 :           ASSERT_NO_SWITCH_DEF();
     921                 :       }
     922           10904 :       req->error_xmsg = xmsg; /* restore xmsg too */
     923                 : 
     924           10904 :       if (!conf_ret)
     925               0 :         goto fail_custom_err;
     926           10904 :       if (ncode)
     927               0 :         goto fail_custom_err; /* don't allow remapping errors -- loops */
     928                 :     }
     929           11064 :     fname_cstr = vstr_export_cstr_ptr(fname, 1, fname->len);
     930                 :     
     931           11064 :     if (fname->conf->malloc_bad)
     932               0 :       goto fail_custom_err;
     933                 : 
     934           11064 :     if (req->policy->use_noatime)
     935               0 :       open_flags |= O_NOATIME;
     936                 :     
     937            5532 :     ASSERT(con->fs && (con->fs->fd == -1));
     938           11064 :     if ((con->fs->fd = io__open(fname_cstr, open_flags)) == -1)
     939            9048 :       goto fail_custom_err;
     940                 : 
     941            3024 :     if (fstat64(con->fs->fd, f_stat) == -1)
     942               0 :       goto fail_custom_err;
     943            2016 :     if (req->policy->use_public_only && !(f_stat->st_mode & S_IROTH))
     944               0 :       goto fail_custom_err;
     945            2016 :     if (!S_ISREG(f_stat->st_mode))
     946               0 :       goto fail_custom_err;
     947                 : 
     948            2016 :     con->fs_off  = 0;
     949            2016 :     con->fs_num  = 0;
     950            2016 :     con->fs->len = f_stat->st_size;
     951            2016 :     req->fs_len  = 0;
     952                 :     
     953            2016 :     if (!req->ver_0_9)
     954            2016 :       httpd_parse_sc_try_fd_encoding(con, req, f_stat, &f_stat->st_size, fname);
     955                 : 
     956                 :     /* FIXME: gzipped error documents weren't tested for */
     957            2016 :     httpd_serv_file_sects_none(con, req, f_stat->st_size);
     958                 :     
     959            2016 :     con->use_mmap = FALSE;
     960                 :     
     961            2016 :     if (!req->head_op)
     962            1760 :       httpd_serv_call_mmap(con, req, con->fs);
     963                 : 
     964            2016 :     req->error_len = http_serv_file_len(con, req);
     965            2016 :     cust_err_msg = TRUE;
     966                 :     
     967           11064 :    fail_custom_err:
     968           11064 :     if (!cust_err_msg)
     969            9048 :       httpd_fin_fd_close(con);
     970           11064 :     fname->conf->malloc_bad = FALSE;
     971           11064 :     vstr_free_base(fname);
     972                 :   }
     973                 : 
     974           18134 :   if (!cust_err_msg)
     975                 :   {
     976           16118 :     req->content_type_vs1 = NULL;
     977           16118 :     req->content_type_pos = 0;
     978           16118 :     req->content_type_len = 0;
     979                 :   }
     980                 :   
     981                 :   /* HEAD op might seem normal, but again HTTP asks that GET and HEAD
     982                 :      produce identical headers */
     983           18134 :   if (!req->policy->use_text_redirect)
     984           17110 :     switch (req->error_code)
     985                 :     { /* make sure browsers don't allow XSS */
     986                 :       case 301:
     987                 :       {
     988            1920 :         unsigned int repl = http__safe_html_url(req->fname);
     989                 :         
     990             960 :         ASSERT((req->error_len + (repl * 2)) == CONF_MSG_LEN_301(req->fname));
     991                 :           
     992            1920 :         req->error_len = CONF_MSG_LEN_301(req->fname);
     993                 :       }
     994            1920 :       break;
     995                 :       
     996                 :       case 302:
     997                 :       {
     998             256 :         unsigned int repl = http__safe_html_url(req->fname);
     999                 :         
    1000             128 :         ASSERT((req->error_len + (repl * 2)) == CONF_MSG_LEN_302(req->fname));
    1001                 :           
    1002             256 :         req->error_len = CONF_MSG_LEN_302(req->fname);
    1003                 :       }
    1004             256 :       break;
    1005                 :       
    1006                 :       case 303:
    1007                 :       {
    1008             256 :         unsigned int repl = http__safe_html_url(req->fname);
    1009                 :         
    1010             128 :         ASSERT((req->error_len + (repl * 2)) == CONF_MSG_LEN_303(req->fname));
    1011                 :           
    1012             256 :         req->error_len = CONF_MSG_LEN_303(req->fname);
    1013                 :       }
    1014             256 :       break;
    1015                 :       
    1016                 :       case 307:
    1017                 :       {
    1018             384 :         unsigned int repl = http__safe_html_url(req->fname);
    1019                 :         
    1020             192 :         ASSERT((req->error_len + (repl * 2)) == CONF_MSG_LEN_307(req->fname));
    1021                 :           
    1022             384 :         req->error_len = CONF_MSG_LEN_307(req->fname);
    1023                 :       }
    1024                 :       break;      
    1025                 :     }
    1026                 : 
    1027           18134 :   if (!req->ver_0_9)
    1028                 :   { /* use_range is dealt with inside */
    1029           17654 :     const char *content_type = "text/html";
    1030                 :     
    1031           17654 :     switch (req->error_code)
    1032                 :     {
    1033                 :       case 301: case 302: case 303: case 307:
    1034            3648 :         if (req->policy->use_text_redirect)
    1035             832 :           content_type = "text/plain";
    1036                 :         else /* make sure browsers don't allow XSS */
    1037            2816 :           http__safe_html_url(req->fname);
    1038                 :     }
    1039                 : 
    1040           17654 :     http_app_def_hdrs(con, req, req->error_code, req->error_line,
    1041                 :                       httpd_opts->beg_time, content_type, TRUE, req->error_len);
    1042                 :     
    1043           17654 :     if (req->error_code == 416)
    1044             288 :       http_app_hdr_fmt(out, "Content-Range", "%s */%ju", "bytes",
    1045                 :                           (uintmax_t)req->f_stat_st_size);
    1046                 : 
    1047           17654 :     if (req->error_code == 401)
    1048             640 :       http_app_hdr_fmt(out, "WWW-Authenticate",
    1049                 :                        "Basic realm=\"$<vstr.all:%p>\"",
    1050                 :                        req->policy->auth_realm);
    1051                 :     
    1052           17654 :     if ((req->error_code == 405) || (req->error_code == 501))
    1053             576 :       HTTP_APP_HDR_CONST_CSTR(out, "Allow", "GET, HEAD, OPTIONS, TRACE");
    1054                 :     
    1055           17654 :     switch (req->error_code)
    1056                 :     {
    1057                 :       case 301: case 302: case 303: case 307:
    1058                 :       { /* make sure we haven't screwed up and allowed response splitting */
    1059            3648 :         Vstr_base *loc = req->fname;
    1060                 :         
    1061            3648 :         http_app_hdr_vstr(out, "Location",
    1062                 :                           loc, 1, loc->len, VSTR_TYPE_ADD_ALL_BUF);
    1063                 :       }
    1064                 :     }
    1065                 :     
    1066           17654 :     if (req->user_return_error_code || cust_err_msg)
    1067            6144 :       http_app_hdrs_url(con, req);
    1068           17654 :     if (cust_err_msg)
    1069            2016 :       http_app_hdrs_file(con, req);
    1070                 :     
    1071           17654 :     http_app_end_hdrs(out);
    1072                 :   }
    1073                 : 
    1074           18134 :   if (!deleted_req_data)
    1075           18134 :     http__err_vlg_msg(con, req);
    1076                 :   
    1077           18134 :   if (cust_err_msg)
    1078                 :   {
    1079            2016 :     if (con->use_mmap && !vstr_mov(con->evnt->io_w, con->evnt->io_w->len,
    1080                 :                                    req->f_mmap, 1, req->f_mmap->len))
    1081               0 :       return (http_con_close_cleanup(con, req));
    1082                 :     
    1083            2016 :     vlg_dbg3(vlg, "ERROR CUSTOM-ERR REPLY:\n$<vstr.all:%p>\n", out);
    1084                 :     
    1085            2016 :     if (out->conf->malloc_bad)
    1086               0 :       return (http_con_close_cleanup(con, req));
    1087                 :     
    1088            2016 :     return (http_fin_fd_req(con, req));
    1089                 :   }
    1090                 :   
    1091           16118 :   if (!req->head_op)
    1092                 :   { /* default internal error message */
    1093            9934 :     Vstr_base *loc = req->fname;
    1094                 : 
    1095            9934 :     switch (req->error_code)
    1096                 :     {
    1097                 :       case 301:
    1098            1392 :         if (!req->policy->use_text_redirect)
    1099                 :         {
    1100             472 :           ASSERT(req->error_len == CONF_MSG_LEN_301(loc));
    1101             944 :           vstr_add_fmt(out, out->len, CONF_MSG_FMT_301,
    1102                 :                        CONF_MSG__FMT_301_BEG,
    1103                 :                        loc, (size_t)1, loc->len, VSTR_TYPE_ADD_ALL_BUF,
    1104                 :                        CONF_MSG__FMT_30x_END);
    1105             944 :           break;
    1106                 :         }
    1107                 :       case 302:
    1108             448 :         if (!req->policy->use_text_redirect)
    1109                 :         {
    1110               0 :           ASSERT(req->error_len == CONF_MSG_LEN_302(loc));
    1111               0 :           vstr_add_fmt(out, out->len, CONF_MSG_FMT_302,
    1112                 :                        CONF_MSG__FMT_302_BEG,
    1113                 :                        loc, (size_t)1, loc->len, VSTR_TYPE_ADD_ALL_BUF,
    1114                 :                        CONF_MSG__FMT_30x_END);
    1115               0 :           break;
    1116                 :         }
    1117                 :       case 303:
    1118             448 :         if (!req->policy->use_text_redirect)
    1119                 :         {
    1120               0 :           ASSERT(req->error_len == CONF_MSG_LEN_303(loc));
    1121               0 :           vstr_add_fmt(out, out->len, CONF_MSG_FMT_303,
    1122                 :                        CONF_MSG__FMT_303_BEG,
    1123                 :                        loc, (size_t)1, loc->len, VSTR_TYPE_ADD_ALL_BUF,
    1124                 :                        CONF_MSG__FMT_30x_END);
    1125               0 :           break;
    1126                 :         }
    1127                 :       case 307:
    1128             448 :         if (!req->policy->use_text_redirect)
    1129                 :         {
    1130               0 :           ASSERT(req->error_len == CONF_MSG_LEN_307(loc));
    1131               0 :           vstr_add_fmt(out, out->len, CONF_MSG_FMT_307,
    1132                 :                        CONF_MSG__FMT_307_BEG,
    1133                 :                        loc, (size_t)1, loc->len, VSTR_TYPE_ADD_ALL_BUF,
    1134                 :                        CONF_MSG__FMT_30x_END);
    1135               0 :           break;
    1136                 :         }
    1137                 : 
    1138                 :         /* if using text/plain just output the URL */
    1139             224 :         ASSERT((req->error_len - 1) == loc->len);
    1140             448 :         vstr_add_vstr(out, out->len,
    1141                 :                       loc, (size_t)1, loc->len, VSTR_TYPE_ADD_ALL_BUF);
    1142             448 :         vstr_add_cstr_ptr(out, out->len, "\n");
    1143             448 :         break;
    1144                 :         
    1145                 :       default:
    1146            4271 :         assert(req->error_len < SIZE_MAX);
    1147            8542 :         vstr_add_ptr(out, out->len, req->error_msg, req->error_len);
    1148                 :     }
    1149                 :   }
    1150                 :   
    1151           16118 :   vlg_dbg3(vlg, "ERROR REPLY:\n$<vstr.all:%p>\n", out);
    1152                 : 
    1153           16118 :   if (out->conf->malloc_bad)
    1154               0 :     return (http_con_cleanup(con, req));
    1155                 :   
    1156           16118 :   return (http_fin_req(con, req));
    1157                 : }
    1158                 : 
    1159                 : int http_fin_errmem_req(struct Con *con, struct Httpd_req_data *req)
    1160               0 : { /* try sending a 500 as the last msg */
    1161               0 :   Vstr_base *out = con->evnt->io_w;
    1162                 :   
    1163                 :   /* remove anything we can to free space */
    1164               0 :   vstr_sc_reduce(out, 1, out->len, out->len - req->orig_io_w_len);
    1165                 :   
    1166               0 :   con->evnt->io_r->conf->malloc_bad = FALSE;
    1167               0 :   con->evnt->io_w->conf->malloc_bad = FALSE;
    1168               0 :   req->malloc_bad = TRUE;
    1169                 :   
    1170               0 :   HTTPD_ERR_MSG_RET(req, 500, "Memory failure", http_fin_err_req(con, req));
    1171                 : }
    1172                 : 
    1173                 : static int http_fin_err_close_req(struct Con *con, Httpd_req_data *req)
    1174            1792 : {
    1175            1792 :   httpd_fin_fd_close(con);
    1176            1792 :   return (http_fin_err_req(con, req));
    1177                 : }
    1178                 : 
    1179                 : int httpd_sc_add_default_hostname(struct Con *con,
    1180                 :                                   Httpd_req_data *req,
    1181                 :                                   Vstr_base *lfn, size_t pos)
    1182           18080 : {
    1183           18080 :   const Httpd_policy_opts *opts = req->policy;
    1184           18080 :   const Vstr_base *d_h = opts->default_hostname;
    1185           18080 :   int ret = FALSE;
    1186                 :   
    1187           18080 :   ret = vstr_add_vstr(lfn, pos, d_h, 1, d_h->len, VSTR_TYPE_ADD_DEF);
    1188                 : 
    1189           18080 :   if (ret && req->policy->add_def_port)
    1190                 :   { /* FIXME: ipv6 */
    1191               0 :     struct sockaddr_in *sinv4 = EVNT_ACPT_SA_IN4(con->evnt);
    1192                 : 
    1193               0 :     ASSERT(sinv4->sin_family == AF_INET);
    1194                 : 
    1195               0 :     if (ntohs(sinv4->sin_port) != 80)
    1196               0 :       ret = vstr_add_fmt(lfn, pos + d_h->len, ":%hu", ntohs(sinv4->sin_port));
    1197                 :   }
    1198                 : 
    1199           18080 :   return (ret);
    1200                 : }
    1201                 : 
    1202                 : int httpd_sc_add_req_hostname(struct Con *con, Httpd_req_data *req,
    1203                 :                               Vstr_base *s1, size_t pos)
    1204           28832 : {
    1205           28832 :   Vstr_base *http_data = con->evnt->io_r;
    1206           28832 :   Vstr_sect_node *h_h = req->http_hdrs->hdr_host;
    1207                 :   
    1208           14416 :   ASSERT(h_h->len);
    1209                 : 
    1210           28832 :   if (vstr_add_vstr(s1, pos, http_data, h_h->pos, h_h->len, VSTR_TYPE_ADD_DEF))
    1211                 :   {
    1212           28832 :     if (req->http_host_port != 80) /* if port 80, ignore it */
    1213            1776 :       vstr_add_sysfmt(s1, pos + h_h->len, ":%hu", req->http_host_port);
    1214           28832 :     vstr_conv_lowercase(s1, pos + 1, h_h->len);
    1215                 :   }
    1216                 : 
    1217           28832 :   return (!!s1->conf->malloc_bad);
    1218                 : }
    1219                 : 
    1220                 : int httpd_sc_add_hostname(struct Con *con, Httpd_req_data *req,
    1221                 :                           Vstr_base *s1, size_t pos)
    1222           46864 : {
    1223           46864 :   if (req->http_hdrs->hdr_host->len)
    1224           28832 :     return (httpd_sc_add_req_hostname(con, req, s1, pos));
    1225                 : 
    1226           18032 :   return (httpd_sc_add_default_hostname(con, req, s1, pos));
    1227                 : }
    1228                 : 
    1229                 : 
    1230                 : static void httpd_sc_add_default_filename(Httpd_req_data *req, Vstr_base *fname)
    1231           27873 : {
    1232           27873 :   if (vstr_export_chr(fname, fname->len) == '/')
    1233           17648 :     HTTPD_APP_REF_ALLVSTR(fname, req->policy->dir_filename);
    1234           27873 : }                                  
    1235                 : 
    1236                 : /* turn //foo//bar// into /foo/bar/ */
    1237                 : int httpd_canon_path(Vstr_base *s1)
    1238             606 : {
    1239             606 :   size_t tmp = 0;
    1240                 :   
    1241            1500 :   while ((tmp = vstr_srch_cstr_buf_fwd(s1, 1, s1->len, "//")))
    1242                 :   {
    1243             288 :     if (!vstr_del(s1, tmp, 1))
    1244               0 :       return (FALSE);
    1245                 :   }
    1246                 : 
    1247             606 :   return (TRUE);
    1248                 : }
    1249                 : 
    1250                 : int httpd_canon_dir_path(Vstr_base *s1)
    1251             414 : {
    1252             414 :   if (!httpd_canon_path(s1))
    1253               0 :     return (FALSE);
    1254                 : 
    1255             414 :   if (s1->len && (vstr_export_chr(s1, s1->len) != '/'))
    1256             256 :     return (vstr_add_cstr_ptr(s1, s1->len, "/"));
    1257                 : 
    1258             158 :   return (TRUE);
    1259                 : }
    1260                 : 
    1261                 : int httpd_canon_abs_dir_path(Vstr_base *s1)
    1262               0 : {
    1263               0 :   if (!httpd_canon_dir_path(s1))
    1264               0 :     return (FALSE);
    1265                 : 
    1266               0 :   if (s1->len && (vstr_export_chr(s1, 1) != '/'))
    1267               0 :     return (vstr_add_cstr_ptr(s1, 0, "/"));
    1268                 :   
    1269               0 :   return (TRUE);
    1270                 : }
    1271                 :   
    1272                 : 
    1273                 : static int http__policy_req(struct Con *con, Httpd_req_data *req)
    1274           31841 : {
    1275           31841 :   if (!httpd_policy_request(con, req,
    1276                 :                             httpd_opts->conf, httpd_opts->match_request))
    1277                 :   {
    1278            3296 :     Vstr_base *s1 = httpd_opts->conf->tmp;
    1279            3296 :     if (!req->user_return_error_code)
    1280              64 :       vlg_info(vlg, "CONF-MATCH-REQ-ERR from[$<sa:%p>]:"
    1281                 :                " backtrace: $<vstr.all:%p>\n", CON_CEVNT_SA(con), s1);
    1282            3296 :     return (TRUE);
    1283                 :   }
    1284                 :   
    1285           28545 :   if (con->evnt->flag_q_closed)
    1286                 :   {
    1287              32 :     Vstr_base *s1 = req->policy->s->policy_name;
    1288                 :     
    1289              32 :     vlg_info(vlg, "BLOCKED from[$<sa:%p>]: policy $<vstr.all:%p>\n",
    1290                 :              CON_CEVNT_SA(con), s1);
    1291              32 :     return (http_con_cleanup(con, req));
    1292                 :   }
    1293                 : 
    1294           28513 :   if (req->direct_uri)
    1295                 :   {
    1296               0 :     Vstr_base *s1 = req->policy->s->policy_name;
    1297               0 :     vlg_info(vlg, "CONF-MATCH-REQ-ERR from[$<sa:%p>]: policy $<vstr.all:%p>"
    1298                 :              " Has URI.\n", CON_CEVNT_SA(con), s1);
    1299               0 :     HTTPD_ERR_MSG_RET(req, 503, "Has URI", TRUE);
    1300                 :   }
    1301                 :   
    1302           28513 :   if (req->policy->auth_token->len) /* they need rfc2617 auth */
    1303                 :   {
    1304            1184 :     Vstr_base *data = con->evnt->io_r;
    1305            1184 :     size_t pos = req->http_hdrs->hdr_authorization->pos;
    1306            1184 :     size_t len = req->http_hdrs->hdr_authorization->len;
    1307            1184 :     Vstr_base *auth_token = req->policy->auth_token;
    1308            1184 :     int auth_ok = TRUE;
    1309                 :     
    1310            1600 :     if (!VIPREFIX(data, pos, len, "Basic"))
    1311             416 :       auth_ok = FALSE;
    1312                 :     else
    1313                 :     {
    1314             768 :       len -= CLEN("Basic"); pos += CLEN("Basic");
    1315             768 :       HTTP_SKIP_LWS(data, pos, len);
    1316             768 :       if (!vstr_cmp_eq(data, pos, len, auth_token, 1, auth_token->len))
    1317             224 :         auth_ok = FALSE;
    1318                 :     }
    1319                 :     
    1320            1184 :     if (!auth_ok)
    1321                 :     {
    1322             640 :       req->user_return_error_code = FALSE;
    1323             640 :       HTTPD_ERR(req, 401);
    1324                 :     }
    1325                 :   }
    1326                 :   
    1327           28513 :   return (TRUE);
    1328                 : }
    1329                 : 
    1330                 : int http_req_op_get(struct Con *con, Httpd_req_data *req)
    1331           32033 : { /* GET or HEAD ops */
    1332           32033 :   Vstr_base *data = con->evnt->io_r;
    1333           32033 :   Vstr_base *out  = con->evnt->io_w;
    1334           32033 :   Vstr_base *fname = req->fname;
    1335           32033 :   const char *fname_cstr = NULL;
    1336           32033 :   unsigned int http_ret_code = 200;
    1337           32033 :   const char * http_ret_line = "OK";
    1338           32033 :   int open_flags = O_NONBLOCK;
    1339           32033 :   uintmax_t resp_len = 0;
    1340                 :   
    1341           32033 :   if (fname->conf->malloc_bad)
    1342               0 :     goto malloc_err;
    1343                 : 
    1344           16024 :   assert(VPREFIX(fname, 1, fname->len, "/"));
    1345                 : 
    1346                 :   /* final act of vengance, before policy */
    1347           32033 :   if (vstr_srch_cstr_buf_fwd(data, req->path_pos, req->path_len, "//"))
    1348                 :   { /* in theory we can skip this if there is no policy */
    1349             192 :     vstr_sub_vstr(fname, 1, fname->len, data, req->path_pos, req->path_len, 0);
    1350             192 :     if (!httpd_canon_path(fname))
    1351               0 :       goto malloc_err;
    1352             192 :     httpd_req_absolute_uri(con, req, fname, 1, fname->len);
    1353             192 :     HTTPD_REDIR_MSG(req, 301, "Path contains //");
    1354                 :   
    1355             192 :     return (http_fin_err_req(con, req));
    1356                 :   }
    1357                 :   
    1358           31841 :   if (!http__policy_req(con, req))
    1359              32 :     return (FALSE);
    1360           31809 :   if (req->error_code)
    1361            3936 :     return (http_fin_err_req(con, req));
    1362                 : 
    1363           27873 :   httpd_sc_add_default_filename(req, fname);
    1364                 :   
    1365           27873 :   req->conf_flags = HTTPD_CONF_REQ_FLAGS_PARSE_FILE_DEFAULT;
    1366           27873 :   if (!http__conf_req(con, req, 0))
    1367               0 :     return (FALSE);
    1368           27873 :   if (req->error_code)
    1369             224 :     return (http_fin_err_req(con, req));
    1370                 :   
    1371                 :   /* Add the document root now, this must be at least . so
    1372                 :    * "///foo" becomes ".///foo" ... this is done now
    1373                 :    * so nothing has to deal with document_root values */
    1374           27649 :   if (!req->skip_document_root)
    1375           27585 :     http_prepend_doc_root(fname, req);
    1376                 :   
    1377           27649 :   fname_cstr = vstr_export_cstr_ptr(fname, 1, fname->len);
    1378                 :   
    1379           27649 :   if (fname->conf->malloc_bad)
    1380               0 :     goto malloc_err;
    1381                 : 
    1382           27649 :   if (!http_req_content_type(req))
    1383             384 :     return (http_fin_err_req(con, req));
    1384                 :   
    1385                 :   /* don't change vary_a/vary_al just because of 406 */
    1386           27265 :   if (req->parse_accept)
    1387                 :   {
    1388           22016 :     if (!http_parse_accept(req, HTTP__XTRA_HDR_PARAMS(req, content_type)))
    1389            1168 :       HTTPD_ERR_MSG_RET(req, 406, "Type", http_fin_err_req(con, req));
    1390                 :   }
    1391           26097 :   if (!req->content_language_vs1 || !req->content_language_len)
    1392           24785 :     req->parse_accept_language = FALSE;
    1393           26097 :   if (req->parse_accept_language)
    1394                 :   {
    1395               0 :     if (!http_parse_accept_language(req,
    1396                 :                                     HTTP__XTRA_HDR_PARAMS(req,
    1397                 :                                                           content_language)))
    1398               0 :       HTTPD_ERR_MSG_RET(req, 406, "Language", http_fin_err_req(con, req));
    1399                 :   }
    1400                 :   
    1401           26097 :   if (req->policy->use_noatime)
    1402               0 :     open_flags |= O_NOATIME;
    1403                 :   
    1404           13056 :   ASSERT(con->fs && !con->fs_num && !con->fs_off && (con->fs->fd == -1));
    1405           26097 :   if ((con->fs->fd = io__open(fname_cstr, open_flags)) == -1)
    1406                 :   {
    1407                 :     if (0) { }
    1408            2472 :     else if (req->direct_filename && (errno == EISDIR)) /* don't allow */
    1409               0 :       HTTPD_ERR_MSG(req, 404, "Direct filename is DIR");
    1410            2472 :     else if (errno == EISDIR)
    1411               0 :       return (http_req_chk_dir(con, req, "open(EISDIR)"));
    1412            2472 :     else if (req->conf_friendly_file && (errno == ENOENT))
    1413              32 :       return (http_req_chk_dir(con, req, "open(ENOENT)"));
    1414            2440 :     else if (req->conf_friendly_file &&
    1415                 :              (errno == ENOTDIR)) /* part of path was not a dir */
    1416               0 :       return (http_req_chk_dir(con, req, "open(ENOTDIR)"));
    1417            2440 :     else if (req->conf_friendly_file && (errno == ENAMETOOLONG)) /* 414 ? */
    1418               0 :       return (http_req_chk_dir(con, req, "open(ENAMETOOLONG)"));
    1419            2440 :     else if ((errno == ENOENT) && req->conf_friendly_dirs)
    1420               0 :       return (http_req_chk_file(con, req, "open(ENOENT)"));
    1421            2440 :     else if (errno == ENOTDIR) /* part of path was not a dir */
    1422              64 :       return (http_req_chk_file(con, req, "open(ENOTDIR)"));
    1423            2376 :     else if (errno == ENAMETOOLONG) /* 414 ? */
    1424               0 :       return (http_req_chk_file(con, req, "open(ENAMETOOLONG)"));
    1425            2376 :     else if (errno == EACCES)
    1426             144 :       HTTPD_ERR_MSG(req, 403, "open(EACCES)");
    1427            2232 :     else if (errno == ENOENT)
    1428            2232 :       HTTPD_ERR_MSG(req, 404, "open(ENOENT)");
    1429               0 :     else if (errno == ENODEV) /* device file, with no driver */
    1430               0 :       HTTPD_ERR_MSG(req, 404, "open(ENODEV)");
    1431               0 :     else if (errno == ENXIO) /* device file, with no driver */
    1432               0 :       HTTPD_ERR_MSG(req, 404, "open(ENXIO)");
    1433               0 :     else if (errno == ELOOP) /* symlinks */
    1434               0 :       HTTPD_ERR_MSG(req, 404, "open(ELOOP)");
    1435               0 :     else if (errno == EMFILE) /* can't create fd ... just close */
    1436               0 :       return (http_con_cleanup(con, req));
    1437                 :     else
    1438                 :     {
    1439               0 :       vlg_warn(vlg, "open(%s): %m\n", fname_cstr);
    1440               0 :       HTTPD_ERR_MSG(req, 500, "open()");
    1441                 :     }
    1442                 :     
    1443            2376 :     return (http_fin_err_req(con, req));
    1444                 :   }
    1445           23625 :   if (fstat64(con->fs->fd, req->f_stat) == -1)
    1446               0 :     HTTPD_ERR_MSG_RET(req, 500, "fstat()", http_fin_err_close_req(con, req));
    1447           23625 :   req->f_stat_st_size = req->f_stat->st_size;
    1448           23625 :   if (req->policy->use_public_only && !(req->f_stat->st_mode & S_IROTH))
    1449              48 :     HTTPD_ERR_MSG_RET(req, 403, "Filename is not PUBLIC",
    1450                 :                       http_fin_err_close_req(con, req));
    1451                 :   
    1452           23577 :   if (S_ISDIR(req->f_stat->st_mode))
    1453                 :   {
    1454             576 :     if (req->direct_filename) /* don't allow */
    1455               0 :       HTTPD_ERR_MSG_RET(req, 404, "Direct filename is DIR",
    1456                 :                         http_fin_err_close_req(con, req));
    1457             576 :     httpd_fin_fd_close(con);
    1458             576 :     return (http_req_chk_dir(con, req, "ISDIR"));
    1459                 :   }
    1460           23001 :   if (!S_ISREG(req->f_stat->st_mode))
    1461             144 :     HTTPD_ERR_MSG_RET(req, 403, "File not ISREG",
    1462                 :                       http_fin_err_close_req(con, req));
    1463                 : 
    1464           22857 :   con->fs->len = req->f_stat_st_size;
    1465                 :   
    1466           22857 :   if (req->ver_0_9)
    1467                 :   {
    1468             192 :     httpd_serv_file_sects_none(con, req, req->f_stat_st_size);
    1469             192 :     httpd_serv_call_file_init(con, req, &http_ret_code, &http_ret_line);
    1470             192 :     http_ret_line = "OK - HTTP/0.9";
    1471                 :   }
    1472           22665 :   else if (!http_req_1_x(con, req, &http_ret_code, &http_ret_line))
    1473            1600 :     return (http_fin_err_close_req(con, req));
    1474                 :   
    1475           21257 :   if (out->conf->malloc_bad)
    1476               0 :     goto malloc_close_err;
    1477                 :   
    1478           21257 :   vlg_dbg3(vlg, "REPLY:\n$<vstr.all:%p>\n", out);
    1479                 :   
    1480           21257 :   if (con->use_mmap && !vstr_mov(con->evnt->io_w, con->evnt->io_w->len,
    1481                 :                                  req->f_mmap, 1, req->f_mmap->len))
    1482               0 :     goto malloc_close_err;
    1483                 : 
    1484                 :   /* req->head_op is set for 304 returns */
    1485           21257 :   resp_len = http_serv_file_len(con, req);
    1486           21257 :   vlg_info(vlg, "REQ $<vstr.sect:%p%p%u> from[$<sa:%p>] ret[%03u %s]"
    1487                 :            " sz[${BKMG.ju:%ju}:%ju]", data, req->sects, 1U, CON_CEVNT_SA(con),
    1488                 :            http_ret_code, http_ret_line, resp_len, resp_len);
    1489           21257 :   http_vlg_def(con, req, FALSE);
    1490                 :   
    1491           21257 :   return (http_fin_fd_req(con, req));
    1492                 :   
    1493               0 :  malloc_close_err:
    1494               0 :   httpd_fin_fd_close(con);
    1495               0 :  malloc_err:
    1496               0 :   VLG_WARNNOMEM_RET(http_fin_errmem_req(con, req), (vlg, "op_get(): %m\n"));
    1497                 : }
    1498                 : 
    1499                 : int http_req_op_opts(struct Con *con, Httpd_req_data *req)
    1500             528 : {
    1501             528 :   Vstr_base *out = con->evnt->io_w;
    1502             528 :   Vstr_base *fname = req->fname;
    1503             528 :   uintmax_t tmp = 0;
    1504                 : 
    1505             528 :   if (fname->conf->malloc_bad)
    1506               0 :     goto malloc_err;
    1507                 :   
    1508             264 :   assert(VPREFIX(fname, 1, fname->len, "/") ||
    1509                 :          !req->policy->use_vhosts_name ||
    1510                 :          !req->policy->use_host_chk ||
    1511                 :          !req->policy->use_host_err_400 ||
    1512                 :          VEQ(con->evnt->io_r, req->path_pos, req->path_len, "*"));
    1513                 :   
    1514                 :   /* apache doesn't test for 404's here ... which seems weird */
    1515                 :   
    1516             528 :   http_app_def_hdrs(con, req, 200, "OK", 0, NULL, TRUE, 0);
    1517             528 :   HTTP_APP_HDR_CONST_CSTR(out, "Allow", "GET, HEAD, OPTIONS, TRACE");
    1518             528 :   http_app_end_hdrs(out);
    1519             528 :   if (out->conf->malloc_bad)
    1520               0 :     goto malloc_err;
    1521                 :   
    1522             528 :   vlg_info(vlg, "REQ %s from[$<sa:%p>] ret[%03u %s] sz[${BKMG.ju:%ju}:%ju]",
    1523                 :            "OPTIONS", CON_CEVNT_SA(con), 200, "OK", tmp, tmp);
    1524             528 :   http_vlg_def(con, req, FALSE);
    1525                 :   
    1526             528 :   return (http_fin_req(con, req));
    1527                 :   
    1528               0 :  malloc_err:
    1529               0 :   VLG_WARNNOMEM_RET(http_fin_errmem_req(con, req), (vlg, "op_opts(): %m\n"));
    1530                 : }
    1531                 : 
    1532                 : int http_req_op_trace(struct Con *con, Httpd_req_data *req)
    1533             312 : {
    1534             312 :   Vstr_base *data = con->evnt->io_r;
    1535             312 :   Vstr_base *out  = con->evnt->io_w;
    1536             312 :   uintmax_t tmp = req->len;
    1537                 :   
    1538             312 :   http_app_def_hdrs(con, req, 200, "OK", req->now,
    1539                 :                     "message/http", FALSE, tmp);
    1540             312 :   http_app_end_hdrs(out);
    1541             312 :   vstr_add_vstr(out, out->len, data, 1, req->len, VSTR_TYPE_ADD_DEF);
    1542             312 :   if (out->conf->malloc_bad)
    1543               0 :     VLG_WARNNOMEM_RET(http_fin_errmem_req(con, req), (vlg, "op_trace(): %m\n"));
    1544                 : 
    1545             312 :   vlg_info(vlg, "REQ %s from[$<sa:%p>] ret[%03u %s] sz[${BKMG.ju:%ju}:%ju]",
    1546                 :            "TRACE", CON_CEVNT_SA(con), 200, "OK", tmp, tmp);
    1547             312 :   http_vlg_def(con, req, FALSE);
    1548                 :       
    1549             312 :   return (http_fin_req(con, req));
    1550                 : }
    1551                 : 
    1552                 : int httpd_init_default_hostname(Opt_serv_policy_opts *sopts)
    1553             178 : {
    1554             178 :   Httpd_policy_opts *popts = (Httpd_policy_opts *)sopts;
    1555             178 :   Vstr_base *nhn = popts->default_hostname;
    1556             178 :   Vstr_base *chn = NULL;
    1557                 :   
    1558             178 :   if (!httpd__valid_hostname(nhn, 1, nhn->len, FALSE))
    1559               0 :     vstr_del(nhn, 1, nhn->len);
    1560                 : 
    1561             178 :   if (nhn->len)
    1562             142 :     return (TRUE);
    1563                 :   
    1564              36 :   if (sopts != sopts->beg->def_policy)
    1565               6 :     chn = ((Httpd_policy_opts *)sopts->beg->def_policy)->default_hostname;
    1566                 :   
    1567              36 :   if (chn)
    1568               6 :     HTTPD_APP_REF_ALLVSTR(nhn, chn);
    1569                 :   else
    1570                 :   {
    1571              30 :     opt_serv_sc_append_hostname(nhn, 0);
    1572              30 :     vstr_conv_lowercase(nhn, 1, nhn->len);
    1573                 :   }
    1574                 : 
    1575              36 :   return (!nhn->conf->malloc_bad);
    1576                 : }
    1577                 : 
    1578                 : static int httpd__serv_send_err(struct Con *con, const char *msg)
    1579               0 : {
    1580               0 :   if (errno != EPIPE)
    1581               0 :     vlg_warn(vlg, "send(%s): %m\n", msg);
    1582                 :   else
    1583               0 :     vlg_dbg2(vlg, "send(%s): SIGPIPE $<sa:%p>\n", msg, CON_CEVNT_SA(con));
    1584                 : 
    1585               0 :   return (FALSE);
    1586                 : }
    1587                 : 
    1588                 : static int httpd_serv_q_send(struct Con *con)
    1589        17787532 : {
    1590        17787532 :   vlg_dbg2(vlg, "http Q send $<sa:%p>\n", CON_CEVNT_SA(con));
    1591        17787532 :   if (!evnt_send_add(con->evnt, TRUE, HTTPD_CONF_MAX_WAIT_SEND))
    1592               0 :     return (httpd__serv_send_err(con, "Q"));
    1593                 :       
    1594                 :   /* queued */
    1595        17787532 :   return (TRUE);
    1596                 : }
    1597                 : 
    1598                 : static int httpd__serv_fin_send(struct Con *con)
    1599           39559 : {
    1600           39559 :   if (con->keep_alive)
    1601                 :     /* need to try immediately, as we might have already got the next req */
    1602           27602 :     return (http_parse_req(con));
    1603                 : 
    1604           11957 :   return (evnt_shutdown_w(con->evnt));
    1605                 : }
    1606                 : 
    1607                 : /* NOTE: lim is just a hint ... we can send more */
    1608                 : static int httpd__serv_send_lim(struct Con *con, const char *emsg,
    1609                 :                                 unsigned int lim, int *cont)
    1610        17840982 : {
    1611        17840982 :   Vstr_base *out = con->evnt->io_w;
    1612                 :   
    1613        17840982 :   *cont = FALSE;
    1614                 :   
    1615        47467851 :   while (out->len >= lim)
    1616                 :   {
    1617        23555725 :     if (!con->io_limit_num--) return (httpd_serv_q_send(con));
    1618                 :     
    1619        11785887 :     if (!evnt_send(con->evnt))
    1620               0 :       return (httpd__serv_send_err(con, emsg));
    1621                 :   }
    1622                 : 
    1623         6071144 :   *cont = TRUE;
    1624         6071144 :   return (TRUE);
    1625                 : }
    1626                 : 
    1627                 : int httpd_serv_send(struct Con *con)
    1628        17838664 : {
    1629        17838664 :   Vstr_base *out = con->evnt->io_w;
    1630        17838664 :   int cont = FALSE;
    1631        17838664 :   int ret = FALSE;
    1632        17838664 :   struct File_sect *fs = NULL;
    1633                 :   
    1634         3722343 :   ASSERT(!out->conf->malloc_bad);
    1635                 :     
    1636        17838664 :   if (!con->fs_num)
    1637                 :   {
    1638         1928817 :     ASSERT(!con->fs_off);
    1639                 :     
    1640        11525516 :     ret = httpd__serv_send_lim(con, "end", 1, &cont);
    1641        11525516 :     if (!cont)
    1642        11485957 :       return (ret);
    1643                 :     
    1644           39559 :     return (httpd__serv_fin_send(con));
    1645                 :   }
    1646                 : 
    1647         1793526 :   ASSERT(con->fs && (con->fs_off < con->fs_num) && (con->fs_num <= con->fs_sz));
    1648         6313148 :   fs = &con->fs[con->fs_off];
    1649         1793526 :   ASSERT((fs->fd != -1) && fs->len);
    1650                 :   
    1651         6313148 :   if (con->use_sendfile)
    1652                 :   {
    1653         6030501 :     unsigned int ern = 0;
    1654                 : 
    1655         6030501 :     ret = httpd__serv_send_lim(con, "sendfile", 1, &cont);
    1656         6030501 :     if (!cont)
    1657            5362 :       return (ret);
    1658                 :     
    1659        16343619 :     while (fs->len)
    1660                 :     {
    1661        12041613 :       if (!con->io_limit_num--) return (httpd_serv_q_send(con));
    1662                 :       
    1663         6023919 :       if (!evnt_sendfile(con->evnt, fs->fd, &fs->off, &fs->len, &ern))
    1664                 :       {
    1665               3 :         if (ern == VSTR_TYPE_SC_READ_FD_ERR_EOF)
    1666               3 :           goto file_eof_end;
    1667                 :         
    1668               0 :         if (errno == EPIPE)
    1669                 :         {
    1670               0 :           vlg_dbg2(vlg, "sendfile: SIGPIPE $<sa:%p>\n", CON_CEVNT_SA(con));
    1671               0 :           return (FALSE);
    1672                 :         }
    1673                 : 
    1674               0 :         if (errno == ENOSYS)
    1675               0 :           httpd__disable_sendfile();
    1676               0 :         vlg_warn(vlg, "sendfile: %m\n");
    1677                 :         
    1678               0 :         if (lseek64(fs->fd, fs->off, SEEK_SET) == -1)
    1679               0 :           VLG_WARN_RET(FALSE,
    1680                 :                        (vlg, "lseek(<sendfile>,off=%ju): %m\n", fs->off));
    1681                 : 
    1682               0 :         con->use_sendfile = FALSE;
    1683               0 :         return (httpd_serv_send(con)); /* recurse */
    1684                 :       }
    1685                 :     }
    1686                 :     
    1687            3713 :     goto file_end;
    1688                 :   }
    1689                 : 
    1690          507351 :   while (fs->len)
    1691                 :   {
    1692          284965 :     ret = httpd__serv_send_lim(con, "max", EX_MAX_W_DATA_INCORE, &cont);
    1693          284965 :     if (!cont)
    1694          278519 :       return (ret);
    1695                 :     
    1696            6446 :     switch (evnt_sc_read_send(con->evnt, fs->fd, &fs->len))
    1697                 :     {
    1698                 :       case EVNT_IO_OK:
    1699            1155 :         ASSERT_NO_SWITCH_DEF();
    1700                 :         
    1701                 :       case EVNT_IO_READ_ERR:
    1702               0 :         vlg_warn(vlg, "read: %m\n");
    1703               0 :         out->conf->malloc_bad = FALSE;
    1704                 :         
    1705            2229 :       case EVNT_IO_READ_FIN: goto file_end;
    1706               1 :       case EVNT_IO_READ_EOF: goto file_eof_end;
    1707                 :         
    1708                 :       case EVNT_IO_SEND_ERR:
    1709               0 :         return (httpd__serv_send_err(con, "io_get"));
    1710                 :     }
    1711                 :   }
    1712                 : 
    1713               0 :   ASSERT_NOT_REACHED();
    1714                 : 
    1715           11568 :  file_end:
    1716            5626 :   ASSERT(!fs->len);
    1717           11568 :   if (con->use_mpbr) /* multipart/byterange */
    1718                 :   {
    1719             208 :     ASSERT(con->mpbr_ct);
    1720             208 :     ASSERT(con->mpbr_fs_len);
    1721                 : 
    1722             416 :     if (!(fs = httpd__fd_next(con)))
    1723                 :     {
    1724             128 :       vstr_add_cstr_ptr(out, out->len, "--SEP--" HTTP_EOL);
    1725             128 :       return (httpd_serv_send(con)); /* restart with a read, or finish */
    1726                 :     }
    1727             288 :     con->use_mmap = FALSE;
    1728             288 :     if (!httpd_serv_call_seek(con, fs))
    1729               0 :       VLG_WARN_RET(FALSE, (vlg, "lseek(<mpbr>,off=%ju): %m\n", fs->off));
    1730                 : 
    1731             288 :     http_app_hdrs_mpbr(con, fs);
    1732             288 :     return (httpd_serv_send(con)); /* start outputting next file section */
    1733                 :   }
    1734                 :   
    1735           11157 :  file_eof_end:
    1736           11157 :   if (fs->len) /* something bad happened, just kill the connection */
    1737               5 :     con->keep_alive = HTTP_NON_KEEP_ALIVE;
    1738                 :   
    1739           11157 :   httpd_fin_fd_close(con);
    1740           11157 :   return (httpd_serv_send(con)); /* restart with a read, or finish */
    1741                 : }
    1742                 : 
    1743                 : int httpd_serv_recv(struct Con *con)
    1744           50488 : {
    1745           50488 :   unsigned int ern = 0;
    1746           50488 :   int ret = 0;
    1747           50488 :   Vstr_base *data = con->evnt->io_r;
    1748                 : 
    1749           24463 :   ASSERT(!con->evnt->io_r_shutdown);
    1750                 :   
    1751           50488 :   if (!con->io_limit_num--)
    1752               0 :     return (TRUE);
    1753                 :   
    1754           50488 :   if (!(ret = evnt_recv(con->evnt, &ern)))
    1755                 :   {
    1756           11938 :     if (ern != VSTR_TYPE_SC_READ_FD_ERR_EOF)
    1757                 :     {
    1758               0 :       vlg_dbg2(vlg, "RECV ERR from[$<sa:%p>]: %u\n", CON_CEVNT_SA(con), ern);
    1759               0 :       goto con_cleanup;
    1760                 :     }
    1761           11938 :     if (!evnt_shutdown_r(con->evnt, TRUE))
    1762           11638 :       goto con_cleanup;
    1763                 :   }
    1764                 : 
    1765           38850 :   if (con->fs_num) /* may need to stop input, until we can deal with next req */
    1766                 :   {
    1767             569 :     ASSERT(con->keep_alive || con->parsed_method_ver_1_0);
    1768                 :     
    1769             804 :     if (con->policy->max_header_sz && (data->len > con->policy->max_header_sz))
    1770              74 :       evnt_wait_cntl_del(con->evnt, POLLIN);
    1771                 : 
    1772             804 :     return (TRUE);
    1773                 :   }
    1774                 :   
    1775           38046 :   if (http_parse_req(con))
    1776           37850 :     return (TRUE);
    1777                 :   
    1778           11834 :  con_cleanup:
    1779           11834 :   con->evnt->io_r->conf->malloc_bad = FALSE;
    1780           11834 :   con->evnt->io_w->conf->malloc_bad = FALSE;
    1781                 :     
    1782           11834 :   return (FALSE);
    1783                 : }
    1784                 : 
    1785                 : int httpd_con_init(struct Con *con, struct Acpt_listener *acpt_listener)
    1786           12052 : {
    1787           12052 :   int ret = TRUE;
    1788           12052 :   Httpd_policy_opts *po = (Httpd_policy_opts *)httpd_opts->s->def_policy;
    1789                 :   
    1790           12052 :   con->mpbr_ct = NULL;
    1791                 :   
    1792           12052 :   con->fs      = con->fs_store;
    1793           12052 :   con->fs->len = 0;
    1794           12052 :   con->fs->fd  = -1;
    1795           12052 :   con->fs_off  = 0;
    1796           12052 :   con->fs_num  = 0;
    1797           12052 :   con->fs_sz   = 1;
    1798                 : 
    1799           12052 :   con->vary_star   = FALSE;
    1800           12052 :   con->keep_alive  = HTTP_NON_KEEP_ALIVE;
    1801           12052 :   con->evnt->acpt_sa_ref = vstr_ref_add(acpt_listener->ref);
    1802           12052 :   con->use_mpbr    = FALSE;
    1803           12052 :   con->use_mmap    = FALSE;
    1804                 : 
    1805           12052 :   con->parsed_method_ver_1_0 = FALSE;
    1806                 : 
    1807           12052 :   if (acpt_listener->def_policy)
    1808             416 :     po = acpt_listener->def_policy->ptr;
    1809                 :   
    1810           12052 :   httpd_policy_change_con(con, po);
    1811                 : 
    1812           12052 :   if (!httpd_policy_connection(con,
    1813                 :                                httpd_opts->conf, httpd_opts->match_connection))
    1814                 :   {
    1815               0 :     Vstr_base *s1 = con->policy->s->policy_name;
    1816               0 :     Vstr_base *s2 = httpd_opts->conf->tmp;
    1817                 : 
    1818               0 :     vlg_info(vlg, "CONF-MAIN-ERR from[$<sa:%p>]: policy $<vstr.all:%p>"
    1819                 :              " backtrace: $<vstr.all:%p>\n", CON_CEVNT_SA(con), s1, s2);
    1820               0 :     ret = FALSE;
    1821                 :   }
    1822           12052 :   else if (con->evnt->flag_q_closed)
    1823                 :   {
    1824               0 :     Vstr_base *s1 = con->policy->s->policy_name;
    1825               0 :     vlg_info(vlg, "BLOCKED from[$<sa:%p>]: policy $<vstr.all:%p>\n",
    1826                 :              CON_CEVNT_SA(con), s1);
    1827               0 :     ret = FALSE;
    1828                 :   }
    1829                 :   
    1830           12052 :   return (ret);
    1831                 : }

Generated by: LTP GCOV extension version 1.4