redirect.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  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. static int
  21. hashasu(char *key, int n)
  22. {
  23. ulong h;
  24. h = 0;
  25. while(*key != 0)
  26. h = 65599*h + *(uchar*)key++;
  27. return h % n;
  28. }
  29. static void
  30. insert(Redir **tab, char *pat, char *repl)
  31. {
  32. Redir **l;
  33. Redir *srch;
  34. ulong hash;
  35. hash = hashasu(pat, HASHSIZE);
  36. for(l = &tab[hash]; *l; l = &(*l)->next)
  37. ;
  38. *l = srch = ezalloc(sizeof(Redir));
  39. srch->pat = pat;
  40. srch->repl = repl;
  41. srch->next = 0;
  42. }
  43. static void
  44. cleartab(Redir **tab)
  45. {
  46. Redir *t;
  47. int i;
  48. for(i = 0; i < HASHSIZE; i++){
  49. while((t = tab[i]) != nil){
  50. tab[i] = t->next;
  51. free(t->pat);
  52. free(t->repl);
  53. free(t);
  54. }
  55. }
  56. }
  57. void
  58. redirectinit(void)
  59. {
  60. static Biobuf *b = nil;
  61. static Qid qid;
  62. char *file, *line, *s, *host, *field[3];
  63. file = "/sys/lib/httpd.rewrite";
  64. if(b != nil){
  65. if(updateQid(Bfildes(b), &qid) == 0)
  66. return;
  67. Bterm(b);
  68. }
  69. b = Bopen(file, OREAD);
  70. if(b == nil)
  71. sysfatal("can't read from %s", file);
  72. updateQid(Bfildes(b), &qid);
  73. cleartab(redirtab);
  74. cleartab(vhosttab);
  75. while((line = Brdline(b, '\n')) != nil){
  76. line[Blinelen(b)-1] = 0;
  77. s = strchr(line, '#');
  78. if(s != nil)
  79. *s = '\0'; /* chop comment */
  80. if(tokenize(line, field, nelem(field)) == 2){
  81. if(strncmp(field[0], "http://", STRLEN("http://")) == 0 &&
  82. strncmp(field[1], "http://", STRLEN("http://")) != 0){
  83. host = field[0]+STRLEN("http://");
  84. s = strpbrk(host, "/");
  85. if(s)
  86. *s = 0; /* chop trailing slash */
  87. insert(vhosttab, estrdup(host), estrdup(field[1]));
  88. }else{
  89. insert(redirtab, estrdup(field[0]), estrdup(field[1]));
  90. }
  91. }
  92. }
  93. syslog(0, HTTPLOG, "redirectinit pid=%d", getpid());
  94. }
  95. static Redir*
  96. lookup(Redir **tab, char *pat)
  97. {
  98. Redir *srch;
  99. ulong hash;
  100. hash = hashasu(pat,HASHSIZE);
  101. for(srch = tab[hash]; srch != nil; srch = srch->next)
  102. if(strcmp(pat, srch->pat) == 0)
  103. return srch;
  104. return nil;
  105. }
  106. static char*
  107. prevslash(char *p, char *s)
  108. {
  109. while(--s > p)
  110. if(*s == '/')
  111. break;
  112. return s;
  113. }
  114. char*
  115. redirect(HConnect *hc, char *path)
  116. {
  117. Redir *redir;
  118. char *s, *newpath;
  119. int c, n;
  120. for(s = strchr(path, '\0'); s > path; s = prevslash(path, s)){
  121. c = *s;
  122. *s = '\0';
  123. redir = lookup(redirtab, path);
  124. *s = c;
  125. if(redir != nil){
  126. n = strlen(redir->repl) + strlen(s) + 2 + UTFmax;
  127. newpath = halloc(hc, n);
  128. snprint(newpath, n, "%s%s", redir->repl, s);
  129. return newpath;
  130. }
  131. }
  132. return nil;
  133. }
  134. // if host is virtual, return implicit prefix for URI within webroot.
  135. // if not, return empty string
  136. // return value should not be freed by caller
  137. char*
  138. masquerade(char *host)
  139. {
  140. Redir *redir;
  141. redir = lookup(vhosttab, host);
  142. if(redir != nil)
  143. return redir->repl;
  144. return emptystring;
  145. }