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

Web服务器

开发平台:

Unix_Linux

  1. /*
  2. ** http.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 <stdlib.h>
  21. #include <unistd.h>
  22. #include <string.h>
  23. #include <errno.h>
  24. #include <stdarg.h>
  25. #include <limits.h>
  26. #include <time.h>
  27. #include <syslog.h>
  28. #include <sys/types.h>
  29. #include <sys/stat.h>
  30. #define IN_DNS_C
  31. #include "phttpd.h"
  32. int phttpd_call(const char *module,
  33. struct connectioninfo *cip)
  34. {
  35.     struct modinfo *mp;
  36.     void *mkey;
  37.     int status;
  38.     char buf[2048];
  39.     
  40.     
  41.     while (*module && *module == '/')
  42. ++module;
  43.     s_strcpy(buf, sizeof(buf), modules_home);
  44.     s_strcat(buf, sizeof(buf), "/");
  45.     s_strcat(buf, sizeof(buf), module);
  46.     
  47.     mp = md_load(buf, &mkey);
  48.     if (mp == NULL)
  49.     {
  50. return http_error(cip, 500,
  51.   "A system error occured while loading module <B>%s</B>:<BR><PRE>%s</PRE>",
  52.   module, md_error());
  53.     }
  54.     status = mp->pm_request(cip);
  55.     
  56.     md_release(mkey);
  57.     return status;
  58. }
  59. int phttpd_request(struct connectioninfo *cip)
  60. {
  61.     const char *handler;
  62.     
  63.     if (cip->hip == NULL)
  64. return -1;
  65.     
  66.     handler = url_gethandler(cip->hip->url);
  67.     if (handler == NULL)
  68. return -1;
  69.     return phttpd_call(handler, cip);
  70. }
  71. void http_sendlastmodified(int fd, time_t ct)
  72. {
  73.     char buf[64];
  74.     
  75.     fd_puts("Last-Modified: ", fd);
  76.     fd_puts(http_time_r(&ct, buf, sizeof(buf)), fd);
  77. }
  78. char *http_sendheaders(int fd,
  79.        struct connectioninfo *cip,
  80.        int code,
  81.        char *type)
  82. {
  83.     char buf[256];
  84.     time_t ct;
  85.     int keepalive;
  86.     ct = cip->cn_time;
  87.     if (cip->hip && cip->hip->mip)
  88. keepalive = cip->hip->mip->connection_flags & MCF_KEEPALIVE;
  89.     else
  90. keepalive = 0;
  91.     
  92.     if (ct == 0)
  93. time(&ct);
  94.     if (type == NULL)
  95. switch (abs(code))
  96. {
  97.   case 200:
  98.     type = "OK";
  99.     break;
  100.   case 201:
  101.     type = "Created";
  102.     break;
  103.   case 202:
  104.     type = "Accepted";
  105.     break;
  106.   case 203:
  107.     type = "Provisional Information";
  108.     break;
  109.   case 204:
  110.     type = "No Content";
  111.     break;
  112.   case 206:
  113.     type = "Partial Content";
  114.     break;
  115.   case 300:
  116.     type = "Multiple Choices";
  117.     break;
  118.   case 301:
  119.     type = "Moved Permanently";
  120.     break;
  121.     
  122.   case 302:
  123.     type = "Moved Temporarily";
  124.     break;
  125.   case 303:
  126.     type = "Method";
  127.     break;
  128.     
  129.   case 304:
  130.     type = "Not Modified";
  131.     break;
  132.   case 400:
  133.     type = "Bad Request";
  134.     break;
  135.   case 401:
  136.     type = "Unauthorized";
  137.     break;
  138.   case 402:
  139.     type = "Payment Forbidden";
  140.     break;
  141.   case 403:
  142.     type = "Forbidden";
  143.     break;
  144.   case 404:
  145.     type = "Not Found";
  146.     break;
  147.   case 405:
  148.     type = "Method Not Allowed";
  149.     break;
  150.   case 406:
  151.     type = "None Acceptable";
  152.     break;
  153.     
  154.   case 407:
  155.     type = "Proxy Authentication Required";
  156.     break;
  157.     
  158.   case 408:
  159.     type = "Request Timeout";
  160.     break;
  161.     
  162.   case 409:
  163.     type = "Conflict";
  164.     break;
  165.     
  166.   case 410:
  167.     type = "Gone";
  168.     break;
  169.   case 412:
  170.     type = "Precondition Failed";
  171.     break;
  172.     
  173.   case 500:
  174.     type = "Internal Server Error";
  175.     break;
  176.   case 501:
  177.     type = "Not Implemented";
  178.     break;
  179.     
  180.   case 502:
  181.     type = "Bad Gateway";
  182.     break;
  183.     
  184.   case 503:
  185.     type = "Service Unavailable";
  186.     break;
  187.     
  188.   case 504:
  189.     type = "Gateway Timeout";
  190.     break;
  191.     
  192.   default:
  193.     type = "?";
  194. }
  195.     if (cip->hip->version)
  196.     {  if ( strcasecmp(cip->hip->version,"HTTP/1.1") !=0 )
  197.          fd_puts("HTTP/1.0 ", fd);
  198.        else
  199.          fd_puts("HTTP/1.1 ", fd);
  200.     }
  201.     else
  202.          fd_puts("HTTP/1.0 ", fd);
  203.     fd_puti(code, fd);
  204.     fd_putc(' ', fd);
  205.     fd_puts(type, fd);
  206.     fd_putc('n', fd);
  207.     
  208.     fd_puts("MIME-Version: 1.0n", fd);
  209. /* Yes, we can that ! rk@netuse.de  check this, only for FILES.so */
  210. /*    fd_puts("Accept-ranges: bytesn", fd); */
  211.     fd_puts("Date: ", fd);
  212.     fd_puts(http_time_r(&ct, buf, sizeof(buf)), fd);
  213.     
  214.     fd_puts("Server: phttpd/", fd);
  215.     fd_puts(server_version, fd);
  216.     fd_putc('n', fd);
  217.     if (keepalive && (keepalive_timeout > 0 || keepalive_maxreq > 0))
  218.     {
  219. fd_puts("Connection: Keep-Alive", fd);
  220. if (keepalive_timeout > 0)
  221.     fd_printf(fd, ", timeout=%d", keepalive_timeout);
  222. if (keepalive_maxreq > 0)
  223.     fd_printf(fd, ", maxreq=%d", keepalive_maxreq);
  224. fd_putc('n', fd);
  225.     }
  226.     
  227.     return type;
  228. }    
  229. int http_unauthorized(struct connectioninfo *cip, const char *realm)
  230. {
  231.     int result;
  232.     int fd = cip->fd;
  233.     struct httpinfo *hip = cip->hip;
  234.     
  235.     if (debug > 1)
  236. fprintf(stderr, "      Sent UNAUTHORIZED messagen");
  237.     result = 401;
  238.     if (hip->mip != NULL)
  239.     {
  240. http_sendheaders(fd, cip, result, NULL);
  241. fd_printf(fd, "WWW-Authenticate: Basic realm="%s"n", realm);
  242. fd_putc('n', fd);
  243.     }
  244.     if(strcasecmp(hip->method, "HEAD") == 0)
  245.        return result;
  246.     html_sysheader(fd, "H2", "Unauthorized");
  247.     fd_printf(fd, "Please send authorization codes for realm "%s".n",
  248.       realm);
  249.     html_sysfooter(fd);
  250.     
  251.     return result;
  252. }
  253. int http_forbidden(struct connectioninfo *cip)
  254. {
  255.     int result;
  256.     int fd = cip->fd;
  257.     struct httpinfo *hip = cip->hip;
  258.     
  259.     if (debug > 1)
  260. fprintf(stderr, "      Sent FORBIDDEN messagen");
  261.     result = 403;
  262.     if (hip->mip != NULL)
  263.     {
  264. http_sendheaders(fd, cip, result, NULL);
  265. fd_putc('n', fd);
  266.     }
  267.     
  268.     if(strcasecmp(hip->method, "HEAD") == 0)
  269.        return result;
  270.     html_sysheader(fd, "H2", "Access Denied");
  271.     fd_printf(fd, "Your request to ");
  272.     if (hip->orig_url == NULL)
  273. fd_printf(fd, "[null]");
  274.     else
  275. html_href(fd, hip->orig_url, hip->orig_url);
  276.     
  277.     fd_printf(fd, " was denied.n");
  278.     html_sysfooter(fd);
  279.     
  280.     return result;
  281. }
  282. int http_authenticate(struct connectioninfo *cip,
  283.       const char *path,
  284.       const char *realm,
  285.       char *request)
  286. {
  287.    if ( debug > 5 )
  288.      fprintf(stderr,"--x-- PATH: %sn",(path!=NULL) ? path : "<NULL>" );
  289.    if (!access_auth(cip->hip, cip, path))
  290. return http_unauthorized(cip, realm);
  291.    return 0;
  292. }
  293. int http_access(struct connectioninfo *cip,
  294. urlinfo_t *uip,
  295. char *request)
  296. {
  297.     if ( access_check(uip, cip) == 0 )
  298. return error_access(cip);
  299. /* access_check does set uip->source etc and so forces password authentification ! */
  300. /* if wanted -- in http.c http_access MUST be called befor http_authenticate */
  301.     return 0;
  302. }
  303. /*
  304.  *  Extract the request (the part after the first '?') in URL and add
  305.  *  it to the beginning of *REQUESTP.
  306.  */
  307. void
  308. http_extract_request(char *url, char **requestp)
  309. {
  310.     char *cp;
  311.     if (url == NULL)
  312. return;
  313.     
  314.     cp = strchr(url, '?');
  315.     if (cp != NULL)
  316.     {
  317. *cp++ = '';
  318. if (requestp == NULL)
  319.     return;
  320. if (!*requestp)
  321. {
  322.     *requestp = s_strdup(cp);
  323. }
  324. else
  325. {
  326.     char *oldrequest = *requestp;
  327.     size_t oldlen = strlen(oldrequest);
  328.     size_t addlen = strlen(cp);
  329.     *requestp = s_malloc(oldlen + 1 + addlen + 1);
  330.     memcpy(*requestp, oldrequest, oldlen);
  331.     *(*requestp + oldlen) = '?';
  332.     memcpy(*requestp + oldlen + 1, cp, addlen);
  333.     *(*requestp + oldlen + 1 + addlen) = '';
  334.     s_free(oldrequest);
  335. }
  336.     }
  337. }
  338. int http_get_request(struct connectioninfo *cip,
  339.      int *keepalive)
  340. {
  341.     char buf[2048], *lastcp, *url, *req, *realurl;
  342.     char ipnrbuf[18];
  343.     struct httpinfo *hip = NULL;
  344.     int result = -1;
  345.     int headerbytes;
  346.     ucentry_t *ucp;
  347.     urlinfo_t *uip;
  348.     char *realm;
  349.     int len;
  350.     char *p1,*p2,*svpath=NULL, *svport=NULL;
  351.     char *xurl=NULL;
  352.     
  353.     ucp = NULL;
  354.     uip = NULL;
  355.     
  356.     if (debug > 1)
  357. fprintf(stderr, "http_get_request(), fd=%dn", cip->fd);
  358.     
  359.     if ((req = fd_gets(NULL, maxurlsize, cip->fd)) == NULL)
  360.     {
  361. if (debug > 2)
  362.     fprintf(stderr, "t->Returning failed (fd=%d)n", cip->fd);
  363. return -1;
  364.     }
  365.     
  366.     hip = s_malloc(sizeof(struct httpinfo));
  367.     headerbytes=strlen(req);
  368.    
  369.     hip->svsname = NULL;
  370.     hip->prefix = NULL;
  371.     hip->method = strtok_r(req, " tnr", &lastcp);
  372.     if (hip->method == NULL)
  373.     {
  374. http_freeinfo(hip);
  375. return -1;
  376.     }
  377.     
  378.     url = strtok_r(NULL, " tnr", &lastcp);
  379.     if (url)
  380. hip->version = s_strdup(strtok_r(NULL, " tnr", &lastcp));
  381.     if (url == NULL)
  382.     {
  383.         http_freeinfo(hip);
  384. return -1;
  385.     }
  386. /* Get the mimeheader first !! */
  387.     if (hip->version != NULL)
  388.     {
  389. hip->mip = mime_getheaders(cip->fd);
  390. if (hip->mip == NULL)
  391. {
  392.     error_bad_request(cip, "Invalid MIME headers");
  393.     goto End;
  394. }
  395. hip->mip->headerbytes=hip->mip->headerbytes+headerbytes;
  396. if (  keepalive && hip->mip &&
  397.       (hip->mip->connection_flags & MCF_KEEPALIVE)  )
  398.     *keepalive = 1;
  399. /* Get the client-supplied authentication information */
  400. hip->aip = auth_get(hip);
  401.     }
  402. /* Clear setup.... */
  403.     hip->prelen=0;
  404. /* Added for Multi-Virtual-Server RK */
  405. /* Some how ugly, might be a nicer way to code this, but it works ! */
  406. /* Maybe one should create differnt global accept code, depending on the
  407. ** mode, we are running. This may look nicer, but more code to maintain. 
  408. ** 23.11.97 rk@netuse.de
  409. */
  410. /* We do allways store the ip number of the incoming interface ! */
  411. if ( mode_dotted == 1 )
  412. s_sprintf(ipnrbuf, 18, "/%s", inet_ntoa(*(struct in_addr *) &(cip->server->sin.sin_addr.s_addr)));
  413. else
  414. s_sprintf(ipnrbuf, 18, "/%08lx", cip->server->sin.sin_addr.s_addr );
  415. hip->vs_ipnr=s_strdup(ipnrbuf);
  416. /* Next we will check, if we get the incoming hostname (like to be used for svs !) */
  417. p1=mime_getheader(hip->mip,"HOST",1);
  418. if ( p1 )
  419. {
  420. p2=strchr(p1,':');
  421. if ( p2 )
  422. hip->svsname=s_strndup(p1,p2-p1);
  423. else
  424. hip->svsname=s_strdup(p1);
  425. }
  426. /* In case, we do NOT get a mime-header-host, we will try to analyze the incoming url for a host[:port] */
  427. if ( hip->svsname == NULL && hip->version != NULL )
  428. {
  429.          if ( strncasecmp(url,"http://",7)== 0 && strlen(url) > 7 )
  430. { /* we got request like ... http://host/path HTTP/1.x */
  431. realurl=url+7; /* now we are the hostposition */
  432. svpath=strchr(realurl,'/'); /* Now find the / after host or host:port
  433.    or we have a NULL, if no host */
  434. svport=strchr(realurl,':'); /* Do we have a port ? */
  435. if ( svport == NULL ) svport=svpath;
  436. if ( svport < svpath ) svpath=svport;
  437. if ( svpath != NULL && realurl != svpath )
  438. {
  439. hip->svstype=SVSINGET;
  440. hip->svsname=s_strndup(realurl,svpath-realurl); /* Store the hostname without the optional port */
  441. }
  442. }
  443. }
  444. if ( svpath == NULL ) svpath=url;
  445. /* In case we cannot retrieve any value, set interface or name */
  446. /* TODO: If not set but needed, we should use some global default: vs_master_name       */
  447.    if ( hip->svsname == NULL )
  448.    {
  449. if ( strcmp(server_host ,"*") == 0 )
  450. hip->svsname=s_strdup(dns_lookup_servername(cip->server));
  451. else
  452. hip->svsname=s_strdup(server_host);
  453. if ( debug > 6 )
  454. fprintf(stderr,"Forced SVS default(hip->svsname) to %sn",hip->svsname);
  455.    }
  456. if ( debug > 6 )
  457. fprintf(stderr,"VirtServer GOT: H: %s SV-Host: %sn",hip->vs_ipnr,(hip->svsname!=NULL)?hip->svsname:"<NULL>");
  458. /* Now we have set: "/aaxxyyzz" or "/a.b.c.d" in ipnrbuf .
  459.    And hip->svsname is set.
  460.    Now we need to put those parts together, depending on the values of rkmultimode and svs
  461.    Here we also take care of sub_server_home, which is only honored in any virtual
  462.    hosting mode. This make it easier to put ftp-chroot together with docroot.
  463.    subserverhome MUST be like /path or "" .
  464.  */
  465. xurl=NULL;
  466. hip->prelen=0;
  467. str_to_lower(hip->svsname);
  468. /* We need to build xurl !  */
  469. /* Format is [rkmultimode]/[softvirtserver]/path */
  470. if ( debug > 8 )
  471. {
  472. fprintf(stderr,"Values:t ipnrbuf=%sn",ipnrbuf);
  473. fprintf(stderr,"       t svsname=%sn",hip->svsname);
  474. fprintf(stderr,"       t sub_s_h=%sn",sub_server_home);
  475. fprintf(stderr,"       t svpath=%sn",svpath?svpath:"<NULL>");
  476. fprintf(stderr,"       t >svpath=%sn",svpath?notslash(svpath):"<NULL>");
  477. }
  478. if ( rkmultimode && softvirtserver )
  479. {
  480. hip->prelen=1+strlen(ipnrbuf)+strlen(hip->svsname)+strlen(sub_server_home);
  481. len=1+hip->prelen+strlen(svpath);
  482. xurl=s_malloc(len);
  483. s_sprintf(xurl, len, "%s/%s%s/%s",ipnrbuf,hip->svsname,sub_server_home,notslash(svpath));
  484. }
  485. if ( rkmultimode && ! softvirtserver )
  486. {
  487. hip->prelen=strlen(ipnrbuf)+strlen(sub_server_home);
  488. len=1+hip->prelen+strlen(svpath);
  489. xurl=s_malloc(len);
  490. s_sprintf(xurl, len, "%s%s/%s",ipnrbuf,sub_server_home,notslash(svpath));
  491. }
  492. if ( ! rkmultimode && softvirtserver )
  493. {
  494. hip->prelen=1+strlen(hip->svsname)+strlen(sub_server_home);
  495. len=1+hip->prelen+strlen(svpath);
  496. xurl=s_malloc(len);
  497. s_sprintf(xurl, len, "/%s%s/%s",hip->svsname,sub_server_home,notslash(svpath));
  498. }
  499. if ( ! rkmultimode && ! softvirtserver )
  500. {
  501. hip->prelen=strlen(sub_server_home);
  502. len=1+hip->prelen+strlen(svpath);
  503. xurl=s_malloc(len);
  504. s_sprintf(xurl, len, "%s/%s",sub_server_home,notslash(svpath));
  505. }
  506. if ( xurl[0] != '/' )
  507. {
  508. fprintf(stderr,"SERVER INTERNAL ERROR ON xurl BUILD (%s)[%s] !n",url ? url : "<null>",xurl);
  509. }
  510.     
  511.     if (debug > 2 )
  512. fprintf(stderr, "Virtualserver: NEWURL: %s (%d)n",(xurl!=NULL)?xurl:"-NONE-",hip->prelen);
  513.     /* if we have some virtual hosting mode, save the prefix to the requests hip-> struct. */
  514.     if ( xurl && hip->prelen > 0 ) hip->prefix=s_strndup(xurl,hip->prelen);
  515.     if (debug > 4)
  516. fprintf(stderr, "Method = %s, URL = %s PL = %dn",
  517. hip->method, url ? url : "<null>", hip->prelen);
  518. /* If we had any kind of virtual hosting, xurl now has the expanded URL-Path with host etc
  519.    stripped off. Otherwise xurl==NULL and we will copy url and continue to work with xurl,
  520.    which gives us a simple cleanup...
  521.  */
  522.     if ( xurl == NULL && url != NULL ) xurl=s_strdup(url);
  523.    
  524. /* we have a memleak somewhere........ maybe here */
  525.     if ( cip->hip )
  526. {  http_freeinfo(cip->hip); 
  527.    fprintf(stderr,"memleak found: pos 1n");
  528. }
  529.     cip->hip = hip;
  530. /* Do not use that new code, seems to be buggy !!!! rk@netuse.de */
  531. #if 0
  532.     hip->orig_url = s_strdup(url);
  533.     hip->orig_request = NULL;
  534.     url_unquote(url, 0);
  535. #else
  536.     http_extract_request(xurl, &hip->request);
  537.     hip->orig_url = s_strdup(xurl);
  538.     hip->orig_request = s_strdup(hip->request);
  539.     url_unquote(xurl, 0);
  540. /* we need to cleanup the url to strip multiple / to a single / 
  541.    we also drop /./ to / and try to handle /../ to move one up, like a unix path.
  542.  */
  543.     url_cleanup(xurl);
  544.     if (debug > 1)
  545. fprintf(stderr, "(x)url=%snorig_url=%snreq=%snorig_req=%sn",
  546. xurl ? xurl : "<null>",
  547. hip->orig_url ? hip->orig_url : "<null>",
  548. hip->request ? hip->request : "<null>",
  549. hip->orig_request ? hip->orig_request : "<null>");
  550. #endif
  551.     
  552.     if (strcasecmp(hip->method, "PING") == 0)
  553.     {
  554. if (hip->mip)
  555. {
  556.     http_sendheaders(cip->fd, cip, 200, NULL);
  557.     result = 200;
  558.     fd_putc('n', cip->fd);
  559. }
  560. fd_puts("PONGn", cip->fd);
  561. goto End;
  562.     }
  563.     
  564.     if (hip->mip && (hip->mip->pragma_flags & MPF_NOCACHE))
  565. ucp = urlcache_lookup(xurl, UCF_ALL+UCF_RELOAD);
  566.     else
  567. ucp = urlcache_lookup(xurl, UCF_ALL);
  568.       
  569.     if (ucp == NULL)
  570. goto End;
  571. /*  XXXX URL (xurl) is now split into url and request part XXXX */
  572.     
  573.     uip = ucp->uip;
  574.     if (uip == NULL)
  575.     {
  576. urlcache_release(ucp);
  577. goto End;
  578.     }
  579.     hip->url = s_strdup(uip->rewrite.url);
  580.     
  581.     if (uip->rewrite.request)
  582.     {
  583. if (hip->request)
  584.     s_free(hip->request);
  585. hip->request = s_strdup(uip->rewrite.request);
  586.     }
  587.     
  588.     if (uip->redirect.url)
  589.     {
  590. result = http_redirect(cip,
  591.        uip->redirect.url,
  592.        uip->redirect.request,
  593.           hip->request,
  594.        302);
  595. goto End;
  596.     }
  597.     
  598.     if (uip->predirect.url)
  599.     {
  600. result = http_redirect(cip,
  601.        uip->predirect.url,
  602.        uip->predirect.request,
  603.           hip->request,
  604.        301);
  605. goto End;
  606.     }
  607.     
  608.     if (uip->access.path)
  609.     {
  610. result = http_access(cip, uip, hip->request);
  611. if (result != 0)
  612.     goto End;
  613.     }
  614.     
  615.     /* ADDED by RK */
  616.     if (debug > 4)
  617. fprintf(stderr,"Check write ACCESSn");
  618.     
  619.     if (write_needs_auth && 
  620. (strcasecmp(hip->method, "PUT")==0 ||
  621.  strcasecmp(hip->method, "DELETE")==0))
  622.     {
  623. if (debug > 4)
  624.     fprintf(stderr,"We have a write CMD...n");
  625.       if (write_getauthenticate(xurl, buf, sizeof(buf))) 
  626.       {
  627.           uip->auth.source=s_strdup(buf);
  628.           realm = uip->auth.source;
  629.           if (realm)
  630.           {   
  631.               while (*realm && !s_isspace(*realm))
  632.   ++realm;
  633.               if (s_isspace(*realm))
  634.   *realm++ = '';
  635.               while (*realm && s_isspace(*realm))
  636.   ++realm;
  637.           }
  638.           uip->auth.realm = realm;
  639.           uip->flags |= UCF_AUTH;
  640.   if ( debug > 4 )
  641.       fprintf(stderr,"Using auth for...%sn",uip->auth.source);
  642.       }
  643.       else
  644.       {
  645.           uip->auth.source=NULL;
  646.   result = -403;
  647.   goto End;
  648.       }
  649.     } /* end of write_needs_auth */
  650.     if (uip->auth.source)
  651.     {
  652. result = http_authenticate(cip,
  653.    uip->auth.source,
  654.    uip->auth.realm,
  655.    hip->request);
  656. if (result != 0)
  657.     goto End;
  658.     }
  659.     if (uip->handler)
  660. result = phttpd_call(uip->handler, cip);
  661.     if (debug > 3)
  662. fprintf(stderr, "MAIN-RETURN: Result=%dn", result);
  663.   End:
  664.     if ( xurl ) s_free(xurl); /* clean up */
  665.     if (result < 0)
  666. switch (result)
  667. {
  668.   case -1:
  669.     result = error_not_found(cip);
  670.     break;
  671.   case -403:
  672.     result = error_access(cip);
  673.     break;
  674.     
  675.   case -405:
  676.     result = error_method_denied(cip);
  677.     break;
  678.     
  679.   default:
  680.     result = error_bad_request(cip, hip->method);
  681.     syslog(LOG_NOTICE, "bad HTTP request (#%d) method: %s",
  682.    cip->request_no,
  683.    hip->method);
  684. }
  685.     if (ucp)
  686. urlcache_release(ucp);
  687.     
  688.     if (hip->length == 0)
  689. *keepalive = 0;
  690.     
  691.     if (debug > 1)
  692. fprintf(stderr, "http_get_request(), fd=%d, returning %dn",
  693. cip->fd, result);
  694.     
  695.     return result;
  696. }
  697. void http_freeinfo(struct httpinfo *hip)
  698. {
  699.     if (hip == NULL)
  700. return;
  701.     
  702.     s_free(hip->method);
  703.     s_free(hip->url);
  704.     s_free(hip->request);
  705.     s_free(hip->orig_url);
  706.     s_free(hip->orig_request);
  707.     s_free(hip->version);
  708.     s_free(hip->prefix);
  709.     s_free(hip->svsname);
  710.     s_free(hip->vs_ipnr);
  711.     
  712.     if (hip->mip) mime_freeheaders(hip->mip);
  713.     auth_free(hip->aip);
  714.     
  715.     s_free(hip);
  716. }
  717. int http_error(struct connectioninfo *cip,
  718.        int code,
  719.        const char *format,
  720.        ...)
  721. {
  722.     va_list ap;
  723.     char *type, buf[256];
  724.     struct httpinfo *hip = cip->hip;
  725.     char *servername=NULL;
  726.     
  727.     if (hip->mip != NULL)
  728.     {
  729. type = http_sendheaders(cip->fd, cip, code, NULL);
  730. fd_puts("Content-Type: text/htmln", cip->fd);
  731. fd_putc('n', cip->fd);
  732.     }
  733.     else
  734.     {
  735.         int blen;
  736.       
  737.         blen = s_strcpy(buf, sizeof(buf), "Error Code #");
  738. s_sprintf(buf+blen, sizeof(buf)-blen, "%d", code);
  739. type = buf;
  740.     }
  741.     if (strcasecmp(hip->method, "HEAD") == 0)
  742. return code;
  743.     
  744.     va_start(ap, format);
  745.   
  746. /* TODO ??? Might be buggy due to new svs-creation code...... */ 
  747.     if ( softvirtserver )   servername=s_strdup(hip->svsname);
  748.     else if ( rkmultimode ) servername=s_strdup(dns_lookup_servername(cip->server));
  749.     html_error(cip->fd, servername, type, format, ap);
  750.     
  751.     va_end(ap);
  752.     hip->length = fd_written(cip->fd);
  753.    
  754.     if ( servername != NULL ) s_free(servername); 
  755.     return code;
  756. }
  757. void http_sendlang(int fd, const char *url)
  758. {
  759.     int i;
  760.     char **pair;
  761.     if(content_language_table == NULL)
  762.         return;
  763.     for(i = 0; i < content_language_table->length; ++i)
  764.     {
  765.         pair = content_language_table->value[i];
  766. if(strmatch(url, pair[0]))
  767. {
  768.     fd_puts("Content-Language: ", fd);
  769.     fd_puts(pair[1], fd);
  770.     fd_putc('n', fd);
  771.     break;
  772. }
  773.     }
  774. }
  775. /* Send a redirect pointer */
  776. int http_redirect(struct connectioninfo *cip,
  777.   const char *url,
  778.   const char *request,
  779.   const char *orig_req,
  780.   int code)
  781. {
  782.     char buf1[2048], buf2[2048], buf3[2048];
  783.     int result, len;
  784.     int fd = cip->fd;
  785.     struct httpinfo *hip = cip->hip;
  786.     url = url_quote(url, buf1, sizeof(buf1), "?", 0);
  787.     if (url == NULL)
  788. return -1;
  789.     
  790.     if (request)
  791.     {
  792. request = url_quote(request, buf2, sizeof(buf2), """, 1);
  793. if (request == NULL)
  794.     return -1;
  795.     }
  796.     if (orig_req)
  797.     {
  798. orig_req = url_quote(orig_req, buf3, sizeof(buf3), """, 1);
  799. if (orig_req == NULL)
  800.     return -1;
  801.     }
  802.     
  803.     if (debug > 1)
  804. fprintf(stderr, "      Sent URL REDIRECT (%s -> %s)n",
  805. hip->url, url);
  806.     result = code;
  807.     
  808.     if (hip->mip != NULL)
  809.     {
  810. http_sendheaders(fd, cip, result, NULL);
  811. fd_printf(fd, "Location: %s%s%s%sn",
  812.   url,
  813.   (orig_req || request) ? "?" : "",
  814.   orig_req ? orig_req : "",
  815.   request ? request : "");
  816.   
  817. http_sendlastmodified(fd, cip->cn_time);
  818. fd_puts("Content-Type: text/htmlnn", fd);
  819.     }
  820.     
  821.     if (strcasecmp(hip->method, "HEAD") == 0)
  822. return result;
  823.     
  824.     len = fd_written(fd);
  825.     html_sysheader(fd, "H2", "Document moved");
  826.     
  827.     fd_puts("The document has moved to this URL:<P>n", fd);
  828.     fd_puts("<UL>n", fd);
  829.     
  830.     fd_printf(fd, "<B><A HREF="%s%s%s%s">%s%s%s%s</A></B>.n",
  831.       url,
  832.       (orig_req || request) ? "?" : "",
  833.       orig_req ? orig_req : "",
  834.       request ? request : "",
  835.       url,
  836.       (orig_req || request) ? "?" : "",
  837.       orig_req ? orig_req : "",
  838.       request ? request : "");
  839.     
  840.     fd_puts("</UL>n", fd);
  841.     
  842.     html_sysfooter(fd);
  843.     if (logheadervolume)
  844. hip->length = fd_written(fd);
  845.     else
  846. hip->length = fd_written(fd) - len; 
  847.     return result;
  848. }
  849. /* Send a 'Not Modified' message */
  850. int http_not_modified(struct connectioninfo *cip)
  851. {
  852.     int result;
  853.     int fd = cip->fd;
  854.     struct httpinfo *hip = cip->hip;
  855.     
  856.     if (debug > 1)
  857. fprintf(stderr, "      Sent NOT MODIFIED messagen");
  858.     result = 304;
  859.     if (hip->mip != NULL)
  860.     {
  861. http_sendheaders(fd, cip, result, NULL);
  862. fd_putc('n', fd);
  863.     }
  864.     hip->length = fd_written(fd);
  865.     return result;
  866. }
  867. /* Send a 'Precondition Failed' message */
  868. int http_precondition_failed(struct connectioninfo *cip)
  869. {
  870.     int result;
  871.     int fd = cip->fd;
  872.     struct httpinfo *hip = cip->hip;
  873.     
  874.     if (debug > 1)
  875. fprintf(stderr, "      Sent PRECONDITION FAILED messagen");
  876.     result = 412;
  877.     if (hip->mip != NULL)
  878.     {
  879. http_sendheaders(fd, cip, result, NULL);
  880. fd_putc('n', fd);
  881.     }
  882.     
  883.     if(strcasecmp(hip->method, "HEAD") == 0)
  884.        return result;
  885.     html_sysheader(fd, "H2", "Precondition Failed");
  886.     fd_printf(fd, "The entity which lives at ");
  887.     if (hip->orig_url == NULL)
  888. fd_printf(fd, "[null]");
  889.     else
  890. html_href(fd, hip->orig_url, hip->orig_url);
  891.     
  892.     fd_printf(fd, " was changed.n");
  893.     html_sysfooter(fd);
  894.     hip->length = fd_written(fd);
  895.     
  896.     return result;
  897. }
  898. static const char *const weekday[] =
  899. {
  900.     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  901. };
  902. static const char *const month[] =
  903. {
  904.     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  905.     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  906. };
  907. char *http_time_r(const time_t *btp, char *buf, int bufsize)
  908. {
  909.     struct tm tpb;
  910.     
  911.     if (bufsize < 31)
  912. return NULL;
  913.     
  914.     if (gmtime_r(btp, &tpb) == NULL)
  915. return NULL;
  916.     s_sprintf(buf, bufsize, "%s, %02d %s %d %02d:%02d:%02d GMTn",
  917.     weekday[tpb.tm_wday],
  918.     tpb.tm_mday,
  919.     month[tpb.tm_mon],
  920.     tpb.tm_year + 1900,
  921.     tpb.tm_hour,
  922.     tpb.tm_min,
  923.     tpb.tm_sec);
  924.     return buf;
  925. }