12 typedef struct Redir Redir;
18 uint flags; /* generated from repl's decorations */
21 static Redir *redirtab[HASHSIZE];
22 static Redir *vhosttab[HASHSIZE];
23 static char emptystring[1];
24 /* these two arrays must be kept in sync */
25 static char decorations[] = { Modsilent, Modperm, Modsubord, Modonly, '\0' };
26 static uint redirflags[] = { Redirsilent, Redirperm, Redirsubord, Redironly, };
28 /* replacement field decorated with redirection modifiers? */
30 isdecorated(char *repl)
32 return strchr(decorations, repl[0]) != nil;
36 decor2flags(char *repl)
42 while ((p = strchr(decorations, *repl++)) != nil)
43 flags |= redirflags[p - decorations];
47 /* return replacement without redirection modifiers */
49 undecorated(char *repl)
51 while (isdecorated(repl))
57 hashasu(char *key, int n)
63 h = 65599*h + *(uchar*)key++;
68 insert(Redir **tab, char *pat, char *repl)
74 hash = hashasu(pat, HASHSIZE);
75 for(l = &tab[hash]; *l; l = &(*l)->next)
77 *l = srch = ezalloc(sizeof(Redir));
79 srch->flags = decor2flags(repl);
80 srch->repl = undecorated(repl);
90 for(i = 0; i < HASHSIZE; i++){
91 while((t = tab[i]) != nil){
103 static Biobuf *b = nil;
105 char *file, *line, *s, *host, *field[3];
106 static char pfx[] = "http://";
108 file = "/sys/lib/httpd.rewrite";
110 if(updateQid(Bfildes(b), &qid) == 0)
114 b = Bopen(file, OREAD);
116 sysfatal("can't read from %s", file);
117 updateQid(Bfildes(b), &qid);
122 while((line = Brdline(b, '\n')) != nil){
123 line[Blinelen(b)-1] = 0;
124 s = strchr(line, '#');
125 if(s != nil && (s == line || s[-1] == ' ' || s[-1] == '\t'))
126 *s = '\0'; /* chop comment iff after whitespace */
127 if(tokenize(line, field, nelem(field)) == 2){
128 if(strncmp(field[0], pfx, STRLEN(pfx)) == 0 &&
129 strncmp(undecorated(field[1]), pfx, STRLEN(pfx)) != 0){
130 /* url -> filename */
131 host = field[0] + STRLEN(pfx);
132 s = strrchr(host, '/');
134 *s = 0; /* chop trailing slash */
136 insert(vhosttab, estrdup(host), estrdup(field[1]));
138 insert(redirtab, estrdup(field[0]), estrdup(field[1]));
142 syslog(0, HTTPLOG, "redirectinit pid=%d", getpid());
146 lookup(Redir **tab, char *pat, int count)
151 hash = hashasu(pat,HASHSIZE);
152 for(srch = tab[hash]; srch != nil; srch = srch->next)
153 if(strcmp(pat, srch->pat) == 0) {
154 /* only exact match wanted? */
155 if (!(srch->flags & Redironly) || count == 0)
162 prevslash(char *p, char *s)
171 * find the longest match of path against the redirection table,
172 * chopping off the rightmost path component until success or
173 * there's nothing left. return a copy of the replacement string
174 * concatenated with a slash and the portion of the path *not* matched.
175 * So a match of /who/gre/some/stuff.html matched against
176 * /who/gre http://gremlinsrus.org
178 * http://gremlinsrus.org/some/stuff.html
180 * further flags: if Redironly, match only the named page and no
181 * subordinate ones. if Redirsubord, map the named patch and any
182 * subordinate ones to the same replacement URL.
185 redirect(HConnect *hc, char *path, uint *flagp)
188 char *s, *newpath, *repl;
192 for(s = strchr(path, '\0'); s > path; s = prevslash(path, s)){
195 redir = lookup(redirtab, path, count++);
199 *flagp = redir->flags;
201 if(redir->flags & Redirsubord)
202 /* don't append s, all matches map to repl */
204 n = strlen(repl) + strlen(s) + 2 + UTFmax;
205 newpath = halloc(hc, n);
206 snprint(newpath, n, "%s%s", repl, s);
214 * if host is virtual, return implicit prefix for URI within webroot.
215 * if not, return empty string.
216 * return value should not be freed by caller.
219 masquerade(char *host)
223 redir = lookup(vhosttab, host, 0);