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