]> git.ipfire.org Git - thirdparty/squid.git/blame - src/store_client.cc
Fixed a small patch merge error
[thirdparty/squid.git] / src / store_client.cc
CommitLineData
9cef6668 1
2/*
50a49a6f 3 * $Id: store_client.cc,v 1.86 2000/04/18 06:06:17 wessels Exp $
9cef6668 4 *
5 * DEBUG: section 20 Storage Manager Client-Side Interface
6 * AUTHOR: Duane Wessels
7 *
8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
13 * National Laboratory for Applied Network Research and funded by the
14 * National Science Foundation. Squid is Copyrighted (C) 1998 by
efd900cb 15 * the Regents of the University of California. Please see the
16 * COPYRIGHT file for full details. Squid incorporates software
17 * developed and/or copyrighted by other sources. Please see the
18 * CREDITS file for full details.
9cef6668 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
f09f5b26 36#include "squid.h"
37
e3ef2b09 38/*
39 * NOTE: 'Header' refers to the swapfile metadata header.
40 * 'Body' refers to the swapfile body, which is the full
41 * HTTP reply (including HTTP headers and body).
42 */
2391a162 43static STRCB storeClientReadBody;
44static STRCB storeClientReadHeader;
f09f5b26 45static void storeClientCopy2(StoreEntry * e, store_client * sc);
cfac48c2 46static void storeClientCopy3(StoreEntry * e, store_client * sc);
e3ef2b09 47static void storeClientFileRead(store_client * sc);
d6f51e3c 48static EVH storeClientCopyEvent;
7405a782 49static store_client_t storeClientType(StoreEntry *);
77b32a34 50static int CheckQuickAbort2(StoreEntry * entry);
51static void CheckQuickAbort(StoreEntry * entry);
f09f5b26 52
53/* check if there is any client waiting for this object at all */
54/* return 1 if there is at least one client */
55int
56storeClientWaiting(const StoreEntry * e)
57{
58 MemObject *mem = e->mem_obj;
59 store_client *sc;
60 for (sc = mem->clients; sc; sc = sc->next) {
61 if (sc->callback_data != NULL)
62 return 1;
63 }
64 return 0;
65}
66
67store_client *
68storeClientListSearch(const MemObject * mem, void *data)
69{
70 store_client *sc;
71 for (sc = mem->clients; sc; sc = sc->next) {
72 if (sc->callback_data == data)
73 break;
74 }
75 return sc;
76}
77
7405a782 78static store_client_t
135171fe 79storeClientType(StoreEntry * e)
7405a782 80{
81 MemObject *mem = e->mem_obj;
7405a782 82 if (mem->inmem_lo)
83 return STORE_DISK_CLIENT;
b7fe0ab0 84 if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
6a888d16 85 /* I don't think we should be adding clients to aborted entries */
b7fe0ab0 86 debug(20, 1) ("storeClientType: adding to ENTRY_ABORTED entry\n");
7405a782 87 return STORE_MEM_CLIENT;
6a888d16 88 }
89 if (e->store_status == STORE_OK) {
90 if (mem->inmem_lo == 0 && mem->inmem_hi > 0)
91 return STORE_MEM_CLIENT;
92 else
93 return STORE_DISK_CLIENT;
94 }
95 /* here and past, entry is STORE_PENDING */
7405a782 96 /*
97 * If this is the first client, let it be the mem client
98 */
6a888d16 99 else if (mem->nclients == 1)
100 return STORE_MEM_CLIENT;
ce872c10 101 /*
102 * If there is no disk file to open yet, we must make this a
103 * mem client. If we can't open the swapin file before writing
104 * to the client, there is no guarantee that we will be able
7e3ce7b9 105 * to open it later when we really need it.
ce872c10 106 */
107 else if (e->swap_status == SWAPOUT_NONE)
108 return STORE_MEM_CLIENT;
7405a782 109 /*
110 * otherwise, make subsequent clients read from disk so they
111 * can not delay the first, and vice-versa.
112 */
113 else
6a888d16 114 return STORE_DISK_CLIENT;
7405a782 115}
116
f09f5b26 117/* add client with fd to client list */
118void
119storeClientListAdd(StoreEntry * e, void *data)
120{
121 MemObject *mem = e->mem_obj;
122 store_client **T;
123 store_client *sc;
124 assert(mem);
125 if (storeClientListSearch(mem, data) != NULL)
126 return;
7e3ce7b9 127 e->refcount++;
f09f5b26 128 mem->nclients++;
7021844c 129 sc = memAllocate(MEM_STORE_CLIENT);
db1cd23c 130 cbdataAdd(sc, memFree, MEM_STORE_CLIENT); /* sc is callback_data for file_read */
7e3ce7b9 131 cbdataLock(data); /* locked while we point to it */
f09f5b26 132 sc->callback_data = data;
133 sc->seen_offset = 0;
134 sc->copy_offset = 0;
f115fadd 135 sc->flags.disk_io_pending = 0;
07304bf9 136 sc->entry = e;
7405a782 137 sc->type = storeClientType(e);
138 if (sc->type == STORE_DISK_CLIENT)
698a99c2 139 /* assert we'll be able to get the data we want */
140 /* maybe we should open swapin_fd here */
5f25e839 141 assert(e->swap_file_number > -1 || storeSwapOutAble(e));
f09f5b26 142 for (T = &mem->clients; *T; T = &(*T)->next);
143 *T = sc;
6b8e7481 144#if DELAY_POOLS
145 sc->delay_id = 0;
6b8e7481 146#endif
f09f5b26 147}
148
b04e66e0 149static void
150storeClientCallback(store_client * sc, ssize_t sz)
151{
152 STCB *callback = sc->callback;
153 char *buf = sc->copy_buf;
154 assert(sc->callback);
155 assert(sc->copy_buf);
b04e66e0 156 sc->callback = NULL;
157 sc->copy_buf = NULL;
158 if (cbdataValid(sc->callback_data))
159 callback(sc->callback_data, buf, sz);
160}
161
f115fadd 162static void
163storeClientCopyEvent(void *data)
164{
165 store_client *sc = data;
fe4a33ac 166 debug(20, 3) ("storeClientCopyEvent: Running\n");
67fd69de 167 sc->flags.copy_event_pending = 0;
a2899918 168 if (!sc->callback)
169 return;
f115fadd 170 storeClientCopy2(sc->entry, sc);
f115fadd 171}
172
f09f5b26 173/* copy bytes requested by the client */
174void
175storeClientCopy(StoreEntry * e,
176 off_t seen_offset,
177 off_t copy_offset,
178 size_t size,
179 char *buf,
180 STCB * callback,
181 void *data)
182{
183 store_client *sc;
b7fe0ab0 184 assert(!EBIT_TEST(e->flags, ENTRY_ABORTED));
f09f5b26 185 debug(20, 3) ("storeClientCopy: %s, seen %d, want %d, size %d, cb %p, cbdata %p\n",
186 storeKeyText(e->key),
187 (int) seen_offset,
188 (int) copy_offset,
189 (int) size,
190 callback,
191 data);
192 sc = storeClientListSearch(e->mem_obj, data);
193 assert(sc != NULL);
194 assert(sc->callback == NULL);
195 sc->copy_offset = copy_offset;
196 sc->seen_offset = seen_offset;
197 sc->callback = callback;
198 sc->copy_buf = buf;
199 sc->copy_size = size;
200 sc->copy_offset = copy_offset;
67fd69de 201 storeClientCopy2(e, sc);
f09f5b26 202}
203
07304bf9 204/*
205 * This function is used below to decide if we have any more data to
0bb129ee 206 * send to the client. If the store_status is STORE_PENDING, then we
b7fe0ab0 207 * do have more data to send. If its STORE_OK, then
0bb129ee 208 * we continue checking. If the object length is negative, then we
209 * don't know the real length and must open the swap file to find out.
210 * If the length is >= 0, then we compare it to the requested copy
211 * offset.
07304bf9 212 */
213static int
214storeClientNoMoreToSend(StoreEntry * e, store_client * sc)
215{
216 ssize_t len;
0bb129ee 217 if (e->store_status == STORE_PENDING)
07304bf9 218 return 0;
219 if ((len = objectLen(e)) < 0)
220 return 0;
221 if (sc->copy_offset < len)
222 return 0;
223 return 1;
224}
225
f09f5b26 226static void
227storeClientCopy2(StoreEntry * e, store_client * sc)
228{
67fd69de 229 if (sc->flags.copy_event_pending)
230 return;
db1cd23c 231 if (EBIT_TEST(e->flags, ENTRY_FWD_HDR_WAIT)) {
232 debug(20, 5) ("storeClientCopy2: returning because ENTRY_FWD_HDR_WAIT set\n");
7e3e1d01 233 return;
db1cd23c 234 }
67fd69de 235 if (sc->flags.store_copying) {
236 sc->flags.copy_event_pending = 1;
3d36b8ab 237 debug(20, 3) ("storeClientCopy2: Queueing storeClientCopyEvent()\n");
c43f5247 238 eventAdd("storeClientCopyEvent", storeClientCopyEvent, sc, 0.0, 0);
67fd69de 239 return;
240 }
a455c097 241 cbdataLock(sc); /* ick, prevent sc from getting freed */
67fd69de 242 sc->flags.store_copying = 1;
f09f5b26 243 debug(20, 3) ("storeClientCopy2: %s\n", storeKeyText(e->key));
b04e66e0 244 assert(sc->callback != NULL);
0bb129ee 245 /*
b7fe0ab0 246 * We used to check for ENTRY_ABORTED here. But there were some
0bb129ee 247 * problems. For example, we might have a slow client (or two) and
248 * the server-side is reading far ahead and swapping to disk. Even
249 * if the server-side aborts, we want to give the client(s)
250 * everything we got before the abort condition occurred.
251 */
cfac48c2 252 storeClientCopy3(e, sc);
253 sc->flags.store_copying = 0;
254 cbdataUnlock(sc); /* ick, allow sc to be freed */
255}
256
257static void
258storeClientCopy3(StoreEntry * e, store_client * sc)
259{
cfac48c2 260 MemObject *mem = e->mem_obj;
261 size_t sz;
0bb129ee 262 if (storeClientNoMoreToSend(e, sc)) {
f09f5b26 263 /* There is no more to send! */
b04e66e0 264 storeClientCallback(sc, 0);
cfac48c2 265 return;
266 }
267 if (e->store_status == STORE_PENDING && sc->seen_offset >= mem->inmem_hi) {
f09f5b26 268 /* client has already seen this, wait for more */
cfac48c2 269 debug(20, 3) ("storeClientCopy3: Waiting for more\n");
270 return;
271 }
272 /*
273 * Slight weirdness here. We open a swapin file for any
274 * STORE_DISK_CLIENT, even if we can copy the requested chunk
275 * from memory in the next block. We must try to open the
276 * swapin file before sending any data to the client side. If
277 * we postpone the open, and then can not open the file later
278 * on, the client loses big time. Its transfer just gets cut
279 * off. Better to open it early (while the client side handler
280 * is clientCacheHit) so that we can fall back to a cache miss
281 * if needed.
282 */
283 if (STORE_DISK_CLIENT == sc->type && NULL == sc->swapin_sio) {
284 debug(20, 3) ("storeClientCopy3: Need to open swap in file\n");
f09f5b26 285 /* gotta open the swapin file */
e11322b2 286 if (storeTooManyDiskFilesOpen()) {
43f3238f 287 /* yuck -- this causes a TCP_SWAPFAIL_MISS on the client side */
b04e66e0 288 storeClientCallback(sc, -1);
289 return;
290 }
291 if (!sc->flags.disk_io_pending) {
7e3ce7b9 292 storeSwapInStart(sc);
293 if (NULL == sc->swapin_sio) {
b04e66e0 294 storeClientCallback(sc, -1);
295 return;
7e3ce7b9 296 }
b04e66e0 297 /*
298 * If the open succeeds we either copy from memory, or
299 * schedule a disk read in the next block.
300 */
7e3ce7b9 301 } else {
f3435962 302 debug(20, 1) ("WARNING: Averted multiple fd operation (1)\n");
cfac48c2 303 return;
f09f5b26 304 }
305 }
cfac48c2 306 if (sc->copy_offset >= mem->inmem_lo && sc->copy_offset < mem->inmem_hi) {
307 /* What the client wants is in memory */
308 debug(20, 3) ("storeClientCopy3: Copying from memory\n");
309 sz = stmemCopy(&mem->data_hdr,
310 sc->copy_offset, sc->copy_buf, sc->copy_size);
b04e66e0 311 storeClientCallback(sc, sz);
cfac48c2 312 return;
313 }
314 assert(STORE_DISK_CLIENT == sc->type);
a928befc 315 assert(!sc->flags.disk_io_pending);
cfac48c2 316 debug(20, 3) ("storeClientCopy3: reading from STORE\n");
cfac48c2 317 storeClientFileRead(sc);
f09f5b26 318}
319
f09f5b26 320static void
e3ef2b09 321storeClientFileRead(store_client * sc)
f09f5b26 322{
07304bf9 323 MemObject *mem = sc->entry->mem_obj;
f09f5b26 324 assert(sc->callback != NULL);
b04e66e0 325 assert(!sc->flags.disk_io_pending);
326 sc->flags.disk_io_pending = 1;
dee51794 327 if (mem->swap_hdr_sz == 0) {
2391a162 328 storeRead(sc->swapin_sio,
d8b9a541 329 sc->copy_buf,
330 sc->copy_size,
e3ef2b09 331 0,
332 storeClientReadHeader,
333 sc);
9d66d521 334 } else {
3157c72f 335 if (sc->entry->swap_status == SWAPOUT_WRITING)
2391a162 336 assert(storeOffset(mem->swapout.sio) > sc->copy_offset + mem->swap_hdr_sz);
337 storeRead(sc->swapin_sio,
e3ef2b09 338 sc->copy_buf,
339 sc->copy_size,
340 sc->copy_offset + mem->swap_hdr_sz,
341 storeClientReadBody,
342 sc);
3157c72f 343 }
f09f5b26 344}
345
346static void
5bd1abac 347storeClientReadBody(void *data, const char *buf, ssize_t len)
f09f5b26 348{
349 store_client *sc = data;
07304bf9 350 MemObject *mem = sc->entry->mem_obj;
27002b34 351 assert(sc->flags.disk_io_pending);
f115fadd 352 sc->flags.disk_io_pending = 0;
f09f5b26 353 assert(sc->callback != NULL);
2391a162 354 debug(20, 3) ("storeClientReadBody: len %d\n", len);
cb69b4c7 355 if (sc->copy_offset == 0 && len > 0 && mem->reply->sline.status == 0)
9bc73deb 356 httpReplyParse(mem->reply, sc->copy_buf, headersEnd(sc->copy_buf, len));
b04e66e0 357 storeClientCallback(sc, len);
f09f5b26 358}
359
e3ef2b09 360static void
5bd1abac 361storeClientReadHeader(void *data, const char *buf, ssize_t len)
e3ef2b09 362{
e3ef2b09 363 store_client *sc = data;
07304bf9 364 StoreEntry *e = sc->entry;
365 MemObject *mem = e->mem_obj;
e3ef2b09 366 int swap_hdr_sz = 0;
367 size_t body_sz;
368 size_t copy_sz;
369 tlv *tlv_list;
7e3ce7b9 370 tlv *t;
371 int swap_object_ok = 1;
27002b34 372 assert(sc->flags.disk_io_pending);
f115fadd 373 sc->flags.disk_io_pending = 0;
e3ef2b09 374 assert(sc->callback != NULL);
2391a162 375 debug(20, 3) ("storeClientReadHeader: len %d\n", len);
e3ef2b09 376 if (len < 0) {
2391a162 377 debug(20, 3) ("storeClientReadHeader: %s\n", xstrerror());
b04e66e0 378 storeClientCallback(sc, len);
e3ef2b09 379 return;
380 }
381 tlv_list = storeSwapMetaUnpack(buf, &swap_hdr_sz);
9bc73deb 382 if (swap_hdr_sz > len) {
383 /* oops, bad disk file? */
efd900cb 384 debug(20, 1) ("WARNING: swapfile header too small\n");
b04e66e0 385 storeClientCallback(sc, -1);
9bc73deb 386 return;
387 }
e3ef2b09 388 if (tlv_list == NULL) {
efd900cb 389 debug(20, 1) ("WRNING: failed to unpack meta data\n");
b04e66e0 390 storeClientCallback(sc, -1);
e3ef2b09 391 return;
392 }
393 /*
7e3ce7b9 394 * Check the meta data and make sure we got the right object.
e3ef2b09 395 */
7e3ce7b9 396 for (t = tlv_list; t; t = t->next) {
397 switch (t->type) {
398 case STORE_META_KEY:
399 assert(t->length == MD5_DIGEST_CHARS);
b04e66e0 400 if (memcmp(t->value, e->key, MD5_DIGEST_CHARS)) {
7e3ce7b9 401 debug(20, 1) ("WARNING: swapin MD5 mismatch\n");
b04e66e0 402 debug(20, 1) ("\t%s\n", storeKeyText(t->value));
403 debug(20, 1) ("\t%s\n", storeKeyText(e->key));
404 }
7e3ce7b9 405 break;
406 case STORE_META_URL:
407 if (NULL == mem->url)
408 (void) 0; /* can't check */
409 else if (0 == strcasecmp(mem->url, t->value))
410 (void) 0; /* a match! */
411 else {
412 debug(20, 1) ("storeClientReadHeader: URL mismatch\n");
413 debug(20, 1) ("\t{%s} != {%s}\n", t->value, mem->url);
414 swap_object_ok = 0;
415 break;
416 }
417 break;
418 case STORE_META_STD:
419 break;
420 default:
421 debug(20, 1) ("WARNING: got unused STORE_META type %d\n", t->type);
422 break;
423 }
424 }
07304bf9 425 storeSwapTLVFree(tlv_list);
7e3ce7b9 426 if (!swap_object_ok) {
b04e66e0 427 storeClientCallback(sc, -1);
7e3ce7b9 428 return;
429 }
e3ef2b09 430 mem->swap_hdr_sz = swap_hdr_sz;
07304bf9 431 mem->object_sz = e->swap_file_sz - swap_hdr_sz;
e3ef2b09 432 /*
433 * If our last read got some data the client wants, then give
434 * it to them, otherwise schedule another read.
435 */
436 body_sz = len - swap_hdr_sz;
437 if (sc->copy_offset < body_sz) {
438 /*
25535cbe 439 * we have (part of) what they want
e3ef2b09 440 */
441 copy_sz = XMIN(sc->copy_size, body_sz);
25535cbe 442 debug(20, 3) ("storeClientReadHeader: copying %d bytes of body\n",
443 copy_sz);
d8b9a541 444 xmemmove(sc->copy_buf, sc->copy_buf + swap_hdr_sz, copy_sz);
cb69b4c7 445 if (sc->copy_offset == 0 && len > 0 && mem->reply->sline.status == 0)
9bc73deb 446 httpReplyParse(mem->reply, sc->copy_buf,
447 headersEnd(sc->copy_buf, copy_sz));
b04e66e0 448 storeClientCallback(sc, copy_sz);
e3ef2b09 449 return;
450 }
451 /*
452 * we don't have what the client wants, but at least we now
453 * know the swap header size.
454 */
e3ef2b09 455 storeClientFileRead(sc);
456}
457
f09f5b26 458int
459storeClientCopyPending(StoreEntry * e, void *data)
460{
461 /* return 1 if there is a callback registered for this client */
462 store_client *sc = storeClientListSearch(e->mem_obj, data);
463 if (sc == NULL)
464 return 0;
465 if (sc->callback == NULL)
466 return 0;
467 return 1;
468}
469
470int
471storeUnregister(StoreEntry * e, void *data)
472{
473 MemObject *mem = e->mem_obj;
474 store_client *sc;
475 store_client **S;
f09f5b26 476 if (mem == NULL)
477 return 0;
478 debug(20, 3) ("storeUnregister: called for '%s'\n", storeKeyText(e->key));
479 for (S = &mem->clients; (sc = *S) != NULL; S = &(*S)->next) {
480 if (sc->callback_data == data)
481 break;
482 }
483 if (sc == NULL)
484 return 0;
4c454c5c 485 if (sc == mem->clients) {
486 /*
487 * If we are unregistering the _first_ client for this
488 * entry, then we have to reset the client FD to -1.
489 */
490 mem->fd = -1;
491 }
f09f5b26 492 *S = sc->next;
493 mem->nclients--;
f09f5b26 494 if (e->store_status == STORE_OK && e->swap_status != SWAPOUT_DONE)
2391a162 495 storeSwapOut(e);
eb824054 496 if (sc->swapin_sio) {
2391a162 497 storeClose(sc->swapin_sio);
cfac48c2 498 cbdataUnlock(sc->swapin_sio);
eb824054 499 sc->swapin_sio = NULL;
500 }
b04e66e0 501 if (NULL != sc->callback) {
f09f5b26 502 /* callback with ssize = -1 to indicate unexpected termination */
503 debug(20, 3) ("storeUnregister: store_client for %s has a callback\n",
504 mem->url);
b04e66e0 505 storeClientCallback(sc, -1);
f09f5b26 506 }
b6a2f15e 507#if DELAY_POOLS
508 delayUnregisterDelayIdPtr(&sc->delay_id);
509#endif
7e3ce7b9 510 cbdataUnlock(sc->callback_data); /* we're done with it now */
a928befc 511 /*assert(!sc->flags.disk_io_pending); */
f09f5b26 512 cbdataFree(sc);
77b32a34 513 assert(e->lock_count > 0);
514 if (mem->nclients == 0)
515 CheckQuickAbort(e);
f09f5b26 516 return 1;
517}
518
519off_t
520storeLowestMemReaderOffset(const StoreEntry * entry)
521{
522 const MemObject *mem = entry->mem_obj;
50a49a6f 523 off_t lowest = mem->inmem_hi + 1;
f09f5b26 524 store_client *sc;
525 store_client *nx = NULL;
526 for (sc = mem->clients; sc; sc = nx) {
527 nx = sc->next;
528 if (sc->callback_data == NULL) /* open slot */
529 continue;
cfac48c2 530 if (sc->type == STORE_DISK_CLIENT)
531 if (NULL != sc->swapin_sio)
532 continue;
f09f5b26 533 if (sc->copy_offset < lowest)
534 lowest = sc->copy_offset;
535 }
536 return lowest;
537}
538
539/* Call handlers waiting for data to be appended to E. */
540void
541InvokeHandlers(StoreEntry * e)
542{
543 int i = 0;
544 MemObject *mem = e->mem_obj;
545 store_client *sc;
546 store_client *nx = NULL;
547 assert(mem->clients != NULL || mem->nclients == 0);
548 debug(20, 3) ("InvokeHandlers: %s\n", storeKeyText(e->key));
549 /* walk the entire list looking for valid callbacks */
550 for (sc = mem->clients; sc; sc = nx) {
551 nx = sc->next;
552 debug(20, 3) ("InvokeHandlers: checking client #%d\n", i++);
553 if (sc->callback_data == NULL)
554 continue;
555 if (sc->callback == NULL)
556 continue;
a928befc 557 if (sc->flags.disk_io_pending)
558 continue;
f09f5b26 559 storeClientCopy2(e, sc);
560 }
561}
562
563int
564storePendingNClients(const StoreEntry * e)
565{
f09f5b26 566 MemObject *mem = e->mem_obj;
36547bcf 567 int npend = NULL == mem ? 0 : mem->nclients;
1afe05c5 568 debug(20, 3) ("storePendingNClients: returning %d\n", npend);
f09f5b26 569 return npend;
570}
77b32a34 571
572/* return 1 if the request should be aborted */
573static int
574CheckQuickAbort2(StoreEntry * entry)
575{
576 int curlen;
577 int minlen;
578 int expectlen;
579 MemObject *mem = entry->mem_obj;
580 assert(mem);
581 debug(20, 3) ("CheckQuickAbort2: entry=%p, mem=%p\n", entry, mem);
0e5bd28f 582 if (mem->request && !mem->request->flags.cachable) {
6946d7e1 583 debug(20, 3) ("CheckQuickAbort2: YES !mem->request->flags.cachable\n");
77b32a34 584 return 1;
585 }
586 if (EBIT_TEST(entry->flags, KEY_PRIVATE)) {
6946d7e1 587 debug(20, 3) ("CheckQuickAbort2: YES KEY_PRIVATE\n");
77b32a34 588 return 1;
589 }
b6a2f15e 590 expectlen = mem->reply->content_length + mem->reply->hdr_sz;
77b32a34 591 curlen = (int) mem->inmem_hi;
592 minlen = (int) Config.quickAbort.min << 10;
593 if (minlen < 0) {
594 debug(20, 3) ("CheckQuickAbort2: NO disabled\n");
595 return 0;
596 }
597 if (curlen > expectlen) {
6946d7e1 598 debug(20, 3) ("CheckQuickAbort2: YES bad content length\n");
77b32a34 599 return 1;
600 }
601 if ((expectlen - curlen) < minlen) {
602 debug(20, 3) ("CheckQuickAbort2: NO only little more left\n");
603 return 0;
604 }
605 if ((expectlen - curlen) > (Config.quickAbort.max << 10)) {
6946d7e1 606 debug(20, 3) ("CheckQuickAbort2: YES too much left to go\n");
77b32a34 607 return 1;
608 }
609 if (expectlen < 100) {
610 debug(20, 3) ("CheckQuickAbort2: NO avoid FPE\n");
611 return 0;
612 }
613 if ((curlen / (expectlen / 100)) > Config.quickAbort.pct) {
614 debug(20, 3) ("CheckQuickAbort2: NO past point of no return\n");
615 return 0;
616 }
6946d7e1 617 debug(20, 3) ("CheckQuickAbort2: YES default, returning 1\n");
77b32a34 618 return 1;
619}
620
621static void
622CheckQuickAbort(StoreEntry * entry)
623{
624 if (entry == NULL)
625 return;
626 if (storePendingNClients(entry) > 0)
627 return;
628 if (entry->store_status != STORE_PENDING)
629 return;
986ebffc 630 if (EBIT_TEST(entry->flags, ENTRY_SPECIAL))
631 return;
77b32a34 632 if (CheckQuickAbort2(entry) == 0)
633 return;
634 Counter.aborted_requests++;
7197b20d 635 storeAbort(entry);
77b32a34 636}