parsereq.c 5.0 KB

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