parsereq.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  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. return 1;
  123. }
  124. static Strings
  125. parseuri(HConnect *c, char *uri)
  126. {
  127. Strings ss;
  128. char *urihost, *p;
  129. urihost = nil;
  130. if(uri[0] != '/'){
  131. if(cistrncmp(uri, "http://", 7) != 0){
  132. ss.s1 = nil;
  133. ss.s2 = nil;
  134. return ss;
  135. }
  136. uri += 5; /* skip http: */
  137. }
  138. /*
  139. * anything starting with // is a host name or number
  140. * hostnames constists of letters, digits, - and .
  141. * for now, just ignore any port given
  142. */
  143. if(uri[0] == '/' && uri[1] == '/'){
  144. urihost = uri + 2;
  145. p = strchr(urihost, '/');
  146. if(p == nil)
  147. uri = hstrdup(c, "/");
  148. else{
  149. uri = hstrdup(c, p);
  150. *p = '\0';
  151. }
  152. p = strchr(urihost, ':');
  153. if(p != nil)
  154. *p = '\0';
  155. }
  156. if(uri[0] != '/' || uri[1] == '/'){
  157. ss.s1 = nil;
  158. ss.s2 = nil;
  159. return ss;
  160. }
  161. ss.s1 = uri;
  162. ss.s2 = hlower(urihost);
  163. return ss;
  164. }
  165. static Strings
  166. stripsearch(char *uri)
  167. {
  168. Strings ss;
  169. char *search;
  170. search = strchr(uri, '?');
  171. if(search != nil)
  172. *search++ = 0;
  173. ss.s1 = uri;
  174. ss.s2 = search;
  175. return ss;
  176. }
  177. /*
  178. * to circumscribe the accessible files we have to eliminate ..'s
  179. * and resolve all names from the root.
  180. */
  181. static char*
  182. abspath(HConnect *cc, char *origpath, char *curdir)
  183. {
  184. char *p, *sp, *path, *work, *rpath;
  185. int len, n, c;
  186. if(curdir == nil)
  187. curdir = "/";
  188. if(origpath == nil)
  189. origpath = "";
  190. work = hstrdup(cc, origpath);
  191. path = work;
  192. /*
  193. * remove any really special characters
  194. */
  195. for(sp = "`;|"; *sp; sp++){
  196. p = strchr(path, *sp);
  197. if(p)
  198. *p = 0;
  199. }
  200. len = strlen(curdir) + strlen(path) + 2 + UTFmax;
  201. if(len < 10)
  202. len = 10;
  203. rpath = halloc(cc, len);
  204. if(*path == '/')
  205. rpath[0] = 0;
  206. else
  207. strcpy(rpath, curdir);
  208. n = strlen(rpath);
  209. while(path){
  210. p = strchr(path, '/');
  211. if(p)
  212. *p++ = 0;
  213. if(strcmp(path, "..") == 0){
  214. while(n > 1){
  215. n--;
  216. c = rpath[n];
  217. rpath[n] = 0;
  218. if(c == '/')
  219. break;
  220. }
  221. }else if(strcmp(path, ".") == 0){
  222. ;
  223. }else if(n == 1)
  224. n += snprint(rpath+n, len-n, "%s", path);
  225. else
  226. n += snprint(rpath+n, len-n, "/%s", path);
  227. path = p;
  228. }
  229. if(strncmp(rpath, "/bin/", 5) == 0)
  230. strcpy(rpath, "/");
  231. return rpath;
  232. }
  233. static char*
  234. getword(HConnect *c)
  235. {
  236. char *buf;
  237. int ch, n;
  238. while((ch = getc(c)) == ' ' || ch == '\t' || ch == '\r')
  239. ;
  240. if(ch == '\n')
  241. return nil;
  242. n = 0;
  243. buf = halloc(c, 1);
  244. for(;;){
  245. switch(ch){
  246. case ' ':
  247. case '\t':
  248. case '\r':
  249. case '\n':
  250. buf[n] = '\0';
  251. return hstrdup(c, buf);
  252. }
  253. if(n < HMaxWord-1){
  254. buf = bingrow(&c->bin, buf, n, n + 1, 0);
  255. if(buf == nil)
  256. return nil;
  257. buf[n++] = ch;
  258. }
  259. ch = getc(c);
  260. }
  261. }
  262. static int
  263. getc(HConnect *c)
  264. {
  265. if(c->hpos < c->hstop)
  266. return *c->hpos++;
  267. return '\n';
  268. }