PageRenderTime 51ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/Client/psiclient/3rdParty/polipo/http_parse.c

https://bitbucket.org/psiphon/psiphon-circumvention-system/
C | 1566 lines | 1425 code | 109 blank | 32 comment | 735 complexity | a9958f6367e02178a50d2b3fed569134 MD5 | raw file
Possible License(s): GPL-3.0
  1. /*
  2. Copyright (c) 2003-2006 by Juliusz Chroboczek
  3. Permission is hereby granted, free of charge, to any person obtaining a copy
  4. of this software and associated documentation files (the "Software"), to deal
  5. in the Software without restriction, including without limitation the rights
  6. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. copies of the Software, and to permit persons to whom the Software is
  8. furnished to do so, subject to the following conditions:
  9. The above copyright notice and this permission notice shall be included in
  10. all copies or substantial portions of the Software.
  11. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  17. THE SOFTWARE.
  18. */
  19. #include "polipo.h"
  20. static int getNextWord(const char *buf, int i, int *x_return, int *y_return);
  21. static int getNextToken(const char *buf, int i, int *x_return, int *y_return);
  22. static int getNextTokenInList(const char *buf, int i,
  23. int *x_return, int *y_return,
  24. int *z_return, int *t_return,
  25. int *end_return);
  26. static AtomPtr atomConnection, atomProxyConnection, atomContentLength,
  27. atomHost, atomAcceptRange, atomTE,
  28. atomReferer, atomProxyAuthenticate, atomProxyAuthorization,
  29. atomKeepAlive, atomTrailer, atomUpgrade, atomDate, atomExpires,
  30. atomIfModifiedSince, atomIfUnmodifiedSince, atomIfRange, atomLastModified,
  31. atomIfMatch, atomIfNoneMatch, atomAge, atomTransferEncoding,
  32. atomETag, atomCacheControl, atomPragma, atomContentRange, atomRange,
  33. atomVia, atomVary, atomExpect, atomAuthorization,
  34. atomSetCookie, atomCookie, atomCookie2,
  35. atomXPolipoDate, atomXPolipoAccess, atomXPolipoLocation,
  36. atomXPolipoBodyOffset;
  37. AtomPtr atomContentType, atomContentEncoding;
  38. int censorReferer = 0;
  39. int laxHttpParser = 1;
  40. static AtomListPtr censoredHeaders;
  41. void
  42. preinitHttpParser()
  43. {
  44. CONFIG_VARIABLE_SETTABLE(censorReferer, CONFIG_TRISTATE, configIntSetter,
  45. "Censor referer headers.");
  46. censoredHeaders = makeAtomList(NULL, 0);
  47. if(censoredHeaders == NULL) {
  48. do_log(L_ERROR, "Couldn't allocate censored atoms.\n");
  49. exit(1);
  50. }
  51. CONFIG_VARIABLE(censoredHeaders, CONFIG_ATOM_LIST_LOWER,
  52. "Headers to censor.");
  53. CONFIG_VARIABLE_SETTABLE(laxHttpParser, CONFIG_BOOLEAN, configIntSetter,
  54. "Ignore unknown HTTP headers.");
  55. }
  56. void
  57. initHttpParser()
  58. {
  59. #define A(name, value) name = internAtom(value); if(!name) goto fail;
  60. /* These must be in lower-case */
  61. A(atomConnection, "connection");
  62. A(atomProxyConnection, "proxy-connection");
  63. A(atomContentLength, "content-length");
  64. A(atomHost, "host");
  65. A(atomAcceptRange, "accept-range");
  66. A(atomTE, "te");
  67. A(atomReferer, "referer");
  68. A(atomProxyAuthenticate, "proxy-authenticate");
  69. A(atomProxyAuthorization, "proxy-authorization");
  70. A(atomKeepAlive, "keep-alive");
  71. A(atomTrailer, "trailer");
  72. A(atomUpgrade, "upgrade");
  73. A(atomDate, "date");
  74. A(atomExpires, "expires");
  75. A(atomIfModifiedSince, "if-modified-since");
  76. A(atomIfUnmodifiedSince, "if-unmodified-since");
  77. A(atomIfRange, "if-range");
  78. A(atomLastModified, "last-modified");
  79. A(atomIfMatch, "if-match");
  80. A(atomIfNoneMatch, "if-none-match");
  81. A(atomAge, "age");
  82. A(atomTransferEncoding, "transfer-encoding");
  83. A(atomETag, "etag");
  84. A(atomCacheControl, "cache-control");
  85. A(atomPragma, "pragma");
  86. A(atomContentRange, "content-range");
  87. A(atomRange, "range");
  88. A(atomVia, "via");
  89. A(atomContentType, "content-type");
  90. A(atomContentEncoding, "content-encoding");
  91. A(atomVary, "vary");
  92. A(atomExpect, "expect");
  93. A(atomAuthorization, "authorization");
  94. A(atomSetCookie, "set-cookie");
  95. A(atomCookie, "cookie");
  96. A(atomCookie2, "cookie2");
  97. A(atomXPolipoDate, "x-polipo-date");
  98. A(atomXPolipoAccess, "x-polipo-access");
  99. A(atomXPolipoLocation, "x-polipo-location");
  100. A(atomXPolipoBodyOffset, "x-polipo-body-offset");
  101. #undef A
  102. return;
  103. fail:
  104. do_log(L_ERROR, "Couldn't allocate atom.\n");
  105. exit(1);
  106. }
  107. static int
  108. getNextWord(const char *restrict buf, int i, int *x_return, int *y_return)
  109. {
  110. int x, y;
  111. while(buf[i] == ' ') i++;
  112. if(buf[i] == '\n' || buf[i] == '\r') return -1;
  113. x = i;
  114. while(buf[i] > 32 && buf[i] < 127) i++;
  115. y = i;
  116. *x_return = x;
  117. *y_return = y;
  118. return 0;
  119. }
  120. static int
  121. skipComment(const char *restrict buf, int i)
  122. {
  123. assert(buf[i] == '(');
  124. i++;
  125. while(1) {
  126. if(buf[i] == '\\' && buf[i + 1] == ')') i+=2;
  127. else if(buf[i] == ')') return i + 1;
  128. else if(buf[i] == '\n') {
  129. if(buf[i + 1] == ' ' || buf[i + 1] == '\t')
  130. i += 2;
  131. else
  132. return -1;
  133. } else if(buf[i] == '\r') {
  134. if(buf[i + 1] != '\n') return -1;
  135. if(buf[i + 2] == ' ' || buf[i + 2] == '\t')
  136. i += 3;
  137. else
  138. return -1;
  139. } else {
  140. i++;
  141. }
  142. }
  143. return i;
  144. }
  145. static int
  146. skipWhitespace(const char *restrict buf, int i)
  147. {
  148. while(1) {
  149. if(buf[i] == ' ' || buf[i] == '\t')
  150. i++;
  151. else if(buf[i] == '(') {
  152. i = skipComment(buf, i);
  153. if(i < 0) return -1;
  154. } else if(buf[i] == '\n') {
  155. if(buf[i + 1] == ' ' || buf[i + 1] == '\t')
  156. i += 2;
  157. else
  158. return i;
  159. } else if(buf[i] == '\r' && buf[i + 1] == '\n') {
  160. if(buf[i + 2] == ' ' || buf[i + 2] == '\t')
  161. i += 3;
  162. else
  163. return i;
  164. } else
  165. return i;
  166. }
  167. }
  168. static int
  169. getNextToken(const char *restrict buf, int i, int *x_return, int *y_return)
  170. {
  171. int x, y;
  172. again:
  173. while(buf[i] == ' ' || buf[i] == '\t')
  174. i++;
  175. if(buf[i] == '(') {
  176. i++;
  177. while(buf[i] != ')') {
  178. if(buf[i] == '\n' || buf[i] == '\r')
  179. return -1;
  180. if(buf[i] == '\\' && buf[i + 1] != '\n' && buf[i + 1] != '\r')
  181. buf += 2;
  182. else
  183. buf++;
  184. }
  185. goto again;
  186. }
  187. if(buf[i] == '\n') {
  188. if(buf[i + 1] == ' ' || buf[i + 1] == '\t') {
  189. i += 2;
  190. goto again;
  191. } else {
  192. return -1;
  193. }
  194. }
  195. if(buf[i] == '\r') {
  196. if(buf[i + 1] == '\n' && (buf[i + 2] == ' ' || buf[i + 2] == '\t')) {
  197. i += 3;
  198. goto again;
  199. } else {
  200. return -1;
  201. }
  202. }
  203. x = i;
  204. while(buf[i] > 32 && buf[i] < 127) {
  205. switch(buf[i]) {
  206. case '(': case ')': case '<': case '>': case '@':
  207. case ',': case ';': case ':': case '\\': case '/':
  208. case '[': case ']': case '?': case '=':
  209. case '{': case '}': case ' ': case '\t':
  210. goto out;
  211. default:
  212. i++;
  213. }
  214. }
  215. out:
  216. y = i;
  217. *x_return = x;
  218. *y_return = y;
  219. return y;
  220. }
  221. static int
  222. getNextETag(const char * restrict buf, int i,
  223. int *x_return, int *y_return, int *weak_return)
  224. {
  225. int weak = 0;
  226. int x, y;
  227. while(buf[i] == ' ' || buf[i] == '\t')
  228. i++;
  229. if(buf[i] == 'W' && buf[i + 1] == '/') {
  230. weak = 1;
  231. i += 2;
  232. }
  233. if(buf[i] == '"')
  234. i++;
  235. else
  236. return -1;
  237. x = i;
  238. while(buf[i] != '"') {
  239. if(buf[i] == '\r' && buf[i] == '\n')
  240. return -1;
  241. i++;
  242. }
  243. y = i;
  244. i++;
  245. *x_return = x;
  246. *y_return = y;
  247. *weak_return = weak;
  248. return i;
  249. }
  250. static int
  251. getNextTokenInList(const char *restrict buf, int i,
  252. int *x_return, int *y_return,
  253. int *z_return, int *t_return,
  254. int *end_return)
  255. {
  256. int j, x, y, z = -1, t = -1, end;
  257. j = getNextToken(buf, i, &x, &y);
  258. if(j < 0)
  259. return -1;
  260. while(buf[j] == ' ' || buf[j] == '\t')
  261. j++;
  262. if(buf[j] == '=') {
  263. j++;
  264. while(buf[j] == ' ' || buf[j] == '\t')
  265. j++;
  266. z = j;
  267. while(buf[j] != ',' && buf[j] != '\n' && buf[j] != '\r')
  268. j++;
  269. }
  270. if(buf[j] == '\n' || buf[j] == '\r') {
  271. if(buf[j] == '\r') {
  272. if(buf[j + 1] != '\n')
  273. return -1;
  274. j += 2;
  275. } else
  276. j++;
  277. end = 1;
  278. if(buf[j] == ' ' || buf[j] == '\t') {
  279. while(buf[j] == ' ' || buf[j] == '\t')
  280. j++;
  281. end = 0;
  282. }
  283. } else if(buf[j] == ',') {
  284. j++;
  285. while(buf[j] == ' ' || buf[j] == '\t')
  286. j++;
  287. end = 0;
  288. } else {
  289. return -1;
  290. }
  291. *x_return = x;
  292. *y_return = y;
  293. if(z_return)
  294. *z_return = z;
  295. if(t_return)
  296. *t_return = t;
  297. *end_return = end;
  298. return j;
  299. }
  300. static inline int
  301. token_compare(const char *buf, int start, int end, const char *s)
  302. {
  303. return (strcasecmp_n(s, buf + start, end - start) == 0);
  304. }
  305. static int
  306. skipEol(const char *restrict buf, int i)
  307. {
  308. while(buf[i] == ' ')
  309. i++;
  310. if(buf[i] == '\n')
  311. return i + 1;
  312. else if(buf[i] == '\r') {
  313. if(buf[i + 1] == '\n')
  314. return i + 2;
  315. else
  316. return -1;
  317. } else {
  318. return -1;
  319. }
  320. }
  321. static int
  322. skipToEol(const char *restrict buf, int i, int *start_return)
  323. {
  324. while(buf[i] != '\n' && buf[i] != '\r')
  325. i++;
  326. if(buf[i] == '\n') {
  327. *start_return = i;
  328. return i + 1;
  329. } else if(buf[i] == '\r') {
  330. if(buf[i + 1] == '\n') {
  331. *start_return = i;
  332. return i + 2;
  333. } else {
  334. return -1;
  335. }
  336. }
  337. return -1;
  338. }
  339. static int
  340. getHeaderValue(const char *restrict buf, int start,
  341. int *value_start_return, int *value_end_return)
  342. {
  343. int i, j, k;
  344. while(buf[start] == ' ' || buf[start] == '\t')
  345. start++;
  346. i = start;
  347. again:
  348. j = skipToEol(buf, i, &k);
  349. if(j < 0)
  350. return -1;
  351. if(buf[j] == ' ' || buf[j] == '\t') {
  352. i = j + 1;
  353. goto again;
  354. }
  355. *value_start_return = start;
  356. *value_end_return = k;
  357. return j;
  358. }
  359. int
  360. httpParseClientFirstLine(const char *restrict buf, int offset,
  361. int *method_return,
  362. AtomPtr *url_return,
  363. int *version_return)
  364. {
  365. int i = 0;
  366. int x, y;
  367. int method;
  368. AtomPtr url;
  369. int version = HTTP_UNKNOWN;
  370. int eol;
  371. i = offset;
  372. i = getNextWord(buf, i, &x, &y);
  373. if(i < 0) return -1;
  374. if(y == x + 3 && memcmp(buf + x, "GET", 3) == 0)
  375. method = METHOD_GET;
  376. else if(y == x + 4 && memcmp(buf + x, "HEAD", 4) == 0)
  377. method = METHOD_HEAD;
  378. else if(y == x + 4 && memcmp(buf + x, "POST", 4) == 0)
  379. method = METHOD_POST;
  380. else if(y == x + 3 && memcmp(buf + x, "PUT", 3) == 0)
  381. method = METHOD_PUT;
  382. else if(y == x + 7 && memcmp(buf + x, "CONNECT", 7) == 0)
  383. method = METHOD_CONNECT;
  384. else
  385. method = METHOD_UNKNOWN;
  386. i = getNextWord(buf, y + 1, &x, &y);
  387. if(i < 0) return -1;
  388. url = internAtomN(buf + x, y - x);
  389. i = getNextWord(buf, y + 1, &x, &y);
  390. if(i < 0) {
  391. releaseAtom(url);
  392. return -1;
  393. }
  394. if(y == x + 8) {
  395. if(memcmp(buf + x, "HTTP/1.", 7) != 0)
  396. version = HTTP_UNKNOWN;
  397. else if(buf[x + 7] == '0')
  398. version = HTTP_10;
  399. else if(buf[x + 7] >= '1' && buf[x + 7] <= '9')
  400. version = HTTP_11;
  401. else
  402. version = HTTP_UNKNOWN;
  403. }
  404. eol = skipEol(buf, y);
  405. if(eol < 0) return -1;
  406. *method_return = method;
  407. if(url_return)
  408. *url_return = url;
  409. else
  410. releaseAtom(url);
  411. *version_return = version;
  412. return eol;
  413. }
  414. int
  415. httpParseServerFirstLine(const char *restrict buf,
  416. int *status_return,
  417. int *version_return,
  418. AtomPtr *message_return)
  419. {
  420. int i = 0;
  421. int x, y, eol;
  422. int status;
  423. int version = HTTP_UNKNOWN;
  424. i = getNextWord(buf, 0, &x, &y);
  425. if(i < 0)
  426. return -1;
  427. if(y == x + 8 && memcmp(buf + x, "HTTP/1.0", 8) == 0)
  428. version = HTTP_10;
  429. else if(y >= x + 8 && memcmp(buf + x, "HTTP/1.", 7) == 0)
  430. version = HTTP_11;
  431. else
  432. version = HTTP_UNKNOWN;
  433. i = getNextWord(buf, y + 1, &x, &y);
  434. if(i < 0) return -1;
  435. if(y == x + 3)
  436. status = atol(buf + x);
  437. else return -1;
  438. i = skipToEol(buf, y, &eol);
  439. if(i < 0) return -1;
  440. *status_return = status;
  441. *version_return = version;
  442. if(message_return) {
  443. /* Netscape enterprise bug */
  444. if(eol > y)
  445. *message_return = internAtomN(buf + y + 1, eol - y - 1);
  446. else
  447. *message_return = internAtom("No message");
  448. }
  449. return i;
  450. }
  451. static int
  452. parseInt(const char *restrict buf, int start, int *val_return)
  453. {
  454. int i = start, val = 0;
  455. if(!digit(buf[i]))
  456. return -1;
  457. while(digit(buf[i])) {
  458. val = val * 10 + (buf[i] - '0');
  459. i++;
  460. }
  461. *val_return = val;
  462. return i;
  463. }
  464. /* Returned *name_start_return is -1 at end of headers, -2 if the line
  465. couldn't be parsed. */
  466. static int
  467. parseHeaderLine(const char *restrict buf, int start,
  468. int *name_start_return, int *name_end_return,
  469. int *value_start_return, int *value_end_return)
  470. {
  471. int i;
  472. int name_start, name_end, value_start, value_end;
  473. if(buf[start] == '\n') {
  474. *name_start_return = -1;
  475. return start + 1;
  476. }
  477. if(buf[start] == '\r' && buf[start + 1] == '\n') {
  478. *name_start_return = -1;
  479. return start + 2;
  480. }
  481. i = getNextToken(buf, start, &name_start, &name_end);
  482. if(i < 0 || buf[i] != ':')
  483. goto syntax;
  484. i++;
  485. while(buf[i] == ' ' || buf[i] == '\t')
  486. i++;
  487. i = getHeaderValue(buf, i, &value_start, &value_end);
  488. if(i < 0)
  489. goto syntax;
  490. *name_start_return = name_start;
  491. *name_end_return = name_end;
  492. *value_start_return = value_start;
  493. *value_end_return = value_end;
  494. return i;
  495. syntax:
  496. i = start;
  497. while(1) {
  498. if(buf[i] == '\n') {
  499. i++;
  500. break;
  501. }
  502. if(buf[i] == '\r' && buf[i + 1] == '\n') {
  503. i += 2;
  504. break;
  505. }
  506. i++;
  507. }
  508. *name_start_return = -2;
  509. return i;
  510. }
  511. int
  512. findEndOfHeaders(const char *restrict buf, int from, int to, int *body_return)
  513. {
  514. int i = from;
  515. int eol = 0;
  516. while(i < to) {
  517. if(buf[i] == '\n') {
  518. if(eol) {
  519. *body_return = i + 1;
  520. return eol;
  521. }
  522. eol = i;
  523. i++;
  524. } else if(buf[i] == '\r') {
  525. if(i < to - 1 && buf[i + 1] == '\n') {
  526. if(eol) {
  527. *body_return = eol;
  528. return i + 2;
  529. }
  530. eol = i;
  531. i += 2;
  532. } else {
  533. eol = 0;
  534. i++;
  535. }
  536. } else {
  537. eol = 0;
  538. i++;
  539. }
  540. }
  541. return -1;
  542. }
  543. static int
  544. parseContentRange(const char *restrict buf, int i,
  545. int *from_return, int *to_return, int *full_len_return)
  546. {
  547. int j;
  548. int from, to, full_len;
  549. i = skipWhitespace(buf, i);
  550. if(i < 0) return -1;
  551. if(!token_compare(buf, i, i + 5, "bytes"))
  552. return -1;
  553. i += 5;
  554. i = skipWhitespace(buf, i);
  555. if(buf[i] == '*') {
  556. from = 0;
  557. to = -1;
  558. i++;
  559. } else {
  560. i = parseInt(buf, i, &from);
  561. if(i < 0) return -1;
  562. if(buf[i] != '-') return -1;
  563. i++;
  564. i = parseInt(buf, i, &to);
  565. if(i < 0) return -1;
  566. to = to + 1;
  567. }
  568. if(buf[i] != '/')
  569. return -1;
  570. i++;
  571. if(buf[i] == '*')
  572. full_len = -1;
  573. else {
  574. i = parseInt(buf, i, &full_len);
  575. if(i < 0) return -1;
  576. }
  577. j = skipEol(buf, i);
  578. if(j < 0)
  579. return -1;
  580. *from_return = from;
  581. *to_return = to;
  582. *full_len_return = full_len;
  583. return i;
  584. }
  585. static int
  586. parseRange(const char *restrict buf, int i,
  587. int *from_return, int *to_return)
  588. {
  589. int j;
  590. int from, to;
  591. i = skipWhitespace(buf, i);
  592. if(i < 0)
  593. return -1;
  594. if(!token_compare(buf, i, i + 6, "bytes="))
  595. return -1;
  596. i += 6;
  597. i = skipWhitespace(buf, i);
  598. if(buf[i] == '-') {
  599. from = 0;
  600. } else {
  601. i = parseInt(buf, i, &from);
  602. if(i < 0) return -1;
  603. }
  604. if(buf[i] != '-')
  605. return -1;
  606. i++;
  607. j = parseInt(buf, i, &to);
  608. if(j < 0)
  609. to = -1;
  610. else {
  611. to = to + 1;
  612. i = j;
  613. }
  614. j = skipEol(buf, i);
  615. if(j < 0) return -1;
  616. *from_return = from;
  617. *to_return = to;
  618. return i;
  619. }
  620. static int
  621. urlSameHost(const char *url1, int len1, const char *url2, int len2)
  622. {
  623. int i;
  624. if(len1 < 7 || len2 < 7)
  625. return 0;
  626. if(memcmp(url1 + 4, "://", 3) != 0 || memcmp(url2 + 4, "://", 3) != 0)
  627. return 0;
  628. i = 7;
  629. while(i < len1 && i < len2 && url1[i] != '/' && url2[i] != '/') {
  630. if((url1[i] | 0x20) != (url2[i] | 0x20))
  631. break;
  632. i++;
  633. }
  634. if((i == len1 || url1[i] == '/') && ((i == len2 || url2[i] == '/')))
  635. return 1;
  636. return 0;
  637. }
  638. static char *
  639. resize_hbuf(char *hbuf, int *size, char *hbuf_small)
  640. {
  641. int new_size = 2 * *size;
  642. char *new_hbuf;
  643. if(new_size <= *size)
  644. goto fail;
  645. if(hbuf == hbuf_small) {
  646. new_hbuf = malloc(new_size);
  647. if(new_hbuf == NULL) goto fail;
  648. memcpy(new_hbuf, hbuf, *size);
  649. } else {
  650. new_hbuf = realloc(hbuf, new_size);
  651. if(new_hbuf == NULL) goto fail;
  652. }
  653. *size = new_size;
  654. return new_hbuf;
  655. fail:
  656. if(hbuf != hbuf_small)
  657. free(hbuf);
  658. *size = 0;
  659. return NULL;
  660. }
  661. int
  662. httpParseHeaders(int client, AtomPtr url,
  663. const char *buf, int start, HTTPRequestPtr request,
  664. AtomPtr *headers_return,
  665. int *len_return, CacheControlPtr cache_control_return,
  666. HTTPConditionPtr *condition_return, int *te_return,
  667. time_t *date_return, time_t *last_modified_return,
  668. time_t *expires_return, time_t *polipo_age_return,
  669. time_t *polipo_access_return, int *polipo_body_offset_return,
  670. int *age_return, char **etag_return, AtomPtr *expect_return,
  671. HTTPRangePtr range_return, HTTPRangePtr content_range_return,
  672. char **location_return, AtomPtr *via_return,
  673. AtomPtr *auth_return)
  674. {
  675. int local = url ? urlIsLocal(url->string, url->length) : 0;
  676. char hbuf_small[512];
  677. char *hbuf = hbuf_small;
  678. int hbuf_size = 512, hbuf_length = 0;
  679. int i, j,
  680. name_start, name_end, value_start, value_end,
  681. token_start, token_end, end;
  682. AtomPtr name = NULL;
  683. time_t date = -1, last_modified = -1, expires = -1, polipo_age = -1,
  684. polipo_access = -1, polipo_body_offset = -1;
  685. int len = -1;
  686. CacheControlRec cache_control;
  687. char *endptr;
  688. int te = TE_IDENTITY;
  689. int age = -1;
  690. char *etag = NULL, *ifrange = NULL;
  691. int persistent = (!request || (request->connection->version != HTTP_10));
  692. char *location = NULL;
  693. AtomPtr via = NULL;
  694. AtomPtr auth = NULL;
  695. AtomPtr expect = NULL;
  696. HTTPConditionPtr condition;
  697. time_t ims = -1, inms = -1;
  698. char *im = NULL, *inm = NULL;
  699. AtomListPtr hopToHop = NULL;
  700. HTTPRangeRec range = {-1, -1, -1}, content_range = {-1, -1, -1};
  701. int haveCacheControl = 0;
  702. #define RESIZE_HBUF() \
  703. do { \
  704. hbuf = resize_hbuf(hbuf, &hbuf_size, hbuf_small); \
  705. if(hbuf == NULL) \
  706. goto fail; \
  707. } while(0)
  708. cache_control.flags = 0;
  709. cache_control.max_age = -1;
  710. cache_control.s_maxage = -1;
  711. cache_control.min_fresh = -1;
  712. cache_control.max_stale = -1;
  713. i = start;
  714. while(1) {
  715. i = parseHeaderLine(buf, i,
  716. &name_start, &name_end, &value_start, &value_end);
  717. if(i < 0) {
  718. do_log(L_ERROR, "Couldn't find end of header line.\n");
  719. goto fail;
  720. }
  721. if(name_start == -1)
  722. break;
  723. if(name_start < 0)
  724. continue;
  725. name = internAtomLowerN(buf + name_start, name_end - name_start);
  726. if(name == atomConnection) {
  727. j = getNextTokenInList(buf, value_start,
  728. &token_start, &token_end, NULL, NULL,
  729. &end);
  730. while(1) {
  731. if(j < 0) {
  732. do_log(L_ERROR, "Couldn't parse Connection: ");
  733. do_log_n(L_ERROR, buf + value_start,
  734. value_end - value_start);
  735. do_log(L_ERROR, ".\n");
  736. goto fail;
  737. }
  738. if(token_compare(buf, token_start, token_end, "close")) {
  739. persistent = 0;
  740. } else if(token_compare(buf, token_start, token_end,
  741. "keep-alive")) {
  742. persistent = 1;
  743. } else {
  744. if(hopToHop == NULL)
  745. hopToHop = makeAtomList(NULL, 0);
  746. if(hopToHop == NULL) {
  747. do_log(L_ERROR, "Couldn't allocate atom list.\n");
  748. goto fail;
  749. }
  750. atomListCons(internAtomLowerN(buf + token_start,
  751. token_end - token_start),
  752. hopToHop);
  753. }
  754. if(end)
  755. break;
  756. j = getNextTokenInList(buf, j,
  757. &token_start, &token_end, NULL, NULL,
  758. &end);
  759. }
  760. } else if(name == atomCacheControl)
  761. haveCacheControl = 1;
  762. releaseAtom(name);
  763. name = NULL;
  764. }
  765. i = start;
  766. while(1) {
  767. i = parseHeaderLine(buf, i,
  768. &name_start, &name_end, &value_start, &value_end);
  769. if(i < 0) {
  770. do_log(L_ERROR, "Couldn't find end of header line.\n");
  771. goto fail;
  772. }
  773. if(name_start == -1)
  774. break;
  775. if(name_start < 0) {
  776. do_log(L_WARN, "Couldn't parse header line.\n");
  777. if(laxHttpParser)
  778. continue;
  779. else
  780. goto fail;
  781. }
  782. name = internAtomLowerN(buf + name_start, name_end - name_start);
  783. if(name == atomProxyConnection) {
  784. j = getNextTokenInList(buf, value_start,
  785. &token_start, &token_end, NULL, NULL,
  786. &end);
  787. while(1) {
  788. if(j < 0) {
  789. do_log(L_WARN, "Couldn't parse Proxy-Connection:");
  790. do_log_n(L_WARN, buf + value_start,
  791. value_end - value_start);
  792. do_log(L_WARN, ".\n");
  793. persistent = 0;
  794. break;
  795. }
  796. if(token_compare(buf, token_start, token_end, "close")) {
  797. persistent = 0;
  798. } else if(token_compare(buf, token_start, token_end,
  799. "keep-alive")) {
  800. persistent = 1;
  801. }
  802. if(end)
  803. break;
  804. j = getNextTokenInList(buf, j,
  805. &token_start, &token_end, NULL, NULL,
  806. &end);
  807. }
  808. } else if(name == atomContentLength) {
  809. j = skipWhitespace(buf, value_start);
  810. if(j < 0) {
  811. do_log(L_WARN, "Couldn't parse Content-Length: \n");
  812. do_log_n(L_WARN, buf + value_start, value_end - value_start);
  813. do_log(L_WARN, ".\n");
  814. len = -1;
  815. } else {
  816. len = strtol(buf + value_start, &endptr, 10);
  817. if(endptr <= buf + value_start) {
  818. do_log(L_WARN, "Couldn't parse Content-Length: \n");
  819. do_log_n(L_WARN, buf + value_start,
  820. value_end - value_start);
  821. do_log(L_WARN, ".\n");
  822. len = -1;
  823. }
  824. }
  825. } else if((!local && name == atomProxyAuthorization) ||
  826. (local && name == atomAuthorization)) {
  827. if(auth_return) {
  828. auth = internAtomN(buf + value_start, value_end - value_start);
  829. if(auth == NULL) {
  830. do_log(L_ERROR, "Couldn't allocate authorization.\n");
  831. goto fail;
  832. }
  833. }
  834. } else if(name == atomReferer) {
  835. int h;
  836. if(censorReferer == 0 ||
  837. (censorReferer == 1 && url != NULL &&
  838. urlSameHost(url->string, url->length,
  839. buf + value_start, value_end - value_start))) {
  840. while(hbuf_length > hbuf_size - 2)
  841. RESIZE_HBUF();
  842. hbuf[hbuf_length++] = '\r';
  843. hbuf[hbuf_length++] = '\n';
  844. do {
  845. h = snnprint_n(hbuf, hbuf_length, hbuf_size,
  846. buf + name_start, value_end - name_start);
  847. if(h < 0) RESIZE_HBUF();
  848. } while(h < 0);
  849. hbuf_length = h;
  850. }
  851. } else if(name == atomTrailer || name == atomUpgrade) {
  852. do_log(L_ERROR, "Trailers or upgrade present.\n");
  853. goto fail;
  854. } else if(name == atomDate || name == atomExpires ||
  855. name == atomIfModifiedSince ||
  856. name == atomIfUnmodifiedSince ||
  857. name == atomLastModified ||
  858. name == atomXPolipoDate || name == atomXPolipoAccess) {
  859. time_t t;
  860. j = parse_time(buf, value_start, value_end, &t);
  861. if(j < 0) {
  862. if(name != atomExpires) {
  863. do_log(L_WARN, "Couldn't parse %s: ", name->string);
  864. do_log_n(L_WARN, buf + value_start,
  865. value_end - value_start);
  866. do_log(L_WARN, "\n");
  867. }
  868. t = -1;
  869. }
  870. if(name == atomDate) {
  871. if(t >= 0)
  872. date = t;
  873. } else if(name == atomExpires) {
  874. if(t >= 0)
  875. expires = t;
  876. else
  877. expires = 0;
  878. } else if(name == atomLastModified)
  879. last_modified = t;
  880. else if(name == atomIfModifiedSince)
  881. ims = t;
  882. else if(name == atomIfUnmodifiedSince)
  883. inms = t;
  884. else if(name == atomXPolipoDate)
  885. polipo_age = t;
  886. else if(name == atomXPolipoAccess)
  887. polipo_access = t;
  888. } else if(name == atomAge) {
  889. j = skipWhitespace(buf, value_start);
  890. if(j < 0) {
  891. age = -1;
  892. } else {
  893. age = strtol(buf + value_start, &endptr, 10);
  894. if(endptr <= buf + value_start)
  895. age = -1;
  896. }
  897. if(age < 0) {
  898. do_log(L_WARN, "Couldn't parse age: \n");
  899. do_log_n(L_WARN, buf + value_start, value_end - value_start);
  900. do_log(L_WARN, " -- ignored.\n");
  901. }
  902. } else if(name == atomXPolipoBodyOffset) {
  903. j = skipWhitespace(buf, value_start);
  904. if(j < 0) {
  905. do_log(L_ERROR, "Couldn't parse body offset.\n");
  906. goto fail;
  907. } else {
  908. polipo_body_offset = strtol(buf + value_start, &endptr, 10);
  909. if(endptr <= buf + value_start) {
  910. do_log(L_ERROR, "Couldn't parse body offset.\n");
  911. goto fail;
  912. }
  913. }
  914. } else if(name == atomTransferEncoding) {
  915. if(token_compare(buf, value_start, value_end, "identity"))
  916. te = TE_IDENTITY;
  917. else if(token_compare(buf, value_start, value_end, "chunked"))
  918. te = TE_CHUNKED;
  919. else
  920. te = TE_UNKNOWN;
  921. } else if(name == atomETag ||
  922. name == atomIfNoneMatch || name == atomIfMatch ||
  923. name == atomIfRange) {
  924. int x, y;
  925. int weak;
  926. char *e;
  927. j = getNextETag(buf, value_start, &x, &y, &weak);
  928. if(j < 0) {
  929. if(buf[value_start] != '\r' && buf[value_start] != '\n')
  930. do_log(L_ERROR, "Couldn't parse ETag.\n");
  931. } else if(weak) {
  932. do_log(L_WARN, "Server returned weak ETag -- ignored.\n");
  933. } else {
  934. e = strdup_n(buf + x, y - x);
  935. if(e == NULL) goto fail;
  936. if(name == atomETag) {
  937. if(!etag)
  938. etag = e;
  939. else
  940. free(e);
  941. } else if(name == atomIfNoneMatch) {
  942. if(!inm)
  943. inm = e;
  944. else
  945. free(e);
  946. } else if(name == atomIfMatch) {
  947. if(!im)
  948. im = e;
  949. else
  950. free(e);
  951. } else if(name == atomIfRange) {
  952. if(!ifrange)
  953. ifrange = e;
  954. else
  955. free(e);
  956. } else {
  957. abort();
  958. }
  959. }
  960. } else if(name == atomCacheControl) {
  961. int v_start, v_end;
  962. j = getNextTokenInList(buf, value_start,
  963. &token_start, &token_end,
  964. &v_start, &v_end,
  965. &end);
  966. while(1) {
  967. if(j < 0) {
  968. do_log(L_WARN, "Couldn't parse Cache-Control.\n");
  969. cache_control.flags |= CACHE_NO;
  970. break;
  971. }
  972. if(token_compare(buf, token_start, token_end, "no-cache")) {
  973. cache_control.flags |= CACHE_NO;
  974. } else if(token_compare(buf, token_start, token_end,
  975. "public")) {
  976. cache_control.flags |= CACHE_PUBLIC;
  977. } else if(token_compare(buf, token_start, token_end,
  978. "private")) {
  979. cache_control.flags |= CACHE_PRIVATE;
  980. } else if(token_compare(buf, token_start, token_end,
  981. "no-store")) {
  982. cache_control.flags |= CACHE_NO_STORE;
  983. } else if(token_compare(buf, token_start, token_end,
  984. "no-transform")) {
  985. cache_control.flags |= CACHE_NO_TRANSFORM;
  986. } else if(token_compare(buf, token_start, token_end,
  987. "must-revalidate") ||
  988. token_compare(buf, token_start, token_end,
  989. "must-validate")) { /* losers */
  990. cache_control.flags |= CACHE_MUST_REVALIDATE;
  991. } else if(token_compare(buf, token_start, token_end,
  992. "proxy-revalidate")) {
  993. cache_control.flags |= CACHE_PROXY_REVALIDATE;
  994. } else if(token_compare(buf, token_start, token_end,
  995. "only-if-cached")) {
  996. cache_control.flags |= CACHE_ONLY_IF_CACHED;
  997. } else if(token_compare(buf, token_start, token_end,
  998. "max-age") ||
  999. token_compare(buf, token_start, token_end,
  1000. "maxage")) { /* losers */
  1001. int a;
  1002. if(v_start <= 0 || !digit(buf[v_start])) {
  1003. do_log(L_WARN, "Couldn't parse Cache-Control: ");
  1004. do_log_n(L_WARN, buf + token_start,
  1005. (v_end >= 0 ? v_end : token_end) -
  1006. token_start);
  1007. do_log(L_WARN, "\n");
  1008. } else {
  1009. a = atoi(buf + v_start);
  1010. cache_control.max_age = a;
  1011. }
  1012. } else if(token_compare(buf, token_start, token_end,
  1013. "s-maxage")) {
  1014. int a;
  1015. if(v_start <= 0 || !digit(buf[v_start])) {
  1016. do_log(L_WARN, "Couldn't parse Cache-Control: ");
  1017. do_log_n(L_WARN, buf + token_start,
  1018. (v_end >= 0 ? v_end : token_end) -
  1019. token_start);
  1020. do_log(L_WARN, "\n");
  1021. } else {
  1022. a = atoi(buf + v_start);
  1023. cache_control.max_age = a;
  1024. }
  1025. } else if(token_compare(buf, token_start, token_end,
  1026. "min-fresh")) {
  1027. int a;
  1028. if(v_start <= 0 || !digit(buf[v_start])) {
  1029. do_log(L_WARN, "Couldn't parse Cache-Control: ");
  1030. do_log_n(L_WARN, buf + token_start,
  1031. (v_end >= 0 ? v_end : token_end) -
  1032. token_start);
  1033. do_log(L_WARN, "\n");
  1034. } else {
  1035. a = atoi(buf + v_start);
  1036. cache_control.max_age = a;
  1037. }
  1038. } else if(token_compare(buf, token_start, token_end,
  1039. "max-stale")) {
  1040. int a;
  1041. if(v_start <= 0 || !digit(buf[v_start])) {
  1042. do_log(L_WARN, "Couldn't parse Cache-Control: ");
  1043. do_log_n(L_WARN, buf + token_start,
  1044. (v_end >= 0 ? v_end : token_end) -
  1045. token_start);
  1046. do_log(L_WARN, "\n");
  1047. } else {
  1048. a = atoi(buf + v_start);
  1049. cache_control.max_stale = a;
  1050. }
  1051. } else {
  1052. do_log(L_WARN, "Unsupported Cache-Control directive ");
  1053. do_log_n(L_WARN, buf + token_start,
  1054. (v_end >= 0 ? v_end : token_end) - token_start);
  1055. do_log(L_WARN, " -- ignored.\n");
  1056. }
  1057. if(end)
  1058. break;
  1059. j = getNextTokenInList(buf, j,
  1060. &token_start, &token_end,
  1061. &v_start, &v_end,
  1062. &end);
  1063. }
  1064. } else if(name == atomContentRange) {
  1065. if(!client) {
  1066. j = parseContentRange(buf, value_start,
  1067. &content_range.from, &content_range.to,
  1068. &content_range.full_length);
  1069. if(j < 0) {
  1070. do_log(L_ERROR, "Couldn't parse Content-Range: ");
  1071. do_log_n(L_ERROR, buf + value_start,
  1072. value_end - value_start);
  1073. do_log(L_ERROR, "\n");
  1074. goto fail;
  1075. }
  1076. } else {
  1077. do_log(L_ERROR, "Content-Range from client.\n");
  1078. goto fail;
  1079. }
  1080. } else if(name == atomRange) {
  1081. if(client) {
  1082. j = parseRange(buf, value_start, &range.from, &range.to);
  1083. if(j < 0) {
  1084. do_log(L_WARN, "Couldn't parse Range -- ignored.\n");
  1085. range.from = -1;
  1086. range.to = -1;
  1087. }
  1088. } else {
  1089. do_log(L_WARN, "Range from server -- ignored\n");
  1090. }
  1091. } else if(name == atomXPolipoLocation) {
  1092. if(location_return) {
  1093. location =
  1094. strdup_n(buf + value_start, value_end - value_start);
  1095. if(location == NULL) {
  1096. do_log(L_ERROR, "Couldn't allocate location.\n");
  1097. goto fail;
  1098. }
  1099. }
  1100. } else if(name == atomVia) {
  1101. if(via_return) {
  1102. AtomPtr new_via, full_via;
  1103. new_via =
  1104. internAtomN(buf + value_start, value_end - value_start);
  1105. if(new_via == NULL) {
  1106. do_log(L_ERROR, "Couldn't allocate via.\n");
  1107. goto fail;
  1108. }
  1109. if(via) {
  1110. full_via =
  1111. internAtomF("%s, %s", via->string, new_via->string);
  1112. releaseAtom(new_via);
  1113. if(full_via == NULL) {
  1114. do_log(L_ERROR, "Couldn't allocate via");
  1115. goto fail;
  1116. }
  1117. releaseAtom(via);
  1118. via = full_via;
  1119. } else {
  1120. via = new_via;
  1121. }
  1122. }
  1123. } else if(name == atomExpect) {
  1124. if(expect_return) {
  1125. expect = internAtomLowerN(buf + value_start,
  1126. value_end - value_start);
  1127. if(expect == NULL) {
  1128. do_log(L_ERROR, "Couldn't allocate expect.\n");
  1129. goto fail;
  1130. }
  1131. }
  1132. } else {
  1133. if(!client && name == atomContentType) {
  1134. if(token_compare(buf, value_start, value_end,
  1135. "multipart/byteranges")) {
  1136. do_log(L_ERROR,
  1137. "Server returned multipart/byteranges -- yuck!\n");
  1138. goto fail;
  1139. }
  1140. }
  1141. if(name == atomVary) {
  1142. if(!token_compare(buf, value_start, value_end, "host") &&
  1143. !token_compare(buf, value_start, value_end, "*")) {
  1144. /* What other vary headers should be ignored? */
  1145. do_log(L_VARY, "Vary header present (");
  1146. do_log_n(L_VARY,
  1147. buf + value_start, value_end - value_start);
  1148. do_log(L_VARY, ").\n");
  1149. }
  1150. cache_control.flags |= CACHE_VARY;
  1151. } else if(name == atomAuthorization) {
  1152. cache_control.flags |= CACHE_AUTHORIZATION;
  1153. }
  1154. if(name == atomPragma) {
  1155. /* Pragma is only defined for the client, and the only
  1156. standard value is no-cache (RFC 1945, 10.12).
  1157. However, we honour a Pragma: no-cache for both the client
  1158. and the server when there's no Cache-Control header. In
  1159. all cases, we pass the Pragma header to the next hop. */
  1160. if(!haveCacheControl) {
  1161. j = getNextTokenInList(buf, value_start,
  1162. &token_start, &token_end, NULL, NULL,
  1163. &end);
  1164. while(1) {
  1165. if(j < 0) {
  1166. do_log(L_WARN, "Couldn't parse Pragma.\n");
  1167. cache_control.flags |= CACHE_NO;
  1168. break;
  1169. }
  1170. if(token_compare(buf, token_start, token_end,
  1171. "no-cache"))
  1172. cache_control.flags = CACHE_NO;
  1173. if(end)
  1174. break;
  1175. j = getNextTokenInList(buf, j, &token_start, &token_end,
  1176. NULL, NULL, &end);
  1177. }
  1178. }
  1179. }
  1180. if(!client &&
  1181. (name == atomSetCookie ||
  1182. name == atomCookie || name == atomCookie2))
  1183. cache_control.flags |= CACHE_COOKIE;
  1184. if(hbuf) {
  1185. if(name != atomConnection && name != atomHost &&
  1186. name != atomAcceptRange && name != atomTE &&
  1187. name != atomProxyAuthenticate &&
  1188. name != atomKeepAlive &&
  1189. (!hopToHop || !atomListMember(name, hopToHop)) &&
  1190. !atomListMember(name, censoredHeaders)) {
  1191. int h;
  1192. while(hbuf_length > hbuf_size - 2)
  1193. RESIZE_HBUF();
  1194. hbuf[hbuf_length++] = '\r';
  1195. hbuf[hbuf_length++] = '\n';
  1196. do {
  1197. h = snnprint_n(hbuf, hbuf_length, hbuf_size,
  1198. buf + name_start,
  1199. value_end - name_start);
  1200. if(h < 0) RESIZE_HBUF();
  1201. } while(h < 0);
  1202. hbuf_length = h;
  1203. }
  1204. }
  1205. }
  1206. releaseAtom(name);
  1207. name = NULL;
  1208. }
  1209. if(headers_return) {
  1210. AtomPtr pheaders = NULL;
  1211. pheaders = internAtomN(hbuf, hbuf_length);
  1212. if(!pheaders)
  1213. goto fail;
  1214. *headers_return = pheaders;
  1215. }
  1216. if(hbuf != hbuf_small)
  1217. free(hbuf);
  1218. hbuf = NULL;
  1219. hbuf_size = 0;
  1220. if(request)
  1221. if(!persistent)
  1222. request->flags &= ~REQUEST_PERSISTENT;
  1223. if(te != TE_IDENTITY) len = -1;
  1224. if(len_return) *len_return = len;
  1225. if(cache_control_return) *cache_control_return = cache_control;
  1226. if(condition_return) {
  1227. if(ims >= 0 || inms >= 0 || im || inm || ifrange) {
  1228. condition = httpMakeCondition();
  1229. if(condition) {
  1230. condition->ims = ims;
  1231. condition->inms = inms;
  1232. condition->im = im;
  1233. condition->inm = inm;
  1234. condition->ifrange = ifrange;
  1235. } else {
  1236. do_log(L_ERROR, "Couldn't allocate condition.\n");
  1237. if(im) free(im);
  1238. if(inm) free(inm);
  1239. }
  1240. } else {
  1241. condition = NULL;
  1242. }
  1243. *condition_return = condition;
  1244. } else {
  1245. assert(!im && !inm);
  1246. }
  1247. if(te_return) *te_return = te;
  1248. if(date_return) *date_return = date;
  1249. if(last_modified_return) *last_modified_return = last_modified;
  1250. if(expires_return) *expires_return = expires;
  1251. if(polipo_age_return) *polipo_age_return = polipo_age;
  1252. if(polipo_access_return) *polipo_access_return = polipo_access;
  1253. if(polipo_body_offset_return)
  1254. *polipo_body_offset_return = polipo_body_offset;
  1255. if(age_return) *age_return = age;
  1256. if(etag_return)
  1257. *etag_return = etag;
  1258. else {
  1259. if(etag) free(etag);
  1260. }
  1261. if(range_return) *range_return = range;
  1262. if(content_range_return) *content_range_return = content_range;
  1263. if(location_return) {
  1264. *location_return = location;
  1265. } else {
  1266. if(location)
  1267. free(location);
  1268. }
  1269. if(via_return)
  1270. *via_return = via;
  1271. else {
  1272. if(via)
  1273. releaseAtom(via);
  1274. }
  1275. if(expect_return)
  1276. *expect_return = expect;
  1277. else {
  1278. if(expect)
  1279. releaseAtom(expect);
  1280. }
  1281. if(auth_return)
  1282. *auth_return = auth;
  1283. else {
  1284. if(auth)
  1285. releaseAtom(auth);
  1286. }
  1287. if(hopToHop) destroyAtomList(hopToHop);
  1288. return i;
  1289. fail:
  1290. if(hbuf && hbuf != hbuf_small) free(hbuf);
  1291. if(name) releaseAtom(name);
  1292. if(etag) free(etag);
  1293. if(location) free(location);
  1294. if(via) releaseAtom(via);
  1295. if(expect) releaseAtom(expect);
  1296. if(auth) releaseAtom(auth);
  1297. if(hopToHop) destroyAtomList(hopToHop);
  1298. return -1;
  1299. #undef RESIZE_HBUF
  1300. }
  1301. int
  1302. httpFindHeader(AtomPtr header, const char *headers, int hlen,
  1303. int *value_begin_return, int *value_end_return)
  1304. {
  1305. int len = header->length;
  1306. int i = 0;
  1307. while(i + len + 1 < hlen) {
  1308. if(headers[i + len] == ':' &&
  1309. lwrcmp(headers + i, header->string, len) == 0) {
  1310. int j = i + len + 1, k;
  1311. while(j < hlen && headers[j] == ' ')
  1312. j++;
  1313. k = j;
  1314. while(k < hlen && headers[k] != '\n' && headers[k] != '\r')
  1315. k++;
  1316. *value_begin_return = j;
  1317. *value_end_return = k;
  1318. return 1;
  1319. } else {
  1320. while(i < hlen && headers[i] != '\n' && headers[i] != '\r')
  1321. i++;
  1322. i++;
  1323. if(i < hlen && headers[i] == '\n')
  1324. i++;
  1325. }
  1326. }
  1327. return 0;
  1328. }
  1329. int
  1330. parseUrl(const char *url, int len,
  1331. int *x_return, int *y_return, int *port_return, int *z_return)
  1332. {
  1333. int x, y, z, port = -1, i = 0;
  1334. if(len >= 7 && lwrcmp(url, "http://", 7) == 0) {
  1335. x = 7;
  1336. if(x < len && url[x] == '[') {
  1337. /* RFC 2732 */
  1338. for(i = x + 1; i < len; i++) {
  1339. if(url[i] == ']') {
  1340. i++;
  1341. break;
  1342. }
  1343. if((url[i] != ':') && !letter(url[i]) && !digit(url[i]))
  1344. break;
  1345. }
  1346. } else {
  1347. for(i = x; i < len; i++)
  1348. if(url[i] == ':' || url[i] == '/')
  1349. break;
  1350. }
  1351. y = i;
  1352. if(i < len && url[i] == ':') {
  1353. int j;
  1354. j = atoi_n(url, i + 1, len, &port);
  1355. if(j < 0) {
  1356. port = 80;
  1357. } else {
  1358. i = j;
  1359. }
  1360. } else {
  1361. port = 80;
  1362. }
  1363. } else {
  1364. x = -1;
  1365. y = -1;
  1366. }
  1367. z = i;
  1368. *x_return = x;
  1369. *y_return = y;
  1370. *port_return = port;
  1371. *z_return = z;
  1372. return 0;
  1373. }
  1374. int
  1375. urlIsLocal(const char *url, int len)
  1376. {
  1377. return (len > 0 && url[0] == '/');
  1378. }
  1379. int
  1380. urlIsSpecial(const char *url, int len)
  1381. {
  1382. return (len >= 8 && memcmp(url, "/polipo/", 8) == 0);
  1383. }
  1384. int
  1385. parseChunkSize(const char *restrict buf, int i, int end,
  1386. int *chunk_size_return)
  1387. {
  1388. int v, d;
  1389. v = h2i(buf[i]);
  1390. if(v < 0)
  1391. return -1;
  1392. i++;
  1393. while(i < end) {
  1394. d = h2i(buf[i]);
  1395. if(d < 0)
  1396. break;
  1397. v = v * 16 + d;
  1398. i++;
  1399. }
  1400. while(i < end) {
  1401. if(buf[i] == ' ' || buf[i] == '\t')
  1402. i++;
  1403. else
  1404. break;
  1405. }
  1406. if(i >= end - 1)
  1407. return 0;
  1408. if(buf[i] != '\r' || buf[i + 1] != '\n')
  1409. return -1;
  1410. i += 2;
  1411. if(v == 0) {
  1412. if(i >= end - 1)
  1413. return 0;
  1414. if(buf[i] != '\r') {
  1415. do_log(L_ERROR, "Trailers present!\n");
  1416. return -1;
  1417. }
  1418. i++;
  1419. if(buf[i] != '\n')
  1420. return -1;
  1421. i++;
  1422. }
  1423. *chunk_size_return = v;
  1424. return i;
  1425. }
  1426. int
  1427. checkVia(AtomPtr name, AtomPtr via)
  1428. {
  1429. int i;
  1430. char *v;
  1431. if(via == NULL || via->length == 0)
  1432. return 1;
  1433. v = via->string;
  1434. i = 0;
  1435. while(i < via->length) {
  1436. while(v[i] == ' ' || v[i] == '\t' || v[i] == ',' ||
  1437. v[i] == '\r' || v[i] == '\n' ||
  1438. digit(v[i]) || v[i] == '.')
  1439. i++;
  1440. if(i + name->length > via->length)
  1441. break;
  1442. if(memcmp(v + i, name->string, name->length) == 0) {
  1443. char c = v[i + name->length];
  1444. if(c == '\0' || c == ' ' || c == '\t' || c == ',' ||
  1445. c == '\r' || c == '\n')
  1446. return 0;
  1447. }
  1448. i++;
  1449. while(letter(v[i]) || digit(v[i]) || v[i] == '.')
  1450. i++;
  1451. }
  1452. return 1;
  1453. }