parsereq.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  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. ss.s1 = ss.s2 = nil;
  133. if(uri[0] != '/')
  134. if(cistrncmp(uri, "http://", 7) == 0)
  135. uri += 5; /* skip http: */
  136. else if (cistrncmp(uri, "https://", 8) == 0)
  137. uri += 6; /* skip https: */
  138. else
  139. return ss;
  140. /*
  141. * anything starting with // is a host name or number
  142. * hostnames consists 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. return ss;
  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. }
  261. static int
  262. getc(HConnect *c)
  263. {
  264. if(c->hpos < c->hstop)
  265. return *c->hpos++;
  266. return '\n';
  267. }