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

Web服务器

开发平台:

Unix_Linux

  1. /*
  2. ** url.c
  3. **
  4. ** Copyright (c) 1994-1997 Peter Eriksson <pen@signum.se>
  5. **
  6. ** This program is free software; you can redistribute it and/or modify
  7. ** it under the terms of the GNU General Public License as published by
  8. ** the Free Software Foundation; either version 2 of the License, or
  9. ** (at your option) any later version.
  10. **
  11. ** This program is distributed in the hope that it will be useful,
  12. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. ** GNU General Public License for more details.
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program; if not, write to the Free Software
  17. ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19. #include <stdio.h>
  20. #include <alloca.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <pwd.h>
  24. #include <unistd.h>
  25. #include <errno.h>
  26. #include <syslog.h>
  27. #include <sys/types.h>
  28. #include <sys/stat.h>
  29. #define IN_DNS_C
  30. #include "phttpd.h"
  31. #define HTOI(c) (((c) >= 'A') ? (((c) & 0xDF) - 'A') + 10 : (c) - '0')
  32. struct table *url_handlers_table = NULL;
  33. struct table *url_redirects_table = NULL;
  34. struct table *url_predirects_table = NULL;
  35. struct table *url_rewrites_table = NULL;
  36. struct table *read_authenticate_table = NULL;
  37. struct table *write_authenticate_table = NULL;
  38. struct table *host_access_table = NULL;
  39. struct table *url_expand_table = NULL;
  40. struct table *content_language_table = NULL;
  41. char *expand_symlink(const char *path,
  42.      char *realpath,
  43.      int maxsize)
  44. {
  45.     char *buf;
  46.     char *cp;
  47.     int len;
  48.     
  49.     buf = (char *) alloca(maxsize+1);
  50.     if (buf == NULL)
  51. return NULL;
  52.     
  53.     if ((len = s_readlink(path, buf, maxsize)) < 0)
  54.     {
  55. if (errno == EINVAL)
  56. {
  57.     s_strcpy(realpath, maxsize, path);
  58.     return realpath;
  59. }
  60. return NULL;
  61.     }
  62.     
  63.     buf[len] = '';
  64.     if (buf[0] == '/')
  65. s_strcpy(realpath, maxsize, buf);
  66.     else
  67.     {
  68. cp = strrchr(path, '/'); /* Find last / in filename */
  69. if (cp)
  70. {
  71.     s_strcpy(realpath, maxsize, path);
  72.     s_strcpy(realpath + (cp - path) + 1, maxsize, buf);
  73. }
  74. else
  75.     s_strcpy(realpath, maxsize, buf);
  76.     }
  77.     return realpath;
  78. }
  79. char *url_expand(const char *path,
  80.  char *realpath,
  81.  int maxsize,
  82.  struct stat *sp,
  83.  uid_t *uid,
  84.  gid_t *gid)
  85. {
  86.     const char *cp;
  87.     char *outpath;
  88.     struct passwd *pwp;
  89.     void *uc_key;
  90.     char buf[2048];
  91.     char name[64];
  92.     char *end;
  93.     int len;
  94.     int i;
  95.     outpath = (char *) alloca(maxsize);
  96.     if (outpath == NULL)
  97. return NULL;
  98.     /* An URL must begin with a '/' */
  99.     if (*path++ != '/')
  100. return NULL;
  101.     /* And the second character must NOT be a '/' */
  102.     if (*path == '/')
  103. return NULL;
  104.     
  105.     /* "/../" is not allowed in the path */
  106.     for (cp = path-1; *cp; cp++)
  107. if (cp[0] == '/' && cp[1] == '.' && cp[2] == '.' &&
  108.     (cp[3] == '/' || cp[3] == ''))
  109. {
  110.     return NULL;
  111. }
  112.     /* Handle ~user expansion */
  113.     if (*path == '~')
  114.     {
  115. /* Locate end of username */
  116. end = strchr(++path, '/');
  117. if (end)
  118. {
  119.     len = end - path;
  120.     if (len+1 > sizeof(buf))
  121. len = sizeof(buf)-1;
  122. }
  123. else
  124.     len = strlen(path);
  125.     
  126. s_strncpy(name, sizeof(name), path, len);
  127. if ((uc_key = usercache_lookup(name, 0, &pwp)) == NULL)
  128.     return NULL;
  129. if (pwp == NULL || pwp->pw_dir == NULL)
  130. {
  131.     usercache_release(uc_key);
  132.     return NULL;
  133. }
  134. if (uid)
  135.     *uid = pwp->pw_uid;
  136. if (gid)
  137.     *gid = pwp->pw_gid;
  138. if (user_basedir)
  139. {
  140.     len = s_strcpy(outpath, maxsize, user_basedir);
  141.     if (len > 0 && outpath[len-1] != '/')
  142. s_strcat(outpath, maxsize, "/");
  143.     len = s_strcat(outpath, maxsize, name);
  144. }
  145. else
  146.     len = s_strcpy(outpath, maxsize, pwp->pw_dir);
  147. if (user_dir && user_dir[0])
  148. {
  149.     if (len > 0 && outpath[len-1] != '/')
  150. len = s_strcat(outpath, maxsize, "/");
  151.     
  152.     s_strcat(outpath, maxsize, user_dir);
  153. }
  154. if (end)
  155.     s_strcat(outpath, maxsize, end);
  156. usercache_release(uc_key);
  157.     }
  158.     else
  159. s_strcpy(outpath, maxsize, path);
  160.     
  161.     i = strlen(outpath) - 1;
  162.     while (i >= 0 && outpath[i] == '/')
  163. i--;
  164.     outpath[i+1] = '';
  165.     if (outpath[0] == '')
  166. s_strcpy(outpath, maxsize, ".");
  167.     
  168.     if (sp && s_stat(outpath, sp) < 0)
  169. return NULL;
  170.     s_strcpy(realpath, maxsize, outpath);
  171.     return realpath;
  172. }
  173. char *url_getparent(const char *path, char *buf, int bufsize)
  174. {
  175.     char *cp;
  176.     
  177.     s_strcpy(buf, bufsize, path);
  178.     cp = strrchr(buf, '/');
  179.     if (cp && cp > buf)
  180.     {
  181. /* Remove trailing '/' */
  182. *cp = '';
  183. cp = strrchr(buf, '/');
  184. if (cp)
  185.     *++cp = '';
  186. else
  187. {
  188.     s_strcpy(buf, bufsize, "/");
  189.     return buf;
  190. }
  191. return buf;
  192.     }
  193.     else
  194.     {
  195. s_strcpy(buf, bufsize, "/");
  196. return buf;
  197.     }
  198. }
  199. char *url_quote(const char *from,
  200. char *to,
  201. int size,
  202. char *quotemap,
  203. int only_qm)
  204. {
  205.     static const char bin2hex[] = "0123456789ABCDEF";
  206.     char *retval;
  207.     const unsigned char *fp;
  208.     
  209.     fp = (const unsigned char *) from;
  210.     retval = to;
  211.     if (quotemap == NULL)
  212. quotemap = ""+?& ";
  213.     
  214.     while (*fp)
  215.     {
  216. if (only_qm ?
  217.     (strchr(quotemap, *fp) != NULL) :
  218.     (*fp == '%' ||
  219.      *fp == '"' ||
  220.      *fp <= ' ' ||
  221.      strchr(quotemap, *fp) != NULL ||
  222.      (*fp >= 127 && 
  223.       *fp <= (unsigned char) (128+(unsigned char)' ')) ||
  224.      *fp == 255))
  225. {
  226.     if ((to-retval) < size-3)
  227.     {
  228. *to++ = '%';
  229. *to++ = bin2hex[((*fp) >> 4) & 0x0F];
  230. *to++ = bin2hex[(*fp) & 0x0F];
  231. ++fp;
  232.     }
  233.     else
  234. break;
  235. }
  236. else
  237.     if ((to-retval) < size-1)
  238. *to++ = *fp++;
  239.     else
  240. break;
  241. }
  242.     *to = '';
  243.     /* to=retval; */
  244.     return retval;
  245. }
  246. void url_unquote(char *str, int plus_flag)
  247. {
  248.     char *to;
  249.     int val;
  250.     
  251.     to = str;
  252.     
  253.     while (*str)
  254. switch (*str)
  255. {
  256.   case '+':
  257.     if (plus_flag)
  258. *to++ = ' ';
  259.     else
  260. *to++ = '+';
  261.     
  262.     ++str;
  263.     break;
  264.     
  265.   case '%':
  266.     ++str;
  267.     val = 0;
  268.     
  269.     if (*str && s_isxdigit(*str))
  270.     {
  271. val = HTOI(*str);
  272. ++str;
  273.     }
  274.     if (*str && s_isxdigit(*str))
  275.     {
  276. val *= 16;
  277. val += HTOI(*str);
  278. ++str;
  279.     }
  280.     *to++ = val;
  281.     
  282.     break;
  283.     
  284.   default:
  285.     *to++ = *str++;
  286. }
  287.     *to = '';
  288. }
  289. /* this will strip // -> /, /./ -> /  and /dir/../ -> /dir/.
  290.  */
  291. void url_cleanup(char *str)
  292. {
  293.     char *to;
  294.     char *start;
  295.     char *back=NULL;
  296.     to = str;
  297.     start=to;
  298.     while (*str)
  299. {
  300.   if ( strncmp(str,"//",2) == 0 ) { str++; }
  301.           else if ( strncmp(str,"/./",3) == 0 ) { str++; str++; }
  302.   else if ( strncmp(str,"/../",4) == 0 )
  303. {
  304. if ( to!=start) 
  305. back=to-1;
  306. while ( back!=start && *back!='/' ) back--;
  307. }
  308. if ( back != NULL ) to=back;
  309. str=str+3;
  310. }
  311.   else
  312.   { *to++ = *str++; }
  313. }
  314.     *to = '';
  315. }
  316. const char *url_gethandler(char *url)
  317. {
  318.     int i;
  319.     int len;
  320.     
  321.     len = strlen(url);
  322.     
  323.     if (url_handlers_table)
  324.     {
  325. for (i = 0; i < url_handlers_table->length; i++)
  326. {
  327.     char **pair = url_handlers_table->value[i];
  328.     
  329.     if (debug > 3)
  330. fprintf(stderr, "       (Checking URL %s vs %s)n",
  331. url, pair[0]);
  332.     if (strmatch(url, pair[0]))
  333.     {
  334.         if (debug > 1)
  335.     fprintf(stderr, "      (URL %s -> Handler %s)n",
  336.     url, pair[1]);
  337.     
  338. return pair[1];
  339.     }
  340.   }
  341.     }
  342.     
  343.     if (len > 0 && url[len-1] == '/')
  344.     {
  345. if (debug > 1)
  346.     fprintf(stderr, "      (URL %s -> Handler %s)n",
  347.     url, default_dir_handler);
  348. return default_dir_handler;
  349.     }
  350.     else
  351.     {
  352. if (debug > 1)
  353.     fprintf(stderr, "      (URL %s -> Handler %s)n",
  354.     url, default_file_handler);
  355. return default_file_handler;
  356.     }
  357. }
  358. char *url_match(struct table *tp,
  359. const char *url,
  360. char *result,
  361. int size)
  362. {
  363.     int i;
  364.     
  365.     if (tp == NULL)
  366. return NULL;
  367.     
  368.     for (i = 0; i < tp->length; i++)
  369.     {
  370. char **pair = tp->value[i];
  371. if (strmatch(url, pair[0]))
  372. {
  373.     s_strcpy(result, size, pair[1]);
  374.     return result;
  375. }
  376.     }
  377.     return NULL;
  378. }
  379. char *url_getredirect(const char *url,
  380.       char *out_url,
  381.       int size)
  382. {
  383.     char rewrite_pattern[256];
  384.     
  385.     if (url_match(url_redirects_table, url, 
  386.   rewrite_pattern, sizeof(rewrite_pattern)))
  387.     {
  388. if (url_rewrite(url, rewrite_pattern, out_url, size))
  389.     return out_url;
  390.     }
  391.     return NULL;
  392. }
  393. char *url_getpredirect(const char *url,
  394.        char *out_url,
  395.        int size)
  396. {
  397.     char rewrite_pattern[256];
  398.     
  399.     if (url_match(url_predirects_table, url, 
  400.   rewrite_pattern, sizeof(rewrite_pattern)))
  401.     {
  402. if (url_rewrite(url, rewrite_pattern, out_url, size))
  403.     return out_url;
  404.     }
  405.     return NULL;
  406. }
  407. char *url_getrewrite(const char *url,
  408.      char *out_url,
  409.      int url_size)
  410. {
  411.     char rewrite_pattern[1024];
  412.     
  413.     if (url_match(url_rewrites_table, url,
  414.   rewrite_pattern, sizeof(rewrite_pattern)))
  415.     {
  416. return url_rewrite(url, rewrite_pattern,
  417.    out_url, url_size);
  418.     }
  419.     return NULL;
  420. }
  421. /* added RK */
  422. char *write_getauthenticate(const char *url,
  423.   char *out_url,
  424.   int size)
  425. {
  426.     char auth_buf[1024];
  427.     
  428.     if (url_match(write_authenticate_table, url, 
  429.   auth_buf, sizeof(auth_buf)))
  430.     {
  431. s_strcpy(out_url, size, auth_buf);
  432. return out_url;
  433.     }
  434.     return NULL;
  435. }
  436. char *read_getauthenticate(const char *url,
  437.   char *out_url,
  438.   int size)
  439. {
  440.     char auth_buf[1024];
  441.     
  442.     if (url_match(read_authenticate_table, url, 
  443.   auth_buf, sizeof(auth_buf)))
  444.     {
  445. s_strcpy(out_url, size, auth_buf);
  446. return out_url;
  447.     }
  448.     return NULL;
  449. }
  450. char *host_getaccess(const char *url,
  451.     char *out_url,
  452.     int size)
  453. {
  454.     return url_match(host_access_table, url, out_url, size);
  455. }
  456. static int get_num(char **cp)
  457. {
  458.     int val = 0;
  459.     
  460.     while (s_isdigit(**cp))
  461.     {
  462. val *= 10;
  463. val += (**cp - '0');
  464. ++*cp;
  465.     }
  466.     return val;
  467. }
  468. static int get_args(char **cp, int *v1, int *v2)
  469. {
  470.     if (**cp != '{')
  471. return 0;
  472.     ++*cp;
  473.     
  474.     if (s_isdigit(**cp))
  475.     {
  476. *v1 = get_num(cp);
  477. if (**cp == '}') /* %{99} */
  478. {
  479.     *v2 = *v1;
  480.     ++*cp;
  481.     
  482.     return 1;
  483. }
  484. else if (**cp == '-')
  485. {
  486.     ++*cp;
  487.     
  488.     if (s_isdigit(**cp)) /* %{1-99} */
  489.     {
  490. *v2 = get_num(cp);
  491. if (**cp == '}')
  492. {
  493.     ++*cp;
  494.     return 1;
  495. }
  496.     }
  497.     else if (**cp == '}')
  498.     {
  499. *v2 = 99999;
  500. ++*cp;
  501. return 1;
  502.     }
  503.     return 0;
  504. }
  505. else
  506. {
  507.     return 0;
  508. }
  509.     }
  510.     
  511.     else if ((*cp)[0] == '*' && (*cp)[1] == '}') /* %{*} */
  512.     {
  513. *v1 = 0;
  514. *v2 = 999999; /* Some huge number */
  515. ++*cp;
  516. ++*cp;
  517. return 1;
  518.     }
  519.     
  520.     else if (**cp == '-') /* %{-99} */
  521.     {
  522. *v1 = 0;
  523. ++*cp;
  524. if (s_isdigit(**cp))
  525. {
  526.     *v2 = get_num(cp);
  527.     
  528.     if (**cp == '}')
  529.     {
  530. ++*cp;
  531. return 1;
  532.     }
  533.     else
  534.     {
  535. return 0;
  536.     }
  537. }
  538. else if (**cp == '}') /* %{-} */
  539. {
  540.     *v2 = -1;
  541.     ++*cp;
  542.     
  543.     return 1;
  544. }
  545. return 0;
  546.     }
  547.     else
  548. return 0;
  549. }
  550. /*
  551. ** Yuk! This code is _ugly_! Can't someone rewrite it to be nicer
  552. ** to read, and have more features?
  553. **
  554. ** TODO: Fix the handling of the "?request" part.
  555. */
  556. char *url_rewrite(const char *url,
  557.   const char *pattern,
  558.   char *buf,
  559.   int size)
  560. {
  561.     char **argv;
  562.     char *start = buf;
  563.     const char *ppos = pattern;
  564.     char *cp;
  565.     int i;
  566.     int argc;
  567.     char *tmp, *qtmp;
  568.     int tlen,xlen;
  569.     
  570.     if (debug > 2)
  571. fprintf(stderr, "url_rewrite("%s", "%s", ..., %d)n",
  572. url, pattern, size);
  573.     tlen = strlen(url)+1;
  574.     tmp = (char *) alloca(tlen);
  575.     if (tmp == NULL)
  576.     {
  577. if (debug > 2)
  578.     fprintf(stderr, "t-> NULLn");
  579. return NULL;
  580.     }
  581.     s_strcpy(tmp, tlen, url+1);
  582.     qtmp= strchr(tmp,'?'); /* encoding ?? RK */
  583.     if ( qtmp != NULL ) { *qtmp=0x00; qtmp++; } 
  584.     argv = strsplit(tmp, '/', 0);
  585.     
  586.     for (argc = 0; argv[argc]; argc++)
  587. ;
  588.     while ((cp = strchr(ppos, '%')) != NULL)
  589.     {
  590. int len = cp - ppos;
  591. int v1, v2;
  592. if (len > 0)
  593. {
  594.     s_strncpy(buf, size, ppos, len);
  595.     buf += len;
  596.     size -= len;
  597. }
  598. ++cp;
  599. if (get_args(&cp, &v1, &v2))
  600. {
  601.     for (i = v1; i <= v2 && i < argc; i++)
  602.     {
  603. s_strcpy(buf, size, argv[i]);
  604.     
  605. while (*buf)
  606. {
  607.     ++buf;
  608.     --size;
  609. }
  610. if (i < v2 && i + 1< argc)
  611. {
  612.     *buf++ = '/';
  613.     --size;
  614. }
  615.     }
  616. }
  617. ppos = cp;
  618.     }
  619.     xlen=strlen(ppos);
  620.     s_strncpy(buf, size, ppos,xlen);
  621.     buf += xlen;
  622.     size -= xlen;
  623.     if ( qtmp != NULL )
  624.     { s_strncpy(buf, size, "?" , 1 );
  625.       buf++; size--;
  626.       if ( *qtmp != 0x00 )
  627.       s_strncpy(buf, size, qtmp , strlen(qtmp));
  628.     }
  629.     s_free(argv);
  630.     if (debug > 2)
  631. fprintf(stderr, "t-> "%s"n", start);
  632.     
  633.     return start;
  634. }
  635. /* In case of mulitmode or SVS, we need to build cip->sip->url (http://server.name.domain/) */
  636. /* from the data we got. This is needed in file.c, error.c dir.c and may be some more. */
  637. /* Added RK@netuse.de */
  638. char *make_sip_url(struct connectioninfo *cip, char *extname, int retsize )
  639. {
  640.    char *hnl,*surl;
  641. /* ADDED RK: we need to get the servername for corect redirects here manual :-( */
  642.         if ( softvirtserver == 0 )
  643.          {
  644.           if (rkmultimode==0)
  645. /* Standart mode, only copy url. */
  646.             s_strcpy(extname, retsize, cip->sip->url);
  647.           else
  648.           {
  649. /* If we run rkmultimode, we need to do a reverse lookup to our socket, since we */
  650. /* do not have a table. For performance reasons, a reverse lookup it not done on */
  651. /* every request near the accept, but only here in case of a redirect, since */
  652. /* that case happens fewer times :-( (and DNS is not MT-Safe, */
  653. /* thus the call may block */
  654.             hnl=dns_lookup_servername(cip->server);
  655.             if ( hnl==NULL ) hnl=s_strdup(inet_ntoa(cip->server->sin.sin_addr));
  656.             surl=make_server_url(hnl,cip->sip->port);
  657.             s_strcpy(extname, retsize, surl);
  658.             s_free(surl);
  659.           }
  660.          }
  661.         else
  662. /* we have softvirtserver: Easy-we got the Servername in the Request */
  663.           {
  664.             surl=make_server_url(cip->hip->svsname,cip->sip->port);
  665.             s_strcpy(extname, retsize, surl);
  666.             s_free(surl);
  667.           }
  668.     return (extname);
  669. }