#include #include #include #include "httpd.h" #include "httpsrv.h" enum { HASHSIZE = 1019, }; typedef struct Redir Redir; struct Redir { Redir *next; char *pat; char *repl; }; static Redir *redirtab[HASHSIZE]; static Redir *vhosttab[HASHSIZE]; static char emptystring[1]; static int hashasu(char *key, int n) { ulong h; h = 0; while(*key != 0) h = 65599*h + *(uchar*)key++; return h % n; } static void insert(Redir **tab, char *pat, char *repl) { Redir **l; Redir *srch; ulong hash; hash = hashasu(pat, HASHSIZE); for(l = &tab[hash]; *l; l = &(*l)->next) ; *l = srch = ezalloc(sizeof(Redir)); srch->pat = pat; srch->repl = repl; srch->next = 0; } static void cleartab(Redir **tab) { Redir *t; int i; for(i = 0; i < HASHSIZE; i++){ while((t = tab[i]) != nil){ tab[i] = t->next; free(t->pat); free(t->repl); free(t); } } } void redirectinit(void) { static Biobuf *b = nil; static Qid qid; char *file, *line, *s, *host, *field[3]; file = "/sys/lib/httpd.rewrite"; if(b != nil){ if(updateQid(Bfildes(b), &qid) == 0) return; Bterm(b); } b = Bopen(file, OREAD); if(b == nil) sysfatal("can't read from %s", file); updateQid(Bfildes(b), &qid); cleartab(redirtab); cleartab(vhosttab); while((line = Brdline(b, '\n')) != nil){ line[Blinelen(b)-1] = 0; s = strchr(line, '#'); if(s != nil) *s = '\0'; /* chop comment */ if(tokenize(line, field, nelem(field)) == 2){ if(strncmp(field[0], "http://", STRLEN("http://")) == 0 && strncmp(field[1], "http://", STRLEN("http://")) != 0){ host = field[0]+STRLEN("http://"); s = strpbrk(host, "/"); if(s) *s = 0; /* chop trailing slash */ insert(vhosttab, estrdup(host), estrdup(field[1])); }else{ insert(redirtab, estrdup(field[0]), estrdup(field[1])); } } } syslog(0, HTTPLOG, "redirectinit pid=%d", getpid()); } static Redir* lookup(Redir **tab, char *pat) { Redir *srch; ulong hash; hash = hashasu(pat,HASHSIZE); for(srch = tab[hash]; srch != nil; srch = srch->next) if(strcmp(pat, srch->pat) == 0) return srch; return nil; } static char* prevslash(char *p, char *s) { while(--s > p) if(*s == '/') break; return s; } char* redirect(HConnect *hc, char *path) { Redir *redir; char *s, *newpath; int c, n; for(s = strchr(path, '\0'); s > path; s = prevslash(path, s)){ c = *s; *s = '\0'; redir = lookup(redirtab, path); *s = c; if(redir != nil){ n = strlen(redir->repl) + strlen(s) + 2 + UTFmax; newpath = halloc(hc, n); snprint(newpath, n, "%s%s", redir->repl, s); return newpath; } } return nil; } // if host is virtual, return implicit prefix for URI within webroot. // if not, return empty string // return value should not be freed by caller char* masquerade(char *host) { Redir *redir; redir = lookup(vhosttab, host); if(redir != nil) return redir->repl; return emptystring; }