http_parse.c 47 KB

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