http.c 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094
  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. int disableProxy = 0;
  21. AtomPtr proxyName = NULL;
  22. int proxyPort = 8123;
  23. int clientTimeout = 120;
  24. int serverTimeout = 90;
  25. int serverIdleTimeout = 45;
  26. int bigBufferSize = (32 * 1024);
  27. AtomPtr displayName = NULL;
  28. AtomPtr authRealm = NULL;
  29. AtomPtr authCredentials = NULL;
  30. AtomPtr parentAuthCredentials = NULL;
  31. AtomListPtr allowedClients = NULL;
  32. NetAddressPtr allowedNets = NULL;
  33. IntListPtr allowedPorts = NULL;
  34. IntListPtr tunnelAllowedPorts = NULL;
  35. int expectContinue = 1;
  36. int dontTrustVaryETag = 1;
  37. AtomPtr atom100Continue;
  38. int disableVia = 1;
  39. /* 0 means that all failures lead to errors. 1 means that failures to
  40. connect are reported in a Warning header when stale objects are
  41. served. 2 means that only missing data is fetched from the net,
  42. stale data is served without revalidation (browser-side
  43. Cache-Control directives are still honoured). 3 means that no
  44. connections are ever attempted. */
  45. int proxyOffline = 0;
  46. int relaxTransparency = 0;
  47. AtomPtr proxyAddress = NULL;
  48. static int timeoutSetter(ConfigVariablePtr var, void *value);
  49. void
  50. preinitHttp()
  51. {
  52. proxyAddress = internAtom("127.0.0.1");
  53. CONFIG_VARIABLE_SETTABLE(disableProxy, CONFIG_BOOLEAN, configIntSetter,
  54. "Whether to be a web server only.");
  55. CONFIG_VARIABLE_SETTABLE(proxyOffline, CONFIG_BOOLEAN, configIntSetter,
  56. "Avoid contacting remote servers.");
  57. CONFIG_VARIABLE_SETTABLE(relaxTransparency, CONFIG_TRISTATE,
  58. configIntSetter,
  59. "Avoid contacting remote servers.");
  60. CONFIG_VARIABLE(proxyPort, CONFIG_INT,
  61. "The TCP port on which the proxy listens.");
  62. CONFIG_VARIABLE(proxyAddress, CONFIG_ATOM_LOWER,
  63. "The IP address on which the proxy listens.");
  64. CONFIG_VARIABLE_SETTABLE(proxyName, CONFIG_ATOM_LOWER, configAtomSetter,
  65. "The name by which the proxy is known.");
  66. CONFIG_VARIABLE_SETTABLE(clientTimeout, CONFIG_TIME,
  67. timeoutSetter, "Client-side timeout.");
  68. CONFIG_VARIABLE_SETTABLE(serverTimeout, CONFIG_TIME,
  69. timeoutSetter, "Server-side timeout.");
  70. CONFIG_VARIABLE_SETTABLE(serverIdleTimeout, CONFIG_TIME,
  71. timeoutSetter, "Server-side idle timeout.");
  72. CONFIG_VARIABLE(authRealm, CONFIG_ATOM,
  73. "Authentication realm.");
  74. CONFIG_VARIABLE(displayName, CONFIG_ATOM,
  75. "Server name displayed on error pages.");
  76. CONFIG_VARIABLE(authCredentials, CONFIG_PASSWORD,
  77. "username:password.");
  78. CONFIG_VARIABLE(parentAuthCredentials, CONFIG_PASSWORD,
  79. "username:password.");
  80. CONFIG_VARIABLE(allowedClients, CONFIG_ATOM_LIST_LOWER,
  81. "Networks from which clients are allowed to connect.");
  82. CONFIG_VARIABLE(tunnelAllowedPorts, CONFIG_INT_LIST,
  83. "Ports to which tunnelled connections are allowed.");
  84. CONFIG_VARIABLE(allowedPorts, CONFIG_INT_LIST,
  85. "Ports to which connections are allowed.");
  86. CONFIG_VARIABLE(expectContinue, CONFIG_TRISTATE,
  87. "Send Expect-Continue to servers.");
  88. CONFIG_VARIABLE(bigBufferSize, CONFIG_INT,
  89. "Size of big buffers (max size of headers).");
  90. CONFIG_VARIABLE_SETTABLE(disableVia, CONFIG_BOOLEAN, configIntSetter,
  91. "Don't use Via headers.");
  92. CONFIG_VARIABLE(dontTrustVaryETag, CONFIG_TRISTATE,
  93. "Whether to trust the ETag when there's Vary.");
  94. preinitHttpParser();
  95. }
  96. static int
  97. timeoutSetter(ConfigVariablePtr var, void *value)
  98. {
  99. configIntSetter(var, value);
  100. if(clientTimeout <= serverTimeout)
  101. clientTimeout = serverTimeout + 1;
  102. return 1;
  103. }
  104. void
  105. initHttp()
  106. {
  107. char *buf = NULL;
  108. int namelen;
  109. int n;
  110. struct hostent *host;
  111. initHttpParser();
  112. atom100Continue = internAtom("100-continue");
  113. if(clientTimeout <= serverTimeout) {
  114. clientTimeout = serverTimeout + 1;
  115. do_log(L_WARN, "Value of clientTimeout too small -- setting to %d.\n",
  116. clientTimeout);
  117. }
  118. if(displayName == NULL)
  119. displayName = internAtom("Polipo");
  120. if(authCredentials != NULL && authRealm == NULL)
  121. authRealm = internAtom("Polipo");
  122. if(allowedClients) {
  123. allowedNets = parseNetAddress(allowedClients);
  124. if(allowedNets == NULL)
  125. exit(1);
  126. }
  127. if(allowedPorts == NULL) {
  128. allowedPorts = makeIntList(0);
  129. if(allowedPorts == NULL) {
  130. do_log(L_ERROR, "Couldn't allocate allowedPorts.\n");
  131. exit(1);
  132. }
  133. intListCons(80, 100, allowedPorts);
  134. intListCons(1024, 0xFFFF, allowedPorts);
  135. }
  136. if(tunnelAllowedPorts == NULL) {
  137. tunnelAllowedPorts = makeIntList(0);
  138. if(tunnelAllowedPorts == NULL) {
  139. do_log(L_ERROR, "Couldn't allocate tunnelAllowedPorts.\n");
  140. exit(1);
  141. }
  142. intListCons(22, 22, tunnelAllowedPorts); /* ssh */
  143. intListCons(80, 80, tunnelAllowedPorts); /* HTTP */
  144. intListCons(109, 110, tunnelAllowedPorts); /* POP 2 and 3*/
  145. intListCons(143, 143, tunnelAllowedPorts); /* IMAP 2/4 */
  146. intListCons(443, 443, tunnelAllowedPorts); /* HTTP/SSL */
  147. intListCons(873, 873, tunnelAllowedPorts); /* rsync */
  148. intListCons(993, 993, tunnelAllowedPorts); /* IMAP/SSL */
  149. intListCons(995, 995, tunnelAllowedPorts); /* POP/SSL */
  150. intListCons(2401, 2401, tunnelAllowedPorts); /* CVS */
  151. intListCons(5222, 5223, tunnelAllowedPorts); /* Jabber */
  152. intListCons(9418, 9418, tunnelAllowedPorts); /* Git */
  153. }
  154. if(proxyName)
  155. return;
  156. buf = get_chunk();
  157. if(buf == NULL) {
  158. do_log(L_ERROR, "Couldn't allocate chunk for host name.\n");
  159. goto fail;
  160. }
  161. n = gethostname(buf, CHUNK_SIZE);
  162. if(n != 0) {
  163. do_log_error(L_WARN, errno, "Gethostname");
  164. strcpy(buf, "polipo");
  165. goto success;
  166. }
  167. /* gethostname doesn't necessarily NUL-terminate on overflow */
  168. buf[CHUNK_SIZE - 1] = '\0';
  169. if(strcmp(buf, "(none)") == 0 ||
  170. strcmp(buf, "localhost") == 0 ||
  171. strcmp(buf, "localhost.localdomain") == 0) {
  172. do_log(L_WARN, "Couldn't determine host name -- using ``polipo''.\n");
  173. strcpy(buf, "polipo");
  174. goto success;
  175. }
  176. if(strchr(buf, '.') != NULL)
  177. goto success;
  178. host = gethostbyname(buf);
  179. if(host == NULL) {
  180. goto success;
  181. }
  182. if(host->h_addrtype != AF_INET)
  183. goto success;
  184. host = gethostbyaddr(host->h_addr_list[0], host->h_length, AF_INET);
  185. if(!host || !host->h_name || strcmp(host->h_name, "localhost") == 0 ||
  186. strcmp(host->h_name, "localhost.localdomain") == 0)
  187. goto success;
  188. namelen = strlen(host->h_name);
  189. if(namelen >= CHUNK_SIZE) {
  190. do_log(L_ERROR, "Host name too long.\n");
  191. goto success;
  192. }
  193. memcpy(buf, host->h_name, namelen + 1);
  194. success:
  195. proxyName = internAtom(buf);
  196. if(proxyName == NULL) {
  197. do_log(L_ERROR, "Couldn't allocate proxy name.\n");
  198. goto fail;
  199. }
  200. dispose_chunk(buf);
  201. return;
  202. fail:
  203. if(buf)
  204. dispose_chunk(buf);
  205. exit(1);
  206. return;
  207. }
  208. int
  209. httpSetTimeout(HTTPConnectionPtr connection, int secs)
  210. {
  211. TimeEventHandlerPtr new;
  212. if(connection->timeout)
  213. cancelTimeEvent(connection->timeout);
  214. connection->timeout = NULL;
  215. if(secs > 0) {
  216. new = scheduleTimeEvent(secs, httpTimeoutHandler,
  217. sizeof(connection), &connection);
  218. if(!new) {
  219. do_log(L_ERROR, "Couldn't schedule timeout for connection 0x%lx\n",
  220. (unsigned long)connection);
  221. return -1;
  222. }
  223. } else {
  224. new = NULL;
  225. }
  226. connection->timeout = new;
  227. return 1;
  228. }
  229. int
  230. httpTimeoutHandler(TimeEventHandlerPtr event)
  231. {
  232. HTTPConnectionPtr connection = *(HTTPConnectionPtr*)event->data;
  233. if(connection->fd >= 0) {
  234. int rc;
  235. rc = shutdown(connection->fd, 2);
  236. if(rc < 0 && errno != ENOTCONN)
  237. do_log_error(L_ERROR, errno, "Timeout: shutdown failed");
  238. pokeFdEvent(connection->fd, -EDOTIMEOUT, POLLIN | POLLOUT);
  239. }
  240. connection->timeout = NULL;
  241. return 1;
  242. }
  243. int
  244. httpWriteObjectHeaders(char *buf, int offset, int len,
  245. ObjectPtr object, int from, int to)
  246. {
  247. int n = offset;
  248. CacheControlRec cache_control;
  249. cache_control.flags = object->cache_control;
  250. cache_control.max_age = object->max_age;
  251. cache_control.s_maxage = object->s_maxage;
  252. cache_control.max_stale = -1;
  253. cache_control.min_fresh = -1;
  254. if(from <= 0 && to < 0) {
  255. if(object->length >= 0) {
  256. n = snnprintf(buf, n, len,
  257. "\r\nContent-Length: %d", object->length);
  258. }
  259. } else {
  260. if(to >= 0) {
  261. n = snnprintf(buf, n, len,
  262. "\r\nContent-Length: %d", to - from);
  263. }
  264. }
  265. if(from > 0 || to > 0) {
  266. if(object->length >= 0) {
  267. if(from >= to) {
  268. n = snnprintf(buf, n, len,
  269. "\r\nContent-Range: bytes */%d",
  270. object->length);
  271. } else {
  272. n = snnprintf(buf, n, len,
  273. "\r\nContent-Range: bytes %d-%d/%d",
  274. from, to - 1,
  275. object->length);
  276. }
  277. } else {
  278. if(to >= 0) {
  279. n = snnprintf(buf, n, len,
  280. "\r\nContent-Range: bytes %d-/*",
  281. from);
  282. } else {
  283. n = snnprintf(buf, n, len,
  284. "\r\nContent-Range: bytes %d-%d/*",
  285. from, to);
  286. }
  287. }
  288. }
  289. if(object->etag) {
  290. n = snnprintf(buf, n, len, "\r\nETag: \"%s\"", object->etag);
  291. }
  292. if((object->flags & OBJECT_LOCAL) || object->date >= 0) {
  293. n = snnprintf(buf, n, len, "\r\nDate: ");
  294. n = format_time(buf, n, len,
  295. (object->flags & OBJECT_LOCAL) ?
  296. current_time.tv_sec : object->date);
  297. if(n < 0)
  298. goto fail;
  299. }
  300. if(object->last_modified >= 0) {
  301. n = snnprintf(buf, n, len, "\r\nLast-Modified: ");
  302. n = format_time(buf, n, len, object->last_modified);
  303. if(n < 0)
  304. goto fail;
  305. }
  306. if(object->expires >= 0) {
  307. n = snnprintf(buf, n, len, "\r\nExpires: ");
  308. n = format_time(buf, n, len, object->expires);
  309. if(n < 0)
  310. goto fail;
  311. }
  312. n = httpPrintCacheControl(buf, n, len,
  313. object->cache_control, &cache_control);
  314. if(n < 0)
  315. goto fail;
  316. if(!disableVia && object->via)
  317. n = snnprintf(buf, n, len, "\r\nVia: %s", object->via->string);
  318. if(object->headers)
  319. n = snnprint_n(buf, n, len, object->headers->string,
  320. object->headers->length);
  321. if(n < len)
  322. return n;
  323. else
  324. return -1;
  325. fail:
  326. return -1;
  327. }
  328. static int
  329. cachePrintSeparator(char *buf, int offset, int len,
  330. int subsequent)
  331. {
  332. int n = offset;
  333. if(subsequent)
  334. n = snnprintf(buf, offset, len, ", ");
  335. else
  336. n = snnprintf(buf, offset, len, "\r\nCache-Control: ");
  337. return n;
  338. }
  339. int
  340. httpPrintCacheControl(char *buf, int offset, int len,
  341. int flags, CacheControlPtr cache_control)
  342. {
  343. int n = offset;
  344. int sub = 0;
  345. #define PRINT_SEP() \
  346. do {\
  347. n = cachePrintSeparator(buf, n, len, sub); \
  348. sub = 1; \
  349. } while(0)
  350. if(cache_control)
  351. flags |= cache_control->flags;
  352. if(flags & CACHE_NO) {
  353. PRINT_SEP();
  354. n = snnprintf(buf, n, len, "no-cache");
  355. }
  356. if(flags & CACHE_PUBLIC) {
  357. PRINT_SEP();
  358. n = snnprintf(buf, n, len, "public");
  359. }
  360. if(flags & CACHE_PRIVATE) {
  361. PRINT_SEP();
  362. n = snnprintf(buf, n, len, "private");
  363. }
  364. if(flags & CACHE_NO_STORE) {
  365. PRINT_SEP();
  366. n = snnprintf(buf, n, len, "no-store");
  367. }
  368. if(flags & CACHE_NO_TRANSFORM) {
  369. PRINT_SEP();
  370. n = snnprintf(buf, n, len, "no-transform");
  371. }
  372. if(flags & CACHE_MUST_REVALIDATE) {
  373. PRINT_SEP();
  374. n = snnprintf(buf, n, len, "must-revalidate");
  375. }
  376. if(flags & CACHE_PROXY_REVALIDATE) {
  377. PRINT_SEP();
  378. n = snnprintf(buf, n, len, "proxy-revalidate");
  379. }
  380. if(flags & CACHE_ONLY_IF_CACHED) {
  381. PRINT_SEP();
  382. n = snnprintf(buf, n, len, "only-if-cached");
  383. }
  384. if(cache_control) {
  385. if(cache_control->max_age >= 0) {
  386. PRINT_SEP();
  387. n = snnprintf(buf, n, len, "max-age=%d",
  388. cache_control->max_age);
  389. }
  390. if(cache_control->s_maxage >= 0) {
  391. PRINT_SEP();
  392. n = snnprintf(buf, n, len, "s-maxage=%d",
  393. cache_control->s_maxage);
  394. }
  395. if(cache_control->min_fresh > 0) {
  396. PRINT_SEP();
  397. n = snnprintf(buf, n, len, "min-fresh=%d",
  398. cache_control->min_fresh);
  399. }
  400. if(cache_control->max_stale > 0) {
  401. PRINT_SEP();
  402. n = snnprintf(buf, n, len, "max-stale=%d",
  403. cache_control->min_fresh);
  404. }
  405. }
  406. return n;
  407. #undef PRINT_SEP
  408. }
  409. char *
  410. httpMessage(int code)
  411. {
  412. switch(code) {
  413. case 200:
  414. return "Okay";
  415. case 206:
  416. return "Partial content";
  417. case 300:
  418. return "Multiple choices";
  419. case 301:
  420. return "Moved permanently";
  421. case 302:
  422. return "Found";
  423. case 303:
  424. return "See other";
  425. case 304:
  426. return "Not changed";
  427. case 307:
  428. return "Temporary redirect";
  429. case 401:
  430. return "Authentication Required";
  431. case 403:
  432. return "Forbidden";
  433. case 404:
  434. return "Not found";
  435. case 405:
  436. return "Method not allowed";
  437. case 407:
  438. return "Proxy authentication required";
  439. default:
  440. return "Unknown error code";
  441. }
  442. }
  443. int
  444. htmlString(char *buf, int n, int len, char *s, int slen)
  445. {
  446. int i = 0;
  447. while(i < slen && n + 5 < len) {
  448. switch(s[i]) {
  449. case '&':
  450. buf[n++] = '&'; buf[n++] = 'a'; buf[n++] = 'm'; buf[n++] = 'p';
  451. buf[n++] = ';';
  452. break;
  453. case '<':
  454. buf[n++] = '&'; buf[n++] = 'l'; buf[n++] = 't'; buf[n++] = ';';
  455. break;
  456. case '>':
  457. buf[n++] = '&'; buf[n++] = 'g'; buf[n++] = 't'; buf[n++] = ';';
  458. break;
  459. case '"':
  460. buf[n++] = '&'; buf[n++] = 'q'; buf[n++] = 'u'; buf[n++] = 'o';
  461. buf[n++] = 't'; buf[n++] = ';';
  462. break;
  463. case '\0':
  464. break;
  465. default:
  466. buf[n++] = s[i];
  467. }
  468. i++;
  469. }
  470. return n;
  471. }
  472. void
  473. htmlPrint(FILE *out, char *s, int slen)
  474. {
  475. int i;
  476. for(i = 0; i < slen; i++) {
  477. switch(s[i]) {
  478. case '&':
  479. fputs("&amp;", out);
  480. break;
  481. case '<':
  482. fputs("&lt;", out);
  483. break;
  484. case '>':
  485. fputs("&gt;", out);
  486. break;
  487. default:
  488. fputc(s[i], out);
  489. }
  490. }
  491. }
  492. HTTPConnectionPtr
  493. httpMakeConnection()
  494. {
  495. HTTPConnectionPtr connection;
  496. connection = malloc(sizeof(HTTPConnectionRec));
  497. if(connection == NULL)
  498. return NULL;
  499. connection->flags = 0;
  500. connection->fd = -1;
  501. connection->buf = NULL;
  502. connection->len = 0;
  503. connection->offset = 0;
  504. connection->request = NULL;
  505. connection->request_last = NULL;
  506. connection->serviced = 0;
  507. connection->version = HTTP_UNKNOWN;
  508. connection->time = current_time.tv_sec;
  509. connection->timeout = NULL;
  510. connection->te = TE_IDENTITY;
  511. connection->reqbuf = NULL;
  512. connection->reqlen = 0;
  513. connection->reqbegin = 0;
  514. connection->reqoffset = 0;
  515. connection->bodylen = -1;
  516. connection->reqte = TE_IDENTITY;
  517. connection->chunk_remaining = 0;
  518. connection->server = NULL;
  519. connection->pipelined = 0;
  520. connection->connecting = 0;
  521. connection->server = NULL;
  522. return connection;
  523. }
  524. void
  525. httpDestroyConnection(HTTPConnectionPtr connection)
  526. {
  527. assert(connection->flags == 0);
  528. httpConnectionDestroyBuf(connection);
  529. assert(!connection->request);
  530. assert(!connection->request_last);
  531. httpConnectionDestroyReqbuf(connection);
  532. assert(!connection->timeout);
  533. assert(!connection->server);
  534. free(connection);
  535. }
  536. void
  537. httpConnectionDestroyBuf(HTTPConnectionPtr connection)
  538. {
  539. if(connection->buf) {
  540. if(connection->flags & CONN_BIGBUF)
  541. free(connection->buf);
  542. else
  543. dispose_chunk(connection->buf);
  544. }
  545. connection->flags &= ~CONN_BIGBUF;
  546. connection->buf = NULL;
  547. }
  548. void
  549. httpConnectionDestroyReqbuf(HTTPConnectionPtr connection)
  550. {
  551. if(connection->reqbuf) {
  552. if(connection->flags & CONN_BIGREQBUF)
  553. free(connection->reqbuf);
  554. else
  555. dispose_chunk(connection->reqbuf);
  556. }
  557. connection->flags &= ~CONN_BIGREQBUF;
  558. connection->reqbuf = NULL;
  559. }
  560. HTTPRequestPtr
  561. httpMakeRequest()
  562. {
  563. HTTPRequestPtr request;
  564. request = malloc(sizeof(HTTPRequestRec));
  565. if(request == NULL)
  566. return NULL;
  567. request->flags = 0;
  568. request->connection = NULL;
  569. request->object = NULL;
  570. request->method = METHOD_UNKNOWN;
  571. request->from = 0;
  572. request->to = -1;
  573. request->cache_control = no_cache_control;
  574. request->condition = NULL;
  575. request->via = NULL;
  576. request->chandler = NULL;
  577. request->can_mutate = NULL;
  578. request->error_code = 0;
  579. request->error_message = NULL;
  580. request->error_headers = NULL;
  581. request->headers = NULL;
  582. request->time0 = null_time;
  583. request->time1 = null_time;
  584. request->request = NULL;
  585. request->next = NULL;
  586. return request;
  587. }
  588. void
  589. httpDestroyRequest(HTTPRequestPtr request)
  590. {
  591. if(request->object)
  592. releaseObject(request->object);
  593. if(request->condition)
  594. httpDestroyCondition(request->condition);
  595. releaseAtom(request->via);
  596. assert(request->chandler == NULL);
  597. releaseAtom(request->error_message);
  598. releaseAtom(request->headers);
  599. releaseAtom(request->error_headers);
  600. assert(request->request == NULL);
  601. assert(request->next == NULL);
  602. free(request);
  603. }
  604. void
  605. httpQueueRequest(HTTPConnectionPtr connection, HTTPRequestPtr request)
  606. {
  607. assert(request->next == NULL && request->connection == NULL);
  608. request->connection = connection;
  609. if(connection->request_last) {
  610. assert(connection->request);
  611. connection->request_last->next = request;
  612. connection->request_last = request;
  613. } else {
  614. assert(!connection->request_last);
  615. connection->request = request;
  616. connection->request_last = request;
  617. }
  618. }
  619. HTTPRequestPtr
  620. httpDequeueRequest(HTTPConnectionPtr connection)
  621. {
  622. HTTPRequestPtr request = connection->request;
  623. if(request) {
  624. assert(connection->request_last);
  625. connection->request = request->next;
  626. if(!connection->request) connection->request_last = NULL;
  627. request->next = NULL;
  628. }
  629. return request;
  630. }
  631. int
  632. httpConnectionBigify(HTTPConnectionPtr connection)
  633. {
  634. char *bigbuf;
  635. assert(!(connection->flags & CONN_BIGBUF));
  636. if(bigBufferSize <= CHUNK_SIZE)
  637. return 0;
  638. bigbuf = malloc(bigBufferSize);
  639. if(bigbuf == NULL)
  640. return -1;
  641. if(connection->len > 0)
  642. memcpy(bigbuf, connection->buf, connection->len);
  643. if(connection->buf)
  644. dispose_chunk(connection->buf);
  645. connection->buf = bigbuf;
  646. connection->flags |= CONN_BIGBUF;
  647. return 1;
  648. }
  649. int
  650. httpConnectionBigifyReqbuf(HTTPConnectionPtr connection)
  651. {
  652. char *bigbuf;
  653. assert(!(connection->flags & CONN_BIGREQBUF));
  654. if(bigBufferSize <= CHUNK_SIZE)
  655. return 0;
  656. bigbuf = malloc(bigBufferSize);
  657. if(bigbuf == NULL)
  658. return -1;
  659. if(connection->reqlen > 0)
  660. memcpy(bigbuf, connection->reqbuf, connection->reqlen);
  661. if(connection->reqbuf)
  662. dispose_chunk(connection->reqbuf);
  663. connection->reqbuf = bigbuf;
  664. connection->flags |= CONN_BIGREQBUF;
  665. return 1;
  666. }
  667. int
  668. httpConnectionUnbigify(HTTPConnectionPtr connection)
  669. {
  670. char *buf;
  671. assert(connection->flags & CONN_BIGBUF);
  672. assert(connection->len < CHUNK_SIZE);
  673. buf = get_chunk();
  674. if(buf == NULL)
  675. return -1;
  676. if(connection->len > 0)
  677. memcpy(buf, connection->buf, connection->len);
  678. free(connection->buf);
  679. connection->buf = buf;
  680. connection->flags &= ~CONN_BIGBUF;
  681. return 1;
  682. }
  683. int
  684. httpConnectionUnbigifyReqbuf(HTTPConnectionPtr connection)
  685. {
  686. char *buf;
  687. assert(connection->flags & CONN_BIGREQBUF);
  688. assert(connection->reqlen < CHUNK_SIZE);
  689. buf = get_chunk();
  690. if(buf == NULL)
  691. return -1;
  692. if(connection->reqlen > 0)
  693. memcpy(buf, connection->reqbuf, connection->reqlen);
  694. free(connection->reqbuf);
  695. connection->reqbuf = buf;
  696. connection->flags &= ~CONN_BIGREQBUF;
  697. return 1;
  698. }
  699. HTTPConditionPtr
  700. httpMakeCondition()
  701. {
  702. HTTPConditionPtr condition;
  703. condition = malloc(sizeof(HTTPConditionRec));
  704. if(condition == NULL)
  705. return NULL;
  706. condition->ims = -1;
  707. condition->inms = -1;
  708. condition->im = NULL;
  709. condition->inm = NULL;
  710. condition->ifrange = NULL;
  711. return condition;
  712. }
  713. void
  714. httpDestroyCondition(HTTPConditionPtr condition)
  715. {
  716. if(condition->inm)
  717. free(condition->inm);
  718. if(condition->im)
  719. free(condition->im);
  720. if(condition->ifrange)
  721. free(condition->ifrange);
  722. free(condition);
  723. }
  724. int
  725. httpCondition(ObjectPtr object, HTTPConditionPtr condition)
  726. {
  727. int rc = CONDITION_MATCH;
  728. assert(!(object->flags & OBJECT_INITIAL));
  729. if(!condition) return CONDITION_MATCH;
  730. if(condition->ims >= 0) {
  731. if(object->last_modified < 0 ||
  732. condition->ims < object->last_modified)
  733. return rc;
  734. else
  735. rc = CONDITION_NOT_MODIFIED;
  736. }
  737. if(condition->inms >= 0) {
  738. if(object->last_modified < 0 ||
  739. condition->inms >= object->last_modified)
  740. return rc;
  741. else
  742. rc = CONDITION_FAILED;
  743. }
  744. if(condition->inm) {
  745. if(!object->etag || strcmp(object->etag, condition->inm) != 0)
  746. return rc;
  747. else
  748. rc = CONDITION_NOT_MODIFIED;
  749. }
  750. if(condition->im) {
  751. if(!object->etag || strcmp(object->etag, condition->im) != 0)
  752. rc = CONDITION_FAILED;
  753. else
  754. return rc;
  755. }
  756. return rc;
  757. }
  758. int
  759. httpWriteErrorHeaders(char *buf, int size, int offset, int do_body,
  760. int code, AtomPtr message, int close, AtomPtr headers,
  761. char *url, int url_len, char *etag)
  762. {
  763. int n, m, i;
  764. char *body;
  765. char htmlMessage[100];
  766. char timeStr[100];
  767. assert(code != 0);
  768. i = htmlString(htmlMessage, 0, 100, message->string, message->length);
  769. if(i < 0)
  770. strcpy(htmlMessage, "(Couldn't format message)");
  771. else
  772. htmlMessage[MIN(i, 99)] = '\0';
  773. if(code != 304) {
  774. body = get_chunk();
  775. if(!body) {
  776. do_log(L_ERROR, "Couldn't allocate body buffer.\n");
  777. return -1;
  778. }
  779. m = snnprintf(body, 0, CHUNK_SIZE,
  780. "<!DOCTYPE HTML PUBLIC "
  781. "\"-//W3C//DTD HTML 4.01 Transitional//EN\" "
  782. "\"http://www.w3.org/TR/html4/loose.dtd\">"
  783. "\n<html><head>"
  784. "\n<title>Proxy %s: %3d %s.</title>"
  785. "\n</head><body>"
  786. "\n<h1>%3d %s</h1>"
  787. "\n<p>The following %s",
  788. code >= 400 ? "error" : "result",
  789. code, htmlMessage,
  790. code, htmlMessage,
  791. code >= 400 ?
  792. "error occurred" :
  793. "status was returned");
  794. if(url_len > 0) {
  795. m = snnprintf(body, m, CHUNK_SIZE,
  796. " while trying to access <strong>");
  797. m = htmlString(body, m, CHUNK_SIZE, url, url_len);
  798. m = snnprintf(body, m, CHUNK_SIZE, "</strong>");
  799. }
  800. {
  801. /* On BSD systems, tv_sec is a long. */
  802. const time_t ct = current_time.tv_sec;
  803. /*Mon, 24 Sep 2004 17:46:35 GMT*/
  804. strftime(timeStr, sizeof(timeStr), "%a, %d %b %Y %H:%M:%S %Z",
  805. localtime(&ct));
  806. }
  807. m = snnprintf(body, m, CHUNK_SIZE,
  808. ":<br><br>"
  809. "\n<strong>%3d %s</strong></p>"
  810. "\n<hr>Generated %s by %s on <em>%s:%d</em>."
  811. "\n</body></html>\r\n",
  812. code, htmlMessage,
  813. timeStr, displayName->string, proxyName->string, proxyPort);
  814. if(m <= 0 || m >= CHUNK_SIZE) {
  815. do_log(L_ERROR, "Couldn't write error body.\n");
  816. dispose_chunk(body);
  817. return -1;
  818. }
  819. } else {
  820. body = NULL;
  821. m = 0;
  822. }
  823. n = snnprintf(buf, 0, size,
  824. "HTTP/1.1 %3d %s"
  825. "\r\nConnection: %s"
  826. "\r\nDate: ",
  827. code, atomString(message),
  828. close ? "close" : "keep-alive");
  829. n = format_time(buf, n, size, current_time.tv_sec);
  830. if(code != 304) {
  831. n = snnprintf(buf, n, size,
  832. "\r\nContent-Type: text/html"
  833. "\r\nContent-Length: %d", m);
  834. } else {
  835. if(etag)
  836. n = snnprintf(buf, n, size, "\r\nETag: \"%s\"", etag);
  837. }
  838. if(code != 304 && code != 412) {
  839. n = snnprintf(buf, n, size,
  840. "\r\nExpires: 0"
  841. "\r\nCache-Control: no-cache"
  842. "\r\nPragma: no-cache");
  843. }
  844. if(headers)
  845. n = snnprint_n(buf, n, size,
  846. headers->string, headers->length);
  847. n = snnprintf(buf, n, size, "\r\n\r\n");
  848. if(n < 0 || n >= size) {
  849. do_log(L_ERROR, "Couldn't write error.\n");
  850. dispose_chunk(body);
  851. return -1;
  852. }
  853. if(code != 304 && do_body) {
  854. if(m > 0) memcpy(buf + n, body, m);
  855. n += m;
  856. }
  857. if(body)
  858. dispose_chunk(body);
  859. return n;
  860. }
  861. AtomListPtr
  862. urlDecode(char *buf, int n)
  863. {
  864. char mybuf[500];
  865. int i, j = 0;
  866. AtomListPtr list;
  867. AtomPtr atom;
  868. list = makeAtomList(NULL, 0);
  869. if(list == NULL)
  870. return NULL;
  871. i = 0;
  872. while(i < n) {
  873. if(buf[i] == '%') {
  874. int a, b;
  875. if(i + 3 > n)
  876. goto fail;
  877. a = h2i(buf[i + 1]);
  878. b = h2i(buf[i + 2]);
  879. if(a < 0 || b < 0)
  880. goto fail;
  881. mybuf[j++] = (char)((a << 4) | b);
  882. i += 3;
  883. if(j >= 500) goto fail;
  884. } else if(buf[i] == '&') {
  885. atom = internAtomN(mybuf, j);
  886. if(atom == NULL)
  887. goto fail;
  888. atomListCons(atom, list);
  889. j = 0;
  890. i++;
  891. } else {
  892. mybuf[j++] = buf[i++];
  893. if(j >= 500) goto fail;
  894. }
  895. }
  896. atom = internAtomN(mybuf, j);
  897. if(atom == NULL)
  898. goto fail;
  899. atomListCons(atom, list);
  900. return list;
  901. fail:
  902. destroyAtomList(list);
  903. return NULL;
  904. }
  905. void
  906. httpTweakCachability(ObjectPtr object)
  907. {
  908. int code = object->code;
  909. if((object->cache_control & CACHE_AUTHORIZATION) &&
  910. !(object->cache_control & CACHE_PUBLIC)) {
  911. object->cache_control |= CACHE_NO_HIDDEN;
  912. object->flags |= OBJECT_LINEAR;
  913. }
  914. /* This is not required by RFC 2616 -- but see RFC 3143 2.1.1. We
  915. manically avoid caching replies that we don't know how to
  916. handle, even if Expires or Cache-Control says otherwise. As to
  917. known uncacheable replies, we obey Cache-Control and default to
  918. allowing sharing but not caching. */
  919. if(code != 200 && code != 206 &&
  920. code != 300 && code != 301 && code != 302 && code != 303 &&
  921. code != 304 && code != 307 &&
  922. code != 403 && code != 404 && code != 405 && code != 416) {
  923. object->cache_control |= (CACHE_NO_HIDDEN | CACHE_MISMATCH);
  924. object->flags |= OBJECT_LINEAR;
  925. } else if(code != 200 && code != 206 &&
  926. code != 300 && code != 301 && code != 304 &&
  927. code != 410) {
  928. if(object->expires < 0 && !(object->cache_control & CACHE_PUBLIC)) {
  929. object->cache_control |= CACHE_NO_HIDDEN;
  930. }
  931. } else if(dontCacheRedirects && (code == 301 || code == 302)) {
  932. object->cache_control |= CACHE_NO_HIDDEN;
  933. }
  934. if(urlIsUncachable(object->key, object->key_size)) {
  935. object->cache_control |= CACHE_NO_HIDDEN;
  936. }
  937. if((object->cache_control & CACHE_NO_STORE) != 0) {
  938. object->cache_control |= CACHE_NO_HIDDEN;
  939. }
  940. if(object->cache_control & CACHE_VARY) {
  941. if(!object->etag || dontTrustVaryETag >= 2) {
  942. object->cache_control |= CACHE_MISMATCH;
  943. }
  944. }
  945. }
  946. int
  947. httpHeaderMatch(AtomPtr header, AtomPtr headers1, AtomPtr headers2)
  948. {
  949. int rc1, b1, e1, rc2, b2, e2;
  950. /* Short cut if both sets of headers are identical */
  951. if(headers1 == headers2)
  952. return 1;
  953. rc1 = httpFindHeader(header, headers1->string, headers1->length,
  954. &b1, &e1);
  955. rc2 = httpFindHeader(header, headers2->string, headers2->length,
  956. &b2, &e2);
  957. if(rc1 == 0 && rc2 == 0)
  958. return 1;
  959. if(rc1 == 0 || rc2 == 0)
  960. return 0;
  961. if(e1 - b1 != e2 - b2)
  962. return 0;
  963. if(memcmp(headers1->string + b1, headers2->string + b2, e1 - b1) != 0)
  964. return 0;
  965. return 1;
  966. }