17dd7cddfSDavid du Colombier #include <u.h> 27dd7cddfSDavid du Colombier #include <libc.h> 37dd7cddfSDavid du Colombier #include <auth.h> 49a747e4fSDavid du Colombier #include <mp.h> 59a747e4fSDavid du Colombier #include <libsec.h> 67dd7cddfSDavid du Colombier #include "httpd.h" 780ee5cbfSDavid du Colombier #include "httpsrv.h" 87dd7cddfSDavid du Colombier 97dd7cddfSDavid du Colombier typedef struct Strings Strings; 107dd7cddfSDavid du Colombier 117dd7cddfSDavid du Colombier struct Strings 127dd7cddfSDavid du Colombier { 137dd7cddfSDavid du Colombier char *s1; 147dd7cddfSDavid du Colombier char *s2; 157dd7cddfSDavid du Colombier }; 167dd7cddfSDavid du Colombier 1780ee5cbfSDavid du Colombier char *netdir; 1880ee5cbfSDavid du Colombier char *webroot; 1980ee5cbfSDavid du Colombier char *HTTPLOG = "httpd/log"; 207dd7cddfSDavid du Colombier 2180ee5cbfSDavid du Colombier static char netdirb[256]; 2280ee5cbfSDavid du Colombier static char *namespace; 2380ee5cbfSDavid du Colombier 247dd7cddfSDavid du Colombier static void becomenone(char*); 257dd7cddfSDavid du Colombier static char *csquery(char*, char*, char*); 267dd7cddfSDavid du Colombier static void dolisten(char*); 2780ee5cbfSDavid du Colombier static int doreq(HConnect*); 2880ee5cbfSDavid du Colombier static int send(HConnect*); 2980ee5cbfSDavid du Colombier static Strings stripmagic(HConnect*, char*); 307dd7cddfSDavid du Colombier static char* stripprefix(char*, char*); 317dd7cddfSDavid du Colombier static char* sysdom(void); 329a747e4fSDavid du Colombier static int notfound(HConnect *c, char *url); 339a747e4fSDavid du Colombier 349a747e4fSDavid du Colombier uchar *certificate; 359a747e4fSDavid du Colombier int certlen; 365ede6b93SDavid du Colombier PEMChain *certchain; 377dd7cddfSDavid du Colombier 387dd7cddfSDavid du Colombier void 397dd7cddfSDavid du Colombier usage(void) 407dd7cddfSDavid du Colombier { 415ede6b93SDavid du Colombier fprint(2, "usage: httpd [-c certificate] [-C CAchain] [-a srvaddress] [-d domain] [-n namespace] [-w webroot]\n"); 427dd7cddfSDavid du Colombier exits("usage"); 437dd7cddfSDavid du Colombier } 447dd7cddfSDavid du Colombier 457dd7cddfSDavid du Colombier void 467dd7cddfSDavid du Colombier main(int argc, char **argv) 477dd7cddfSDavid du Colombier { 487dd7cddfSDavid du Colombier char *address; 497dd7cddfSDavid du Colombier 507dd7cddfSDavid du Colombier namespace = nil; 517dd7cddfSDavid du Colombier address = nil; 5280ee5cbfSDavid du Colombier hmydomain = nil; 5380ee5cbfSDavid du Colombier netdir = "/net"; 549a747e4fSDavid du Colombier fmtinstall('D', hdatefmt); 559a747e4fSDavid du Colombier fmtinstall('H', httpfmt); 569a747e4fSDavid du Colombier fmtinstall('U', hurlfmt); 577dd7cddfSDavid du Colombier ARGBEGIN{ 589a747e4fSDavid du Colombier case 'c': 599a747e4fSDavid du Colombier certificate = readcert(ARGF(), &certlen); 609a747e4fSDavid du Colombier if(certificate == nil) 61d9306527SDavid du Colombier sysfatal("reading certificate: %r"); 629a747e4fSDavid du Colombier break; 635ede6b93SDavid du Colombier case 'C': 645ede6b93SDavid du Colombier certchain = readcertchain(ARGF()); 655ede6b93SDavid du Colombier if (certchain == nil) 665ede6b93SDavid du Colombier sysfatal("reading certificate chain: %r"); 675ede6b93SDavid du Colombier break; 687dd7cddfSDavid du Colombier case 'n': 697dd7cddfSDavid du Colombier namespace = ARGF(); 707dd7cddfSDavid du Colombier break; 717dd7cddfSDavid du Colombier case 'a': 727dd7cddfSDavid du Colombier address = ARGF(); 737dd7cddfSDavid du Colombier break; 747dd7cddfSDavid du Colombier case 'd': 7580ee5cbfSDavid du Colombier hmydomain = ARGF(); 767dd7cddfSDavid du Colombier break; 777dd7cddfSDavid du Colombier case 'w': 787dd7cddfSDavid du Colombier webroot = ARGF(); 797dd7cddfSDavid du Colombier break; 807dd7cddfSDavid du Colombier default: 817dd7cddfSDavid du Colombier usage(); 827dd7cddfSDavid du Colombier break; 837dd7cddfSDavid du Colombier }ARGEND 847dd7cddfSDavid du Colombier 857dd7cddfSDavid du Colombier if(argc) 867dd7cddfSDavid du Colombier usage(); 877dd7cddfSDavid du Colombier 887dd7cddfSDavid du Colombier if(namespace == nil) 897dd7cddfSDavid du Colombier namespace = "/lib/namespace.httpd"; 907dd7cddfSDavid du Colombier if(address == nil) 919a747e4fSDavid du Colombier address = "*"; 927dd7cddfSDavid du Colombier if(webroot == nil) 937dd7cddfSDavid du Colombier webroot = "/usr/web"; 947dd7cddfSDavid du Colombier else{ 957dd7cddfSDavid du Colombier cleanname(webroot); 967dd7cddfSDavid du Colombier if(webroot[0] != '/') 977dd7cddfSDavid du Colombier webroot = "/usr/web"; 987dd7cddfSDavid du Colombier } 997dd7cddfSDavid du Colombier 1007dd7cddfSDavid du Colombier switch(rfork(RFNOTEG|RFPROC|RFFDG|RFNAMEG)) { 1017dd7cddfSDavid du Colombier case -1: 1027dd7cddfSDavid du Colombier sysfatal("fork"); 1037dd7cddfSDavid du Colombier case 0: 1047dd7cddfSDavid du Colombier break; 1057dd7cddfSDavid du Colombier default: 1067dd7cddfSDavid du Colombier exits(nil); 1077dd7cddfSDavid du Colombier } 1087dd7cddfSDavid du Colombier 1097dd7cddfSDavid du Colombier /* 1107dd7cddfSDavid du Colombier * open all files we might need before castrating namespace 1117dd7cddfSDavid du Colombier */ 1127dd7cddfSDavid du Colombier time(nil); 11380ee5cbfSDavid du Colombier if(hmydomain == nil) 11480ee5cbfSDavid du Colombier hmydomain = sysdom(); 1157dd7cddfSDavid du Colombier syslog(0, HTTPLOG, nil); 1167dd7cddfSDavid du Colombier logall[0] = open("/sys/log/httpd/0", OWRITE); 1177dd7cddfSDavid du Colombier logall[1] = open("/sys/log/httpd/1", OWRITE); 118499069deSDavid du Colombier logall[2] = open("/sys/log/httpd/clf", OWRITE); 1197dd7cddfSDavid du Colombier redirectinit(); 1207dd7cddfSDavid du Colombier contentinit(); 1217dd7cddfSDavid du Colombier urlinit(); 1227dd7cddfSDavid du Colombier statsinit(); 1237dd7cddfSDavid du Colombier 1247dd7cddfSDavid du Colombier becomenone(namespace); 1259a747e4fSDavid du Colombier dolisten(netmkaddr(address, "tcp", certificate == nil ? "http" : "https")); 1267dd7cddfSDavid du Colombier exits(nil); 1277dd7cddfSDavid du Colombier } 1287dd7cddfSDavid du Colombier 1297dd7cddfSDavid du Colombier static void 1307dd7cddfSDavid du Colombier becomenone(char *namespace) 1317dd7cddfSDavid du Colombier { 1327dd7cddfSDavid du Colombier int fd; 1337dd7cddfSDavid du Colombier 1347dd7cddfSDavid du Colombier fd = open("#c/user", OWRITE); 1357dd7cddfSDavid du Colombier if(fd < 0 || write(fd, "none", strlen("none")) < 0) 1367dd7cddfSDavid du Colombier sysfatal("can't become none"); 1377dd7cddfSDavid du Colombier close(fd); 1387dd7cddfSDavid du Colombier if(newns("none", nil) < 0) 1397dd7cddfSDavid du Colombier sysfatal("can't build normal namespace"); 1407dd7cddfSDavid du Colombier if(addns("none", namespace) < 0) 1417dd7cddfSDavid du Colombier sysfatal("can't build httpd namespace"); 1427dd7cddfSDavid du Colombier } 1437dd7cddfSDavid du Colombier 14480ee5cbfSDavid du Colombier static HConnect* 1457dd7cddfSDavid du Colombier mkconnect(void) 1467dd7cddfSDavid du Colombier { 14780ee5cbfSDavid du Colombier HConnect *c; 1487dd7cddfSDavid du Colombier 14980ee5cbfSDavid du Colombier c = ezalloc(sizeof(HConnect)); 1507dd7cddfSDavid du Colombier c->hpos = c->header; 1517dd7cddfSDavid du Colombier c->hstop = c->header; 15280ee5cbfSDavid du Colombier c->replog = writelog; 1537dd7cddfSDavid du Colombier return c; 1547dd7cddfSDavid du Colombier } 1557dd7cddfSDavid du Colombier 15680ee5cbfSDavid du Colombier static HSPriv* 15780ee5cbfSDavid du Colombier mkhspriv(void) 15880ee5cbfSDavid du Colombier { 15980ee5cbfSDavid du Colombier HSPriv *p; 16080ee5cbfSDavid du Colombier 16180ee5cbfSDavid du Colombier p = ezalloc(sizeof(HSPriv)); 16280ee5cbfSDavid du Colombier return p; 16380ee5cbfSDavid du Colombier } 16480ee5cbfSDavid du Colombier 1657dd7cddfSDavid du Colombier static void 1667dd7cddfSDavid du Colombier dolisten(char *address) 1677dd7cddfSDavid du Colombier { 16880ee5cbfSDavid du Colombier HSPriv *hp; 16980ee5cbfSDavid du Colombier HConnect *c; 1709a747e4fSDavid du Colombier NetConnInfo *nci; 1717dd7cddfSDavid du Colombier char ndir[NETPATHLEN], dir[NETPATHLEN], *p; 17280ee5cbfSDavid du Colombier int ctl, nctl, data, t, ok, spotchk; 1739a747e4fSDavid du Colombier TLSconn conn; 1747dd7cddfSDavid du Colombier 17580ee5cbfSDavid du Colombier spotchk = 0; 1767dd7cddfSDavid du Colombier syslog(0, HTTPLOG, "httpd starting"); 1777dd7cddfSDavid du Colombier ctl = announce(address, dir); 1787dd7cddfSDavid du Colombier if(ctl < 0){ 1797dd7cddfSDavid du Colombier syslog(0, HTTPLOG, "can't announce on %s: %r", address); 1807dd7cddfSDavid du Colombier return; 1817dd7cddfSDavid du Colombier } 18280ee5cbfSDavid du Colombier strcpy(netdirb, dir); 1837dd7cddfSDavid du Colombier p = nil; 1847dd7cddfSDavid du Colombier if(netdir[0] == '/'){ 18580ee5cbfSDavid du Colombier p = strchr(netdirb+1, '/'); 1867dd7cddfSDavid du Colombier if(p != nil) 1877dd7cddfSDavid du Colombier *p = '\0'; 1887dd7cddfSDavid du Colombier } 1897dd7cddfSDavid du Colombier if(p == nil) 19080ee5cbfSDavid du Colombier strcpy(netdirb, "/net"); 19180ee5cbfSDavid du Colombier netdir = netdirb; 1927dd7cddfSDavid du Colombier 1937dd7cddfSDavid du Colombier for(;;){ 1947dd7cddfSDavid du Colombier 1957dd7cddfSDavid du Colombier /* 1967dd7cddfSDavid du Colombier * wait for a call (or an error) 1977dd7cddfSDavid du Colombier */ 1987dd7cddfSDavid du Colombier nctl = listen(dir, ndir); 1997dd7cddfSDavid du Colombier if(nctl < 0){ 2007dd7cddfSDavid du Colombier syslog(0, HTTPLOG, "can't listen on %s: %r", address); 2017dd7cddfSDavid du Colombier syslog(0, HTTPLOG, "ctls = %d", ctl); 2027dd7cddfSDavid du Colombier return; 2037dd7cddfSDavid du Colombier } 2047dd7cddfSDavid du Colombier 2057dd7cddfSDavid du Colombier /* 2067dd7cddfSDavid du Colombier * start a process for the service 2077dd7cddfSDavid du Colombier */ 2087dd7cddfSDavid du Colombier switch(rfork(RFFDG|RFPROC|RFNOWAIT|RFNAMEG)){ 2097dd7cddfSDavid du Colombier case -1: 2107dd7cddfSDavid du Colombier close(nctl); 2117dd7cddfSDavid du Colombier continue; 2127dd7cddfSDavid du Colombier case 0: 2137dd7cddfSDavid du Colombier /* 2147dd7cddfSDavid du Colombier * see if we know the service requested 2157dd7cddfSDavid du Colombier */ 2167dd7cddfSDavid du Colombier data = accept(ctl, ndir); 2179a747e4fSDavid du Colombier if(data >= 0 && certificate != nil){ 2189a747e4fSDavid du Colombier memset(&conn, 0, sizeof(conn)); 2199a747e4fSDavid du Colombier conn.cert = certificate; 2209a747e4fSDavid du Colombier conn.certlen = certlen; 2215ede6b93SDavid du Colombier if (certchain != nil) 2225ede6b93SDavid du Colombier conn.chain = certchain; 2239a747e4fSDavid du Colombier data = tlsServer(data, &conn); 2249a747e4fSDavid du Colombier } 2257dd7cddfSDavid du Colombier if(data < 0){ 2267dd7cddfSDavid du Colombier syslog(0, HTTPLOG, "can't open %s/data: %r", ndir); 2277dd7cddfSDavid du Colombier exits(nil); 2287dd7cddfSDavid du Colombier } 2297dd7cddfSDavid du Colombier dup(data, 0); 2307dd7cddfSDavid du Colombier dup(data, 1); 2317dd7cddfSDavid du Colombier dup(data, 2); 2327dd7cddfSDavid du Colombier close(data); 2337dd7cddfSDavid du Colombier close(ctl); 2347dd7cddfSDavid du Colombier close(nctl); 2357dd7cddfSDavid du Colombier 2369a747e4fSDavid du Colombier nci = getnetconninfo(ndir, -1); 2377dd7cddfSDavid du Colombier c = mkconnect(); 23880ee5cbfSDavid du Colombier hp = mkhspriv(); 2399a747e4fSDavid du Colombier hp->remotesys = nci->rsys; 2409a747e4fSDavid du Colombier hp->remoteserv = nci->rserv; 24180ee5cbfSDavid du Colombier c->private = hp; 2427dd7cddfSDavid du Colombier 2437dd7cddfSDavid du Colombier hinit(&c->hin, 0, Hread); 2447dd7cddfSDavid du Colombier hinit(&c->hout, 1, Hwrite); 2457dd7cddfSDavid du Colombier 24680ee5cbfSDavid du Colombier /* 24780ee5cbfSDavid du Colombier * serve requests until a magic request. 24880ee5cbfSDavid du Colombier * later requests have to come quickly. 24980ee5cbfSDavid du Colombier * only works for http/1.1 or later. 25080ee5cbfSDavid du Colombier */ 25180ee5cbfSDavid du Colombier for(t = 15*60*1000; ; t = 15*1000){ 25280ee5cbfSDavid du Colombier if(hparsereq(c, t) <= 0) 25380ee5cbfSDavid du Colombier exits(nil); 25480ee5cbfSDavid du Colombier ok = doreq(c); 25580ee5cbfSDavid du Colombier 2569a747e4fSDavid du Colombier hflush(&c->hout); 2579a747e4fSDavid du Colombier 25880ee5cbfSDavid du Colombier if(c->head.closeit || ok < 0) 25980ee5cbfSDavid du Colombier exits(nil); 26080ee5cbfSDavid du Colombier 26180ee5cbfSDavid du Colombier hreqcleanup(c); 26280ee5cbfSDavid du Colombier } 263b85a8364SDavid du Colombier /* not reached */ 2647dd7cddfSDavid du Colombier 2657dd7cddfSDavid du Colombier default: 2667dd7cddfSDavid du Colombier close(nctl); 2677dd7cddfSDavid du Colombier break; 2687dd7cddfSDavid du Colombier } 2697dd7cddfSDavid du Colombier 2707dd7cddfSDavid du Colombier if(++spotchk > 50){ 2717dd7cddfSDavid du Colombier spotchk = 0; 2727dd7cddfSDavid du Colombier redirectinit(); 2737dd7cddfSDavid du Colombier contentinit(); 2747dd7cddfSDavid du Colombier urlinit(); 2757dd7cddfSDavid du Colombier statsinit(); 2767dd7cddfSDavid du Colombier } 2777dd7cddfSDavid du Colombier } 2787dd7cddfSDavid du Colombier } 2797dd7cddfSDavid du Colombier 2807dd7cddfSDavid du Colombier static int 28180ee5cbfSDavid du Colombier doreq(HConnect *c) 2827dd7cddfSDavid du Colombier { 28380ee5cbfSDavid du Colombier HSPriv *hp; 2847dd7cddfSDavid du Colombier Strings ss; 285499069deSDavid du Colombier char *magic, *uri, *newuri, *origuri, *newpath, *hb; 28680ee5cbfSDavid du Colombier char virtualhost[100], logfd0[10], logfd1[10], vers[16]; 287*b51d2625SDavid du Colombier int n, nredirect; 2887dd7cddfSDavid du Colombier 2897dd7cddfSDavid du Colombier /* 29080ee5cbfSDavid du Colombier * munge uri for magic 2917dd7cddfSDavid du Colombier */ 29280ee5cbfSDavid du Colombier uri = c->req.uri; 293499069deSDavid du Colombier nredirect = 0; 294499069deSDavid du Colombier top: 295499069deSDavid du Colombier if(++nredirect > 10){ 296499069deSDavid du Colombier if(hparseheaders(c, 15*60*1000) < 0) 297499069deSDavid du Colombier exits("failed"); 298dc6ece7cSDavid du Colombier werrstr("redirection loop"); 299499069deSDavid du Colombier return hfail(c, HNotFound, uri); 300499069deSDavid du Colombier } 30180ee5cbfSDavid du Colombier ss = stripmagic(c, uri); 3027dd7cddfSDavid du Colombier uri = ss.s1; 303499069deSDavid du Colombier origuri = uri; 3047dd7cddfSDavid du Colombier magic = ss.s2; 305499069deSDavid du Colombier if(magic) 306499069deSDavid du Colombier goto magic; 307499069deSDavid du Colombier 308499069deSDavid du Colombier /* 309499069deSDavid du Colombier * Apply redirects. Do this before reading headers 310499069deSDavid du Colombier * (if possible) so that we can redirect to magic invisibly. 311499069deSDavid du Colombier */ 312499069deSDavid du Colombier if(origuri[0]=='/' && origuri[1]=='~'){ 313499069deSDavid du Colombier n = strlen(origuri) + 4 + UTFmax; 314499069deSDavid du Colombier newpath = halloc(c, n); 315499069deSDavid du Colombier snprint(newpath, n, "/who/%s", origuri+2); 316499069deSDavid du Colombier c->req.uri = newpath; 317499069deSDavid du Colombier newuri = newpath; 318499069deSDavid du Colombier }else if(origuri[0]=='/' && origuri[1]==0){ 319dc6ece7cSDavid du Colombier /* can't redirect / until we read the headers below */ 320499069deSDavid du Colombier newuri = nil; 321499069deSDavid du Colombier }else 322499069deSDavid du Colombier newuri = redirect(c, origuri); 323499069deSDavid du Colombier 324499069deSDavid du Colombier if(newuri != nil){ 325dc6ece7cSDavid du Colombier if(isdecorated(newuri)){ 326*b51d2625SDavid du Colombier if(newuri[0] == Modperm) { 327*b51d2625SDavid du Colombier logit(c, "%s: permanently moved to %s", 328*b51d2625SDavid du Colombier origuri, undecorated(newuri)); 329*b51d2625SDavid du Colombier return hmoved(c, undecorated(newuri)); 330*b51d2625SDavid du Colombier } 331dc6ece7cSDavid du Colombier c->req.uri = uri = undecorated(newuri); 332*b51d2625SDavid du Colombier // logit(c, "%s: silent replacement %s", origuri, uri); 333499069deSDavid du Colombier goto top; 334499069deSDavid du Colombier } 335499069deSDavid du Colombier if(hparseheaders(c, 15*60*1000) < 0) 336499069deSDavid du Colombier exits("failed"); 337dc6ece7cSDavid du Colombier /* 338dc6ece7cSDavid du Colombier * try temporary redirect instead of permanent, 339dc6ece7cSDavid du Colombier */ 340dc6ece7cSDavid du Colombier if (http11(c)) 341dc6ece7cSDavid du Colombier return hredirected(c, "307 Temporary Redirect", newuri); 342dc6ece7cSDavid du Colombier else 343dc6ece7cSDavid du Colombier return hredirected(c, "302 Temporary Redirect", newuri); 344499069deSDavid du Colombier } 3457dd7cddfSDavid du Colombier 34680ee5cbfSDavid du Colombier /* 34780ee5cbfSDavid du Colombier * for magic we exec a new program and serve no more requests 34880ee5cbfSDavid du Colombier */ 349499069deSDavid du Colombier magic: 35080ee5cbfSDavid du Colombier if(magic != nil && strcmp(magic, "httpd") != 0){ 35180ee5cbfSDavid du Colombier snprint(c->xferbuf, HBufSize, "/bin/ip/httpd/%s", magic); 35280ee5cbfSDavid du Colombier snprint(logfd0, sizeof(logfd0), "%d", logall[0]); 35380ee5cbfSDavid du Colombier snprint(logfd1, sizeof(logfd1), "%d", logall[1]); 35480ee5cbfSDavid du Colombier snprint(vers, sizeof(vers), "HTTP/%d.%d", c->req.vermaj, c->req.vermin); 35580ee5cbfSDavid du Colombier hb = hunload(&c->hin); 3569a747e4fSDavid du Colombier if(hb == nil){ 35780ee5cbfSDavid du Colombier hfail(c, HInternal); 3589a747e4fSDavid du Colombier return -1; 3599a747e4fSDavid du Colombier } 36080ee5cbfSDavid du Colombier hp = c->private; 36180ee5cbfSDavid du Colombier execl(c->xferbuf, magic, "-d", hmydomain, "-w", webroot, "-r", hp->remotesys, "-N", netdir, "-b", hb, 36280ee5cbfSDavid du Colombier "-L", logfd0, logfd1, "-R", c->header, 36380ee5cbfSDavid du Colombier c->req.meth, vers, uri, c->req.search, nil); 36480ee5cbfSDavid du Colombier logit(c, "no magic %s uri %s", magic, uri); 36580ee5cbfSDavid du Colombier hfail(c, HNotFound, uri); 36680ee5cbfSDavid du Colombier return -1; 36780ee5cbfSDavid du Colombier } 3687dd7cddfSDavid du Colombier 3697dd7cddfSDavid du Colombier /* 3707dd7cddfSDavid du Colombier * normal case is just file transfer 3717dd7cddfSDavid du Colombier */ 37280ee5cbfSDavid du Colombier if(hparseheaders(c, 15*60*1000) < 0) 37380ee5cbfSDavid du Colombier exits("failed"); 374499069deSDavid du Colombier if(origuri[0] == '/' && origuri[1] == 0){ 375499069deSDavid du Colombier snprint(virtualhost, sizeof virtualhost, "http://%s/", c->head.host); 376499069deSDavid du Colombier newuri = redirect(c, virtualhost); 377499069deSDavid du Colombier if(newuri == nil) 378499069deSDavid du Colombier newuri = redirect(c, origuri); 379499069deSDavid du Colombier if(newuri) 380499069deSDavid du Colombier return hmoved(c, newuri); 381499069deSDavid du Colombier } 3827dd7cddfSDavid du Colombier if(!http11(c) && !c->head.persist) 3837dd7cddfSDavid du Colombier c->head.closeit = 1; 38480ee5cbfSDavid du Colombier return send(c); 3857dd7cddfSDavid du Colombier } 3867dd7cddfSDavid du Colombier 3877dd7cddfSDavid du Colombier static int 38880ee5cbfSDavid du Colombier send(HConnect *c) 3897dd7cddfSDavid du Colombier { 3909a747e4fSDavid du Colombier Dir *dir; 391fe853e23SDavid du Colombier char *w, *w2, *p, *masque; 3927dd7cddfSDavid du Colombier int fd, fd1, n, force301, ok; 3937dd7cddfSDavid du Colombier 3947dd7cddfSDavid du Colombier if(c->req.search) 39580ee5cbfSDavid du Colombier return hfail(c, HNoSearch, c->req.uri); 3967dd7cddfSDavid du Colombier if(strcmp(c->req.meth, "GET") != 0 && strcmp(c->req.meth, "HEAD") != 0) 39780ee5cbfSDavid du Colombier return hunallowed(c, "GET, HEAD"); 3987dd7cddfSDavid du Colombier if(c->head.expectother || c->head.expectcont) 39980ee5cbfSDavid du Colombier return hfail(c, HExpectFail); 4007dd7cddfSDavid du Colombier 4019a747e4fSDavid du Colombier masque = masquerade(c->head.host); 4027dd7cddfSDavid du Colombier 4037dd7cddfSDavid du Colombier /* 4047dd7cddfSDavid du Colombier * check for directory/file mismatch with trailing /, 4057dd7cddfSDavid du Colombier * and send any redirections. 4067dd7cddfSDavid du Colombier */ 4079a747e4fSDavid du Colombier n = strlen(webroot) + strlen(masque) + strlen(c->req.uri) + 4089a747e4fSDavid du Colombier STRLEN("/index.html") + STRLEN("/.httplogin") + 1; 40980ee5cbfSDavid du Colombier w = halloc(c, n); 4107dd7cddfSDavid du Colombier strcpy(w, webroot); 4119a747e4fSDavid du Colombier strcat(w, masque); 4129a747e4fSDavid du Colombier strcat(w, c->req.uri); 4133ff48bf5SDavid du Colombier 4143ff48bf5SDavid du Colombier /* 415fe853e23SDavid du Colombier * favicon can be overridden by hostname.ico 416fe853e23SDavid du Colombier */ 417fe853e23SDavid du Colombier if(strcmp(c->req.uri, "/favicon.ico") == 0){ 418fe853e23SDavid du Colombier w2 = halloc(c, n+strlen(c->head.host)+2); 419fe853e23SDavid du Colombier strcpy(w2, webroot); 420fe853e23SDavid du Colombier strcat(w2, masque); 421fe853e23SDavid du Colombier strcat(w2, "/"); 422fe853e23SDavid du Colombier strcat(w2, c->head.host); 423fe853e23SDavid du Colombier strcat(w2, ".ico"); 424fe853e23SDavid du Colombier if(access(w2, AREAD)==0) 425fe853e23SDavid du Colombier w = w2; 426fe853e23SDavid du Colombier } 427fe853e23SDavid du Colombier 428fe853e23SDavid du Colombier /* 4293ff48bf5SDavid du Colombier * don't show the contents of .httplogin 4303ff48bf5SDavid du Colombier */ 4313ff48bf5SDavid du Colombier n = strlen(w); 4323ff48bf5SDavid du Colombier if(strcmp(w+n-STRLEN(".httplogin"), ".httplogin") == 0) 4333ff48bf5SDavid du Colombier return notfound(c, c->req.uri); 4343ff48bf5SDavid du Colombier 4359a747e4fSDavid du Colombier fd = open(w, OREAD); 4369a747e4fSDavid du Colombier if(fd < 0 && strlen(masque)>0 && strncmp(c->req.uri, masque, strlen(masque)) == 0){ 4379a747e4fSDavid du Colombier // may be a URI from before virtual hosts; try again without masque 4389a747e4fSDavid du Colombier strcpy(w, webroot); 4397dd7cddfSDavid du Colombier strcat(w, c->req.uri); 4407dd7cddfSDavid du Colombier fd = open(w, OREAD); 4419a747e4fSDavid du Colombier } 4427dd7cddfSDavid du Colombier if(fd < 0) 4437dd7cddfSDavid du Colombier return notfound(c, c->req.uri); 4449a747e4fSDavid du Colombier dir = dirfstat(fd); 4459a747e4fSDavid du Colombier if(dir == nil){ 4467dd7cddfSDavid du Colombier close(fd); 44780ee5cbfSDavid du Colombier return hfail(c, HInternal); 4487dd7cddfSDavid du Colombier } 4497dd7cddfSDavid du Colombier p = strchr(w, '\0'); 4509a747e4fSDavid du Colombier if(dir->mode & DMDIR){ 4519a747e4fSDavid du Colombier free(dir); 4527dd7cddfSDavid du Colombier if(p > w && p[-1] == '/'){ 4537dd7cddfSDavid du Colombier strcat(w, "index.html"); 4547dd7cddfSDavid du Colombier force301 = 0; 4557dd7cddfSDavid du Colombier }else{ 4567dd7cddfSDavid du Colombier strcat(w, "/index.html"); 4577dd7cddfSDavid du Colombier force301 = 1; 4587dd7cddfSDavid du Colombier } 4597dd7cddfSDavid du Colombier fd1 = open(w, OREAD); 4607dd7cddfSDavid du Colombier if(fd1 < 0){ 4617dd7cddfSDavid du Colombier close(fd); 4627dd7cddfSDavid du Colombier return notfound(c, c->req.uri); 4637dd7cddfSDavid du Colombier } 4649a747e4fSDavid du Colombier c->req.uri = w + strlen(webroot) + strlen(masque); 4657dd7cddfSDavid du Colombier if(force301 && c->req.vermaj){ 4667dd7cddfSDavid du Colombier close(fd); 4677dd7cddfSDavid du Colombier close(fd1); 46880ee5cbfSDavid du Colombier return hmoved(c, c->req.uri); 4697dd7cddfSDavid du Colombier } 4707dd7cddfSDavid du Colombier close(fd); 4717dd7cddfSDavid du Colombier fd = fd1; 4729a747e4fSDavid du Colombier dir = dirfstat(fd); 4739a747e4fSDavid du Colombier if(dir == nil){ 4747dd7cddfSDavid du Colombier close(fd); 47580ee5cbfSDavid du Colombier return hfail(c, HInternal); 4767dd7cddfSDavid du Colombier } 4777dd7cddfSDavid du Colombier }else if(p > w && p[-1] == '/'){ 4789a747e4fSDavid du Colombier free(dir); 4797dd7cddfSDavid du Colombier close(fd); 4807dd7cddfSDavid du Colombier *strrchr(c->req.uri, '/') = '\0'; 48180ee5cbfSDavid du Colombier return hmoved(c, c->req.uri); 4827dd7cddfSDavid du Colombier } 4837dd7cddfSDavid du Colombier 4849a747e4fSDavid du Colombier ok = authorize(c, w); 4859a747e4fSDavid du Colombier if(ok <= 0){ 4869a747e4fSDavid du Colombier free(dir); 4879a747e4fSDavid du Colombier close(fd); 4889a747e4fSDavid du Colombier return ok; 4899a747e4fSDavid du Colombier } 4909a747e4fSDavid du Colombier 4919a747e4fSDavid du Colombier return sendfd(c, fd, dir, nil, nil); 4927dd7cddfSDavid du Colombier } 4937dd7cddfSDavid du Colombier 4947dd7cddfSDavid du Colombier static Strings 49580ee5cbfSDavid du Colombier stripmagic(HConnect *hc, char *uri) 4967dd7cddfSDavid du Colombier { 4977dd7cddfSDavid du Colombier Strings ss; 4987dd7cddfSDavid du Colombier char *newuri, *prog, *s; 4997dd7cddfSDavid du Colombier 5007dd7cddfSDavid du Colombier prog = stripprefix("/magic/", uri); 5017dd7cddfSDavid du Colombier if(prog == nil){ 5027dd7cddfSDavid du Colombier ss.s1 = uri; 5037dd7cddfSDavid du Colombier ss.s2 = nil; 5047dd7cddfSDavid du Colombier return ss; 5057dd7cddfSDavid du Colombier } 5067dd7cddfSDavid du Colombier 5077dd7cddfSDavid du Colombier s = strchr(prog, '/'); 5087dd7cddfSDavid du Colombier if(s == nil) 5097dd7cddfSDavid du Colombier newuri = ""; 5107dd7cddfSDavid du Colombier else{ 51180ee5cbfSDavid du Colombier newuri = hstrdup(hc, s); 5127dd7cddfSDavid du Colombier *s = 0; 5137dd7cddfSDavid du Colombier s = strrchr(s, '/'); 5147dd7cddfSDavid du Colombier if(s != nil && s[1] == 0) 5157dd7cddfSDavid du Colombier *s = 0; 5167dd7cddfSDavid du Colombier } 5177dd7cddfSDavid du Colombier ss.s1 = newuri; 5187dd7cddfSDavid du Colombier ss.s2 = prog; 5197dd7cddfSDavid du Colombier return ss; 5207dd7cddfSDavid du Colombier } 5217dd7cddfSDavid du Colombier 5227dd7cddfSDavid du Colombier static char* 5237dd7cddfSDavid du Colombier stripprefix(char *pre, char *str) 5247dd7cddfSDavid du Colombier { 5257dd7cddfSDavid du Colombier while(*pre) 5267dd7cddfSDavid du Colombier if(*str++ != *pre++) 5277dd7cddfSDavid du Colombier return nil; 5287dd7cddfSDavid du Colombier return str; 5297dd7cddfSDavid du Colombier } 5307dd7cddfSDavid du Colombier 5319a747e4fSDavid du Colombier /* 5329a747e4fSDavid du Colombier * couldn't open a file 5339a747e4fSDavid du Colombier * figure out why and return and error message 5349a747e4fSDavid du Colombier */ 5359a747e4fSDavid du Colombier static int 5369a747e4fSDavid du Colombier notfound(HConnect *c, char *url) 5379a747e4fSDavid du Colombier { 5389a747e4fSDavid du Colombier c->xferbuf[0] = 0; 539dc6ece7cSDavid du Colombier rerrstr(c->xferbuf, sizeof c->xferbuf); 5409a747e4fSDavid du Colombier if(strstr(c->xferbuf, "file does not exist") != nil) 5419a747e4fSDavid du Colombier return hfail(c, HNotFound, url); 5429a747e4fSDavid du Colombier if(strstr(c->xferbuf, "permission denied") != nil) 5439a747e4fSDavid du Colombier return hfail(c, HUnauth, url); 5449a747e4fSDavid du Colombier return hfail(c, HNotFound, url); 5459a747e4fSDavid du Colombier } 5469a747e4fSDavid du Colombier 5477dd7cddfSDavid du Colombier static char* 5487dd7cddfSDavid du Colombier sysdom(void) 5497dd7cddfSDavid du Colombier { 5507dd7cddfSDavid du Colombier char *dn; 5517dd7cddfSDavid du Colombier 5527dd7cddfSDavid du Colombier dn = csquery("sys" , sysname(), "dom"); 5537dd7cddfSDavid du Colombier if(dn == nil) 5547dd7cddfSDavid du Colombier dn = "who cares"; 5557dd7cddfSDavid du Colombier return dn; 5567dd7cddfSDavid du Colombier } 5577dd7cddfSDavid du Colombier 5587dd7cddfSDavid du Colombier /* 5597dd7cddfSDavid du Colombier * query the connection server 5607dd7cddfSDavid du Colombier */ 5617dd7cddfSDavid du Colombier static char* 5627dd7cddfSDavid du Colombier csquery(char *attr, char *val, char *rattr) 5637dd7cddfSDavid du Colombier { 5647dd7cddfSDavid du Colombier char token[64+4]; 5657dd7cddfSDavid du Colombier char buf[256], *p, *sp; 5667dd7cddfSDavid du Colombier int fd, n; 5677dd7cddfSDavid du Colombier 5687dd7cddfSDavid du Colombier if(val == nil || val[0] == 0) 5697dd7cddfSDavid du Colombier return nil; 5707dd7cddfSDavid du Colombier snprint(buf, sizeof(buf), "%s/cs", netdir); 5717dd7cddfSDavid du Colombier fd = open(buf, ORDWR); 5727dd7cddfSDavid du Colombier if(fd < 0) 5737dd7cddfSDavid du Colombier return nil; 5747dd7cddfSDavid du Colombier fprint(fd, "!%s=%s", attr, val); 5757dd7cddfSDavid du Colombier seek(fd, 0, 0); 5767dd7cddfSDavid du Colombier snprint(token, sizeof(token), "%s=", rattr); 5777dd7cddfSDavid du Colombier for(;;){ 5787dd7cddfSDavid du Colombier n = read(fd, buf, sizeof(buf)-1); 5797dd7cddfSDavid du Colombier if(n <= 0) 5807dd7cddfSDavid du Colombier break; 5817dd7cddfSDavid du Colombier buf[n] = 0; 5827dd7cddfSDavid du Colombier p = strstr(buf, token); 5837dd7cddfSDavid du Colombier if(p != nil && (p == buf || *(p-1) == 0)){ 5847dd7cddfSDavid du Colombier close(fd); 5857dd7cddfSDavid du Colombier sp = strchr(p, ' '); 5867dd7cddfSDavid du Colombier if(sp) 5877dd7cddfSDavid du Colombier *sp = 0; 5887dd7cddfSDavid du Colombier p = strchr(p, '='); 5897dd7cddfSDavid du Colombier if(p == nil) 5907dd7cddfSDavid du Colombier return nil; 5917dd7cddfSDavid du Colombier return estrdup(p+1); 5927dd7cddfSDavid du Colombier } 5937dd7cddfSDavid du Colombier } 5947dd7cddfSDavid du Colombier close(fd); 5957dd7cddfSDavid du Colombier return nil; 5967dd7cddfSDavid du Colombier } 597