ncsa-html.c
上传用户:ladybrid91
上传日期:2007-01-04
资源大小:287k
文件大小:43k
源码类别:

Web服务器

开发平台:

Unix_Linux

  1. /*
  2. ** ncsa-html.c
  3. **
  4. ** Copyright (c) 1995 Marcus E. Hennecke <marcush@leland.stanford.edu>
  5. ** Copyright (c) 1994-1997 Peter Eriksson <pen@signum.se>
  6. **
  7. ** This program is free software; you can redistribute it and/or modify
  8. ** it under the terms of the GNU General Public License as published by
  9. ** the Free Software Foundation; either version 2 of the License, or
  10. ** (at your option) any later version.
  11. **
  12. ** This program is distributed in the hope that it will be useful,
  13. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. ** GNU General Public License for more details.
  16. ** You should have received a copy of the GNU General Public License
  17. ** along with this program; if not, write to the Free Software
  18. ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. */
  20. #include <stdio.h>
  21. #include <time.h>
  22. #include <string.h>
  23. #include <fcntl.h>
  24. #include <unistd.h>
  25. #include <errno.h>
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28. #include <sys/mman.h>
  29. #include <stdlib.h>
  30. #include <alloca.h>
  31. #include <syslog.h>
  32. #include "phttpd.h"
  33. #include "ncsa-html.h"
  34. #define DEFAULT_TIMEFMT "%A, %d-%b-%y %T %Z"
  35. #ifndef MAP_FAILED
  36. #define MAP_FAILED ((caddr_t) -1)
  37. #endif
  38. static char *exec_user = NULL;
  39. static char *exec_group = NULL;
  40. static int max_environ = 256;
  41. static char *exec_path = NULL;
  42. static char *exec_newroot = NULL;
  43. static rlim_t exec_niceval = 5;
  44. static rlim_t exec_vmem = 0;
  45. static rlim_t exec_fdmax = 0;
  46. static rlim_t exec_maxcputime = 0;
  47. static int exec_enabled = 0;
  48. static int exec_user_enabled = 0;
  49. static uid_t default_exec_uid = 60001; /* Nobody */
  50. static gid_t default_exec_gid = 60001; /* Nobody */
  51. /* These functions implement server side includes */
  52. static void cmd_config(struct segment *,
  53.        struct attr_pair *,
  54.        struct includeinfo *);
  55. static void cmd_user(struct segment *,
  56.      struct attr_pair *,
  57.      struct includeinfo *);
  58. static void cmd_echo(struct segment *,
  59.      struct attr_pair *,
  60.      struct includeinfo *);
  61. static void cmd_include(struct segment *,
  62. struct attr_pair *,
  63. struct includeinfo *);
  64. static void cmd_fsize(struct segment *,
  65.       struct attr_pair *,
  66.       struct includeinfo *);
  67. static void cmd_flastmod(struct segment *,
  68.  struct attr_pair *,
  69.  struct includeinfo *);
  70. static void cmd_count(struct segment *,
  71.       struct attr_pair *,
  72.       struct includeinfo *);
  73. static void cmd_exec(struct segment *,
  74.       struct attr_pair *,
  75.       struct includeinfo *);
  76. static struct command commands[] =
  77. {
  78.     { "config", cmd_config, 1 },
  79.     { "echo", cmd_echo, 1 },
  80.     { "include", cmd_include, 1 },
  81.     { "fsize", cmd_fsize, 1 },
  82.     { "flastmod", cmd_flastmod, 1 },
  83.     { "count", cmd_count, 1 },
  84.     { "exec", cmd_exec, 1 },
  85.     { "user", cmd_user, 1 },
  86.     { NULL, NULL, 0 }
  87. };
  88. /* (very simple) state machines for the searches */
  89. static int start_fsm[256];
  90. static int end_fsm[256];
  91. /* This lookup table is used for escaping shell characters */
  92. #define SHELL_ESCAPE 1
  93. static char ch_type[256];
  94. #define isshesc(c) (ch_type[((unsigned int)(c))&255] & SHELL_ESCAPE)
  95. static struct options shtml_cfg_table[] =
  96. {
  97.     { "default-exec-user", T_STRING, &exec_user, NULL },
  98.     { "default-exec-group", T_STRING, &exec_group, NULL },
  99.     { "exec-path", T_STRING, &exec_path, NULL },
  100.     { "exec-environ-size", T_NUMBER, &max_environ, NULL },
  101.     { "allow-exec", T_BOOL,   &exec_enabled, NULL },
  102.     { "allow-user-exec", T_BOOL,   &exec_user_enabled, NULL },
  103.     { "newroot", T_STRING, &exec_newroot, NULL },
  104.     { "nicevalue",       T_NUMBER, &exec_niceval, NULL },
  105.     { "maxcputime",       T_NUMBER, &exec_maxcputime, NULL },
  106.     { "max-vmem",        T_NUMBER, &exec_vmem, NULL },
  107.     { "max-fd",          T_NUMBER, &exec_fdmax, NULL },
  108.     
  109.     { NULL, 0, NULL, NULL }
  110. };
  111. int pm_init(const char **argv)
  112. {
  113.     struct passwd *pwp, pwb;
  114.     char pbuf[1024];
  115.     char *cfg_path, *cp;
  116.     const char *name;
  117.     int i, cfg_size;
  118.     
  119.     name = argv[0];
  120.     
  121.     if (debug > 1)
  122. fprintf(stderr, "*** ncsa-html/pm_init("%s") called ***n", name);
  123.     cfg_path = s_strxdup(name, 6, &cfg_size);
  124.     
  125.     cp = strrchr(cfg_path, '.');
  126.     if (cp && strcmp(cp, ".so") == 0)
  127. *cp = '';
  128.     
  129.     s_strcat(cfg_path, cfg_size, ".conf");
  130.     if (config_parse_file(cfg_path, shtml_cfg_table, 0) < 0)
  131. return -1;
  132.     
  133.     if (config_parse_argv(argv+1, shtml_cfg_table) < 0)
  134. return -1;
  135.     
  136.     if (uidgid_get(exec_user, exec_group,
  137.    &default_exec_uid, &default_exec_gid,
  138.    &pwp, &pwb, pbuf, sizeof(pbuf)) < 0)
  139.     {
  140. syslog(LOG_ERR,
  141.        "ncsa-html: uidgid_get("%s", "%s") failed, using default",
  142.        exec_user, exec_group);
  143.     }
  144.     
  145.     if (default_exec_uid == -1)
  146.         default_exec_uid = server_uid;
  147.     
  148.     if (default_exec_gid == -1)
  149.         default_exec_gid = server_gid;
  150.     
  151.     if (exec_path == NULL)
  152. exec_path = s_strdup("/bin:/usr/bin");
  153.     
  154.     /* Set up the state machines for the search. */
  155.     for ( i = 0; i < 256; i++ )
  156.     {
  157. start_fsm[i] = 5;
  158. end_fsm[i] = 3;
  159.     }
  160.     start_fsm[(int)('<')] = 4;
  161.     start_fsm[(int)('!')] = 3;
  162.     start_fsm[(int)('-')] = 1;
  163.     end_fsm[(int)('-')] = 1;
  164.     /* Set up lookup tables for escaping shell specials */
  165.     for ( i = 0; i < 256; i++ )
  166. ch_type[i] = 0;
  167.     ch_type['&'] = ch_type[';'] = ch_type['''] = 
  168. ch_type['`'] = ch_type['"'] = ch_type['|'] = 
  169.     ch_type['*'] = ch_type['?'] = ch_type['~'] = 
  170. ch_type['<'] = ch_type['>'] = ch_type['^'] = 
  171.     ch_type['('] = ch_type[')'] = ch_type['['] = 
  172. ch_type[']'] = ch_type['{'] = ch_type['}'] = 
  173.     ch_type['$'] = ch_type['\'] = SHELL_ESCAPE;
  174.     return 0;
  175. }
  176. void pm_exit(void)
  177. {
  178.     if (debug > 1)
  179. fprintf(stderr, "*** ncsa-html/pm_exit()n");
  180.     if (exec_path)
  181. s_free(exec_path);
  182. }
  183. static int do_parse(struct segment *, struct includeinfo *);
  184. char *unescape_query(char *query)
  185. {
  186.     char ch1, ch2, *buf, *char_pt;
  187.     int len = 0;
  188.   
  189.     if (query == NULL)
  190. return NULL;
  191.     if (query[0] == '')
  192. return NULL;
  193.   
  194.     /* Compute a conservative estimate of the resulting length */
  195.     for ( char_pt = query; (ch1 = *char_pt); char_pt++ )
  196. if ( isshesc(ch1) )
  197.     len++;
  198.   
  199.     len += char_pt - query;
  200.     buf = s_malloc(len+1);
  201.   
  202.     if (buf == NULL) return(NULL);
  203.   
  204.     for ( char_pt = buf; (ch1 = *query); query++ )
  205.     {
  206. if ( ch1 == '%' && (ch2=query[1]) && s_isxdigit(ch2))
  207. {
  208.     query++;
  209.     ch1 = ( s_isdigit(ch2) ?  ch2 - '0' : s_toupper(ch2)-'A' +10);
  210.     if ( (ch2=query[1]) && s_isxdigit(ch2))
  211.     {
  212. query++;
  213. ch1 = (ch1 << 4) |
  214.     (s_isdigit(ch2) ? ch2-'0' : s_toupper(ch2)-'A'+10);
  215.     }
  216. }
  217. if ( isshesc(ch1) )
  218.     *char_pt++ = '\';
  219. *char_pt++ = ch1;
  220.     }
  221.   
  222.     return buf;
  223. }
  224. /* This function goes through the attribute pairs and searches for */
  225. /* attributes that change the configuration of the includes. */
  226. /* Currently, these are errmsg, timefmt and sizefmt. The function is */
  227. /* used by all includes. When called from config, it changes the */
  228. /* global configuration, otherwise only the local configuration. */
  229. static void config_include(struct attr_pair *ap, struct includeinfo *ip)
  230. {
  231.     /* Go through the attribute list */
  232.     for ( ; ap != NULL; ap = ap->next )
  233.     {
  234. /* Skip attributes that have already been dealt with. */
  235. if ( ap->name == NULL )
  236.     continue;
  237.     
  238. /* Check if the attribute is one of the config attributes */
  239. if ( strcmp(ap->name, "errmsg") == 0 )
  240. { /* errmsg */
  241.     if (ip->errmsg != NULL)
  242. s_free(ip->errmsg);
  243.     ip->errmsg = ap->value;
  244.     s_free(ap->name);
  245.     ap->name = ap->value = NULL; /* Mark it as being read */
  246. }
  247. else if ( strcmp(ap->name, "sizefmt") == 0 )
  248. { /* sizefmt */
  249.     if (ip->sizefmt != NULL)
  250. s_free(ip->sizefmt);
  251.     ip->sizefmt = ap->value;
  252.     s_free(ap->name);
  253.     ap->name = ap->value = NULL; /* Mark it as being read */
  254. }
  255. else if ( strcmp(ap->name, "timefmt") == 0 )
  256. { /* timefmt */
  257.     if (ip->timefmt != NULL)
  258. s_free(ip->timefmt);
  259.     ip->timefmt = ap->value;
  260.     s_free(ap->name);
  261.     ap->name = ap->value = NULL; /* Mark it as being read */
  262. }
  263.     }
  264. }
  265. /* Frees global or local config info. */
  266. static void config_include_free(struct includeinfo *ip)
  267. {
  268.     if (ip->timefmt != NULL)
  269. s_free(ip->timefmt);
  270.     if (ip->sizefmt != NULL)
  271. s_free(ip->sizefmt);
  272.     if (ip->errmsg  != NULL)
  273. s_free(ip->errmsg);
  274.     ip->timefmt = ip->sizefmt = ip->errmsg = NULL;
  275. }
  276. /*
  277. ** Search the attribute list for a file reference and access it.
  278. **
  279. ** Returns -1 in case of error (and then the buffer might point to
  280. ** an error), else 0.
  281. */
  282. static int reference_file(struct attr_pair *ap,
  283.     struct includeinfo *ip, int flags,
  284.     char **buffer)
  285. {
  286.     char url_buf[2048], *url_pt, *char_pt;
  287.     fscentry_t *fep = NULL;
  288.     
  289.     url_buf[0] = '';
  290. #if 0
  291.     ip->fep = NULL;
  292. #endif
  293.     
  294.     /* Go through the attribute list */
  295.     for ( ; ap != NULL; ap = ap->next )
  296.     {
  297. /* Skip attributes that have already been dealt with. */
  298. if ( ap->name == NULL )
  299.     continue;
  300.     
  301. if ( strcmp(ap->name, "virtual") == 0 )
  302. {
  303.     s_free(ap->name);
  304.     ap->name = NULL; /* Mark it as being read */
  305.       
  306.     if (ap->value == NULL)
  307.     {
  308. *buffer = "[No URL specified]";
  309. return -1;
  310.     }
  311.       
  312.     break;
  313. }
  314.     
  315. if ( strcmp(ap->name, "file") == 0)
  316. {
  317.     s_free(ap->name);
  318.     ap->name = NULL; /* Mark it as being read */
  319.       
  320.     if (ap->value == NULL)
  321.     {
  322. *buffer = "[No file specified]";
  323. return -1;
  324.     }
  325.       
  326.     if ( ap->value[0] == '/' )
  327.     {
  328. *buffer = "[Path must be relative]";
  329. return -1;
  330.     }
  331.     
  332.     char_pt = ap->value;
  333.     
  334.     if (char_pt[0] == '.' && char_pt[1] == '.' &&
  335. (char_pt[2] == '/' || char_pt[2] == ''))
  336.     {
  337. *buffer = "[No '..' allowed in file path]";
  338. return -1;
  339.     }
  340.     
  341.     for ( ; char_pt[3]; char_pt++ )
  342. if (char_pt[0] == '/' && char_pt[1] == '.' &&
  343.     char_pt[2] == '.' &&
  344.     (char_pt[3] == '/' || char_pt[3] == ''))
  345. {
  346.     *buffer = "[No '/..' allowed in file path]";
  347.     return -1;
  348. }
  349.       
  350.     break;
  351. }
  352.     }
  353.     if ( ap != NULL )
  354.     {
  355. url_pt = url_buf;
  356. if ( ap->value[0] != '/' )
  357. {
  358.     /* Url is relative */
  359.     
  360.     s_strcpy(url_buf, sizeof(url_buf), ip->cip->hip->url);
  361.     char_pt = strrchr(url_buf, '/');
  362.     if (char_pt)
  363. char_pt[1] = '';
  364. }
  365. s_strcat(url_buf, sizeof(url_buf), ap->value);
  366.       
  367. fep = fscache_lookup(url_buf, flags|ip->fsc_flags);
  368. if ( fep == NULL || fep->fip == NULL)
  369. {
  370.     if (debug > 2)
  371. fprintf(stderr, "fscache_lookup("%s"): not foundn",
  372. url_buf);
  373.     *buffer = "[File not found]";
  374.     return -1;
  375. }
  376. ip->fep = fep;
  377.     }
  378.     return 0;
  379. }
  380. /* The following functions are called for server-side includes. They */
  381. /* are passed a pointer to a segment structure which they are supposed */
  382. /* to fill, a pointer to a list of attributes, and a pointer to a */
  383. /* structure with general information. */
  384. static void cmd_config(struct segment *cp, struct attr_pair *ap,
  385.        struct includeinfo *ip)
  386. {
  387.     config_include(ap, ip);
  388.     cp->block = NULL;
  389.     cp->size = 0;
  390.     cp->free_start = NULL;
  391.     cp->free_size = 0;
  392. }
  393. static void cmd_user(struct segment *cp, struct attr_pair *ap,
  394.      struct includeinfo *ip)
  395. {
  396.     char buf[1048];
  397.     char buf2[2048];
  398.     struct passwd *pwp, pwb;
  399.     pwp = NULL;
  400.     buf2[0] = '';
  401.     
  402.     cp->block = NULL;
  403.     cp->size = 0;
  404.     cp->free_start = NULL;
  405.     cp->free_size = 0;
  406.     
  407.     /* Go through the attribute list */
  408.     for ( ; ap != NULL; ap = ap->next )
  409.     {
  410. /* Skip attributes that have already been dealt with. */
  411. if ( ap->name == NULL ) continue;
  412.     
  413. if ( strcmp(ap->name, "name") == 0 && ap->value != NULL)
  414. {
  415.     s_free(ap->name);
  416.     ap->name = NULL; /* Mark it as being read */
  417.     pwp = s_getpwnam_r(ap->value, &pwb, buf, sizeof(buf));
  418.     if (pwp == NULL)
  419.     {
  420. if (debug > 2)
  421.     fprintf(stderr, "cgi.c:cmd_user(), user %s not foundn",
  422.     ap->value);
  423. s_strcpy(buf2, sizeof(buf2), "[User not found]");
  424. break;
  425.     }
  426.     s_sprintf(buf2, sizeof(buf2),
  427.       "<a href="/~%s">%s</a>", ap->value, pwp->pw_gecos);
  428.     cp->free_start = cp->block = s_strdup(buf2);
  429.     cp->size = strlen(buf2);
  430. }
  431. else if ( strcmp(ap->name, "mailto") == 0 && ap->value != NULL )
  432. {
  433.     s_free(ap->name);
  434.     ap->name = NULL; /* Mark it as being read */
  435.     if (buf2[0])
  436. s_strcat(buf2, sizeof(buf2), " ");
  437.     
  438.     s_strcat(buf2, sizeof(buf2), "<a href="mailto:");
  439.     if (strchr(ap->value, '@') == NULL)
  440.     {
  441. if (pwp == NULL)
  442. {
  443.     s_strcpy(buf2, sizeof(buf2),
  444.      "[name must occur before mailto]");
  445.     break;
  446. }
  447.     
  448. s_strcat(buf2, sizeof(buf2), pwp->pw_name);
  449. s_strcat(buf2, sizeof(buf2), "@");
  450.     }
  451.     s_strcat(buf2, sizeof(buf2), ap->value);
  452.     s_strcat(buf2, sizeof(buf2), "">&lt;");
  453.     if (strchr(ap->value, '@') == NULL)
  454.     {
  455. s_strcat(buf2, sizeof(buf2), pwp->pw_name);
  456. s_strcat(buf2, sizeof(buf2), "@");
  457.     }
  458.     s_strcat(buf2, sizeof(buf2), ap->value);
  459.     s_strcat(buf2, sizeof(buf2), "&gt;</a>");
  460. }
  461. else
  462. {
  463.     s_strcpy(buf2, sizeof(buf2), "[Unknown tag]");
  464.     break;
  465. }
  466.     }
  467.     cp->free_start = cp->block = s_strdup(buf2);
  468.     cp->size = strlen(cp->block);
  469.     time(&ip->lastmod);
  470. }
  471. static void cmd_echo(struct segment *cp, struct attr_pair *ap,
  472.      struct includeinfo *ip)
  473. {
  474.     struct connectioninfo *cip;
  475.     struct httpinfo *hip;
  476.     struct mimeinfo *mip = NULL;
  477.     char *var_name;
  478.     char buf[1025];
  479.     struct tm time_pt;
  480.     struct includeinfo local_ip = {NULL, 0, 0, NULL, 0, 0, NULL, NULL, NULL};
  481.     char *timefmt;
  482.   
  483.     cip = ip->cip;
  484.     hip = cip->hip;
  485.     if (hip) mip = hip->mip;
  486.   
  487.     config_include(ap, &local_ip);
  488.     if ( (timefmt = local_ip.timefmt) == NULL )
  489. timefmt = ip->timefmt;
  490.   
  491.     cp->block = NULL;
  492.     cp->size = 0;
  493.     cp->free_start = NULL;
  494.     cp->free_size = 0;
  495.   
  496.     /* Go through the attribute list */
  497.     for ( ; ap != NULL; ap = ap->next )
  498.     {
  499. /* Skip attributes that have already been dealt with. */
  500. if ( ap->name == NULL ) continue;
  501.     
  502. if ( strcmp(ap->name, "var") == 0 && ap->value != NULL)
  503. {
  504.     s_free(ap->name);
  505.     ap->name = NULL; /* Mark it as being read */
  506.       
  507.     var_name = ap->value;
  508.     if (strcmp(var_name, "DOCUMENT_NAME") == 0)
  509.     {
  510.       if (!(cp->block = strrchr(ip->fep->fip->path, '/')))
  511.   cp->block = ip->fep->fip->path;
  512.     }
  513.     else if (strcmp(var_name, "DOCUMENT_URI") == 0)
  514.     {
  515. cp->block = hip->orig_url;
  516.     }
  517.     else if (strcmp(var_name, "DOCUMENT_ROOT") == 0)
  518.     {
  519. cp->block = server_home;
  520.     } else if (strcmp(var_name, "DATE_LOCAL") == 0)
  521.     {
  522. strftime(buf, sizeof(buf), timefmt,
  523.  localtime_r(&(cip->cn_time), &time_pt) );
  524. cp->free_start = cp->block = s_strdup(buf);
  525.     }
  526.     else if (strcmp(var_name, "DATE_GMT") == 0)
  527.     {
  528. strftime(buf, sizeof(buf), timefmt,
  529.  gmtime_r(&(cip->cn_time), &time_pt) );
  530. cp->free_start = cp->block = s_strdup(buf);
  531.     }
  532.     else if (strcmp(var_name, "LAST_MODIFIED") == 0)
  533.     {
  534. strftime(buf, sizeof(buf), timefmt,
  535.  localtime_r(&(ip->fep->fip->sb.st_mtime), &time_pt) );
  536. cp->free_start = cp->block = s_strdup(buf);
  537.     }
  538.     else if (strcmp(var_name, "SERVER_SOFTWARE") == 0)
  539.     {
  540. s_sprintf(buf, sizeof(buf), "phttpd/%s", server_version);
  541. cp->free_start = cp->block = s_strdup(buf);
  542.     }
  543.     else if (strcmp(var_name, "SERVER_NAME") == 0)
  544.     {
  545. cp->block = server_host;
  546.     }
  547.     else if (strcmp(var_name, "GATEWAY_INTERFACE") == 0)
  548.     {
  549. cp->block = "CGI/1.1";
  550.     }
  551.     else if (strcmp(var_name, "SERVER_PROTOCOL") == 0)
  552.     {
  553. cp->block = hip->version;
  554.     }
  555.     else if (strcmp(var_name, "SERVER_PORT") == 0)
  556.     {
  557. s_sprintf(buf, sizeof(buf), "%d", server_port);
  558. cp->free_start = cp->block = s_strdup(buf);
  559.     }
  560.     else if (strcmp(var_name, "REQUEST_METHOD") == 0)
  561.     {
  562. cp->block = hip->method;
  563.     }
  564.     else if (strcmp(var_name, "QUERY_STRING") == 0)
  565.     {
  566. cp->block = hip->request;
  567.     }
  568.     else if (strcmp(var_name, "QUERY_STRING_UNESCAPED") == 0)
  569.     {
  570. cp->free_start = cp->block = unescape_query(hip->request);
  571.     }
  572.     else if (strcmp(var_name, "LOCAL_ADDR") == 0)
  573.     {
  574. #if 1
  575. cp->block = NULL;
  576. dns_get(cip->server, NULL, NULL, &cp->block, NULL);
  577. #else
  578. cp->block = cip->server.addr_s;
  579. #endif
  580.     }
  581.     else if (strcmp(var_name, "LOCAL_HOST") == 0)
  582.     {
  583. #if 1
  584. cp->block = NULL;
  585. dns_get(cip->server, NULL, &cp->block, NULL, NULL);
  586. #else
  587. cp->block = get_hostname(&cip->server);
  588. #endif
  589.     }
  590.     else if (strcmp(var_name, "REMOTE_ADDR") == 0)
  591.     {
  592. #if 1
  593. cp->block = NULL;
  594. dns_get(cip->client, NULL, NULL, &cp->block, NULL);
  595. #else
  596. cp->block = cip->client.addr_s;
  597. #endif
  598.     }
  599.     else if (strcmp(var_name, "REMOTE_HOST") == 0)
  600.     {
  601. #if 1
  602. cp->block = NULL;
  603. dns_get(cip->client, NULL, &cp->block, NULL, NULL);
  604. #else
  605. cp->block = get_hostname(&cip->client);
  606. #endif
  607.     }
  608.     else if (mip == NULL)
  609. continue;
  610.     else if (strcmp(var_name, "REQUEST_METHOD") == 0)
  611.     {
  612. cp->block = hip->method;
  613.     }
  614.     else if (strcmp(var_name, "CONTENT_TYPE") == 0)
  615.     {
  616. cp->block = mime_getheader(mip, var_name, 1);
  617.     }
  618.     else if (strcmp(var_name, "REFERER") == 0)
  619.     {
  620. cp->block = mime_getheader(mip, var_name, 1);
  621.     }
  622.     else if (strcmp(var_name, "CONTENT_LENGTH") == 0)
  623.     {
  624. cp->block = mime_getheader(mip, var_name, 1);
  625.     }
  626.     else if (strncmp(var_name, "HTTP_", 5) == 0 &&
  627.      strcmp(var_name, "HTTP_AUTHORIZATION") != 0)
  628.     {
  629. char *name, *p;
  630. int nsize;
  631. #if 1
  632. S_STRALLOCA(var_name+5, &name, 0, &nsize);
  633. #else
  634. nsize = strlen(var_name+5)+1;
  635. name = (char *) alloca(nsize);
  636. s_strcpy(name, nsize, var_name+5);
  637. #endif
  638. for (p = name; *p; p++)
  639.     if (*p == '_')
  640. *p = '-';
  641. cp->block = mime_getheader(mip, name, 1);
  642.     }
  643.     
  644.     if ( cp->block != NULL )
  645. cp->size = strlen(cp->block);
  646.     break;
  647. }
  648.     }
  649.     
  650.     time(&ip->lastmod);
  651. }
  652. static void cmd_include(struct segment *cp, struct attr_pair *ap,
  653. struct includeinfo *ip)
  654. {
  655.     fscentry_t *fep, *old_fep;
  656.     fsinfo_t *fip;
  657.     
  658.     cp->free_start = NULL;
  659.     if ( ip->level >= MAXINCLUDE )
  660.     { /* Don't nest too deep. */
  661. cp->block = NULL;
  662. cp->size = 0;
  663. return;
  664.     }
  665.   
  666.     old_fep = ip->fep;
  667.     
  668.     if (reference_file(ap, ip, FSCF_GETDATA, &cp->block) < 0)
  669.     {
  670. /* Failed */
  671. cp->size = strlen(cp->block);
  672. return;
  673.     }
  674.     if (ip->fep == NULL)
  675. fep = old_fep;
  676.     else
  677. fep = ip->fep;
  678.     
  679.     fip = fep->fip;
  680.     
  681.     if (S_ISDIR(fip->sb.st_mode))
  682.     {
  683. cp->block = "[Can not include a directory]";
  684. cp->size = strlen(cp->block);
  685. if (fep != NULL && fep != old_fep)
  686. {
  687.     ip->fep = old_fep;
  688.     fscache_release(fep);
  689. }
  690. return;
  691.     }
  692.   
  693.     if ( ip->lastmod )
  694. if ( ip->lastmod < fip->sb.st_mtime )
  695.     ip->lastmod = fip->sb.st_mtime;
  696.   
  697.     cp->fep = fep;
  698.     cp->block = fip->data.file.content;
  699.     cp->free_size = cp->size = fip->sb.st_size;
  700.     cp->free_start = cp->block;
  701.     madvise(cp->block, fip->sb.st_size, MADV_WILLNEED);
  702.     ip->level++;
  703.     do_parse(cp, ip);
  704.     ip->level--;
  705.     madvise(cp->block, fip->sb.st_size, MADV_SEQUENTIAL);
  706.     
  707.     ip->fep = old_fep;
  708. }
  709. static void cmd_fsize(struct segment *cp, struct attr_pair *ap,
  710.       struct includeinfo *ip)
  711. {
  712.     char buf[32];
  713.     off_t fsize = 0;
  714.     struct includeinfo local_ip = {NULL, 0, 0, NULL, 0, 0, NULL, NULL, NULL};
  715.     fscentry_t *fep, *old_fep;
  716.     fsinfo_t *fip;
  717.     char *sizefmt;
  718.     config_include(ap, &local_ip);
  719.     if ( (sizefmt = local_ip.sizefmt) == NULL )
  720. sizefmt = ip->sizefmt;
  721.   
  722.     old_fep = ip->fep;
  723.     
  724.     if (reference_file(ap, ip, 0, &cp->block) < 0)
  725.     {
  726. /* Failed */
  727. ip->fep = old_fep;
  728. cp->size = strlen(cp->block);
  729. return;
  730.     }
  731.     if (ip->fep == NULL)
  732. fep = old_fep;
  733.     else
  734. fep = ip->fep;
  735.     
  736.     fip = fep->fip;
  737.     
  738.     fsize = fip->sb.st_size;
  739.     if ( ip->lastmod )
  740. if ( ip->lastmod < fip->sb.st_mtime )
  741.     ip->lastmod = fip->sb.st_mtime;
  742.     if (fep != NULL && fep != old_fep)
  743.     {
  744. ip->fep = old_fep;
  745. fscache_release(fep);
  746.     }
  747.   
  748.     if (sizefmt != NULL && strcmp(sizefmt,"bytes")==0)
  749.     {
  750. int len;
  751. char *char_pt1, *char_pt2;
  752.     
  753. s_sprintf(buf, sizeof(buf), "%ld", fsize);
  754. len = strlen(buf);
  755. char_pt1 = cp->free_start = cp->block = s_malloc(len+1+(len-1)/3);
  756.     
  757. for ( char_pt2 = buf; len >= 0; len-- )
  758. {
  759.     *char_pt1++ = *char_pt2++;
  760.     if ( len > 1 && !((len-1)%3) ) *char_pt1++ = ',';
  761. }
  762.     }
  763.     else
  764.     {
  765. if ( fsize < 10240 )
  766. {
  767.     s_sprintf(buf, sizeof(buf), "%d", (int)fsize);
  768. }
  769. else if ( fsize < 1024*10240 )
  770. {
  771.     fsize /= 1024;
  772.     s_sprintf(buf, sizeof(buf), "%dK", (int)fsize);
  773. }
  774. else
  775. {
  776.     fsize /= (1024*1024);
  777.     s_sprintf(buf, sizeof(buf), "%dM", (int)fsize);
  778. }
  779. cp->free_start = cp->block = s_strdup(buf);
  780.     }
  781.     cp->size = strlen(cp->block);
  782.     cp->free_size = 0;
  783.   
  784.     config_include_free(&local_ip);
  785. }
  786. static void cmd_flastmod(struct segment *cp, struct attr_pair *ap,
  787.  struct includeinfo *ip)
  788. {
  789.     char buf[256];
  790.     struct tm time_pt;
  791.     struct includeinfo local_ip = {NULL, 0, 0, NULL, 0, 0, NULL, NULL, NULL};
  792.     fscentry_t *fep, *old_fep;
  793.     fsinfo_t *fip;
  794.     char *timefmt;
  795.     time_t mtime;
  796.     
  797.     old_fep = ip->fep;
  798.     
  799.     config_include(ap, &local_ip);
  800.     if ( (timefmt = local_ip.timefmt) == NULL )
  801. timefmt = ip->timefmt;
  802.     
  803.     if (reference_file(ap, ip, 0, &cp->block) < 0)
  804.     {
  805. /* Failed */
  806. if (debug > 2)
  807.     fprintf(stderr, "cmd_flastmod(): failed: %sn", cp->block);
  808. ip->fep = old_fep;
  809. cp->size = strlen(cp->block);
  810. return;
  811.     }
  812.     if (ip->fep == NULL)
  813. fep = old_fep;
  814.     else
  815. fep = ip->fep;
  816.     
  817.     fip = fep->fip;
  818.     
  819.     mtime = fip->sb.st_mtime;
  820.     if ( ip->lastmod )
  821. if ( ip->lastmod < fip->sb.st_mtime )
  822.     ip->lastmod = fip->sb.st_mtime;
  823.   
  824.     if (fep != NULL && fep != old_fep)
  825.     {
  826. ip->fep = old_fep;
  827. fscache_release(fep);
  828.     }
  829.     strftime(buf, sizeof(buf), timefmt, localtime_r(&(mtime), &time_pt));
  830.     
  831.     cp->free_start = cp->block = s_strdup(buf);
  832.     cp->size = strlen(buf);
  833.     cp->free_size = 0;
  834.   
  835.     config_include_free(&local_ip);
  836. }
  837. static char *cgi_setenv(char **envp, const char *var, const char *val)
  838. {
  839.     char *buf;
  840.     int i, len;
  841.     int size;
  842.     
  843.     if (debug > 5)
  844. fprintf(stderr, "cgi_setenv: var=%s, val=%sn",
  845. var, val ? val : "<null>");
  846.     
  847.     if (val == NULL)
  848. return NULL;
  849.     size = strlen(var)+strlen(val)+2;
  850.     buf = s_malloc(size);
  851.     
  852.     s_strcpy(buf, size, var);
  853.     len = s_strcat(buf, size, "=");
  854.     s_strcat(buf, size, val);
  855.     
  856.     for (i = 0; i < max_environ && envp[i]; i++)
  857. if (strncmp(envp[i], buf, len) == 0)
  858.     break;
  859.     if (i >= max_environ)
  860. return NULL;
  861.     if (envp[i])
  862. s_free(envp[i]);
  863.     
  864.     envp[i] = buf;
  865.     return buf;
  866. }
  867. static char *cgi_setenv_i(char **envp, const char *var, int num)
  868. {
  869.     char buf[256];
  870.     s_sprintf(buf, sizeof(buf), "%d", num);
  871.     return cgi_setenv(envp, var, buf);
  872. }
  873. static int cse_header(hashentry_t *hep, void *envp)
  874. {
  875.     char *name, *cp;
  876.     int nsize;
  877.     
  878.     
  879.     if (strcmp(hep->key, "AUTHORIZATION") == 0)
  880. return 0;
  881.     nsize = strlen(hep->key)+6;
  882.     name = (char *) alloca(nsize);
  883.     s_strcpy(name, nsize, "HTTP_");
  884.     s_strcat(name, nsize, hep->key);
  885.     cp = name+5;
  886.     while (*cp)
  887.     {
  888. if (*cp == '-')
  889.     *cp = '_';
  890. ++cp;
  891.     }
  892.     cp = cgi_setenv(envp, name, hep->data);
  893.     
  894.     return 0;
  895. }
  896. static char **cgi_setup_env(const char *method,
  897.     char *url,
  898.     struct connectioninfo *cip,
  899.     struct httpinfo *hip,
  900.     struct mimeinfo *mip,
  901.     const char *path,
  902.     char *path_info,
  903.     char *path_translated)
  904. {
  905.     char **envp, *buf, *request;
  906.     int blen;
  907.     
  908.     envp = s_malloc((max_environ+1) * sizeof(char *));
  909.     if (envp == NULL)
  910. return NULL;
  911.     cgi_setenv(envp, "DOCUMENT_ROOT",
  912.        (exec_newroot == NULL) ? server_home : "/" );
  913.     cgi_setenv(envp, "TZ", tzname[0]);
  914.     cgi_setenv(envp, "PATH", path);
  915.     blen = strlen(server_version) + 8;
  916.     buf = (char *) alloca(blen);
  917.     s_sprintf(buf, blen, "phttpd/%s", server_version);
  918.     
  919.     cgi_setenv(envp, "SERVER_SOFTWARE", buf);
  920.     cgi_setenv(envp, "SERVER_NAME", server_host);
  921.     cgi_setenv(envp, "GATEWAY_INTERFACE", "CGI/1.1");
  922.     cgi_setenv(envp, "REQUEST_METHOD", method);
  923.     cgi_setenv(envp, "PATH_INFO", path_info);
  924.     
  925.     cgi_setenv_i(envp, "SERVER_PORT", server_port);
  926.     
  927.     if (path_translated && path_translated[0])
  928.     {
  929. if (path_translated[0] != '/')
  930. {
  931.     int bufsize;
  932.     bufsize = strlen(server_home) + strlen(path_translated) + 2;
  933.     buf = (char *) alloca(bufsize);
  934.     s_strcpy(buf, bufsize, server_home);
  935.     if (strcmp(path_translated, ".") != 0)
  936.     {
  937. s_strcat(buf, bufsize, "/");
  938. s_strcat(buf, bufsize, path_translated);
  939.     }
  940.     
  941.     cgi_setenv(envp, "PATH_TRANSLATED", buf);
  942. }
  943. else
  944.     cgi_setenv(envp, "PATH_TRANSLATED", path_translated);
  945.     }
  946.     if (cip)
  947.     {
  948. char *hostname, *address, *user;
  949. hostname = address = NULL;
  950. dns_get(cip->server, NULL, &hostname, &address, NULL);
  951. cgi_setenv(envp, "LOCAL_ADDR", address);
  952. cgi_setenv(envp, "LOCAL_HOST", hostname);
  953. hostname = address = NULL;
  954. dns_get(cip->client, NULL, &hostname, &address, NULL);
  955. cgi_setenv(envp, "REMOTE_ADDR", address);
  956. cgi_setenv(envp, "REMOTE_HOST", hostname);
  957. user = NULL;
  958. ident_get(cip->ident, NULL, NULL, &user);
  959. cgi_setenv(envp, "REMOTE_IDENT", user);
  960.     }
  961.     if (hip)
  962.     {
  963. if (hip->aip)
  964. {
  965.     cgi_setenv(envp, "AUTH_TYPE", hip->aip->type);
  966.     if (hip->aip->type && strcasecmp(hip->aip->type, "basic") == 0)
  967. cgi_setenv(envp, "REMOTE_USER", hip->aip->u.basic.username);
  968. #if 0
  969.     cgi_setenv(envp, "PHTTPD_REMOTE_PASSWORD", hip->aip->password);
  970. #endif
  971.     if (hip->aip->xsetenv)
  972. (*hip->aip->xsetenv)(hip->aip->xinfo, cgi_setenv, envp);
  973. }
  974. cgi_setenv(envp, "SERVER_PROTOCOL", hip->version);
  975. /* rkmultimode hip->prelen */
  976.         cgi_setenv(envp, "SCRIPT_NAME", url+hip->prelen);
  977. cgi_setenv(envp, "QUERY_STRING", hip->request);
  978.     }
  979.     
  980.     if (mip)
  981.     {
  982. cgi_setenv(envp, "CONTENT_TYPE",
  983.    mime_getheader(mip, "CONTENT-TYPE", 1));
  984. cgi_setenv(envp, "CONTENT_LENGTH",
  985.    mime_getheader(mip, "CONTENT-LENGTH", 1));
  986. ht_foreach(&mip->table, cse_header, (void *) envp);
  987.     }
  988.     /* Non CGI/1.1 conformant extension, but very nice to have... */
  989.     if (hip->request && hip->request[0])
  990.     {
  991. char **argv;
  992. int reqsize = strlen(hip->request)+1;
  993. request = (char *) alloca(reqsize);
  994. s_strcpy(request, reqsize, hip->request);
  995. if ((argv = strsplit(request, '&', 0)) != NULL)
  996. {
  997.     int i;
  998.     
  999.     for (i = 0; argv[i]; i++)
  1000.     {
  1001. char **varval, *var_name;
  1002. if ((varval = strsplit(argv[i], '=', 2)) != NULL)
  1003. {
  1004.     if (debug > 4)
  1005. fprintf(stderr, "varval[0] = %s, varval[1] = %sn",
  1006. varval[0],
  1007. varval[1]);
  1008.     
  1009.     if (varval[0] && varval[1])
  1010.     {
  1011.         int varsize = strlen(varval[0])+14;
  1012. var_name = (char *) alloca(varsize);
  1013. s_strcpy(var_name, varsize, "PHTTPD_QUERY_");
  1014. s_strcat(var_name, varsize, varval[0]);
  1015. cgi_setenv(envp, var_name, varval[1]);
  1016.     }
  1017.     s_free(varval);
  1018. }
  1019.     }
  1020.     s_free(argv);
  1021. }
  1022.     }
  1023.     
  1024.     return envp;
  1025. }
  1026. static void cgi_free_env(char **envp)
  1027. {
  1028.     int i;
  1029.     
  1030.     if (envp == NULL)
  1031. return;
  1032.     for (i = 0; i < max_environ && envp[i]; i++)
  1033. s_free(envp[i]);
  1034.     s_free(envp);
  1035. }
  1036. static void cmd_exec(struct segment *cp,
  1037.      struct attr_pair *ap,
  1038.      struct includeinfo *ip)
  1039. {
  1040.     int tmp_fd;
  1041.     
  1042.     time(&ip->lastmod);
  1043.     
  1044.     cp->free_start = NULL;
  1045.     cp->block = NULL;
  1046.     if (!exec_enabled)
  1047.     {
  1048. cp->block = "[The exec directive is not allowed]";
  1049. cp->size = strlen(cp->block);
  1050. return;
  1051.     }
  1052.     for ( ; ap != NULL; ap = ap->next)
  1053.     {
  1054. if (ap->name == NULL)
  1055.     continue;
  1056. if (strcmp(ap->name, "cmd") == 0)
  1057. {
  1058.     s_free(ap->name);
  1059.     ap->name = NULL;
  1060.     if (ap->value == NULL)
  1061.     {
  1062. cp->block = "[No program path specified]";
  1063. cp->size = strlen(cp->block);
  1064. break;
  1065.     }
  1066.     else
  1067.     {
  1068. /* Run process, output to temp file, and then
  1069.    mmap it into the block buffer */
  1070. uid_t uid;
  1071. gid_t gid;
  1072. int fd_0, fd_1, fd_2, why, code;
  1073. pid_t pid;
  1074. char *argv[4], **envp, *wdir, *tmps;
  1075. struct stat sb;
  1076. char tbuf[256];
  1077. time_t bt;
  1078. struct tm tp;
  1079. char *path_info = NULL;
  1080. char *path_translated = NULL;
  1081. uid = ip->fep->fip->uid;
  1082. gid = ip->fep->fip->gid;
  1083. if (exec_user_enabled == 0 && uid != -1)
  1084. {
  1085.     cp->block = "[User Exec not allowed]";
  1086.     cp->size = strlen(cp->block);
  1087.     break;
  1088. }
  1089. if (uid == -1)
  1090.     uid = default_exec_uid;
  1091. if (gid == -1)
  1092.     gid = default_exec_gid;
  1093. if ((tmp_fd = s_tmpfile(NULL, 0)) < 0)
  1094. {
  1095.     cp->block = "[Failure creating temporary file]";
  1096.     cp->size = strlen(cp->block);
  1097.     break;
  1098. }
  1099. fd_0 = -1;
  1100. fd_1 = tmp_fd;
  1101. fd_2 = 2;
  1102. argv[0] = "/bin/sh";
  1103. argv[1] = "-c";
  1104. argv[2] = ap->value;
  1105. argv[3] = NULL;
  1106. envp = cgi_setup_env(ip->cip->hip->method,
  1107.      ip->cip->hip->url,
  1108.      ip->cip,
  1109.      ip->cip->hip,
  1110.      ip->cip->hip->mip,
  1111.      exec_path,
  1112.      path_info,
  1113.      path_translated);
  1114. /* rkmultimode hip->prelen */
  1115. cgi_setenv(envp, "DOCUMENT_URI", ip->cip->hip->url+ip->cip->hip->prelen);
  1116. cgi_setenv(envp, "DOCUMENT_ROOT", server_home);
  1117. cgi_setenv(envp, "DOCUMENT_NAME", ip->fep->fip->path);
  1118. cgi_setenv(envp, "QUERY_STRING_UNESCAPED",
  1119.    (tmps = unescape_query(ip->cip->hip->request)));
  1120. s_free(tmps);
  1121. localtime_r(&ip->fep->fip->sb.st_mtime, &tp);
  1122. strftime(tbuf, sizeof(tbuf), ip->timefmt, &tp);
  1123. cgi_setenv(envp, "LAST_MODIFIED", tbuf);
  1124. time(&bt);
  1125. localtime_r(&bt, &tp);
  1126. strftime(tbuf, sizeof(tbuf), ip->timefmt, &tp);
  1127. cgi_setenv(envp, "DATE_LOCAL", tbuf);
  1128. gmtime_r(&bt, &tp);
  1129. strftime(tbuf, sizeof(tbuf), ip->timefmt, &tp);
  1130. cgi_setenv(envp, "DATE_GMT", tbuf);
  1131. wdir = NULL;
  1132. pid = proc_run("/bin/sh",
  1133.        uid, gid,
  1134.        exec_newroot,
  1135.        exec_niceval, exec_vmem,
  1136.        exec_fdmax, exec_maxcputime,
  1137.        fd_0, fd_1, fd_2,
  1138.        argv, envp,
  1139.        wdir,NULL);
  1140. if (pid < 0)
  1141. {
  1142.     cp->block = "[Error starting program]";
  1143.     cp->size = strlen(cp->block);
  1144.     cgi_free_env(envp);
  1145.     break;
  1146. }
  1147. why = proc_wait(pid, &code);
  1148. if (why != PROC_EXIT)
  1149. {
  1150.     cp->block = "[Process exited unexpectedly]";
  1151.     cp->size = strlen(cp->block);
  1152.     cgi_free_env(envp);
  1153.     s_close(tmp_fd);
  1154.     break;
  1155. }
  1156. cgi_free_env(envp);
  1157. if (lseek(tmp_fd, 0, SEEK_SET) < 0)
  1158. {
  1159.     cp->block = "[Unable to lseek on temporary file]";
  1160.     cp->size = strlen(cp->block);
  1161.     s_close(tmp_fd);
  1162.     break;
  1163. }
  1164. if (fstat(tmp_fd, &sb) < 0)
  1165. {
  1166.     cp->block = "[Unable to stat temporary file]";
  1167.     cp->size = strlen(cp->block);
  1168.     s_close(tmp_fd);
  1169.     break;
  1170. }
  1171. cp->free_start = cp->block = s_malloc(sb.st_size);
  1172. if ((cp->size = s_read(tmp_fd, cp->block, sb.st_size)) < 0)
  1173. {
  1174.     s_free(cp->block);
  1175.     cp->free_start = NULL;
  1176.     cp->block = "[Unable to read temporary file]";
  1177.     cp->size = strlen(cp->block);
  1178.     s_close(tmp_fd);
  1179.     break;
  1180. }
  1181. cp->free_size = 0;
  1182. s_close(tmp_fd);
  1183.     }
  1184. }
  1185. else if (strcmp(ap->name, "cgi") == 0)
  1186. {
  1187.     if (ap->value == NULL) {
  1188. cp->block = "[No CGI virtual path specified]";
  1189. cp->size = strlen(cp->block);
  1190. break;
  1191.     }
  1192.     else
  1193.     {
  1194. /* Expand virtual path, then run CGI process
  1195.    with output to temp file. Then check for "Location:"
  1196.    (which gets included as an Anchor somehow) and if not
  1197.    mmap it into the block buffer */
  1198. cp->block = "[Error: 'exec cgi' is not implemented]";
  1199. cp->size = strlen(cp->block);
  1200. break;
  1201.     }
  1202. }
  1203.     }
  1204. }
  1205. static void cmd_count(struct segment *cp, struct attr_pair *ap,
  1206.       struct includeinfo *ip)
  1207. {
  1208.     struct count_t count, total;
  1209.     char *url, *fmt, ch, *char_pt1, *char_pt2, buf[2049];
  1210.     
  1211.     url = ip->cip->hip->orig_url;
  1212.     fmt = "hits";
  1213.     
  1214.     cp->free_start = cp->block = NULL;
  1215.     
  1216.     /* Go through the attribute list */
  1217.     for ( ; ap != NULL; ap = ap->next )
  1218.     {
  1219. /* Skip attributes that have already been dealt with. */
  1220. if ( ap->name == NULL )
  1221.     continue;
  1222. if ( strcmp(ap->name, "virtual") == 0 )
  1223. {
  1224.     s_free(ap->name);
  1225.     ap->name = NULL; /* Mark it as being read */
  1226.     
  1227.     if (ap->value == NULL)
  1228.     {
  1229. cp->block = "[No URL specified]";
  1230. cp->size = strlen(cp->block);
  1231. return;
  1232.     };
  1233.     
  1234.     char_pt1 = buf;
  1235.     if ( ap->value[0] != '/' )
  1236.     {
  1237. s_strcpy(buf, sizeof(buf), ip->cip->hip->url);
  1238. char_pt2 = buf;
  1239. while ( (ch = *char_pt2++) != '' )
  1240.     if ( ch == '/' )
  1241. char_pt1 = char_pt2;
  1242. s_strcpy(char_pt1, sizeof(buf)-(char_pt1-buf), ap->value);
  1243. url = buf;
  1244.     }
  1245.     else
  1246.     {
  1247. url = ap->value;
  1248.     };
  1249. }
  1250. else
  1251.     if ( strcmp(ap->name, "fmt") == 0 )
  1252.     {
  1253. s_free(ap->name);
  1254. ap->name = NULL; /* Mark it as being read */
  1255. if (ap->value == NULL)
  1256. {
  1257.     cp->block = "[No format specified]";
  1258.     cp->size = strlen(cp->block);
  1259.     return;
  1260. };
  1261. fmt = ap->value;
  1262.     };
  1263.     }
  1264.     
  1265.     get_count(url, &count);
  1266.     get_totals(&total);
  1267.     
  1268.     if ( strcmp(fmt, "%hits") == 0 )
  1269. s_sprintf(buf, sizeof(buf), "%04.2f",
  1270. 100.0*(float)(count.totalhits+1)/(float)(total.totalhits+1));
  1271.     else
  1272. if ( strcmp(fmt, "%bytes") == 0 ) 
  1273.     s_sprintf(buf, sizeof(buf), "%04.2f",
  1274.     100.0*(float)(count.totalbytes)/(float)(total.totalbytes));
  1275. else
  1276.     if ( strcmp(fmt, "hits") == 0 ) 
  1277. s_sprintf(buf, sizeof(buf), "%lu",count.totalhits+1);
  1278.     else
  1279. s_sprintf(buf, sizeof(buf), "%lu",count.totalbytes);
  1280.     
  1281.     cp->free_start = cp->block = s_strdup(buf);
  1282.     cp->size = strlen(cp->block);
  1283.     cp->free_size = 0;
  1284.     time(&ip->lastmod);
  1285. }
  1286. /* Does the actual parsing. It builds up a linked list of elements */
  1287. /* containing the pieces that make up the document. */
  1288. static int do_parse(struct segment *cp, struct includeinfo *ip)
  1289. {
  1290.     struct segment *cp1, *cp2;
  1291.     char *char_pt, *end, *start_inc, *start_attr, *end_attr, *attr_pt;
  1292.     unsigned char ch, quote;
  1293.     int value_found;
  1294.     int i;
  1295.     size_t max;
  1296.     size_t length = 0;
  1297.     struct attr_pair *attributes,*ap;
  1298.     
  1299.     char_pt = cp->block;
  1300.     end = char_pt + cp->size;
  1301.   
  1302.     /* Main loop: go through it until there are no more includes */
  1303.     do
  1304.     {
  1305.     
  1306. /* Search until you either hit "<!--#" or reach the end of the */
  1307. /* file. This is a simple, yet fast algorithm that in a typical */
  1308. /* HTML document only needs to look at between 20% - 25% of the */
  1309. /* characters. */
  1310. char_pt += 4;
  1311. while ( char_pt < end )
  1312. {
  1313.     if ( (ch = *char_pt) == '#' )
  1314. if (strncmp(&char_pt[-4],"<!--",4) == 0)
  1315.     break;
  1316.     char_pt += start_fsm[(int)ch];
  1317. }
  1318. if ( ++char_pt >= end )
  1319.     break; /* Nothing found */
  1320.     
  1321. /* This is where the command name and attribute list starts. */
  1322. start_inc = (start_attr = attr_pt = char_pt) - 5;
  1323.     
  1324. /* Ok, now find the end of the comment. */
  1325. char_pt += 2;
  1326. while ( char_pt < end )
  1327. {
  1328.     if ( (ch = *char_pt) == '>' )
  1329. if (char_pt[-2]=='-' && char_pt[-1]=='-')
  1330.     break;
  1331.     char_pt += end_fsm[(int)ch];
  1332. };
  1333. if ( ++char_pt >= end )
  1334.     break; /* No end found */
  1335.     
  1336. /* The end of the attribute list is 3 characters earlier */
  1337. end_attr = char_pt - 3;
  1338.     
  1339. /* Skip white space */
  1340. while ( attr_pt < end_attr && s_isspace(*attr_pt) )
  1341.     attr_pt++;
  1342. if ( attr_pt >= end_attr )
  1343.     continue; /* No command name */
  1344.     
  1345. /* Find the command name */
  1346. max = end_attr - attr_pt;
  1347. for ( i = 0; commands[i].name != NULL; i++ )
  1348. {
  1349.     length = strlen(commands[i].name);
  1350.     if ( length <= max &&
  1351. strncasecmp(commands[i].name, attr_pt, length)==0 &&
  1352. (s_isspace(attr_pt[length]) || length==max) )
  1353. break;
  1354. };
  1355.     
  1356. /* If no valid command, search for next include */
  1357. if ( commands[i].name == NULL )
  1358.     continue;
  1359.     
  1360. /* There was a valid command. Now we have to include stuff. */
  1361. if ( debug > 2 )
  1362.     fprintf(stderr, "Server-side include: %sn", commands[i].name);
  1363.     
  1364. /* First, check to see if we have to look for attributes. */
  1365. attributes = ap = NULL;
  1366. if ( commands[i].has_attributes)
  1367. {
  1368.       
  1369.     /* Parse attributes */
  1370.     attr_pt += length; /* skip command name */
  1371.     while ( attr_pt < end_attr )
  1372.     {
  1373. /* Skip white space */
  1374. while ( s_isspace(*attr_pt) )
  1375.     attr_pt++;
  1376. if ( attr_pt >= end_attr )
  1377.     break;
  1378. /* Read in attribute name */
  1379. ch = *attr_pt;
  1380. start_attr = attr_pt;
  1381. while ( attr_pt < end_attr && !s_isspace(ch) && ch != '=' )
  1382.     ch = *++attr_pt;
  1383. length = attr_pt - start_attr;
  1384. if ( length <= 0 ) break;
  1385. /* Start another name=value pair */
  1386. if ( attributes == NULL )
  1387. {
  1388.     ap = s_malloc(sizeof(struct attr_pair));
  1389.     attributes = ap;
  1390. }
  1391. else
  1392. {
  1393.     ap->next=s_malloc(sizeof(struct attr_pair));
  1394.     ap = ap->next;
  1395. }
  1396. ap->next = NULL;
  1397. ap->name = s_malloc(length+1);
  1398. s_strncpy(ap->name, length+1, start_attr, length);
  1399. ap->name[length] = '';
  1400. ap->value = NULL;
  1401. /* Is there an attribute value? */
  1402. value_found = 0;
  1403. while ( s_isspace(ch) || ch == '=' )
  1404. {
  1405.     if ( ch == '=' ) value_found = 1;
  1406.     ch = *++attr_pt;
  1407. }
  1408. if ( attr_pt >= end_attr )
  1409.     break;
  1410. /* Is there a value to this attribute? */
  1411. if ( value_found )
  1412.     /* Is it quoted? */
  1413.     if ( ch == '"' || ch == ''' )
  1414.     { /* Yep, is quoted */
  1415. quote = ch;
  1416. ch = *++attr_pt;
  1417.     
  1418. /* Read in attribute value */
  1419. start_attr = attr_pt;
  1420. while ( attr_pt < end_attr && ch != quote )
  1421.     ch = *++attr_pt;
  1422. length = attr_pt - start_attr;
  1423. ap->value = s_malloc(length+1);
  1424. s_strncpy(ap->value, length+1, start_attr, length);
  1425. ap->value[length] = '';
  1426.     
  1427. /* Skip over closing quote. */
  1428. attr_pt++;
  1429.     }
  1430.     else
  1431.     { /* Not quoted */
  1432.     
  1433. /* Read in attribute value */
  1434. start_attr = attr_pt;
  1435. while ( attr_pt < end_attr && !s_isspace(ch) )
  1436.     ch = *++attr_pt;
  1437. length = attr_pt - start_attr;
  1438. ap->value = s_malloc(length+1);
  1439. s_strncpy(ap->value, length+1, start_attr, length);
  1440. ap->value[length] = '';
  1441.     } /* if (ch=='"') */
  1442.     } /* while (attr_pt<end_attr) */
  1443.       
  1444.     if ( attributes && debug > 3 )
  1445.     {
  1446. fprintf(stderr, "  attributes:n");
  1447. for ( ap = attributes; ap != NULL; ap = ap->next )
  1448.     fprintf(stderr, "    %s = %sn",
  1449.     ap->name,
  1450.     ap->value ? ap->value : "<null>");
  1451.     }
  1452. } /* if (has_attributes) */
  1453.     
  1454. /* Cut up old segment in two. */
  1455. cp2 = s_malloc(sizeof(struct segment));
  1456. cp2->next = NULL;
  1457. cp2->block = char_pt;
  1458. cp2->size = end - char_pt;
  1459. cp2->free_start = cp->free_start;
  1460. cp2->free_size  = cp->free_size;
  1461. cp2->fep        = cp->fep;
  1462. cp->next = cp2;
  1463. cp->size = start_inc - cp->block;
  1464. cp->free_start = NULL;
  1465. cp->free_size = 0;
  1466. cp->fep = NULL;
  1467. if ( ip->length )
  1468.     ip->length -= (char_pt - start_inc);
  1469.     
  1470. /* Create a new segment and fill it with text. */
  1471. cp2 = s_malloc(sizeof(struct segment));
  1472. cp2->next = NULL;
  1473. cp2->fep  = NULL;
  1474. commands[i].function(cp2, attributes, ip);
  1475.     
  1476. /* If not empty, insert the segment(s). */
  1477. if ( cp2->block != NULL )
  1478. {
  1479.     cp1 = cp->next;
  1480.     cp->next = cp2;
  1481.     while ( cp->next != NULL)
  1482. cp = cp->next;
  1483.     cp->next = cp1;
  1484. }
  1485. cp = cp->next;
  1486. if ( ip->length )
  1487.     ip->length += cp2->size;
  1488.     
  1489. /* Free up space occupied by attributes */
  1490. while ( attributes != NULL )
  1491. {
  1492.     ap = attributes;
  1493.     attributes = attributes->next;
  1494.     if ( ap->name  != NULL )
  1495. s_free(ap->name);
  1496.     if ( ap->value != NULL )
  1497. s_free(ap->value);
  1498.     s_free(ap);
  1499. }
  1500.     
  1501.     } while (char_pt < end);
  1502.   
  1503.     return 0;
  1504. }
  1505. static int parse_file(struct segment *cp, struct includeinfo *ip)
  1506. {
  1507.     int size;
  1508.   
  1509.     ip->level = 0;
  1510.     ip->timefmt = s_strdup(DEFAULT_TIMEFMT);
  1511.     ip->sizefmt = NULL;
  1512.     ip->errmsg = s_strdup("[an error occurred while processing this directive]");
  1513.   
  1514.     size = do_parse(cp, ip);
  1515.   
  1516.     config_include_free(ip);
  1517.   
  1518.     return size;
  1519. }
  1520. static int send_segment(int fd, struct segment *cp, int send_out)
  1521. {
  1522.     int bytes_sent = 0;
  1523.   
  1524.     /* Do we have to send anything at all? */
  1525.     if (send_out)
  1526.     {
  1527. if (cp->block != NULL)
  1528.     if (fd_write(fd, cp->block, cp->size) < 0)
  1529. bytes_sent = -1;
  1530.     else
  1531. bytes_sent = cp->size;
  1532.     }
  1533.   
  1534.     /* Free the occupied space and close any open files */
  1535.     if ( cp->free_start != NULL && cp->fep == NULL )
  1536. s_free(cp->free_start);
  1537.     if (cp->fep != NULL)
  1538.     {
  1539. fscache_release(cp->fep);
  1540.     }
  1541.     
  1542.     return bytes_sent;
  1543. }
  1544. static int http_get_head(struct connectioninfo *cip)
  1545. {
  1546.     char *s_since;
  1547. #if 0
  1548.     char buf[256];
  1549.     struct tm tm_since;
  1550.     int t_since;
  1551.     int i;
  1552. #endif
  1553.     struct stat sb;
  1554.     int result;
  1555.     int fd = cip->fd;
  1556.     struct httpinfo *hip = cip->hip;
  1557.     fscentry_t *fep;
  1558.     fsinfo_t *fip;
  1559.     int send_out = 1;
  1560.     int bytes_sent = 0;
  1561.     struct segment contents = {NULL, NULL, 0, NULL, 0};
  1562.     struct segment *cp1, *cp2;
  1563.     struct includeinfo parse_config;
  1564.     unsigned int fsc_flags = 0;
  1565.     
  1566.     if (debug > 1)
  1567. fprintf(stderr, "*** ncsa-html/pm_get() called ***n");
  1568.     
  1569.     if (hip && hip->mip && (hip->mip->pragma_flags & MPF_NOCACHE))
  1570. fsc_flags = FSCF_RELOAD;
  1571.     /* Look up information about this document */
  1572.     fep = fscache_lookup(hip->url, fsc_flags|FSCF_GETDATA);
  1573.     
  1574.     if (fep == NULL)
  1575. return -1;
  1576.     if (fep->fip == NULL)
  1577.     {
  1578. fscache_release(fep);
  1579. return -1;
  1580.     }
  1581.     fip = fep->fip;
  1582.     parse_config.cip = cip;
  1583.     parse_config.fep = fep;
  1584.     parse_config.lastmod = fip->sb.st_mtime;
  1585.     parse_config.length = fip->sb.st_size;
  1586.     parse_config.fsc_flags = fsc_flags;
  1587.     result = 200;
  1588.     s_since = mime_getheader(hip->mip, "IF-MODIFIED-SINCE", 1);
  1589.     
  1590.     hip->length = 0;
  1591.     
  1592.     if (strcasecmp(hip->method, "HEAD") == 0)
  1593.     {
  1594. send_out = 0;
  1595.     }
  1596.     if (debug > 2)
  1597. fprintf(stderr, "Setting up contents structure for filen");
  1598.     
  1599.     /* Setup contents structure for file */
  1600.     contents.block = fip->data.file.content;
  1601.     
  1602.     contents.next = NULL;
  1603.     contents.free_size = contents.size = fip->sb.st_size;
  1604.     contents.free_start = contents.block;
  1605.     contents.fep = fep;
  1606.     cp1 = &contents;
  1607.     if (contents.block == (char *) MAP_FAILED)
  1608.     {
  1609. if (debug)
  1610. {
  1611.     fprintf(stderr, "ERROR on #%d: ", cip->request_no);
  1612.     perror("mmap");
  1613. }
  1614. result = 500;
  1615. if ( hip->mip != NULL )
  1616.     http_error(cip, result, "Failed to map file into memory");
  1617.     }
  1618.     else
  1619.     {
  1620. /* Parse file if necessary. This may split up the file into */
  1621. /* several segments. */
  1622. madvise(contents.block, contents.size, MADV_WILLNEED);
  1623. parse_file(cp1, &parse_config);
  1624. madvise(contents.block, sb.st_size, MADV_SEQUENTIAL);
  1625. if (hip->mip != NULL)
  1626. {
  1627. #if 0
  1628.     if (s_since && parse_config.lastmod)
  1629.     {
  1630. t_since = atotm(s_since, &tm_since);
  1631. if (t_since != -1 )
  1632. {
  1633.     if (fip->sb.st_mtime <= (time_t) t_since)
  1634.     {
  1635. result = 304;
  1636. send_out = 0;
  1637.     }
  1638. }
  1639. else
  1640. {
  1641.     /* Could not parse the date format - do a string compare */
  1642.     http_time_r(&parse_config.lastmod, buf, sizeof(buf));
  1643.     i = strlen(buf);
  1644.     buf[i-1] = '';
  1645.     if (strcmp(s_since, buf) == 0)
  1646.     {
  1647. result = 304;
  1648. send_out = 0;
  1649.     }
  1650. }
  1651.     }
  1652. #endif
  1653.     
  1654.     http_sendheaders(fd, cip, result, NULL);
  1655.     if (send_out)
  1656.     {
  1657. if (parse_config.lastmod)
  1658.     http_sendlastmodified(fd, parse_config.lastmod);
  1659. if (parse_config.length)
  1660.     fd_printf(fd, "Content-Length: %dn", parse_config.length);
  1661. fd_puts("Content-Type: text/htmln", fd);
  1662. http_sendlang(fd, hip->url);
  1663.     }
  1664.     fd_putc('n', fd);
  1665. }
  1666. /* Now go through segment by segment and send it out, freeing */
  1667. /* up the memory space or unmapping files if necessary. */
  1668. do
  1669. {
  1670.     if ((bytes_sent = send_segment(fd, cp1, send_out)) < 0)
  1671.     {
  1672. if (debug)
  1673. {
  1674.     fprintf(stderr, "ERROR on #%d: ", cip->request_no);
  1675.     (bytes_sent == -1 ? perror("write") : perror("close"));
  1676. }
  1677.     }
  1678.     else
  1679. hip->length += bytes_sent;
  1680.     cp2 = cp1->next;
  1681.     if ( cp1 != &contents )
  1682. s_free(cp1);
  1683.     cp1 = cp2;
  1684. } while (cp1 != NULL);
  1685.     }
  1686.     if (debug > 2)
  1687. fprintf(stderr, "ncsa-html/http_get: Returningn");
  1688.     
  1689.     return result;
  1690. }
  1691. int pm_request(struct connectioninfo *cip)
  1692. {
  1693.     struct httpinfo *hip = cip->hip;
  1694.     
  1695.     if (strcasecmp(hip->method, "GET") == 0 ||
  1696. strcasecmp(hip->method, "HEAD") == 0)
  1697. return http_get_head(cip);
  1698.     else
  1699. return -2;
  1700. }