client.c 70 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155
  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
  21. httpAcceptAgain(TimeEventHandlerPtr event)
  22. {
  23. FdEventHandlerPtr newevent;
  24. int fd = *(int*)event->data;
  25. newevent = schedule_accept(fd, httpAccept, NULL);
  26. if(newevent == NULL) {
  27. free_chunk_arenas();
  28. newevent = schedule_accept(fd, httpAccept, NULL);
  29. if(newevent == NULL) {
  30. do_log(L_ERROR, "Couldn't schedule accept.\n");
  31. polipoExit();
  32. }
  33. }
  34. return 1;
  35. }
  36. int
  37. httpAccept(int fd, FdEventHandlerPtr event, AcceptRequestPtr request)
  38. {
  39. int rc;
  40. HTTPConnectionPtr connection;
  41. TimeEventHandlerPtr timeout;
  42. if(fd < 0) {
  43. if(-fd == EINTR || -fd == EAGAIN || -fd == EWOULDBLOCK)
  44. return 0;
  45. do_log_error(L_ERROR, -fd, "Couldn't establish listening socket");
  46. if(-fd == EMFILE || -fd == ENOMEM || -fd == ENOBUFS) {
  47. TimeEventHandlerPtr again = NULL;
  48. do_log(L_WARN, "Refusing client connections for one second.\n");
  49. free_chunk_arenas();
  50. again = scheduleTimeEvent(1, httpAcceptAgain,
  51. sizeof(request->fd), &request->fd);
  52. if(!again) {
  53. do_log(L_ERROR, "Couldn't schedule accept -- sleeping.\n");
  54. sleep(1);
  55. again = scheduleTimeEvent(1, httpAcceptAgain,
  56. sizeof(request->fd), &request->fd);
  57. if(!again) {
  58. do_log(L_ERROR, "Couldn't schedule accept -- aborting.\n");
  59. polipoExit();
  60. }
  61. }
  62. return 1;
  63. } else {
  64. polipoExit();
  65. return 1;
  66. }
  67. }
  68. if(allowedNets) {
  69. if(netAddressMatch(fd, allowedNets) != 1) {
  70. do_log(L_WARN, "Refusing connection from unauthorised net\n");
  71. CLOSE(fd);
  72. return 0;
  73. }
  74. }
  75. rc = setNonblocking(fd, 1);
  76. if(rc < 0) {
  77. do_log_error(L_WARN, errno, "Couldn't set non blocking mode");
  78. CLOSE(fd);
  79. return 0;
  80. }
  81. rc = setNodelay(fd, 1);
  82. if(rc < 0)
  83. do_log_error(L_WARN, errno, "Couldn't disable Nagle's algorithm");
  84. connection = httpMakeConnection();
  85. timeout = scheduleTimeEvent(clientTimeout, httpTimeoutHandler,
  86. sizeof(connection), &connection);
  87. if(!timeout) {
  88. CLOSE(fd);
  89. free(connection);
  90. return 0;
  91. }
  92. connection->fd = fd;
  93. connection->timeout = timeout;
  94. do_log(D_CLIENT_CONN, "Accepted client connection 0x%lx\n",
  95. (unsigned long)connection);
  96. connection->flags = CONN_READER;
  97. do_stream_buf(IO_READ | IO_NOTNOW, connection->fd, 0,
  98. &connection->reqbuf, CHUNK_SIZE,
  99. httpClientHandler, connection);
  100. return 0;
  101. }
  102. /* Abort a client connection. It is only safe to abort the requests
  103. if we know the connection is closed. */
  104. void
  105. httpClientAbort(HTTPConnectionPtr connection, int closed)
  106. {
  107. HTTPRequestPtr request = connection->request;
  108. pokeFdEvent(connection->fd, -EDOSHUTDOWN, POLLOUT);
  109. if(closed) {
  110. while(request) {
  111. if(request->chandler) {
  112. request->error_code = 500;
  113. request->error_message = internAtom("Connection finishing");
  114. abortConditionHandler(request->chandler);
  115. request->chandler = NULL;
  116. }
  117. request = request->next;
  118. }
  119. }
  120. }
  121. /* s != 0 specifies that the connection must be shut down. It is 1 in
  122. order to linger the connection, 2 to close it straight away. */
  123. void
  124. httpClientFinish(HTTPConnectionPtr connection, int s)
  125. {
  126. HTTPRequestPtr request = connection->request;
  127. assert(!(request && request->request
  128. && request->request->request != request));
  129. if(s == 0) {
  130. if(!request || !(request->flags & REQUEST_PERSISTENT))
  131. s = 1;
  132. }
  133. httpConnectionDestroyBuf(connection);
  134. connection->flags &= ~CONN_WRITER;
  135. if(connection->flags & CONN_SIDE_READER) {
  136. /* We're in POST or PUT and the reader isn't done yet.
  137. Wait for the read side to close the connection. */
  138. assert(request && (connection->flags & CONN_READER));
  139. if(s >= 2) {
  140. pokeFdEvent(connection->fd, -EDOSHUTDOWN, POLLIN);
  141. } else {
  142. pokeFdEvent(connection->fd, -EDOGRACEFUL, POLLIN);
  143. }
  144. return;
  145. }
  146. if(connection->timeout)
  147. cancelTimeEvent(connection->timeout);
  148. connection->timeout = NULL;
  149. if(request) {
  150. HTTPRequestPtr requestee;
  151. requestee = request->request;
  152. if(requestee) {
  153. request->request = NULL;
  154. requestee->request = NULL;
  155. }
  156. if(requestee)
  157. httpServerClientReset(requestee);
  158. if(request->chandler) {
  159. request->error_code = 500;
  160. request->error_message = internAtom("Connection finishing");
  161. abortConditionHandler(request->chandler);
  162. request->chandler = NULL;
  163. }
  164. if(request->object) {
  165. if(request->object->requestor == request)
  166. request->object->requestor = NULL;
  167. releaseObject(request->object);
  168. request->object = NULL;
  169. }
  170. httpDequeueRequest(connection);
  171. httpDestroyRequest(request);
  172. request = NULL;
  173. }
  174. connection->len = -1;
  175. connection->offset = 0;
  176. connection->te = TE_IDENTITY;
  177. if(!s) {
  178. assert(connection->fd > 0);
  179. connection->serviced++;
  180. httpSetTimeout(connection, clientTimeout);
  181. if(!(connection->flags & CONN_READER)) {
  182. if(connection->reqlen == 0)
  183. httpConnectionDestroyReqbuf(connection);
  184. else if((connection->flags & CONN_BIGREQBUF) &&
  185. connection->reqlen < CHUNK_SIZE)
  186. httpConnectionUnbigifyReqbuf(connection);
  187. connection->flags |= CONN_READER;
  188. httpSetTimeout(connection, clientTimeout);
  189. do_stream_buf(IO_READ | IO_NOTNOW |
  190. (connection->reqlen ? IO_IMMEDIATE : 0),
  191. connection->fd, connection->reqlen,
  192. &connection->reqbuf,
  193. (connection->flags & CONN_BIGREQBUF) ?
  194. bigBufferSize : CHUNK_SIZE,
  195. httpClientHandler, connection);
  196. }
  197. /* The request has already been validated when it first got
  198. into the queue */
  199. if(connection->request) {
  200. if(connection->request->object != NULL)
  201. httpClientNoticeRequest(connection->request, 1);
  202. else
  203. assert(connection->flags & CONN_READER);
  204. }
  205. return;
  206. }
  207. do_log(D_CLIENT_CONN, "Closing client connection 0x%lx\n",
  208. (unsigned long)connection);
  209. if(connection->flags & CONN_READER) {
  210. httpSetTimeout(connection, 10);
  211. if(connection->fd < 0) return;
  212. if(s >= 2) {
  213. pokeFdEvent(connection->fd, -EDOSHUTDOWN, POLLIN);
  214. } else {
  215. pokeFdEvent(connection->fd, -EDOGRACEFUL, POLLIN);
  216. }
  217. return;
  218. }
  219. while(1) {
  220. HTTPRequestPtr requestee;
  221. request = connection->request;
  222. if(!request)
  223. break;
  224. requestee = request->request;
  225. request->request = NULL;
  226. if(requestee) {
  227. requestee->request = NULL;
  228. httpServerClientReset(requestee);
  229. }
  230. if(request->chandler)
  231. abortConditionHandler(request->chandler);
  232. request->chandler = NULL;
  233. if(request->object && request->object->requestor == request)
  234. request->object->requestor = NULL;
  235. httpDequeueRequest(connection);
  236. httpDestroyRequest(request);
  237. }
  238. httpConnectionDestroyReqbuf(connection);
  239. if(connection->timeout)
  240. cancelTimeEvent(connection->timeout);
  241. connection->timeout = NULL;
  242. if(connection->fd >= 0) {
  243. if(s >= 2)
  244. CLOSE(connection->fd);
  245. else
  246. lingeringClose(connection->fd);
  247. }
  248. connection->fd = -1;
  249. free(connection);
  250. }
  251. /* Extremely baroque implementation of close: we need to synchronise
  252. between the writer and the reader. */
  253. static char client_shutdown_buffer[17];
  254. static int httpClientDelayedShutdownHandler(TimeEventHandlerPtr);
  255. static int
  256. httpClientDelayedShutdown(HTTPConnectionPtr connection)
  257. {
  258. TimeEventHandlerPtr handler;
  259. assert(connection->flags & CONN_READER);
  260. handler = scheduleTimeEvent(1, httpClientDelayedShutdownHandler,
  261. sizeof(connection), &connection);
  262. if(!handler) {
  263. do_log(L_ERROR,
  264. "Couldn't schedule delayed shutdown -- freeing memory.");
  265. free_chunk_arenas();
  266. handler = scheduleTimeEvent(1, httpClientDelayedShutdownHandler,
  267. sizeof(connection), &connection);
  268. if(!handler) {
  269. do_log(L_ERROR,
  270. "Couldn't schedule delayed shutdown -- aborting.\n");
  271. polipoExit();
  272. }
  273. }
  274. return 1;
  275. }
  276. static int
  277. httpClientShutdownHandler(int status,
  278. FdEventHandlerPtr event, StreamRequestPtr request)
  279. {
  280. HTTPConnectionPtr connection = request->data;
  281. assert(connection->flags & CONN_READER);
  282. if(!(connection->flags & CONN_WRITER)) {
  283. connection->flags &= ~CONN_READER;
  284. connection->reqlen = 0;
  285. httpConnectionDestroyReqbuf(connection);
  286. if(status && status != -EDOGRACEFUL)
  287. httpClientFinish(connection, 2);
  288. else
  289. httpClientFinish(connection, 1);
  290. return 1;
  291. }
  292. httpClientDelayedShutdown(connection);
  293. return 1;
  294. }
  295. static int
  296. httpClientDelayedShutdownHandler(TimeEventHandlerPtr event)
  297. {
  298. HTTPConnectionPtr connection = *(HTTPConnectionPtr*)event->data;
  299. assert(connection->flags & CONN_READER);
  300. if(!(connection->flags & CONN_WRITER)) {
  301. connection->flags &= ~CONN_READER;
  302. connection->reqlen = 0;
  303. httpConnectionDestroyReqbuf(connection);
  304. httpClientFinish(connection, 1);
  305. return 1;
  306. }
  307. do_stream(IO_READ | IO_NOTNOW, connection->fd,
  308. 0, client_shutdown_buffer, 17,
  309. httpClientShutdownHandler, connection);
  310. return 1;
  311. }
  312. int
  313. httpClientHandler(int status,
  314. FdEventHandlerPtr event, StreamRequestPtr request)
  315. {
  316. HTTPConnectionPtr connection = request->data;
  317. int i, body;
  318. int bufsize =
  319. (connection->flags & CONN_BIGREQBUF) ? bigBufferSize : CHUNK_SIZE;
  320. assert(connection->flags & CONN_READER);
  321. /* There's no point trying to do something with this request if
  322. the client has shut the connection down -- HTTP doesn't do
  323. half-open connections. */
  324. if(status != 0) {
  325. connection->reqlen = 0;
  326. httpConnectionDestroyReqbuf(connection);
  327. if(!(connection->flags & CONN_WRITER)) {
  328. connection->flags &= ~CONN_READER;
  329. if(status > 0 || status == -ECONNRESET || status == -EDOSHUTDOWN)
  330. httpClientFinish(connection, 2);
  331. else
  332. httpClientFinish(connection, 1);
  333. return 1;
  334. }
  335. httpClientAbort(connection, status > 0 || status == -ECONNRESET);
  336. connection->flags &= ~CONN_READER;
  337. return 1;
  338. }
  339. i = findEndOfHeaders(connection->reqbuf, 0, request->offset, &body);
  340. connection->reqlen = request->offset;
  341. if(i >= 0) {
  342. connection->reqbegin = i;
  343. httpClientHandlerHeaders(event, request, connection);
  344. return 1;
  345. }
  346. if(connection->reqlen >= bufsize) {
  347. int rc = 0;
  348. if(!(connection->flags & CONN_BIGREQBUF))
  349. rc = httpConnectionBigifyReqbuf(connection);
  350. if((connection->flags & CONN_BIGREQBUF) &&
  351. connection->reqlen < bigBufferSize) {
  352. do_stream(IO_READ, connection->fd, connection->reqlen,
  353. connection->reqbuf, bigBufferSize,
  354. httpClientHandler, connection);
  355. return 1;
  356. }
  357. connection->reqlen = 0;
  358. httpConnectionDestroyReqbuf(connection);
  359. if(rc < 0) {
  360. do_log(L_ERROR, "Couldn't allocate big buffer.\n");
  361. httpClientNewError(connection, METHOD_UNKNOWN, 0, 400,
  362. internAtom("Couldn't allocate big buffer"));
  363. } else {
  364. do_log(L_ERROR, "Couldn't find end of client's headers.\n");
  365. httpClientNewError(connection, METHOD_UNKNOWN, 0, 400,
  366. internAtom("Couldn't find end of headers"));
  367. }
  368. return 1;
  369. }
  370. httpSetTimeout(connection, clientTimeout);
  371. return 0;
  372. }
  373. int
  374. httpClientRawErrorHeaders(HTTPConnectionPtr connection,
  375. int code, AtomPtr message,
  376. int close, AtomPtr headers)
  377. {
  378. int fd = connection->fd;
  379. int n;
  380. char *url; int url_len;
  381. char *etag;
  382. assert(connection->flags & CONN_WRITER);
  383. assert(code != 0);
  384. if(close >= 0) {
  385. if(connection->request)
  386. close =
  387. close || !(connection->request->flags & REQUEST_PERSISTENT);
  388. else
  389. close = 1;
  390. }
  391. if(connection->request && connection->request->object) {
  392. url = connection->request->object->key;
  393. url_len = connection->request->object->key_size;
  394. etag = connection->request->object->etag;
  395. } else {
  396. url = NULL;
  397. url_len = 0;
  398. etag = NULL;
  399. }
  400. if(connection->buf == NULL) {
  401. connection->buf = get_chunk();
  402. if(connection->buf == NULL) {
  403. httpClientFinish(connection, 1);
  404. return 1;
  405. }
  406. }
  407. n = httpWriteErrorHeaders(connection->buf, CHUNK_SIZE, 0,
  408. connection->request &&
  409. connection->request->method != METHOD_HEAD,
  410. code, message, close > 0, headers,
  411. url, url_len, etag);
  412. if(n <= 0) {
  413. shutdown(connection->fd, 1);
  414. if(close >= 0)
  415. httpClientFinish(connection, 1);
  416. return 1;
  417. }
  418. httpSetTimeout(connection, clientTimeout);
  419. do_stream(IO_WRITE, fd, 0, connection->buf, n,
  420. close > 0 ? httpErrorStreamHandler :
  421. close == 0 ? httpErrorNocloseStreamHandler :
  422. httpErrorNofinishStreamHandler,
  423. connection);
  424. return 1;
  425. }
  426. int
  427. httpClientRawError(HTTPConnectionPtr connection, int code, AtomPtr message,
  428. int close)
  429. {
  430. return httpClientRawErrorHeaders(connection, code, message, close, NULL);
  431. }
  432. int
  433. httpClientNoticeErrorHeaders(HTTPRequestPtr request, int code, AtomPtr message,
  434. AtomPtr headers)
  435. {
  436. if(request->error_message)
  437. releaseAtom(request->error_message);
  438. if(request->error_headers)
  439. releaseAtom(request->error_headers);
  440. request->error_code = code;
  441. request->error_message = message;
  442. request->error_headers = headers;
  443. httpClientNoticeRequest(request, 0);
  444. return 1;
  445. }
  446. int
  447. httpClientNoticeError(HTTPRequestPtr request, int code, AtomPtr message)
  448. {
  449. return httpClientNoticeErrorHeaders(request, code, message, NULL);
  450. }
  451. int
  452. httpClientError(HTTPRequestPtr request, int code, AtomPtr message)
  453. {
  454. if(request->error_message)
  455. releaseAtom(request->error_message);
  456. request->error_code = code;
  457. request->error_message = message;
  458. if(request->chandler) {
  459. abortConditionHandler(request->chandler);
  460. request->chandler = NULL;
  461. } else if(request->object)
  462. notifyObject(request->object);
  463. return 1;
  464. }
  465. /* This may be called from object handlers. */
  466. int
  467. httpClientLeanError(HTTPRequestPtr request, int code, AtomPtr message)
  468. {
  469. if(request->error_message)
  470. releaseAtom(request->error_message);
  471. request->error_code = code;
  472. request->error_message = message;
  473. return 1;
  474. }
  475. int
  476. httpClientNewError(HTTPConnectionPtr connection, int method, int persist,
  477. int code, AtomPtr message)
  478. {
  479. HTTPRequestPtr request;
  480. request = httpMakeRequest();
  481. if(request == NULL) {
  482. do_log(L_ERROR, "Couldn't allocate error request.\n");
  483. httpClientFinish(connection, 1);
  484. return 1;
  485. }
  486. request->method = method;
  487. if(persist)
  488. request->flags |= REQUEST_PERSISTENT;
  489. else
  490. request->flags &= ~REQUEST_PERSISTENT;
  491. request->error_code = code;
  492. request->error_message = message;
  493. httpQueueRequest(connection, request);
  494. httpClientNoticeRequest(request, 0);
  495. return 1;
  496. }
  497. int
  498. httpErrorStreamHandler(int status,
  499. FdEventHandlerPtr event,
  500. StreamRequestPtr srequest)
  501. {
  502. HTTPConnectionPtr connection = srequest->data;
  503. if(status == 0 && !streamRequestDone(srequest))
  504. return 0;
  505. httpClientFinish(connection, 1);
  506. return 1;
  507. }
  508. int
  509. httpErrorNocloseStreamHandler(int status,
  510. FdEventHandlerPtr event,
  511. StreamRequestPtr srequest)
  512. {
  513. HTTPConnectionPtr connection = srequest->data;
  514. if(status == 0 && !streamRequestDone(srequest))
  515. return 0;
  516. httpClientFinish(connection, 0);
  517. return 1;
  518. }
  519. int
  520. httpErrorNofinishStreamHandler(int status,
  521. FdEventHandlerPtr event,
  522. StreamRequestPtr srequest)
  523. {
  524. if(status == 0 && !streamRequestDone(srequest))
  525. return 0;
  526. return 1;
  527. }
  528. int
  529. httpClientHandlerHeaders(FdEventHandlerPtr event, StreamRequestPtr srequest,
  530. HTTPConnectionPtr connection)
  531. {
  532. HTTPRequestPtr request;
  533. int rc;
  534. int method, version;
  535. AtomPtr url = NULL;
  536. int start;
  537. int code;
  538. AtomPtr message;
  539. start = 0;
  540. /* Work around clients working around NCSA lossage. */
  541. if(connection->reqbuf[0] == '\n')
  542. start = 1;
  543. else if(connection->reqbuf[0] == '\r' && connection->reqbuf[1] == '\n')
  544. start = 2;
  545. httpSetTimeout(connection, -1);
  546. rc = httpParseClientFirstLine(connection->reqbuf, start,
  547. &method, &url, &version);
  548. if(rc <= 0) {
  549. do_log(L_ERROR, "Couldn't parse client's request line\n");
  550. code = 400;
  551. message = internAtom("Error in request line");
  552. goto fail;
  553. }
  554. do_log(D_CLIENT_REQ, "Client request: ");
  555. do_log_n(D_CLIENT_REQ, connection->reqbuf, rc - 1);
  556. do_log(D_CLIENT_REQ, "\n");
  557. if(version != HTTP_10 && version != HTTP_11) {
  558. do_log(L_ERROR, "Unknown client HTTP version\n");
  559. code = 400;
  560. message = internAtom("Error in first request line");
  561. goto fail;
  562. }
  563. if(method == METHOD_UNKNOWN) {
  564. code = 501;
  565. message = internAtom("Method not implemented");
  566. goto fail;
  567. }
  568. request = httpMakeRequest();
  569. if(request == NULL) {
  570. do_log(L_ERROR, "Couldn't allocate client request.\n");
  571. code = 500;
  572. message = internAtom("Couldn't allocate client request");
  573. goto fail;
  574. }
  575. if(connection->version != HTTP_UNKNOWN && version != connection->version) {
  576. do_log(L_WARN, "Client version changed!\n");
  577. }
  578. connection->version = version;
  579. request->flags = REQUEST_PERSISTENT;
  580. request->method = method;
  581. request->cache_control = no_cache_control;
  582. httpQueueRequest(connection, request);
  583. connection->reqbegin = rc;
  584. return httpClientRequest(request, url);
  585. fail:
  586. if(url) releaseAtom(url);
  587. shutdown(connection->fd, 0);
  588. connection->reqlen = 0;
  589. connection->reqbegin = 0;
  590. httpConnectionDestroyReqbuf(connection);
  591. connection->flags &= ~CONN_READER;
  592. httpClientNewError(connection, METHOD_UNKNOWN, 0, code, message);
  593. return 1;
  594. }
  595. static int
  596. httpClientRequestDelayed(TimeEventHandlerPtr event)
  597. {
  598. HTTPRequestPtr request = *(HTTPRequestPtr*)event->data;
  599. AtomPtr url;
  600. url = internAtomN(request->object->key, request->object->key_size);
  601. if(url == NULL) {
  602. do_log(L_ERROR, "Couldn't allocate url.\n");
  603. abortObject(request->object, 503, internAtom("Couldn't allocate url"));
  604. return 1;
  605. }
  606. httpClientRequest(request, url);
  607. return 1;
  608. }
  609. int
  610. delayedHttpClientRequest(HTTPRequestPtr request)
  611. {
  612. TimeEventHandlerPtr event;
  613. event = scheduleTimeEvent(-1, httpClientRequestDelayed,
  614. sizeof(request), &request);
  615. if(!event)
  616. return -1;
  617. return 1;
  618. }
  619. int
  620. httpClientRequest(HTTPRequestPtr request, AtomPtr url)
  621. {
  622. HTTPConnectionPtr connection = request->connection;
  623. int i, rc;
  624. int body_len, body_te;
  625. AtomPtr headers;
  626. CacheControlRec cache_control;
  627. AtomPtr via, expect, auth;
  628. HTTPConditionPtr condition;
  629. HTTPRangeRec range;
  630. assert(!request->chandler);
  631. assert(connection->reqbuf);
  632. i = httpParseHeaders(1, url,
  633. connection->reqbuf, connection->reqbegin, request,
  634. &headers, &body_len,
  635. &cache_control, &condition, &body_te,
  636. NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  637. &expect, &range, NULL, NULL, &via, &auth);
  638. if(i < 0) {
  639. releaseAtom(url);
  640. do_log(L_ERROR, "Couldn't parse client headers.\n");
  641. shutdown(connection->fd, 0);
  642. request->flags &= ~REQUEST_PERSISTENT;
  643. connection->flags &= ~CONN_READER;
  644. httpClientNoticeError(request, 503,
  645. internAtom("Couldn't parse client headers"));
  646. return 1;
  647. }
  648. connection->reqbegin = i;
  649. if(body_len < 0) {
  650. if(request->method == METHOD_GET || request->method == METHOD_HEAD ||
  651. request->method == METHOD_POST || request->method == METHOD_OPTIONS ||
  652. request->method == METHOD_DELETE)
  653. body_len = 0;
  654. }
  655. connection->bodylen = body_len;
  656. connection->reqte = body_te;
  657. if(authRealm) {
  658. AtomPtr message = NULL;
  659. AtomPtr challenge = NULL;
  660. int code = checkClientAuth(auth, url, &message, &challenge);
  661. if(auth) {
  662. releaseAtom(auth);
  663. auth = NULL;
  664. }
  665. if(expect) {
  666. releaseAtom(expect);
  667. expect = NULL;
  668. }
  669. if(code) {
  670. request->flags |= REQUEST_FORCE_ERROR;
  671. httpClientDiscardBody(connection);
  672. httpClientNoticeErrorHeaders(request, code, message, challenge);
  673. return 1;
  674. }
  675. }
  676. if(auth) {
  677. releaseAtom(auth);
  678. auth = NULL;
  679. }
  680. if(expect) {
  681. if(expect == atom100Continue && REQUEST_SIDE(request)) {
  682. request->flags |= REQUEST_WAIT_CONTINUE;
  683. } else {
  684. httpClientDiscardBody(connection);
  685. httpClientNoticeError(request, 417,
  686. internAtom("Expectation failed"));
  687. releaseAtom(expect);
  688. return 1;
  689. }
  690. releaseAtom(expect);
  691. }
  692. request->from = range.from < 0 ? 0 : range.from;
  693. request->to = range.to;
  694. request->cache_control = cache_control;
  695. request->via = via;
  696. request->headers = headers;
  697. request->condition = condition;
  698. request->object = NULL;
  699. if(connection->serviced > 500)
  700. request->flags &= ~REQUEST_PERSISTENT;
  701. if(request->method == METHOD_CONNECT) {
  702. if(connection->flags & CONN_WRITER) {
  703. /* For now */
  704. httpClientDiscardBody(connection);
  705. httpClientNoticeError(request, 500,
  706. internAtom("Pipelined CONNECT "
  707. "not supported"));
  708. return 1;
  709. }
  710. if(connection->flags & CONN_BIGREQBUF) {
  711. /* For now */
  712. httpClientDiscardBody(connection);
  713. httpClientNoticeError(request, 500,
  714. internAtom("CONNECT over big buffer "
  715. "not supported"));
  716. return 1;
  717. }
  718. connection->flags &= ~CONN_READER;
  719. do_tunnel(connection->fd, connection->reqbuf,
  720. connection->reqbegin, connection->reqlen, url);
  721. connection->fd = -1;
  722. connection->reqbuf = NULL;
  723. connection->reqlen = 0;
  724. connection->reqbegin = 0;
  725. httpClientFinish(connection, 2);
  726. return 1;
  727. }
  728. rc = urlForbidden(url, httpClientRequestContinue, request);
  729. if(rc < 0) {
  730. do_log(L_ERROR, "Couldn't schedule httpClientRequestContinue.\n");
  731. httpClientDiscardBody(connection);
  732. httpClientNoticeError(request, 500,
  733. internAtom("Couldn't schedule "
  734. "httpClientRequestContinue"));
  735. return 1;
  736. }
  737. return 1;
  738. }
  739. int
  740. httpClientRequestContinue(int forbidden_code, AtomPtr url,
  741. AtomPtr forbidden_message, AtomPtr forbidden_headers,
  742. void *closure)
  743. {
  744. HTTPRequestPtr request = (HTTPRequestPtr)closure;
  745. HTTPConnectionPtr connection = request->connection;
  746. RequestFunction requestfn;
  747. ObjectPtr object = NULL;
  748. if(forbidden_code < 0) {
  749. releaseAtom(url);
  750. httpClientDiscardBody(connection);
  751. httpClientNoticeError(request, 500,
  752. internAtomError(-forbidden_code,
  753. "Couldn't test for forbidden "
  754. "URL"));
  755. return 1;
  756. }
  757. if(forbidden_code) {
  758. releaseAtom(url);
  759. httpClientDiscardBody(connection);
  760. httpClientNoticeErrorHeaders(request,
  761. forbidden_code, forbidden_message,
  762. forbidden_headers);
  763. return 1;
  764. }
  765. requestfn =
  766. urlIsLocal(url->string, url->length) ?
  767. httpLocalRequest :
  768. httpServerRequest;
  769. if(request->method == METHOD_POST || request->method == METHOD_PUT ||
  770. request->method == METHOD_OPTIONS || request->method == METHOD_DELETE) {
  771. do {
  772. object = findObject(OBJECT_HTTP, url->string, url->length);
  773. if(object) {
  774. privatiseObject(object, 0);
  775. releaseObject(object);
  776. }
  777. } while(object);
  778. request->object = makeObject(OBJECT_HTTP, url->string, url->length,
  779. 0, 0, requestfn, NULL);
  780. if(request->object == NULL) {
  781. httpClientDiscardBody(connection);
  782. httpClientNoticeError(request, 503,
  783. internAtom("Couldn't allocate object"));
  784. return 1;
  785. }
  786. if(requestfn == httpLocalRequest)
  787. request->object->flags |= OBJECT_LOCAL;
  788. return httpClientSideRequest(request);
  789. }
  790. if(request->cache_control.flags & CACHE_AUTHORIZATION) {
  791. do {
  792. object = makeObject(OBJECT_HTTP, url->string, url->length, 0, 0,
  793. requestfn, NULL);
  794. if(object && object->flags != OBJECT_INITIAL) {
  795. if(!(object->cache_control & CACHE_PUBLIC)) {
  796. privatiseObject(object, 0);
  797. releaseObject(object);
  798. object = NULL;
  799. } else
  800. break;
  801. }
  802. } while(object == NULL);
  803. if(object)
  804. object->flags |= OBJECT_LINEAR;
  805. } else {
  806. object = findObject(OBJECT_HTTP, url->string, url->length);
  807. if(!object)
  808. object = makeObject(OBJECT_HTTP, url->string, url->length, 1, 1,
  809. requestfn, NULL);
  810. }
  811. releaseAtom(url);
  812. url = NULL;
  813. if(!object) {
  814. do_log(L_ERROR, "Couldn't allocate object.\n");
  815. httpClientDiscardBody(connection);
  816. httpClientNoticeError(request, 503,
  817. internAtom("Couldn't allocate object"));
  818. return 1;
  819. }
  820. if(object->request == httpLocalRequest) {
  821. object->flags |= OBJECT_LOCAL;
  822. } else {
  823. if(disableProxy) {
  824. httpClientDiscardBody(connection);
  825. httpClientNoticeError(request, 403,
  826. internAtom("Proxying disabled"));
  827. releaseObject(object);
  828. return 1;
  829. }
  830. if(!checkVia(proxyName, request->via)) {
  831. httpClientDiscardBody(connection);
  832. httpClientNoticeError(request, 504,
  833. internAtom("Proxy loop detected"));
  834. releaseObject(object);
  835. return 1;
  836. }
  837. }
  838. request->object = object;
  839. httpClientDiscardBody(connection);
  840. httpClientNoticeRequest(request, 0);
  841. return 1;
  842. }
  843. static int httpClientDelayed(TimeEventHandlerPtr handler);
  844. int
  845. httpClientDiscardBody(HTTPConnectionPtr connection)
  846. {
  847. TimeEventHandlerPtr handler;
  848. assert(connection->reqoffset == 0);
  849. assert(connection->flags & CONN_READER);
  850. if(connection->reqte != TE_IDENTITY)
  851. goto fail;
  852. if(connection->bodylen < 0)
  853. goto fail;
  854. if(connection->bodylen < connection->reqlen - connection->reqbegin) {
  855. connection->reqbegin += connection->bodylen;
  856. connection->bodylen = 0;
  857. } else {
  858. connection->bodylen -= connection->reqlen - connection->reqbegin;
  859. connection->reqbegin = 0;
  860. connection->reqlen = 0;
  861. httpConnectionDestroyReqbuf(connection);
  862. }
  863. connection->reqte = TE_UNKNOWN;
  864. if(connection->bodylen > 0) {
  865. httpSetTimeout(connection, clientTimeout);
  866. do_stream_buf(IO_READ | IO_NOTNOW,
  867. connection->fd, connection->reqlen,
  868. &connection->reqbuf, CHUNK_SIZE,
  869. httpClientDiscardHandler, connection);
  870. return 1;
  871. }
  872. if(connection->reqlen > connection->reqbegin) {
  873. memmove(connection->reqbuf, connection->reqbuf + connection->reqbegin,
  874. connection->reqlen - connection->reqbegin);
  875. connection->reqlen -= connection->reqbegin;
  876. connection->reqbegin = 0;
  877. } else {
  878. connection->reqlen = 0;
  879. connection->reqbegin = 0;
  880. }
  881. httpSetTimeout(connection, clientTimeout);
  882. /* We need to delay in order to make sure the previous request
  883. gets queued on the server side. IO_NOTNOW isn't strong enough
  884. for that due to IO_IMMEDIATE. */
  885. handler = scheduleTimeEvent(-1, httpClientDelayed,
  886. sizeof(connection), &connection);
  887. if(handler == NULL) {
  888. do_log(L_ERROR, "Couldn't schedule reading from client.");
  889. goto fail;
  890. }
  891. return 1;
  892. fail:
  893. connection->reqlen = 0;
  894. connection->reqbegin = 0;
  895. connection->bodylen = 0;
  896. connection->reqte = TE_UNKNOWN;
  897. shutdown(connection->fd, 2);
  898. handler = scheduleTimeEvent(-1, httpClientDelayed,
  899. sizeof(connection), &connection);
  900. if(handler == NULL) {
  901. do_log(L_ERROR, "Couldn't schedule reading from client.");
  902. connection->flags &= ~CONN_READER;
  903. }
  904. return 1;
  905. }
  906. static int
  907. httpClientDelayed(TimeEventHandlerPtr event)
  908. {
  909. HTTPConnectionPtr connection = *(HTTPConnectionPtr*)event->data;
  910. /* IO_NOTNOW is unfortunate, but needed to avoid starvation if a
  911. client is pipelining a lot of requests. */
  912. if(connection->reqlen > 0) {
  913. int bufsize;
  914. if((connection->flags & CONN_BIGREQBUF) &&
  915. connection->reqlen < CHUNK_SIZE)
  916. httpConnectionUnbigifyReqbuf(connection);
  917. /* Don't read new requests if buffer is big. */
  918. bufsize = (connection->flags & CONN_BIGREQBUF) ?
  919. connection->reqlen : CHUNK_SIZE;
  920. do_stream(IO_READ | IO_IMMEDIATE | IO_NOTNOW,
  921. connection->fd, connection->reqlen,
  922. connection->reqbuf, bufsize,
  923. httpClientHandler, connection);
  924. } else {
  925. httpConnectionDestroyReqbuf(connection);
  926. do_stream_buf(IO_READ | IO_NOTNOW,
  927. connection->fd, 0,
  928. &connection->reqbuf, CHUNK_SIZE,
  929. httpClientHandler, connection);
  930. }
  931. return 1;
  932. }
  933. int
  934. httpClientDiscardHandler(int status,
  935. FdEventHandlerPtr event, StreamRequestPtr request)
  936. {
  937. HTTPConnectionPtr connection = request->data;
  938. assert(connection->flags & CONN_READER);
  939. if(status) {
  940. if(status < 0 && status != -EPIPE && status != -ECONNRESET)
  941. do_log_error(L_ERROR, -status, "Couldn't read from client");
  942. connection->bodylen = -1;
  943. return httpClientDiscardBody(connection);
  944. }
  945. assert(request->offset > connection->reqlen);
  946. connection->reqlen = request->offset;
  947. httpClientDiscardBody(connection);
  948. return 1;
  949. }
  950. int
  951. httpClientNoticeRequest(HTTPRequestPtr request, int novalidate)
  952. {
  953. HTTPConnectionPtr connection = request->connection;
  954. ObjectPtr object = request->object;
  955. int serveNow = (request == connection->request);
  956. int validate = 0;
  957. int conditional = 0;
  958. int local, haveData;
  959. int rc;
  960. assert(!request->chandler);
  961. if(request->error_code) {
  962. if((request->flags & REQUEST_FORCE_ERROR) || REQUEST_SIDE(request) ||
  963. request->object == NULL ||
  964. (request->object->flags & OBJECT_LOCAL) ||
  965. (request->object->flags & OBJECT_ABORTED) ||
  966. (relaxTransparency < 1 && !proxyOffline)) {
  967. if(serveNow) {
  968. connection->flags |= CONN_WRITER;
  969. return httpClientRawErrorHeaders(connection,
  970. request->error_code,
  971. retainAtom(request->
  972. error_message),
  973. 0, request->error_headers);
  974. } else {
  975. return 1;
  976. }
  977. }
  978. }
  979. if(REQUEST_SIDE(request)) {
  980. assert(!(request->flags & REQUEST_REQUESTED));
  981. if(serveNow) {
  982. assert(!request->chandler);
  983. request->chandler =
  984. conditionWait(&request->object->condition,
  985. httpClientGetHandler,
  986. sizeof(request), &request);
  987. if(request->chandler == NULL) {
  988. do_log(L_ERROR, "Couldn't register condition handler.\n");
  989. connection->flags |= CONN_WRITER;
  990. httpClientRawError(connection, 500,
  991. internAtom("Couldn't register "
  992. "condition handler"),
  993. 0);
  994. return 1;
  995. }
  996. connection->flags |= CONN_WRITER;
  997. rc = object->request(request->object,
  998. request->method,
  999. request->from, request->to,
  1000. request,
  1001. request->object->request_closure);
  1002. }
  1003. return 1;
  1004. }
  1005. local = urlIsLocal(object->key, object->key_size);
  1006. objectFillFromDisk(object, request->from,
  1007. request->method == METHOD_HEAD ? 0 : 1);
  1008. /* The spec doesn't strictly forbid 206 for non-200 instances, but doing
  1009. that breaks some client software. */
  1010. if(object->code && object->code != 200) {
  1011. request->from = 0;
  1012. request->to = -1;
  1013. }
  1014. if(request->condition && request->condition->ifrange) {
  1015. if(!object->etag ||
  1016. strcmp(object->etag, request->condition->ifrange) != 0) {
  1017. request->from = 0;
  1018. request->to = -1;
  1019. }
  1020. }
  1021. if(object->flags & OBJECT_DYNAMIC) {
  1022. request->from = 0;
  1023. request->to = -1;
  1024. }
  1025. if(request->method == METHOD_HEAD)
  1026. haveData = !(request->object->flags & OBJECT_INITIAL);
  1027. else
  1028. haveData =
  1029. (request->object->length >= 0 &&
  1030. request->object->length <= request->from) ||
  1031. (objectHoleSize(request->object, request->from) == 0);
  1032. if(request->flags & REQUEST_REQUESTED)
  1033. validate = 0;
  1034. else if(novalidate || (!local && proxyOffline))
  1035. validate = 0;
  1036. else if(local)
  1037. validate =
  1038. objectMustRevalidate(request->object, &request->cache_control);
  1039. else if(request->cache_control.flags & CACHE_ONLY_IF_CACHED)
  1040. validate = 0;
  1041. else if((request->object->flags & OBJECT_FAILED) &&
  1042. !(object->flags & OBJECT_INPROGRESS) &&
  1043. !relaxTransparency)
  1044. validate = 1;
  1045. else if(request->method != METHOD_HEAD &&
  1046. !objectHasData(object, request->from, request->to) &&
  1047. !(object->flags & OBJECT_INPROGRESS))
  1048. validate = 1;
  1049. else if(objectMustRevalidate((relaxTransparency <= 1 ?
  1050. request->object : NULL),
  1051. &request->cache_control))
  1052. validate = 1;
  1053. else
  1054. validate = 0;
  1055. if(request->cache_control.flags & CACHE_ONLY_IF_CACHED) {
  1056. validate = 0;
  1057. if(!haveData) {
  1058. if(serveNow) {
  1059. connection->flags |= CONN_WRITER;
  1060. return httpClientRawError(connection, 504,
  1061. internAtom("Object not in cache"),
  1062. 0);
  1063. } else
  1064. return 1;
  1065. }
  1066. }
  1067. if(!(request->object->flags & OBJECT_VALIDATING) &&
  1068. ((!validate && haveData) ||
  1069. (request->object->flags & OBJECT_FAILED))) {
  1070. if(serveNow) {
  1071. connection->flags |= CONN_WRITER;
  1072. lockChunk(request->object, request->from / CHUNK_SIZE);
  1073. return httpServeObject(connection);
  1074. } else {
  1075. return 1;
  1076. }
  1077. }
  1078. if((request->flags & REQUEST_REQUESTED) &&
  1079. !(request->object->flags & OBJECT_INPROGRESS)) {
  1080. /* This can happen either because the server side ran out of
  1081. memory, or because it is using HEAD validation. We mark
  1082. the object to be fetched again. */
  1083. request->flags &= ~REQUEST_REQUESTED;
  1084. }
  1085. if(serveNow) {
  1086. connection->flags |= CONN_WRITER;
  1087. if(!local && proxyOffline)
  1088. return httpClientRawError(connection, 502,
  1089. internAtom("Disconnected operation "
  1090. "and object not in cache"),
  1091. 0);
  1092. request->chandler =
  1093. conditionWait(&request->object->condition, httpClientGetHandler,
  1094. sizeof(request), &request);
  1095. if(request->chandler == NULL) {
  1096. do_log(L_ERROR, "Couldn't register condition handler.\n");
  1097. return httpClientRawError(connection, 503,
  1098. internAtom("Couldn't register "
  1099. "condition handler"), 0);
  1100. }
  1101. }
  1102. if(request->object->flags & OBJECT_VALIDATING)
  1103. return 1;
  1104. conditional = (haveData && request->method == METHOD_GET);
  1105. if(!mindlesslyCacheVary && (request->object->cache_control & CACHE_VARY))
  1106. conditional = conditional && (request->object->etag != NULL);
  1107. conditional =
  1108. conditional && !(request->object->cache_control & CACHE_MISMATCH);
  1109. if(!(request->object->flags & OBJECT_INPROGRESS))
  1110. request->object->flags |= OBJECT_VALIDATING;
  1111. rc = request->object->request(request->object,
  1112. conditional ? METHOD_CONDITIONAL_GET :
  1113. request->method,
  1114. request->from, request->to, request,
  1115. request->object->request_closure);
  1116. if(rc < 0) {
  1117. if(request->chandler)
  1118. unregisterConditionHandler(request->chandler);
  1119. request->chandler = NULL;
  1120. request->object->flags &= ~OBJECT_VALIDATING;
  1121. request->object->flags |= OBJECT_FAILED;
  1122. if(request->error_message)
  1123. releaseAtom(request->error_message);
  1124. request->error_code = 503;
  1125. request->error_message = internAtom("Couldn't schedule get");
  1126. }
  1127. return 1;
  1128. }
  1129. static int
  1130. httpClientNoticeRequestDelayed(TimeEventHandlerPtr event)
  1131. {
  1132. HTTPRequestPtr request = *(HTTPRequestPtr*)event->data;
  1133. httpClientNoticeRequest(request, 0);
  1134. return 1;
  1135. }
  1136. int
  1137. delayedHttpClientNoticeRequest(HTTPRequestPtr request)
  1138. {
  1139. TimeEventHandlerPtr event;
  1140. event = scheduleTimeEvent(-1, httpClientNoticeRequestDelayed,
  1141. sizeof(request), &request);
  1142. if(!event)
  1143. return -1;
  1144. return 1;
  1145. }
  1146. int
  1147. httpClientContinueDelayed(TimeEventHandlerPtr event)
  1148. {
  1149. static char httpContinue[] = "HTTP/1.1 100 Continue\r\n\r\n";
  1150. HTTPConnectionPtr connection = *(HTTPConnectionPtr*)event->data;
  1151. do_stream(IO_WRITE, connection->fd, 0, httpContinue, 25,
  1152. httpErrorNofinishStreamHandler, connection);
  1153. return 1;
  1154. }
  1155. int
  1156. delayedHttpClientContinue(HTTPConnectionPtr connection)
  1157. {
  1158. TimeEventHandlerPtr event;
  1159. event = scheduleTimeEvent(-1, httpClientContinueDelayed,
  1160. sizeof(connection), &connection);
  1161. if(!event)
  1162. return -1;
  1163. return 1;
  1164. }
  1165. int
  1166. httpClientGetHandler(int status, ConditionHandlerPtr chandler)
  1167. {
  1168. HTTPRequestPtr request = *(HTTPRequestPtr*)chandler->data;
  1169. HTTPConnectionPtr connection = request->connection;
  1170. ObjectPtr object = request->object;
  1171. int rc;
  1172. assert(request == connection->request);
  1173. if(request->request) {
  1174. assert(request->object->flags & OBJECT_INPROGRESS);
  1175. assert(!request->request->object ||
  1176. request->request->object == request->object);
  1177. }
  1178. if(status < 0) {
  1179. object->flags &= ~OBJECT_VALIDATING; /* for now */
  1180. if(request->request && request->request->request == request)
  1181. httpServerClientReset(request->request);
  1182. lockChunk(object, request->from / CHUNK_SIZE);
  1183. request->chandler = NULL;
  1184. rc = delayedHttpServeObject(connection);
  1185. if(rc < 0) {
  1186. unlockChunk(object, request->from / CHUNK_SIZE);
  1187. do_log(L_ERROR, "Couldn't schedule serving.\n");
  1188. abortObject(object, 503, internAtom("Couldn't schedule serving"));
  1189. }
  1190. return 1;
  1191. }
  1192. if(object->flags & OBJECT_VALIDATING)
  1193. return 0;
  1194. if(request->error_code) {
  1195. lockChunk(object, request->from / CHUNK_SIZE);
  1196. request->chandler = NULL;
  1197. rc = delayedHttpServeObject(connection);
  1198. if(rc < 0) {
  1199. unlockChunk(object, request->from / CHUNK_SIZE);
  1200. do_log(L_ERROR, "Couldn't schedule serving.\n");
  1201. abortObject(object, 503, internAtom("Couldn't schedule serving"));
  1202. }
  1203. return 1;
  1204. }
  1205. if(request->flags & REQUEST_WAIT_CONTINUE) {
  1206. if(request->request &&
  1207. !(request->request->flags & REQUEST_WAIT_CONTINUE)) {
  1208. request->flags &= ~REQUEST_WAIT_CONTINUE;
  1209. delayedHttpClientContinue(connection);
  1210. }
  1211. return 0;
  1212. }
  1213. /* See httpServerHandlerHeaders */
  1214. if((object->flags & OBJECT_SUPERSEDED) &&
  1215. /* Avoid superseding loops. */
  1216. !(request->flags & REQUEST_SUPERSEDED) &&
  1217. request->request && request->request->can_mutate) {
  1218. ObjectPtr new_object = retainObject(request->request->can_mutate);
  1219. if(object->requestor == request) {
  1220. if(new_object->requestor == NULL)
  1221. new_object->requestor = request;
  1222. object->requestor = NULL;
  1223. /* Avoid superseding the same request more than once. */
  1224. request->flags |= REQUEST_SUPERSEDED;
  1225. }
  1226. request->chandler = NULL;
  1227. releaseObject(object);
  1228. request->object = new_object;
  1229. request->request->object = new_object;
  1230. /* We're handling the wrong object now. It's simpler to
  1231. rebuild the whole data structure from scratch rather than
  1232. trying to compensate. */
  1233. rc = delayedHttpClientNoticeRequest(request);
  1234. if(rc < 0) {
  1235. do_log(L_ERROR, "Couldn't schedule noticing of request.");
  1236. abortObject(object, 500,
  1237. internAtom("Couldn't schedule "
  1238. "noticing of request"));
  1239. /* We're probably out of memory. What can we do? */
  1240. shutdown(connection->fd, 1);
  1241. }
  1242. return 1;
  1243. }
  1244. if(object->requestor != request && !(object->flags & OBJECT_ABORTED)) {
  1245. /* Make sure we don't serve an object that is stale for us
  1246. unless we're the requestor. */
  1247. if((object->flags & (OBJECT_LINEAR | OBJECT_MUTATING)) ||
  1248. objectMustRevalidate(object, &request->cache_control)) {
  1249. if(object->flags & OBJECT_INPROGRESS)
  1250. return 0;
  1251. rc = delayedHttpClientNoticeRequest(request);
  1252. if(rc < 0) {
  1253. do_log(L_ERROR, "Couldn't schedule noticing of request.");
  1254. abortObject(object, 500,
  1255. internAtom("Couldn't schedule "
  1256. "noticing of request"));
  1257. } else {
  1258. request->chandler = NULL;
  1259. return 1;
  1260. }
  1261. }
  1262. }
  1263. if(object->flags & (OBJECT_INITIAL | OBJECT_VALIDATING)) {
  1264. if(object->flags & (OBJECT_INPROGRESS | OBJECT_VALIDATING)) {
  1265. return 0;
  1266. } else if(object->flags & OBJECT_FAILED) {
  1267. if(request->error_code)
  1268. abortObject(object,
  1269. request->error_code,
  1270. retainAtom(request->error_message));
  1271. else {
  1272. abortObject(object, 500,
  1273. internAtom("Error message lost in transit"));
  1274. }
  1275. } else {
  1276. /* The request was pruned by httpServerDiscardRequests */
  1277. if(chandler == request->chandler) {
  1278. int rc;
  1279. request->chandler = NULL;
  1280. rc = delayedHttpClientNoticeRequest(request);
  1281. if(rc < 0)
  1282. abortObject(object, 500,
  1283. internAtom("Couldn't allocate "
  1284. "delayed notice request"));
  1285. else
  1286. return 1;
  1287. } else {
  1288. abortObject(object, 500,
  1289. internAtom("Wrong request pruned -- "
  1290. "this shouldn't happen"));
  1291. }
  1292. }
  1293. }
  1294. if(request->object->flags & OBJECT_DYNAMIC) {
  1295. if(objectHoleSize(request->object, 0) == 0) {
  1296. request->from = 0;
  1297. request->to = -1;
  1298. } else {
  1299. /* We really should request again if that is not the case */
  1300. }
  1301. }
  1302. lockChunk(object, request->from / CHUNK_SIZE);
  1303. request->chandler = NULL;
  1304. rc = delayedHttpServeObject(connection);
  1305. if(rc < 0) {
  1306. unlockChunk(object, request->from / CHUNK_SIZE);
  1307. do_log(L_ERROR, "Couldn't schedule serving.\n");
  1308. abortObject(object, 503, internAtom("Couldn't schedule serving"));
  1309. }
  1310. return 1;
  1311. }
  1312. int
  1313. httpClientSideRequest(HTTPRequestPtr request)
  1314. {
  1315. HTTPConnectionPtr connection = request->connection;
  1316. if(request->from < 0 || request->to >= 0) {
  1317. httpClientNoticeError(request, 501,
  1318. internAtom("Partial requests not implemented"));
  1319. httpClientDiscardBody(connection);
  1320. return 1;
  1321. }
  1322. if(connection->reqte != TE_IDENTITY) {
  1323. httpClientNoticeError(request, 501,
  1324. internAtom("Chunked requests not implemented"));
  1325. httpClientDiscardBody(connection);
  1326. return 1;
  1327. }
  1328. if(connection->bodylen < 0) {
  1329. httpClientNoticeError(request, 502,
  1330. internAtom("POST or PUT without "
  1331. "Content-Length"));
  1332. httpClientDiscardBody(connection);
  1333. return 1;
  1334. }
  1335. if(connection->reqlen < 0) {
  1336. httpClientNoticeError(request, 502,
  1337. internAtom("Incomplete POST or PUT"));
  1338. httpClientDiscardBody(connection);
  1339. return 1;
  1340. }
  1341. return httpClientNoticeRequest(request, 0);
  1342. }
  1343. int
  1344. httpClientSideHandler(int status,
  1345. FdEventHandlerPtr event,
  1346. StreamRequestPtr srequest)
  1347. {
  1348. HTTPConnectionPtr connection = srequest->data;
  1349. HTTPRequestPtr request = connection->request;
  1350. HTTPRequestPtr requestee;
  1351. HTTPConnectionPtr server;
  1352. int push;
  1353. int code;
  1354. AtomPtr message = NULL;
  1355. assert(connection->flags & CONN_SIDE_READER);
  1356. if((request->object->flags & OBJECT_ABORTED) ||
  1357. !(request->object->flags & OBJECT_INPROGRESS)) {
  1358. code = request->object->code;
  1359. message = retainAtom(request->object->message);
  1360. goto fail;
  1361. }
  1362. if(status < 0) {
  1363. do_log_error(L_ERROR, -status, "Reading from client");
  1364. code = 502;
  1365. message = internAtomError(-status, "Couldn't read from client");
  1366. goto fail;
  1367. }
  1368. requestee = request->request;
  1369. server = requestee->connection;
  1370. push = MIN(srequest->offset - connection->reqlen,
  1371. connection->bodylen - connection->reqoffset);
  1372. if(push > 0) {
  1373. connection->reqlen += push;
  1374. httpServerDoSide(server);
  1375. return 1;
  1376. }
  1377. if(server->reqoffset >= connection->bodylen) {
  1378. connection->flags &= ~(CONN_READER | CONN_SIDE_READER);
  1379. return 1;
  1380. }
  1381. assert(status);
  1382. do_log(L_ERROR, "Incomplete client request.\n");
  1383. code = 502;
  1384. message = internAtom("Incomplete client request");
  1385. fail:
  1386. request->error_code = code;
  1387. if(request->error_message)
  1388. releaseAtom(request->error_message);
  1389. request->error_message = message;
  1390. if(request->error_headers)
  1391. releaseAtom(request->error_headers);
  1392. request->error_headers = NULL;
  1393. if(request->request) {
  1394. shutdown(request->request->connection->fd, 2);
  1395. pokeFdEvent(request->request->connection->fd, -ESHUTDOWN, POLLOUT);
  1396. }
  1397. notifyObject(request->object);
  1398. connection->flags &= ~CONN_SIDE_READER;
  1399. httpClientDiscardBody(connection);
  1400. return 1;
  1401. }
  1402. int
  1403. httpServeObject(HTTPConnectionPtr connection)
  1404. {
  1405. HTTPRequestPtr request = connection->request;
  1406. ObjectPtr object = request->object;
  1407. int i = request->from / CHUNK_SIZE;
  1408. int j = request->from % CHUNK_SIZE;
  1409. int n, len, rc;
  1410. int bufsize = CHUNK_SIZE;
  1411. int condition_result;
  1412. object->atime = current_time.tv_sec;
  1413. objectMetadataChanged(object, 0);
  1414. httpSetTimeout(connection, -1);
  1415. if((request->error_code && relaxTransparency <= 0) ||
  1416. object->flags & OBJECT_INITIAL) {
  1417. object->flags &= ~OBJECT_FAILED;
  1418. unlockChunk(object, i);
  1419. if(request->error_code)
  1420. return httpClientRawError(connection,
  1421. request->error_code,
  1422. retainAtom(request->error_message), 0);
  1423. else
  1424. return httpClientRawError(connection,
  1425. 500, internAtom("Object vanished."), 0);
  1426. }
  1427. if(!(object->flags & OBJECT_INPROGRESS) && object->code == 0) {
  1428. if(object->flags & OBJECT_INITIAL) {
  1429. unlockChunk(object, i);
  1430. return httpClientRawError(connection, 503,
  1431. internAtom("Error message lost"), 0);
  1432. } else {
  1433. unlockChunk(object, i);
  1434. do_log(L_ERROR, "Internal proxy error: object has no code.\n");
  1435. return httpClientRawError(connection, 500,
  1436. internAtom("Internal proxy error: "
  1437. "object has no code"), 0);
  1438. }
  1439. }
  1440. condition_result = httpCondition(object, request->condition);
  1441. if(condition_result == CONDITION_FAILED) {
  1442. unlockChunk(object, i);
  1443. return httpClientRawError(connection, 412,
  1444. internAtom("Precondition failed"), 0);
  1445. } else if(condition_result == CONDITION_NOT_MODIFIED) {
  1446. unlockChunk(object, i);
  1447. return httpClientRawError(connection, 304,
  1448. internAtom("Not modified"), 0);
  1449. }
  1450. objectFillFromDisk(object, request->from,
  1451. (request->method == METHOD_HEAD ||
  1452. condition_result != CONDITION_MATCH) ? 0 : 1);
  1453. if(((object->flags & OBJECT_LINEAR) &&
  1454. (object->requestor != connection->request)) ||
  1455. ((object->flags & OBJECT_SUPERSEDED) &&
  1456. !(object->flags & OBJECT_LINEAR))) {
  1457. if(request->request) {
  1458. request->request->request = NULL;
  1459. request->request = NULL;
  1460. request->object->requestor = NULL;
  1461. }
  1462. object = makeObject(OBJECT_HTTP,
  1463. object->key, object->key_size, 1, 0,
  1464. object->request, NULL);
  1465. if(request->object->requestor == request)
  1466. request->object->requestor = NULL;
  1467. unlockChunk(request->object, i);
  1468. releaseObject(request->object);
  1469. request->object = NULL;
  1470. if(object == NULL) {
  1471. do_log(L_ERROR, "Couldn't allocate object.");
  1472. return httpClientRawError(connection, 501,
  1473. internAtom("Couldn't allocate object"),
  1474. 1);
  1475. }
  1476. if(urlIsLocal(object->key, object->key_size)) {
  1477. object->flags |= OBJECT_LOCAL;
  1478. object->request = httpLocalRequest;
  1479. }
  1480. request->object = object;
  1481. connection->flags &= ~CONN_WRITER;
  1482. return httpClientNoticeRequest(request, 1);
  1483. }
  1484. if(object->flags & OBJECT_ABORTED) {
  1485. unlockChunk(object, i);
  1486. return httpClientNoticeError(request, object->code,
  1487. retainAtom(object->message));
  1488. }
  1489. if(connection->buf == NULL)
  1490. connection->buf = get_chunk();
  1491. if(connection->buf == NULL) {
  1492. unlockChunk(object, i);
  1493. do_log(L_ERROR, "Couldn't allocate client buffer.\n");
  1494. connection->flags &= ~CONN_WRITER;
  1495. httpClientFinish(connection, 1);
  1496. return 1;
  1497. }
  1498. if(object->length >= 0 && request->to >= object->length)
  1499. request->to = object->length;
  1500. if(request->from > 0 || request->to >= 0) {
  1501. if(request->method == METHOD_HEAD) {
  1502. request->to = request->from;
  1503. } else if(request->to < 0) {
  1504. if(object->length >= 0)
  1505. request->to = object->length;
  1506. }
  1507. }
  1508. again:
  1509. connection->len = 0;
  1510. if((request->from <= 0 && request->to < 0) ||
  1511. request->method == METHOD_HEAD) {
  1512. n = snnprintf(connection->buf, 0, bufsize,
  1513. "HTTP/1.1 %d %s",
  1514. object->code, atomString(object->message));
  1515. } else {
  1516. if((object->length >= 0 && request->from >= object->length) ||
  1517. (request->to >= 0 && request->from >= request->to)) {
  1518. unlockChunk(object, i);
  1519. return httpClientRawError(connection, 416,
  1520. internAtom("Requested range "
  1521. "not satisfiable"),
  1522. 0);
  1523. } else {
  1524. n = snnprintf(connection->buf, 0, bufsize,
  1525. "HTTP/1.1 206 Partial content");
  1526. }
  1527. }
  1528. n = httpWriteObjectHeaders(connection->buf, n, bufsize,
  1529. object, request->from, request->to);
  1530. if(n < 0)
  1531. goto fail;
  1532. if(request->method != METHOD_HEAD &&
  1533. condition_result != CONDITION_NOT_MODIFIED &&
  1534. request->to < 0 && object->length < 0) {
  1535. if(connection->version == HTTP_11) {
  1536. connection->te = TE_CHUNKED;
  1537. n = snnprintf(connection->buf, n, bufsize,
  1538. "\r\nTransfer-Encoding: chunked");
  1539. } else {
  1540. request->flags &= ~REQUEST_PERSISTENT;
  1541. }
  1542. }
  1543. if(object->age < current_time.tv_sec) {
  1544. n = snnprintf(connection->buf, n, bufsize,
  1545. "\r\nAge: %d",
  1546. (int)(current_time.tv_sec - object->age));
  1547. }
  1548. n = snnprintf(connection->buf, n, bufsize,
  1549. "\r\nConnection: %s",
  1550. (request->flags & REQUEST_PERSISTENT) ?
  1551. "keep-alive" : "close");
  1552. if(!(object->flags & OBJECT_LOCAL)) {
  1553. if((object->flags & OBJECT_FAILED) && !proxyOffline) {
  1554. n = snnprintf(connection->buf, n, bufsize,
  1555. "\r\nWarning: 111 %s:%d \"Revalidation failed\"",
  1556. proxyName->string, proxyPort);
  1557. if(request->error_code)
  1558. n = snnprintf(connection->buf, n, bufsize,
  1559. " (%d %s)",
  1560. request->error_code,
  1561. atomString(request->error_message));
  1562. object->flags &= ~OBJECT_FAILED;
  1563. } else if(proxyOffline &&
  1564. objectMustRevalidate(object, &request->cache_control)) {
  1565. n = snnprintf(connection->buf, n, bufsize,
  1566. "\r\nWarning: 112 %s:%d \"Disconnected operation\"",
  1567. proxyName->string, proxyPort);
  1568. } else if(objectIsStale(object, &request->cache_control)) {
  1569. n = snnprintf(connection->buf, n, bufsize,
  1570. "\r\nWarning: 110 %s:%d \"Object is stale\"",
  1571. proxyName->string, proxyPort);
  1572. } else if(object->expires < 0 && object->max_age < 0 &&
  1573. object->age < current_time.tv_sec - 24 * 3600) {
  1574. n = snnprintf(connection->buf, n, bufsize,
  1575. "\r\nWarning: 113 %s:%d \"Heuristic expiration\"",
  1576. proxyName->string, proxyPort);
  1577. }
  1578. }
  1579. n = snnprintf(connection->buf, n, bufsize, "\r\n\r\n");
  1580. if(n < 0)
  1581. goto fail;
  1582. connection->offset = request->from;
  1583. if(request->method == METHOD_HEAD ||
  1584. condition_result == CONDITION_NOT_MODIFIED ||
  1585. (object->flags & OBJECT_ABORTED)) {
  1586. len = 0;
  1587. } else {
  1588. if(i < object->numchunks) {
  1589. if(object->chunks[i].size <= j)
  1590. len = 0;
  1591. else
  1592. len = object->chunks[i].size - j;
  1593. } else {
  1594. len = 0;
  1595. }
  1596. if(request->to >= 0)
  1597. len = MIN(len, request->to - request->from);
  1598. }
  1599. connection->offset = request->from;
  1600. httpSetTimeout(connection, clientTimeout);
  1601. do_log(D_CLIENT_DATA, "Serving on 0x%lx for 0x%lx: offset %d len %d\n",
  1602. (unsigned long)connection, (unsigned long)object,
  1603. connection->offset, len);
  1604. do_stream_h(IO_WRITE |
  1605. (connection->te == TE_CHUNKED && len > 0 ? IO_CHUNKED : 0),
  1606. connection->fd, 0,
  1607. connection->buf, n,
  1608. object->chunks[i].data + j, len,
  1609. httpServeObjectStreamHandler, connection);
  1610. return 1;
  1611. fail:
  1612. rc = 0;
  1613. connection->len = 0;
  1614. if(!(connection->flags & CONN_BIGBUF))
  1615. rc = httpConnectionBigify(connection);
  1616. if(rc > 0) {
  1617. bufsize = bigBufferSize;
  1618. goto again;
  1619. }
  1620. unlockChunk(object, i);
  1621. return httpClientRawError(connection, 500,
  1622. rc == 0 ?
  1623. internAtom("No space for headers") :
  1624. internAtom("Couldn't allocate big buffer"), 0);
  1625. }
  1626. static int
  1627. httpServeObjectDelayed(TimeEventHandlerPtr event)
  1628. {
  1629. HTTPConnectionPtr connection = *(HTTPConnectionPtr*)event->data;
  1630. httpServeObject(connection);
  1631. return 1;
  1632. }
  1633. int
  1634. delayedHttpServeObject(HTTPConnectionPtr connection)
  1635. {
  1636. TimeEventHandlerPtr event;
  1637. assert(connection->request->object->chunks[connection->request->from /
  1638. CHUNK_SIZE].locked > 0);
  1639. event = scheduleTimeEvent(-1, httpServeObjectDelayed,
  1640. sizeof(connection), &connection);
  1641. if(!event) return -1;
  1642. return 1;
  1643. }
  1644. static int
  1645. httpServeObjectFinishHandler(int status,
  1646. FdEventHandlerPtr event,
  1647. StreamRequestPtr srequest)
  1648. {
  1649. HTTPConnectionPtr connection = srequest->data;
  1650. HTTPRequestPtr request = connection->request;
  1651. (void)request;
  1652. assert(!request->chandler);
  1653. if(status == 0 && !streamRequestDone(srequest))
  1654. return 0;
  1655. httpSetTimeout(connection, -1);
  1656. if(status < 0) {
  1657. do_log(L_ERROR, "Couldn't terminate chunked reply\n");
  1658. httpClientFinish(connection, 1);
  1659. } else {
  1660. httpClientFinish(connection, 0);
  1661. }
  1662. return 1;
  1663. }
  1664. int
  1665. httpServeChunk(HTTPConnectionPtr connection)
  1666. {
  1667. HTTPRequestPtr request = connection->request;
  1668. ObjectPtr object = request->object;
  1669. int i = connection->offset / CHUNK_SIZE;
  1670. int j = connection->offset - (i * CHUNK_SIZE);
  1671. int to, len, len2, end;
  1672. int rc;
  1673. /* This must be called with chunk i locked. */
  1674. assert(object->chunks[i].locked > 0);
  1675. if(object->flags & OBJECT_ABORTED)
  1676. goto fail;
  1677. if(object->length >= 0 && request->to >= 0)
  1678. to = MIN(request->to, object->length);
  1679. else if(object->length >= 0)
  1680. to = object->length;
  1681. else if(request->to >= 0)
  1682. to = request->to;
  1683. else
  1684. to = -1;
  1685. len = 0;
  1686. if(i < object->numchunks)
  1687. len = object->chunks[i].size - j;
  1688. if(request->method != METHOD_HEAD &&
  1689. len < CHUNK_SIZE && connection->offset + len < to) {
  1690. objectFillFromDisk(object, connection->offset + len, 2);
  1691. len = object->chunks[i].size - j;
  1692. }
  1693. if(to >= 0)
  1694. len = MIN(len, to - connection->offset);
  1695. if(len <= 0) {
  1696. if(to >= 0 && connection->offset >= to) {
  1697. if(request->chandler) {
  1698. unregisterConditionHandler(request->chandler);
  1699. request->chandler = NULL;
  1700. }
  1701. unlockChunk(object, i);
  1702. if(connection->te == TE_CHUNKED) {
  1703. httpSetTimeout(connection, clientTimeout);
  1704. do_stream(IO_WRITE | IO_CHUNKED | IO_END,
  1705. connection->fd, 0, NULL, 0,
  1706. httpServeObjectFinishHandler, connection);
  1707. } else {
  1708. httpClientFinish(connection,
  1709. !(object->length >= 0 &&
  1710. connection->offset >= object->length));
  1711. }
  1712. return 1;
  1713. } else {
  1714. if(!request->chandler) {
  1715. request->chandler =
  1716. conditionWait(&object->condition,
  1717. httpServeObjectHandler,
  1718. sizeof(connection), &connection);
  1719. if(!request->chandler) {
  1720. do_log(L_ERROR, "Couldn't register condition handler\n");
  1721. goto fail;
  1722. }
  1723. }
  1724. if(!(object->flags & OBJECT_INPROGRESS)) {
  1725. if(object->flags & OBJECT_SUPERSEDED) {
  1726. goto fail;
  1727. }
  1728. if(REQUEST_SIDE(request)) goto fail;
  1729. rc = object->request(object, request->method,
  1730. connection->offset, -1, request,
  1731. object->request_closure);
  1732. if(rc <= 0) goto fail;
  1733. }
  1734. return 1;
  1735. }
  1736. } else {
  1737. /* len > 0 */
  1738. if(request->method != METHOD_HEAD)
  1739. objectFillFromDisk(object, (i + 1) * CHUNK_SIZE, 1);
  1740. if(request->chandler) {
  1741. unregisterConditionHandler(request->chandler);
  1742. request->chandler = NULL;
  1743. }
  1744. len2 = 0;
  1745. if(j + len == CHUNK_SIZE && object->numchunks > i + 1) {
  1746. len2 = object->chunks[i + 1].size;
  1747. if(to >= 0)
  1748. len2 = MIN(len2, to - (i + 1) * CHUNK_SIZE);
  1749. }
  1750. /* Lock early -- httpServerRequest may get_chunk */
  1751. if(len2 > 0)
  1752. lockChunk(object, i + 1);
  1753. if(object->length >= 0 &&
  1754. connection->offset + len + len2 == object->length)
  1755. end = 1;
  1756. else
  1757. end = 0;
  1758. /* Prefetch */
  1759. if(!(object->flags & OBJECT_INPROGRESS) && !REQUEST_SIDE(request)) {
  1760. if(object->chunks[i].size < CHUNK_SIZE &&
  1761. to >= 0 && connection->offset + len + 1 < to)
  1762. object->request(object, request->method,
  1763. connection->offset + len, -1, request,
  1764. object->request_closure);
  1765. else if(i + 1 < object->numchunks &&
  1766. object->chunks[i + 1].size == 0 &&
  1767. to >= 0 && (i + 1) * CHUNK_SIZE + 1 < to)
  1768. object->request(object, request->method,
  1769. (i + 1) * CHUNK_SIZE, -1, request,
  1770. object->request_closure);
  1771. }
  1772. if(len2 == 0) {
  1773. httpSetTimeout(connection, clientTimeout);
  1774. do_log(D_CLIENT_DATA,
  1775. "Serving on 0x%lx for 0x%lx: offset %d len %d\n",
  1776. (unsigned long)connection, (unsigned long)object,
  1777. connection->offset, len);
  1778. /* IO_NOTNOW in order to give other clients a chance to run. */
  1779. do_stream(IO_WRITE | IO_NOTNOW |
  1780. (connection->te == TE_CHUNKED ? IO_CHUNKED : 0) |
  1781. (end ? IO_END : 0),
  1782. connection->fd, 0,
  1783. object->chunks[i].data + j, len,
  1784. httpServeObjectStreamHandler, connection);
  1785. } else {
  1786. httpSetTimeout(connection, clientTimeout);
  1787. do_log(D_CLIENT_DATA,
  1788. "Serving on 0x%lx for 0x%lx: offset %d len %d + %d\n",
  1789. (unsigned long)connection, (unsigned long)object,
  1790. connection->offset, len, len2);
  1791. do_stream_2(IO_WRITE | IO_NOTNOW |
  1792. (connection->te == TE_CHUNKED ? IO_CHUNKED : 0) |
  1793. (end ? IO_END : 0),
  1794. connection->fd, 0,
  1795. object->chunks[i].data + j, len,
  1796. object->chunks[i + 1].data, len2,
  1797. httpServeObjectStreamHandler2, connection);
  1798. }
  1799. return 1;
  1800. }
  1801. abort();
  1802. fail:
  1803. unlockChunk(object, i);
  1804. if(request->chandler)
  1805. unregisterConditionHandler(request->chandler);
  1806. request->chandler = NULL;
  1807. httpClientFinish(connection, 1);
  1808. return 1;
  1809. }
  1810. static int
  1811. httpServeChunkDelayed(TimeEventHandlerPtr event)
  1812. {
  1813. HTTPConnectionPtr connection = *(HTTPConnectionPtr*)event->data;
  1814. httpServeChunk(connection);
  1815. return 1;
  1816. }
  1817. int
  1818. delayedHttpServeChunk(HTTPConnectionPtr connection)
  1819. {
  1820. TimeEventHandlerPtr event;
  1821. event = scheduleTimeEvent(-1, httpServeChunkDelayed,
  1822. sizeof(connection), &connection);
  1823. if(!event) return -1;
  1824. return 1;
  1825. }
  1826. int
  1827. httpServeObjectHandler(int status, ConditionHandlerPtr chandler)
  1828. {
  1829. HTTPConnectionPtr connection = *(HTTPConnectionPtr*)chandler->data;
  1830. HTTPRequestPtr request = connection->request;
  1831. int rc;
  1832. if((request->object->flags & OBJECT_ABORTED) || status < 0) {
  1833. shutdown(connection->fd, 1);
  1834. httpSetTimeout(connection, 10);
  1835. /* httpServeChunk will take care of the error. */
  1836. }
  1837. httpSetTimeout(connection, -1);
  1838. request->chandler = NULL;
  1839. rc = delayedHttpServeChunk(connection);
  1840. if(rc < 0) {
  1841. do_log(L_ERROR, "Couldn't schedule serving.\n");
  1842. abortObject(request->object, 503,
  1843. internAtom("Couldn't schedule serving"));
  1844. }
  1845. return 1;
  1846. }
  1847. static int
  1848. httpServeObjectStreamHandlerCommon(int kind, int status,
  1849. FdEventHandlerPtr event,
  1850. StreamRequestPtr srequest)
  1851. {
  1852. HTTPConnectionPtr connection = srequest->data;
  1853. HTTPRequestPtr request = connection->request;
  1854. int condition_result = httpCondition(request->object, request->condition);
  1855. int i = connection->offset / CHUNK_SIZE;
  1856. assert(!request->chandler);
  1857. if(status == 0 && !streamRequestDone(srequest)) {
  1858. httpSetTimeout(connection, clientTimeout);
  1859. return 0;
  1860. }
  1861. httpSetTimeout(connection, -1);
  1862. unlockChunk(request->object, i);
  1863. if(kind == 2)
  1864. unlockChunk(request->object, i + 1);
  1865. if(status) {
  1866. if(status < 0) {
  1867. do_log_error(status == -ECONNRESET ? D_IO : L_ERROR,
  1868. -status, "Couldn't write to client");
  1869. if(status == -EIO || status == -ESHUTDOWN)
  1870. httpClientFinish(connection, 2);
  1871. else
  1872. httpClientFinish(connection, 1);
  1873. } else {
  1874. do_log(D_IO, "Couldn't write to client: short write.\n");
  1875. httpClientFinish(connection, 2);
  1876. }
  1877. return 1;
  1878. }
  1879. if(srequest->operation & IO_CHUNKED) {
  1880. assert(srequest->offset > 2);
  1881. connection->offset += srequest->offset - 2;
  1882. } else {
  1883. connection->offset += srequest->offset;
  1884. }
  1885. request->flags &= ~REQUEST_REQUESTED;
  1886. if(request->object->flags & OBJECT_ABORTED) {
  1887. httpClientFinish(connection, 1);
  1888. return 1;
  1889. }
  1890. if(connection->request->method == METHOD_HEAD ||
  1891. condition_result == CONDITION_NOT_MODIFIED) {
  1892. httpClientFinish(connection, 0);
  1893. return 1;
  1894. }
  1895. if(srequest->operation & IO_END)
  1896. httpClientFinish(connection, 0);
  1897. else {
  1898. httpConnectionDestroyBuf(connection);
  1899. lockChunk(connection->request->object,
  1900. connection->offset / CHUNK_SIZE);
  1901. httpServeChunk(connection);
  1902. }
  1903. return 1;
  1904. }
  1905. int
  1906. httpServeObjectStreamHandler(int status,
  1907. FdEventHandlerPtr event,
  1908. StreamRequestPtr srequest)
  1909. {
  1910. return httpServeObjectStreamHandlerCommon(1, status, event, srequest);
  1911. }
  1912. int
  1913. httpServeObjectStreamHandler2(int status,
  1914. FdEventHandlerPtr event,
  1915. StreamRequestPtr srequest)
  1916. {
  1917. return httpServeObjectStreamHandlerCommon(2, status, event, srequest);
  1918. }