hio.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <httpd.h>
  12. static char hstates[] = "nrewE";
  13. static char hxfers[] = " x";
  14. static int _hflush(Hio*, int, int);
  15. int
  16. hinit(Hio *h, int fd, int mode)
  17. {
  18. if(fd == -1 || mode != Hread && mode != Hwrite)
  19. return -1;
  20. h->hh = nil;
  21. h->fd = fd;
  22. h->seek = 0;
  23. h->state = mode;
  24. h->start = h->buf + 16; /* leave space for chunk length */
  25. h->stop = h->pos = h->start;
  26. if(mode == Hread){
  27. h->bodylen = ~0UL;
  28. *h->pos = '\0';
  29. }else
  30. h->stop = h->start + Hsize;
  31. return 0;
  32. }
  33. int
  34. hiserror(Hio *h)
  35. {
  36. return h->state == Herr;
  37. }
  38. int
  39. hgetc(Hio *h)
  40. {
  41. uint8_t *p;
  42. p = h->pos;
  43. if(p < h->stop){
  44. h->pos = p + 1;
  45. return *p;
  46. }
  47. p -= UTFmax;
  48. if(p < h->start)
  49. p = h->start;
  50. if(!hreadbuf(h, p) || h->pos == h->stop)
  51. return -1;
  52. return *h->pos++;
  53. }
  54. int
  55. hungetc(Hio *h)
  56. {
  57. if(h->state == Hend)
  58. h->state = Hread;
  59. else if(h->state == Hread)
  60. h->pos--;
  61. if(h->pos < h->start || h->state != Hread){
  62. h->state = Herr;
  63. h->pos = h->stop;
  64. return -1;
  65. }
  66. return 0;
  67. }
  68. /*
  69. * fill the buffer, saving contents from vsave onwards.
  70. * nothing is saved if vsave is nil.
  71. * returns the beginning of the buffer.
  72. *
  73. * understands message body sizes and chunked transfer encoding
  74. */
  75. void *
  76. hreadbuf(Hio *h, void *vsave)
  77. {
  78. Hio *hh;
  79. uint8_t *save;
  80. int c, in, cpy, dpos;
  81. save = vsave;
  82. if(save && (save < h->start || save > h->stop)
  83. || h->state != Hread && h->state != Hend){
  84. h->state = Herr;
  85. h->pos = h->stop;
  86. return nil;
  87. }
  88. dpos = 0;
  89. if(save && h->pos > save)
  90. dpos = h->pos - save;
  91. cpy = 0;
  92. if(save){
  93. cpy = h->stop - save;
  94. memmove(h->start, save, cpy);
  95. }
  96. h->seek += h->stop - h->start - cpy;
  97. h->pos = h->start + dpos;
  98. in = Hsize - cpy;
  99. if(h->state == Hend)
  100. in = 0;
  101. else if(in > h->bodylen)
  102. in = h->bodylen;
  103. /*
  104. * for chunked encoding, fill buffer,
  105. * then read in new chunk length and wipe out that line
  106. */
  107. hh = h->hh;
  108. if(hh != nil){
  109. if(!in && h->xferenc && h->state != Hend){
  110. if(h->xferenc == 2){
  111. c = hgetc(hh);
  112. if(c == '\r')
  113. c = hgetc(hh);
  114. if(c != '\n'){
  115. h->pos = h->stop;
  116. h->state = Herr;
  117. return nil;
  118. }
  119. }
  120. h->xferenc = 2;
  121. in = 0;
  122. while((c = hgetc(hh)) != '\n'){
  123. if(c >= '0' && c <= '9')
  124. c -= '0';
  125. else if(c >= 'a' && c <= 'f')
  126. c -= 'a' - 10;
  127. else if(c >= 'A' && c <= 'F')
  128. c -= 'A' - 10;
  129. else
  130. break;
  131. in = in * 16 + c;
  132. }
  133. while(c != '\n'){
  134. if(c < 0){
  135. h->pos = h->stop;
  136. h->state = Herr;
  137. return nil;
  138. }
  139. c = hgetc(hh);
  140. }
  141. h->bodylen = in;
  142. in = Hsize - cpy;
  143. if(in > h->bodylen)
  144. in = h->bodylen;
  145. }
  146. if(in){
  147. while(hh->pos + in > hh->stop){
  148. if(hreadbuf(hh, hh->pos) == nil){
  149. h->pos = h->stop;
  150. h->state = Herr;
  151. return nil;
  152. }
  153. }
  154. memmove(h->start + cpy, hh->pos, in);
  155. hh->pos += in;
  156. }
  157. }else if(in){
  158. if((in = read(h->fd, h->start + cpy, in)) < 0){
  159. h->state = Herr;
  160. h->pos = h->stop;
  161. return nil;
  162. }
  163. }
  164. if(in == 0)
  165. h->state = Hend;
  166. h->bodylen -= in;
  167. h->stop = h->start + cpy + in;
  168. *h->stop = '\0';
  169. if(h->pos == h->stop)
  170. return nil;
  171. return h->start;
  172. }
  173. int
  174. hbuflen(Hio *h, void *p)
  175. {
  176. return h->stop - (uint8_t*)p;
  177. }
  178. /*
  179. * prepare to receive a message body
  180. * len is the content length (~0 => unspecified)
  181. * te is the transfer encoding
  182. * returns < 0 if setup failed
  183. */
  184. Hio*
  185. hbodypush(Hio *hh, uint32_t len, HFields *te)
  186. {
  187. Hio *h;
  188. int xe;
  189. if(hh->state != Hread)
  190. return nil;
  191. xe = 0;
  192. if(te != nil){
  193. if(te->params != nil || te->next != nil)
  194. return nil;
  195. if(cistrcmp(te->s, "chunked") == 0){
  196. xe = 1;
  197. len = 0;
  198. }else if(cistrcmp(te->s, "identity") == 0){
  199. ;
  200. }else
  201. return nil;
  202. }
  203. h = malloc(sizeof *h);
  204. if(h == nil)
  205. return nil;
  206. h->hh = hh;
  207. h->fd = -1;
  208. h->seek = 0;
  209. h->state = Hread;
  210. h->xferenc = xe;
  211. h->start = h->buf + 16; /* leave space for chunk length */
  212. h->stop = h->pos = h->start;
  213. *h->pos = '\0';
  214. h->bodylen = len;
  215. return h;
  216. }
  217. /*
  218. * dump the state of the io buffer into a string
  219. */
  220. char *
  221. hunload(Hio *h)
  222. {
  223. uint8_t *p, *t, *stop, *buf;
  224. int ne, n, c;
  225. stop = h->stop;
  226. ne = 0;
  227. for(p = h->pos; p < stop; p++){
  228. c = *p;
  229. if(c == 0x80)
  230. ne++;
  231. }
  232. p = h->pos;
  233. n = (stop - p) + ne + 3;
  234. buf = mallocz(n, 1);
  235. if(buf == nil)
  236. return nil;
  237. buf[0] = hstates[h->state];
  238. buf[1] = hxfers[h->xferenc];
  239. t = &buf[2];
  240. for(; p < stop; p++){
  241. c = *p;
  242. if(c == 0 || c == 0x80){
  243. *t++ = 0x80;
  244. if(c == 0x80)
  245. *t++ = 0x80;
  246. }else
  247. *t++ = c;
  248. }
  249. *t++ = '\0';
  250. if(t != buf + n)
  251. return nil;
  252. return (char*)buf;
  253. }
  254. /*
  255. * read the io buffer state from a string
  256. */
  257. int
  258. hload(Hio *h, char *buf)
  259. {
  260. uint8_t *p, *t, *stop;
  261. char *s;
  262. int c;
  263. s = strchr(hstates, buf[0]);
  264. if(s == nil)
  265. return -1;
  266. h->state = s - hstates;
  267. s = strchr(hxfers, buf[1]);
  268. if(s == nil)
  269. return -1;
  270. h->xferenc = s - hxfers;
  271. t = h->start;
  272. stop = t + Hsize;
  273. for(p = (uint8_t*)&buf[2]; c = *p; p++){
  274. if(c == 0x80){
  275. if(p[1] != 0x80)
  276. c = 0;
  277. else
  278. p++;
  279. }
  280. *t++ = c;
  281. if(t >= stop)
  282. return -1;
  283. }
  284. *t = '\0';
  285. h->pos = h->start;
  286. h->stop = t;
  287. h->seek = 0;
  288. return 0;
  289. }
  290. void
  291. hclose(Hio *h)
  292. {
  293. if(h->fd >= 0){
  294. if(h->state == Hwrite)
  295. hxferenc(h, 0);
  296. close(h->fd);
  297. }
  298. h->stop = h->pos = nil;
  299. h->fd = -1;
  300. }
  301. /*
  302. * flush the buffer and possibly change encoding modes
  303. */
  304. int
  305. hxferenc(Hio *h, int on)
  306. {
  307. if(h->xferenc && !on && h->pos != h->start)
  308. hflush(h);
  309. if(_hflush(h, 1, 0) < 0)
  310. return -1;
  311. h->xferenc = !!on;
  312. return 0;
  313. }
  314. int
  315. hputc(Hio *h, int c)
  316. {
  317. uint8_t *p;
  318. p = h->pos;
  319. if(p < h->stop){
  320. h->pos = p + 1;
  321. return *p = c;
  322. }
  323. if(hflush(h) < 0)
  324. return -1;
  325. return *h->pos++ = c;
  326. }
  327. static int
  328. fmthflush(Fmt *f)
  329. {
  330. Hio *h;
  331. h = f->farg;
  332. h->pos = f->to;
  333. if(hflush(h) < 0)
  334. return 0;
  335. f->stop = h->stop;
  336. f->to = h->pos;
  337. f->start = h->pos;
  338. return 1;
  339. }
  340. int
  341. hvprint(Hio *h, char *fmt, va_list args)
  342. {
  343. int n;
  344. Fmt f;
  345. f.runes = 0;
  346. f.stop = h->stop;
  347. f.to = h->pos;
  348. f.start = h->pos;
  349. f.flush = fmthflush;
  350. f.farg = h;
  351. f.nfmt = 0;
  352. // fmtlocaleinit(&f, nil, nil, nil);
  353. n = fmtvprint(&f, fmt, args);
  354. h->pos = f.to;
  355. return n;
  356. }
  357. int
  358. hprint(Hio *h, char *fmt, ...)
  359. {
  360. int n;
  361. va_list arg;
  362. va_start(arg, fmt);
  363. n = hvprint(h, fmt, arg);
  364. va_end(arg);
  365. return n;
  366. }
  367. static int
  368. _hflush(Hio *h, int force, int dolength)
  369. {
  370. uint8_t *s;
  371. int w;
  372. if(h == nil)
  373. return -1;
  374. if(h->state != Hwrite){
  375. h->state = Herr;
  376. h->stop = h->pos;
  377. return -1;
  378. }
  379. s = h->start;
  380. w = h->pos - s;
  381. if(w == 0 && !force)
  382. return 0;
  383. if(h->xferenc){
  384. *--s = '\n';
  385. *--s = '\r';
  386. do{
  387. *--s = "0123456789abcdef"[w & 0xf];
  388. w >>= 4;
  389. }while(w);
  390. h->pos[0] = '\r';
  391. h->pos[1] = '\n';
  392. w = &h->pos[2] - s;
  393. }
  394. if(dolength)
  395. fprint(h->fd, "Content-Length: %d\r\n\r\n", w);
  396. if(write(h->fd, s, w) != w){
  397. h->state = Herr;
  398. h->stop = h->pos;
  399. return -1;
  400. }
  401. h->seek += w;
  402. h->pos = h->start;
  403. return 0;
  404. }
  405. int
  406. hflush(Hio *h)
  407. {
  408. return _hflush(h, 0, 0);
  409. }
  410. int
  411. hlflush(Hio* h)
  412. {
  413. return _hflush(h, 0, 1);
  414. }
  415. int
  416. hwrite(Hio *h, void *vbuf, int len)
  417. {
  418. uint8_t *buf;
  419. int n, m;
  420. buf = vbuf;
  421. n = len;
  422. if(n < 0 || h->state != Hwrite){
  423. h->state = Herr;
  424. h->stop = h->pos;
  425. return -1;
  426. }
  427. if(h->pos + n >= h->stop){
  428. if(h->start != h->pos)
  429. if(hflush(h) < 0)
  430. return -1;
  431. while(h->pos + n >= h->stop){
  432. m = h->stop - h->pos;
  433. if(h->xferenc){
  434. memmove(h->pos, buf, m);
  435. h->pos += m;
  436. if(hflush(h) < 0)
  437. return -1;
  438. }else{
  439. if(write(h->fd, buf, m) != m){
  440. h->state = Herr;
  441. h->stop = h->pos;
  442. return -1;
  443. }
  444. h->seek += m;
  445. }
  446. n -= m;
  447. buf += m;
  448. }
  449. }
  450. memmove(h->pos, buf, n);
  451. h->pos += n;
  452. return len;
  453. }