123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- #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];
- /* replacement field decorated with redirection modifiers? */
- int
- isdecorated(char *repl)
- {
- return repl[0] == Modsilent || repl[0] == Modperm;
- }
- /* return replacement without redirection modifiers */
- char *
- undecorated(char *repl)
- {
- while (isdecorated(repl))
- repl++;
- return repl;
- }
- 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, *repl, *field[3];
- static char pfx[] = "http://";
- 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 == line || s[-1] == ' ' || s[-1] == '\t'))
- *s = '\0'; /* chop comment iff after whitespace */
- if(tokenize(line, field, nelem(field)) == 2){
- repl = undecorated(field[1]);
- if(strncmp(field[0], pfx, STRLEN(pfx)) == 0 &&
- strncmp(repl, pfx, STRLEN(pfx)) != 0){
- /* url -> filename */
- host = field[0] + STRLEN(pfx);
- s = strrchr(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, *repl;
- 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){
- repl = undecorated(redir->repl);
- n = strlen(repl) + strlen(s) + 2 + UTFmax;
- newpath = halloc(hc, n);
- snprint(newpath, n, "%s%s", 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 emptystring;
- return undecorated(redir->repl);
- }
|