parsereq.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <bin.h>
  12. #include <httpd.h>
  13. typedef struct Strings Strings;
  14. struct Strings
  15. {
  16. char *s1;
  17. char *s2;
  18. };
  19. static char* abspath(HConnect *cc, char *origpath,
  20. char *curdir);
  21. static int getc(HConnect*);
  22. static char* getword(HConnect*);
  23. static Strings parseuri(HConnect *c, char*);
  24. static Strings stripsearch(char*);
  25. /*
  26. * parse the next request line
  27. * returns:
  28. * 1 ok
  29. * 0 eof
  30. * -1 error
  31. */
  32. int
  33. hparsereq(HConnect *c, int timeout)
  34. {
  35. Strings ss;
  36. char *vs, *v, *search, *uri, *origuri, *extra;
  37. if(c->bin != nil){
  38. hfail(c, HInternal);
  39. return -1;
  40. }
  41. /*
  42. * serve requests until a magic request.
  43. * later requests have to come quickly.
  44. * only works for http/1.1 or later.
  45. */
  46. if(timeout)
  47. alarm(timeout);
  48. if(hgethead(c, 0) < 0)
  49. return -1;
  50. if(timeout)
  51. alarm(0);
  52. c->reqtime = time(nil);
  53. c->req.meth = getword(c);
  54. if(c->req.meth == nil){
  55. hfail(c, HSyntax);
  56. return -1;
  57. }
  58. uri = getword(c);
  59. if(uri == nil || strlen(uri) == 0){
  60. hfail(c, HSyntax);
  61. return -1;
  62. }
  63. v = getword(c);
  64. if(v == nil){
  65. if(strcmp(c->req.meth, "GET") != 0){
  66. hfail(c, HUnimp, c->req.meth);
  67. return -1;
  68. }
  69. c->req.vermaj = 0;
  70. c->req.vermin = 9;
  71. }else{
  72. vs = v;
  73. if(strncmp(vs, "HTTP/", 5) != 0){
  74. hfail(c, HUnkVers, vs);
  75. return -1;
  76. }
  77. vs += 5;
  78. c->req.vermaj = strtoul(vs, &vs, 10);
  79. if(*vs != '.' || c->req.vermaj != 1){
  80. hfail(c, HUnkVers, vs);
  81. return -1;
  82. }
  83. vs++;
  84. c->req.vermin = strtoul(vs, &vs, 10);
  85. if(*vs != '\0'){
  86. hfail(c, HUnkVers, vs);
  87. return -1;
  88. }
  89. extra = getword(c);
  90. if(extra != nil){
  91. hfail(c, HSyntax);
  92. return -1;
  93. }
  94. }
  95. /*
  96. * the fragment is not supposed to be sent
  97. * strip it 'cause some clients send it
  98. */
  99. origuri = uri;
  100. uri = strchr(origuri, '#');
  101. if(uri != nil)
  102. *uri = 0;
  103. /*
  104. * http/1.1 requires the server to accept absolute
  105. * or relative uri's. convert to relative with an absolute path
  106. */
  107. if(http11(c)){
  108. ss = parseuri(c, origuri);
  109. uri = ss.s1;
  110. c->req.urihost = ss.s2;
  111. if(uri == nil){
  112. hfail(c, HBadReq, uri);
  113. return -1;
  114. }
  115. origuri = uri;
  116. }
  117. /*
  118. * munge uri for search, protection, and magic
  119. */
  120. ss = stripsearch(origuri);
  121. origuri = ss.s1;
  122. search = ss.s2;
  123. uri = hurlunesc(c, origuri);
  124. uri = abspath(c, uri, "/");
  125. if(uri == nil || uri[0] == '\0'){
  126. hfail(c, HNotFound, "no object specified");
  127. return -1;
  128. }
  129. c->req.uri = uri;
  130. c->req.search = search;
  131. if(search)
  132. c->req.searchpairs = hparsequery(c, hstrdup(c, search));
  133. return 1;
  134. }
  135. static Strings
  136. parseuri(HConnect *c, char *uri)
  137. {
  138. Strings ss;
  139. char *urihost, *p;
  140. urihost = nil;
  141. ss.s1 = ss.s2 = nil;
  142. if(uri[0] != '/')
  143. if(cistrncmp(uri, "http://", 7) == 0)
  144. uri += 5; /* skip http: */
  145. else if (cistrncmp(uri, "https://", 8) == 0)
  146. uri += 6; /* skip https: */
  147. else
  148. return ss;
  149. /*
  150. * anything starting with // is a host name or number
  151. * hostnames consists of letters, digits, - and .
  152. * for now, just ignore any port given
  153. */
  154. if(uri[0] == '/' && uri[1] == '/'){
  155. urihost = uri + 2;
  156. p = strchr(urihost, '/');
  157. if(p == nil)
  158. uri = hstrdup(c, "/");
  159. else{
  160. uri = hstrdup(c, p);
  161. *p = '\0';
  162. }
  163. p = strchr(urihost, ':');
  164. if(p != nil)
  165. *p = '\0';
  166. }
  167. if(uri[0] != '/' || uri[1] == '/')
  168. return ss;
  169. ss.s1 = uri;
  170. ss.s2 = hlower(urihost);
  171. return ss;
  172. }
  173. static Strings
  174. stripsearch(char *uri)
  175. {
  176. Strings ss;
  177. char *search;
  178. search = strchr(uri, '?');
  179. if(search != nil)
  180. *search++ = 0;
  181. ss.s1 = uri;
  182. ss.s2 = search;
  183. return ss;
  184. }
  185. /*
  186. * to circumscribe the accessible files we have to eliminate ..'s
  187. * and resolve all names from the root.
  188. */
  189. static char*
  190. abspath(HConnect *cc, char *origpath, char *curdir)
  191. {
  192. char *p, *sp, *path, *work, *rpath;
  193. int len, n, c;
  194. if(curdir == nil)
  195. curdir = "/";
  196. if(origpath == nil)
  197. origpath = "";
  198. work = hstrdup(cc, origpath);
  199. path = work;
  200. /*
  201. * remove any really special characters
  202. */
  203. for(sp = "`;|"; *sp; sp++){
  204. p = strchr(path, *sp);
  205. if(p)
  206. *p = 0;
  207. }
  208. len = strlen(curdir) + strlen(path) + 2 + UTFmax;
  209. if(len < 10)
  210. len = 10;
  211. rpath = halloc(cc, len);
  212. if(*path == '/')
  213. rpath[0] = 0;
  214. else
  215. strcpy(rpath, curdir);
  216. n = strlen(rpath);
  217. while(path){
  218. p = strchr(path, '/');
  219. if(p)
  220. *p++ = 0;
  221. if(strcmp(path, "..") == 0){
  222. while(n > 1){
  223. n--;
  224. c = rpath[n];
  225. rpath[n] = 0;
  226. if(c == '/')
  227. break;
  228. }
  229. }else if(strcmp(path, ".") == 0){
  230. ;
  231. }else if(n == 1)
  232. n += snprint(rpath+n, len-n, "%s", path);
  233. else
  234. n += snprint(rpath+n, len-n, "/%s", path);
  235. path = p;
  236. }
  237. if(strncmp(rpath, "/bin/", 5) == 0)
  238. strcpy(rpath, "/");
  239. return rpath;
  240. }
  241. static char*
  242. getword(HConnect *c)
  243. {
  244. char *buf;
  245. int ch, n;
  246. while((ch = getc(c)) == ' ' || ch == '\t' || ch == '\r')
  247. ;
  248. if(ch == '\n')
  249. return nil;
  250. n = 0;
  251. buf = halloc(c, 1);
  252. for(;;){
  253. switch(ch){
  254. case ' ':
  255. case '\t':
  256. case '\r':
  257. case '\n':
  258. buf[n] = '\0';
  259. return hstrdup(c, buf);
  260. }
  261. if(n < HMaxWord-1){
  262. buf = bingrow(&c->bin, buf, n, n + 1, 0);
  263. if(buf == nil)
  264. return nil;
  265. buf[n++] = ch;
  266. }
  267. ch = getc(c);
  268. }
  269. }
  270. static int
  271. getc(HConnect *c)
  272. {
  273. if(c->hpos < c->hstop)
  274. return *c->hpos++;
  275. return '\n';
  276. }