hio.c 7.3 KB

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