http.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include <ip.h>
  5. #include <plumb.h>
  6. #include <thread.h>
  7. #include <fcall.h>
  8. #include <9p.h>
  9. #include "dat.h"
  10. #include "fns.h"
  11. char PostContentType[] = "application/octet-stream";
  12. int httpdebug;
  13. typedef struct HttpState HttpState;
  14. struct HttpState
  15. {
  16. int fd;
  17. Client *c;
  18. char *location;
  19. char *setcookie;
  20. char *netaddr;
  21. Ibuf b;
  22. };
  23. static void
  24. location(HttpState *hs, char *value)
  25. {
  26. if(hs->location == nil)
  27. hs->location = estrdup(value);
  28. }
  29. static void
  30. contenttype(HttpState *hs, char *value)
  31. {
  32. if(hs->c->contenttype == nil)
  33. hs->c->contenttype = estrdup(value);
  34. }
  35. static void
  36. setcookie(HttpState *hs, char *value)
  37. {
  38. char *s, *t;
  39. Fmt f;
  40. s = hs->setcookie;
  41. fmtstrinit(&f);
  42. if(s)
  43. fmtprint(&f, "%s", s);
  44. fmtprint(&f, "set-cookie: ");
  45. fmtprint(&f, "%s", value);
  46. fmtprint(&f, "\n");
  47. t = fmtstrflush(&f);
  48. if(t){
  49. free(s);
  50. hs->setcookie = t;
  51. }
  52. }
  53. struct {
  54. char *name; /* Case-insensitive */
  55. void (*fn)(HttpState *hs, char *value);
  56. } hdrtab[] = {
  57. { "location:", location },
  58. { "content-type:", contenttype },
  59. { "set-cookie:", setcookie },
  60. };
  61. static int
  62. httprcode(HttpState *hs)
  63. {
  64. int n;
  65. char *p;
  66. char buf[256];
  67. n = readline(&hs->b, buf, sizeof(buf)-1);
  68. if(n <= 0)
  69. return n;
  70. if(httpdebug)
  71. fprint(2, "-> %s\n", buf);
  72. p = strchr(buf, ' ');
  73. if(memcmp(buf, "HTTP/", 5) != 0 || p == nil){
  74. werrstr("bad response from server");
  75. return -1;
  76. }
  77. buf[n] = 0;
  78. return atoi(p+1);
  79. }
  80. /*
  81. * read a single mime header, collect continuations.
  82. *
  83. * this routine assumes that there is a blank line twixt
  84. * the header and the message body, otherwise bytes will
  85. * be lost.
  86. */
  87. static int
  88. getheader(HttpState *hs, char *buf, int n)
  89. {
  90. char *p, *e;
  91. int i;
  92. n--;
  93. p = buf;
  94. for(e = p + n; ; p += i){
  95. i = readline(&hs->b, p, e-p);
  96. if(i < 0)
  97. return i;
  98. if(p == buf){
  99. /* first line */
  100. if(strchr(buf, ':') == nil)
  101. break; /* end of headers */
  102. } else {
  103. /* continuation line */
  104. if(*p != ' ' && *p != '\t'){
  105. unreadline(&hs->b, p);
  106. *p = 0;
  107. break; /* end of this header */
  108. }
  109. }
  110. }
  111. if(httpdebug)
  112. fprint(2, "-> %s\n", buf);
  113. return p-buf;
  114. }
  115. static int
  116. httpheaders(HttpState *hs)
  117. {
  118. char buf[2048];
  119. char *p;
  120. int i, n;
  121. for(;;){
  122. n = getheader(hs, buf, sizeof(buf));
  123. if(n < 0)
  124. return -1;
  125. if (n == 0)
  126. return 0;
  127. //print("http header: '%.*s'\n", n, buf);
  128. for(i = 0; i < nelem(hdrtab); i++){
  129. n = strlen(hdrtab[i].name);
  130. if(cistrncmp(buf, hdrtab[i].name, n) == 0){
  131. /* skip field name and leading white */
  132. p = buf + n;
  133. while(*p == ' ' || *p == '\t')
  134. p++;
  135. (*hdrtab[i].fn)(hs, p);
  136. break;
  137. }
  138. }
  139. }
  140. return 0;
  141. }
  142. int
  143. httpopen(Client *c, Url *url)
  144. {
  145. int fd, code, redirect;
  146. char *cookies;
  147. Ioproc *io;
  148. HttpState *hs;
  149. if(httpdebug)
  150. fprint(2, "httpopen\n");
  151. io = c->io;
  152. hs = emalloc(sizeof(*hs));
  153. hs->c = c;
  154. hs->netaddr = estrdup(netmkaddr(url->host, 0, url->scheme));
  155. c->aux = hs;
  156. if(httpdebug)
  157. fprint(2, "dial %s\n", hs->netaddr);
  158. fd = iotlsdial(io, hs->netaddr, 0, 0, 0, url->ischeme==UShttps);
  159. if(fd < 0){
  160. Error:
  161. if(httpdebug)
  162. fprint(2, "iodial: %r\n");
  163. free(hs->netaddr);
  164. free(hs);
  165. close(hs->fd);
  166. hs->fd = -1;
  167. c->aux = nil;
  168. return -1;
  169. }
  170. hs->fd = fd;
  171. if(httpdebug)
  172. fprint(2, "<- %s %s HTTP/1.0\n<- Host: %s\n",
  173. c->havepostbody? "POST": " GET", url->http.page_spec, url->host);
  174. ioprint(io, fd, "%s %s HTTP/1.0\r\nHost: %s\r\n",
  175. c->havepostbody? "POST" : "GET", url->http.page_spec, url->host);
  176. if(httpdebug)
  177. fprint(2, "<- User-Agent: %s\n", c->ctl.useragent);
  178. if(c->ctl.useragent)
  179. ioprint(io, fd, "User-Agent: %s\r\n", c->ctl.useragent);
  180. if(c->ctl.sendcookies){
  181. /* should we use url->page here? sometimes it is nil. */
  182. cookies = httpcookies(url->host, url->http.page_spec, 0);
  183. if(cookies && cookies[0])
  184. ioprint(io, fd, "%s", cookies);
  185. if(httpdebug)
  186. fprint(2, "<- %s", cookies);
  187. free(cookies);
  188. }
  189. if(c->havepostbody){
  190. ioprint(io, fd, "Content-type: %s\r\n", PostContentType);
  191. ioprint(io, fd, "Content-length: %ud\r\n", c->npostbody);
  192. if(httpdebug){
  193. fprint(2, "<- Content-type: %s\n", PostContentType);
  194. fprint(2, "<- Content-length: %ud\n", c->npostbody);
  195. }
  196. }
  197. ioprint(io, fd, "\r\n");
  198. if(c->havepostbody)
  199. if(iowrite(io, fd, c->postbody, c->npostbody) != c->npostbody)
  200. goto Error;
  201. c->havepostbody = 0;
  202. redirect = 0;
  203. initibuf(&hs->b, io, fd);
  204. code = httprcode(hs);
  205. switch(code){
  206. case -1: /* connection timed out */
  207. goto Error;
  208. /*
  209. case Eof:
  210. werrstr("EOF from HTTP server");
  211. goto Error;
  212. */
  213. case 200: /* OK */
  214. case 201: /* Created */
  215. case 202: /* Accepted */
  216. case 204: /* No Content */
  217. #ifdef NOT_DEFINED
  218. if(ofile == nil && r->start != 0)
  219. sysfatal("page changed underfoot");
  220. #endif
  221. break;
  222. case 206: /* Partial Content */
  223. werrstr("Partial Content (206)");
  224. goto Error;
  225. case 301: /* Moved Permanently */
  226. case 302: /* Moved Temporarily */
  227. redirect = 1;
  228. break;
  229. case 304: /* Not Modified */
  230. break;
  231. case 400: /* Bad Request */
  232. werrstr("Bad Request (400)");
  233. goto Error;
  234. case 401: /* Unauthorized */
  235. case 402: /* ??? */
  236. werrstr("Unauthorized (401,402)");
  237. goto Error;
  238. case 403: /* Forbidden */
  239. werrstr("Forbidden by server (403)");
  240. goto Error;
  241. case 404: /* Not Found */
  242. werrstr("Not found on server (404)");
  243. goto Error;
  244. case 500: /* Internal server error */
  245. werrstr("Server choked (500)");
  246. goto Error;
  247. case 501: /* Not implemented */
  248. werrstr("Server can't do it (501)");
  249. goto Error;
  250. case 502: /* Bad gateway */
  251. werrstr("Bad gateway (502)");
  252. goto Error;
  253. case 503: /* Service unavailable */
  254. werrstr("Service unavailable (503)");
  255. goto Error;
  256. default:
  257. /* Bogus: we should treat unknown code XYZ as code X00 */
  258. werrstr("Unknown response code %d", code);
  259. goto Error;
  260. }
  261. if(httpheaders(hs) < 0)
  262. goto Error;
  263. if(c->ctl.acceptcookies && hs->setcookie)
  264. httpsetcookie(hs->setcookie, url->host, url->path);
  265. if(redirect){
  266. if(!hs->location){
  267. werrstr("redirection without Location: header");
  268. return -1;
  269. }
  270. c->redirect = hs->location;
  271. hs->location = nil;
  272. }
  273. return 0;
  274. }
  275. int
  276. httpread(Client *c, Req *r)
  277. {
  278. char *dst;
  279. HttpState *hs;
  280. int n;
  281. long rlen, tot, len;
  282. hs = c->aux;
  283. dst = r->ofcall.data;
  284. len = r->ifcall.count;
  285. tot = 0;
  286. while (tot < len){
  287. rlen = len - tot;
  288. n = readibuf(&hs->b, dst + tot, rlen);
  289. if(n == 0)
  290. break;
  291. else if(n < 0){
  292. if(tot == 0)
  293. return -1;
  294. else
  295. return tot;
  296. }
  297. tot += n;
  298. }
  299. r->ofcall.count = tot;
  300. return 0;
  301. }
  302. void
  303. httpclose(Client *c)
  304. {
  305. HttpState *hs;
  306. hs = c->aux;
  307. if(hs == nil)
  308. return;
  309. ioclose(c->io, hs->fd);
  310. hs->fd = -1;
  311. free(hs->location);
  312. free(hs->setcookie);
  313. free(hs->netaddr);
  314. free(hs);
  315. c->aux = nil;
  316. }