redirect.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include "httpd.h"
  5. #include "httpsrv.h"
  6. enum
  7. {
  8. HASHSIZE = 1019,
  9. };
  10. typedef struct Redir Redir;
  11. struct Redir
  12. {
  13. Redir *next;
  14. char *pat;
  15. char *repl;
  16. };
  17. static Redir *redirtab[HASHSIZE];
  18. static Redir *vhosttab[HASHSIZE];
  19. static char emptystring[1];
  20. /* replacement field decorated with redirection modifiers? */
  21. int
  22. isdecorated(char *repl)
  23. {
  24. return repl[0] == Modsilent || repl[0] == Modperm;
  25. }
  26. /* return replacement without redirection modifiers */
  27. char *
  28. undecorated(char *repl)
  29. {
  30. while (isdecorated(repl))
  31. repl++;
  32. return repl;
  33. }
  34. static int
  35. hashasu(char *key, int n)
  36. {
  37. ulong h;
  38. h = 0;
  39. while(*key != 0)
  40. h = 65599*h + *(uchar*)key++;
  41. return h % n;
  42. }
  43. static void
  44. insert(Redir **tab, char *pat, char *repl)
  45. {
  46. Redir **l;
  47. Redir *srch;
  48. ulong hash;
  49. hash = hashasu(pat, HASHSIZE);
  50. for(l = &tab[hash]; *l; l = &(*l)->next)
  51. ;
  52. *l = srch = ezalloc(sizeof(Redir));
  53. srch->pat = pat;
  54. srch->repl = repl;
  55. srch->next = 0;
  56. }
  57. static void
  58. cleartab(Redir **tab)
  59. {
  60. Redir *t;
  61. int i;
  62. for(i = 0; i < HASHSIZE; i++){
  63. while((t = tab[i]) != nil){
  64. tab[i] = t->next;
  65. free(t->pat);
  66. free(t->repl);
  67. free(t);
  68. }
  69. }
  70. }
  71. void
  72. redirectinit(void)
  73. {
  74. static Biobuf *b = nil;
  75. static Qid qid;
  76. char *file, *line, *s, *host, *repl, *field[3];
  77. static char pfx[] = "http://";
  78. file = "/sys/lib/httpd.rewrite";
  79. if(b != nil){
  80. if(updateQid(Bfildes(b), &qid) == 0)
  81. return;
  82. Bterm(b);
  83. }
  84. b = Bopen(file, OREAD);
  85. if(b == nil)
  86. sysfatal("can't read from %s", file);
  87. updateQid(Bfildes(b), &qid);
  88. cleartab(redirtab);
  89. cleartab(vhosttab);
  90. while((line = Brdline(b, '\n')) != nil){
  91. line[Blinelen(b)-1] = 0;
  92. s = strchr(line, '#');
  93. if(s != nil && (s == line || s[-1] == ' ' || s[-1] == '\t'))
  94. *s = '\0'; /* chop comment iff after whitespace */
  95. if(tokenize(line, field, nelem(field)) == 2){
  96. repl = undecorated(field[1]);
  97. if(strncmp(field[0], pfx, STRLEN(pfx)) == 0 &&
  98. strncmp(repl, pfx, STRLEN(pfx)) != 0){
  99. /* url -> filename */
  100. host = field[0] + STRLEN(pfx);
  101. s = strrchr(host, '/');
  102. if(s)
  103. *s = 0; /* chop trailing slash */
  104. insert(vhosttab, estrdup(host), estrdup(field[1]));
  105. }else{
  106. insert(redirtab, estrdup(field[0]), estrdup(field[1]));
  107. }
  108. }
  109. }
  110. syslog(0, HTTPLOG, "redirectinit pid=%d", getpid());
  111. }
  112. static Redir*
  113. lookup(Redir **tab, char *pat)
  114. {
  115. Redir *srch;
  116. ulong hash;
  117. hash = hashasu(pat,HASHSIZE);
  118. for(srch = tab[hash]; srch != nil; srch = srch->next)
  119. if(strcmp(pat, srch->pat) == 0)
  120. return srch;
  121. return nil;
  122. }
  123. static char*
  124. prevslash(char *p, char *s)
  125. {
  126. while(--s > p)
  127. if(*s == '/')
  128. break;
  129. return s;
  130. }
  131. char*
  132. redirect(HConnect *hc, char *path)
  133. {
  134. Redir *redir;
  135. char *s, *newpath, *repl;
  136. int c, n;
  137. for(s = strchr(path, '\0'); s > path; s = prevslash(path, s)){
  138. c = *s;
  139. *s = '\0';
  140. redir = lookup(redirtab, path);
  141. *s = c;
  142. if(redir != nil){
  143. repl = undecorated(redir->repl);
  144. n = strlen(repl) + strlen(s) + 2 + UTFmax;
  145. newpath = halloc(hc, n);
  146. snprint(newpath, n, "%s%s", repl, s);
  147. return newpath;
  148. }
  149. }
  150. return nil;
  151. }
  152. /*
  153. * if host is virtual, return implicit prefix for URI within webroot.
  154. * if not, return empty string.
  155. * return value should not be freed by caller.
  156. */
  157. char*
  158. masquerade(char *host)
  159. {
  160. Redir *redir;
  161. redir = lookup(vhosttab, host);
  162. if(redir == nil)
  163. return emptystring;
  164. return undecorated(redir->repl);
  165. }