DnsLookupDetails.cc
SBUF_SOURCE= \
+ base/CharacterSet.h \
base/InstanceId.h \
MemBlob.h \
MemBlob.cc \
ClientRequestContext.h \
clientStream.cc \
clientStream.h \
+ CollapsedForwarding.cc \
+ CollapsedForwarding.h \
CompletionDispatcher.cc \
CompletionDispatcher.h \
CommRead.h \
swap_log_op.h \
SwapDir.cc \
SwapDir.h \
+ Transients.cc \
+ Transients.h \
MemStore.cc \
MemStore.h \
time.cc \
# Make location configure settings available to the code
DEFS += -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\" -DDEFAULT_SQUID_DATA_DIR=\"$(datadir)\" -DDEFAULT_SQUID_CONFIG_DIR=\"$(sysconfdir)\"
- snmp_core.o snmp_agent.o: ../lib/snmplib/libsnmplib.a $(top_srcdir)/include/cache_snmp.h
+ snmp_core.o snmp_agent.o: ../lib/snmplib/libsnmplib.la $(top_srcdir)/include/cache_snmp.h
globals.cc: globals.h mk-globals-c.awk
$(AWK) -f $(srcdir)/mk-globals-c.awk < $(srcdir)/globals.h > $@ || ($(RM) -f $@ && exit 1)
tests/testString \
tests/testURL \
tests/testSBuf \
+ tests/testSBufList \
tests/testConfigParser \
tests/testStatHist \
tests/testVector
tests_testACLMaxUserIP_SOURCES= \
cbdata.cc \
ClientInfo.h \
+ tests/stub_CollapsedForwarding.cc \
ConfigOption.cc \
ConfigParser.cc \
DiskIO/ReadRequest.cc \
swap_log_op.h \
tests/stub_SwapDir.cc \
SwapDir.h \
+ Transients.cc \
log/access_log.h \
tests/stub_access_log.cc \
cache_cf.h \
tests/stub_Port.cc \
repl_modules.h \
tests/stub_store.cc \
+ tests/stub_store_client.cc \
store_rebuild.h \
tests/stub_store_rebuild.cc \
tests/stub_store_stats.cc \
client_side_request.cc \
ClientInfo.h \
clientStream.cc \
+ tests/stub_CollapsedForwarding.cc \
ConfigOption.cc \
ConfigParser.cc \
CpuAffinityMap.cc \
StoreSwapLogData.cc \
tools.h \
tools.cc \
+ Transients.cc \
tests/stub_tunnel.cc \
tests/stub_SwapDir.cc \
MemStore.cc \
cbdata.cc \
client_db.h \
ClientInfo.h \
+ tests/stub_CollapsedForwarding.cc \
ConfigOption.cc \
ConfigParser.cc \
$(DELAY_POOL_SOURCE) \
StrList.h \
StrList.cc \
tests/stub_SwapDir.cc \
+ Transients.cc \
log/access_log.h \
tests/stub_access_log.cc \
tests/stub_acl.cc \
tests/stub_mime.cc \
tests/stub_pconn.cc \
tests/stub_Port.cc \
+ tests/stub_stat.cc \
tests/stub_store_client.cc \
tests/stub_store_stats.cc \
store_rebuild.h \
client_side_request.cc \
ClientInfo.h \
clientStream.cc \
+ tests/stub_CollapsedForwarding.cc \
ConfigOption.cc \
ConfigParser.cc \
CpuAffinityMap.cc \
time.cc \
tools.h \
tools.cc \
+ Transients.cc \
tests/stub_tunnel.cc \
MemStore.cc \
$(UNLINKDSOURCE) \
client_side_request.cc \
ClientInfo.h \
clientStream.cc \
+ tests/stub_CollapsedForwarding.cc \
ConfigOption.cc \
ConfigParser.cc \
CpuAffinityMap.cc \
time.cc \
tools.h \
tools.cc \
+ Transients.cc \
tests/stub_tunnel.cc \
MemStore.cc \
$(UNLINKDSOURCE) \
client_side_request.cc \
ClientInfo.h \
clientStream.cc \
+ tests/stub_CollapsedForwarding.cc \
ConfigOption.cc \
ConfigParser.cc \
CpuAffinityMap.cc \
StrList.h \
StrList.cc \
tests/stub_SwapDir.cc \
+ Transients.cc \
tests/test_http_range.cc \
tests/stub_external_acl.cc \
tests/stub_ipc_Forwarder.cc \
HttpParser.h \
MemBuf.cc \
MemBuf.h \
+ tests/stub_MemObject.cc \
Mem.h \
tests/stub_mem.cc \
String.cc \
tests/stub_SBufDetailedStats.cc \
tests/stub_cache_cf.cc \
tests/stub_cache_manager.cc \
+ tests/stub_comm.cc \
+ tests/stub_cbdata.cc \
tests/stub_debug.cc \
tests/stub_event.cc \
tests/stub_HelperChildConfig.cc \
+ tests/stub_stmem.cc \
+ tests/stub_store.cc \
+ tests/stub_store_stats.cc \
tools.h \
tests/stub_tools.cc \
tests/testHttpParser.cc \
client_side_request.cc \
ClientInfo.h \
clientStream.cc \
+ tests/stub_CollapsedForwarding.cc \
ConfigOption.cc \
ConfigParser.cc \
CpuAffinityMap.cc \
event.cc \
tools.h \
tools.cc \
+ Transients.cc \
tests/stub_tunnel.cc \
tests/stub_SwapDir.cc \
MemStore.cc \
tests/stub_CacheDigest.cc \
cbdata.cc \
ClientInfo.h \
+ tests/stub_CollapsedForwarding.cc \
ConfigOption.cc \
ConfigParser.cc \
$(DELAY_POOL_SOURCE) \
mime.h \
tests/stub_mime.cc \
tests/stub_Port.cc \
+ tests/stub_stat.cc \
tests/stub_store_client.cc \
tests/stub_store_stats.cc \
store_rebuild.h \
tests/stub_store_rebuild.cc \
tests/stub_store_swapout.cc \
tools.h \
+ Transients.cc \
tests/stub_tools.cc \
tests/stub_UdsOp.cc \
tests/testMain.cc \
tests/stub_mem.cc \
MemBuf.cc \
String.cc \
+ $(SBUF_SOURCE) \
+ SBufDetailedStats.h \
+ tests/stub_SBufDetailedStats.cc \
tests/testMain.cc \
tests/testString.cc \
tests/testString.h \
tests/testUfs.h \
tests/stub_cache_manager.cc \
tests/stub_client_db.cc \
+ tests/stub_CollapsedForwarding.cc \
tests/stub_HelperChildConfig.cc \
tests/stub_icp.cc \
tests/stub_ipc.cc \
internal.h \
tests/stub_internal.cc \
tests/stub_libformat.cc \
+ tests/stub_stat.cc \
store_rebuild.h \
tests/stub_store_rebuild.cc \
tests/stub_store_stats.cc \
RequestFlags.cc \
SquidList.h \
SquidList.cc \
+ Transients.cc \
MasterXaction.cc \
MasterXaction.h \
MemObject.cc \
tests_testRock_SOURCES = \
cbdata.cc \
CacheDigest.h \
+ CollapsedForwarding.h \
+ CollapsedForwarding.cc \
tests/stub_CacheDigest.cc \
ConfigOption.cc \
ConfigParser.cc \
tests/stub_StatHist.cc \
stmem.cc \
repl_modules.h \
+ tests/stub_stat.cc \
store.cc \
StoreFileSystem.cc \
StoreIOState.cc \
StrList.h \
StrList.cc \
SwapDir.cc \
+ Transients.h \
+ Transients.cc \
tests/testRock.cc \
tests/testMain.cc \
tests/testRock.h \
client_side_request.cc \
ClientInfo.h \
clientStream.cc \
+ tests/stub_CollapsedForwarding.cc \
ConfigOption.cc \
ConfigParser.cc \
CpuAffinityMap.cc \
String.cc \
StrList.h \
StrList.cc \
+ Transients.cc \
tests/stub_SwapDir.cc \
MemStore.cc \
tests/stub_debug.cc \
$(COMMON_LIBS)
tests_testSBuf_DEPENDENCIES= $(SQUID_CPPUNIT_LA)
+ tests_testSBufList_SOURCES= \
+ tests/testSBufList.h \
+ tests/testSBufList.cc \
+ tests/testMain.cc \
+ $(SBUF_SOURCE) \
+ SBufList.h \
+ SBufList.cc \
+ SBufAlgos.h \
+ SBufDetailedStats.h \
+ tests/stub_SBufDetailedStats.cc \
+ SBufStream.h \
+ tests/stub_time.cc \
+ mem.cc \
+ tests/stub_debug.cc \
+ tests/stub_event.cc \
+ tests/stub_fatal.cc \
+ tests/stub_HelperChildConfig.cc \
+ tests/stub_cache_cf.cc \
+ tests/stub_cache_manager.cc \
++ tests/stub_store.cc \
+ tests/stub_store_stats.cc \
+ tests/stub_tools.cc \
+ SquidString.h \
+ String.cc \
+ tests/stub_wordlist.cc \
+ tests/stub_MemBuf.cc
+ nodist_tests_testSBufList_SOURCES=$(TESTSOURCES)
+ tests_testSBufList_LDFLAGS = $(LIBADD_DL)
+ tests_testSBufList_LDADD=\
+ $(SQUID_CPPUNIT_LIBS) \
+ $(SQUID_CPPUNIT_LA) \
+ $(COMPAT_LIB) \
+ libsquid.la \
+ ip/libip.la \
+ mgr/libmgr.la \
+ base/libbase.la \
+ $(top_builddir)/lib/libmiscutil.la \
+ $(COMMON_LIBS)
+ tests_testSBufList_DEPENDENCIES= $(SQUID_CPPUNIT_LA)
+
tests_testConfigParser_SOURCES = \
ClientInfo.h \
Mem.h \
tests/stub_mem.cc \
tests/stub_MemBuf.cc \
tests/stub_time.cc \
+ $(SBUF_SOURCE) \
+ SBufDetailedStats.h \
+ tests/stub_SBufDetailedStats.cc \
String.cc \
ConfigParser.cc \
fatal.h \
*/
#include "squid.h"
+ #include "acl/FilledChecklist.h"
#include "acl/Gadgets.h"
#include "base/TextException.h"
#include "comm/Connection.h"
#include "HttpReply.h"
#include "HttpRequest.h"
#include "Server.h"
+ #include "SquidConfig.h"
#include "SquidTime.h"
#include "StatCounters.h"
#include "Store.h"
#include "adaptation/Answer.h"
#include "adaptation/Iterator.h"
#include "base/AsyncCall.h"
- #include "SquidConfig.h"
#endif
// implemented in client_side_reply.cc until sides have a common parent
fwd = theFwdState;
entry = fwd->entry;
- entry->lock();
+ entry->lock("ServerStateData");
request = fwd->request;
HTTPMSGLOCK(request);
assert(!adaptedBodySource);
#endif
- entry->unlock();
+ entry->unlock("ServerStateData");
HTTPMSGUNLOCK(request);
HTTPMSGUNLOCK(theVirginReply);
// give entry the reply because haveParsedReplyHeaders() expects it there
entry->replaceHttpReply(theFinalReply, false); // but do not write yet
haveParsedReplyHeaders(); // update the entry/reply (e.g., set timestamps)
- if (EBIT_TEST(entry->flags, ENTRY_CACHABLE) && blockCaching())
++ if (!EBIT_TEST(entry->flags, RELEASE_REQUEST) && blockCaching())
+ entry->release();
entry->startWriting(); // write the updated entry to store
return theFinalReply;
currentOffset = partial ? theFinalReply->content_range->spec.offset : 0;
}
+ /// whether to prevent caching of an otherwise cachable response
+ bool
+ ServerStateData::blockCaching()
+ {
+ if (const Acl::Tree *acl = Config.accessList.storeMiss) {
+ // This relatively expensive check is not in StoreEntry::checkCachable:
+ // That method lacks HttpRequest and may be called too many times.
+ ACLFilledChecklist ch(acl, originalRequest(), NULL);
+ ch.reply = const_cast<HttpReply*>(entry->getReply()); // ACLFilledChecklist API bug
+ HTTPMSGLOCK(ch.reply);
+ if (ch.fastCheck() != ACCESS_ALLOWED) { // when in doubt, block
+ debugs(20, 3, "store_miss prohibits caching");
+ return true;
+ }
+ }
+ return false;
+ }
+
HttpRequest *
ServerStateData::originalRequest()
{
int emailErrData;
int httpd_suppress_version_string;
int global_internal_static;
+ int collapsed_forwarding;
#if FOLLOW_X_FORWARDED_FOR
int acl_uses_indirect_client;
acl_access *AlwaysDirect;
acl_access *ASlists;
acl_access *noCache;
+ acl_access *sendHit;
+ acl_access *storeMiss;
acl_access *stats_collection;
#if SQUID_SNMP
This option is not yet supported by Squid-3.
DOC_END
-NAME: collapsed_forwarding
-TYPE: obsolete
-DOC_START
- This option is not yet supported by Squid-3. see http://bugs.squid-cache.org/show_bug.cgi?id=3495
-DOC_END
-
NAME: error_map
TYPE: obsolete
DOC_START
concurrency=
The number of requests each certificate validator helper can handle in
- parallel. Defaults to 0 which indicates the certficate validator
- is a old-style single threaded redirector.
+ parallel. A value of 0 indicates the certficate validator does not
+ support concurrency. Defaults to 1.
When this directive is set to a value >= 1 then the protocol
used to communicate with the helper is modified to include
==== The rock store type ====
Usage:
- cache_dir rock Directory-Name Mbytes <max-size=bytes> [options]
+ cache_dir rock Directory-Name Mbytes [options]
The Rock Store type is a database-style storage. All cached
- entries are stored in a "database" file, using fixed-size slots,
- one entry per slot. The database size is specified in MB. The
- slot size is specified in bytes using the max-size option. See
- below for more info on the max-size option.
+ entries are stored in a "database" file, using fixed-size slots.
+ A single entry occupies one or more slots.
If possible, Squid using Rock Store creates a dedicated kid
process called "disker" to avoid blocking Squid worker(s) on disk
and when set to zero, disables the disk I/O rate limit
enforcement. Currently supported by IpcIo module only.
+ slot-size=bytes: The size of a database "record" used for
+ storing cached responses. A cached response occupies at least
+ one slot and all database I/O is done using individual slots so
+ increasing this parameter leads to more disk space waste while
+ decreasing it leads to more disk I/O overheads. Should be a
+ multiple of your operating system I/O page size. Defaults to
+ 16KBytes. A housekeeping header is stored with each slot and
+ smaller slot-sizes will be rejected. The header is smaller than
+ 100 bytes.
+
==== COMMON OPTIONS ====
NAME: cache no_cache
TYPE: acl_access
DEFAULT: none
- DEFAULT_DOC: Allow caching, unless rules exist in squid.conf.
+ DEFAULT_DOC: By default, this directive is unused and has no effect.
LOC: Config.accessList.noCache
DOC_START
- A list of ACL elements which, if matched and denied, cause the request to
- not be satisfied from the cache and the reply to not be cached.
- In other words, use this to force certain objects to never be cached.
-
- You must use the words 'allow' or 'deny' to indicate whether items
- matching the ACL should be allowed or denied into the cache.
+ Requests denied by this directive will not be served from the cache
+ and their responses will not be stored in the cache. This directive
+ has no effect on other transactions and on already cached responses.
This clause supports both fast and slow acl types.
See http://wiki.squid-cache.org/SquidFaq/SquidAcl for details.
+
+ This and the two other similar caching directives listed below are
+ checked at different transaction processing stages, have different
+ access to response information, affect different cache operations,
+ and differ in slow ACLs support:
+
+ * cache: Checked before Squid makes a hit/miss determination.
+ No access to reply information!
+ Denies both serving a hit and storing a miss.
+ Supports both fast and slow ACLs.
+ * send_hit: Checked after a hit was detected.
+ Has access to reply (hit) information.
+ Denies serving a hit only.
+ Supports fast ACLs only.
+ * store_miss: Checked before storing a cachable miss.
+ Has access to reply (miss) information.
+ Denies storing a miss only.
+ Supports fast ACLs only.
+
+ If you are not sure which of the three directives to use, apply the
+ following decision logic:
+
+ * If your ACL(s) are of slow type _and_ need response info, redesign.
+ Squid does not support that particular combination at this time.
+ Otherwise:
+ * If your directive ACL(s) are of slow type, use "cache"; and/or
+ * if your directive ACL(s) need no response info, use "cache".
+ Otherwise:
+ * If you do not want the response cached, use store_miss; and/or
+ * if you do not want a hit on a cached response, use send_hit.
+ DOC_END
+
+ NAME: send_hit
+ TYPE: acl_access
+ DEFAULT: none
+ DEFAULT_DOC: By default, this directive is unused and has no effect.
+ LOC: Config.accessList.sendHit
+ DOC_START
+ Responses denied by this directive will not be served from the cache
+ (but may still be cached, see store_miss). This directive has no
+ effect on the responses it allows and on the cached objects.
+
+ Please see the "cache" directive for a summary of differences among
+ store_miss, send_hit, and cache directives.
+
+ Unlike the "cache" directive, send_hit only supports fast acl
+ types. See http://wiki.squid-cache.org/SquidFaq/SquidAcl for details.
+
+ For example:
+
+ # apply custom Store ID mapping to some URLs
+ acl MapMe dstdomain .c.example.com
+ store_id_program ...
+ store_id_access allow MapMe
+
+ # but prevent caching of special responses
+ # such as 302 redirects that cause StoreID loops
+ acl Ordinary http_status 200-299
+ store_miss deny MapMe !Ordinary
+
+ # and do not serve any previously stored special responses
+ # from the cache (in case they were already cached before
+ # the above store_miss rule was in effect).
+ send_hit deny MapMe !Ordinary
+ DOC_END
+
+ NAME: store_miss
+ TYPE: acl_access
+ DEFAULT: none
+ DEFAULT_DOC: By default, this directive is unused and has no effect.
+ LOC: Config.accessList.storeMiss
+ DOC_START
+ Responses denied by this directive will not be cached (but may still
+ be served from the cache, see send_hit). This directive has no
+ effect on the responses it allows and on the already cached responses.
+
+ Please see the "cache" directive for a summary of differences among
+ store_miss, send_hit, and cache directives. See the
+ send_hit directive for a usage example.
+
+ Unlike the "cache" directive, store_miss only supports fast acl
+ types. See http://wiki.squid-cache.org/SquidFaq/SquidAcl for details.
DOC_END
NAME: max_stale
or response to be rejected.
DOC_END
+NAME: collapsed_forwarding
+COMMENT: (on|off)
+TYPE: onoff
+LOC: Config.onoff.collapsed_forwarding
+DEFAULT: off
+DOC_START
+ This option controls whether Squid is allowed to merge multiple
+ potentially cachable requests for the same URI before Squid knows
+ whether the response is going to be cachable.
+
+ This feature is disabled by default: Enabling collapsed forwarding
+ needlessly delays forwarding requests that look cachable (when they are
+ collapsed) but then need to be forwarded individually anyway because
+ they end up being for uncachable content. However, in some cases, such
+ as accelleration of highly cachable content with periodic or groupped
+ expiration times, the gains from collapsing [large volumes of
+ simultenous refresh requests] outweigh losses from such delays.
+DOC_END
+
COMMENT_START
TIMEOUTS
-----------------------------------------------------------------------------
#include "esi/Esi.h"
#endif
+ #include <memory>
+
CBDATA_CLASS_INIT(clientReplyContext);
/* Local functions */
void clientReplyContext::setReplyToStoreEntry(StoreEntry *entry)
{
- entry->lock(); // removeClientStoreReference() unlocks
+ entry->lock("clientReplyContext::setReplyToStoreEntry"); // removeClientStoreReference() unlocks
sc = storeClientListAdd(entry, this);
#if USE_DELAY_POOLS
sc->setDelayId(DelayId::DelayClient(http));
*ep = NULL;
storeUnregister(sc_tmp, e, this);
*scp = NULL;
- e->unlock();
+ e->unlock("clientReplyContext::removeStoreReference");
}
}
*/
assert(http->logType == LOG_TCP_HIT);
- if (strcmp(e->mem_obj->url, http->request->storeId()) != 0) {
- debugs(33, DBG_IMPORTANT, "clientProcessHit: URL mismatch, '" << e->mem_obj->url << "' != '" << http->request->storeId() << "'");
+ if (strcmp(e->mem_obj->storeId(), http->request->storeId()) != 0) {
+ debugs(33, DBG_IMPORTANT, "clientProcessHit: URL mismatch, '" << e->mem_obj->storeId() << "' != '" << http->request->storeId() << "'");
http->logType = LOG_TCP_MISS; // we lack a more precise LOG_*_MISS code
processMiss();
return;
) {
http->logType = LOG_TCP_NEGATIVE_HIT;
sendMoreData(result);
+ } else if (blockedHit()) {
+ debugs(88, 5, "send_hit forces a MISS");
+ http->logType = LOG_TCP_MISS;
+ processMiss();
+ return;
} else if (!http->flags.internal && refreshCheckHTTP(e, r)) {
debugs(88, 5, "clientCacheHit: in refreshCheck() block");
/*
}
}
+ /// whether squid.conf send_hit prevents us from serving this hit
+ bool
+ clientReplyContext::blockedHit() const
+ {
+ if (!Config.accessList.sendHit)
+ return false; // hits are not blocked by default
+
+ if (http->flags.internal)
+ return false; // internal content "hits" cannot be blocked
+
+ if (const HttpReply *rep = http->storeEntry()->getReply()) {
+ std::auto_ptr<ACLFilledChecklist> chl(clientAclChecklistCreate(Config.accessList.sendHit, http));
+ chl->reply = const_cast<HttpReply*>(rep); // ACLChecklist API bug
+ HTTPMSGLOCK(chl->reply);
+ return chl->fastCheck() != ACCESS_ALLOWED; // when in doubt, block
+ }
+
+ // This does not happen, I hope, because we are called from CacheHit, which
+ // is called via a storeClientCopy() callback, and store should initialize
+ // the reply before calling that callback.
+ debugs(88, 3, "Missing reply!");
+ return false;
+ }
+
void
clientReplyContext::purgeRequestFindObjectToPurge()
{
for (HttpRequestMethod m(Http::METHOD_NONE); m != Http::METHOD_ENUM_END; ++m) {
if (m.respMaybeCacheable()) {
if (StoreEntry *entry = storeGetPublic(url, m)) {
- debugs(88, 5, "purging " << RequestMethodStr(m) << ' ' << url);
+ debugs(88, 5, "purging " << *entry << ' ' << RequestMethodStr(m) << ' ' << url);
#if USE_HTCP
neighborsHtcpClear(entry, url, req, m, HTCP_CLR_INVALIDATION);
if (m == Http::METHOD_GET || m == Http::METHOD_HEAD) {
ErrorState *err = clientBuildError(ERR_ACCESS_DENIED, Http::scForbidden, NULL,
http->getConn()->clientConnection->remote, http->request);
startError(err);
- return;
+ return; // XXX: leaking unused entry if some store does not keep it
}
StoreIOBuffer localTempBuffer;
/* Swap in the metadata */
http->storeEntry(entry);
- http->storeEntry()->lock();
- http->storeEntry()->createMemObject(storeId(), http->log_uri);
-
- http->storeEntry()->mem_obj->method = http->request->method;
+ http->storeEntry()->lock("clientReplyContext::purgeFoundObject");
+ http->storeEntry()->createMemObject(storeId(), http->log_uri,
+ http->request->method);
sc = storeClientListAdd(http->storeEntry(), this);
}
if ((done = checkTransferDone()) != 0 || flags.complete) {
- debugs(88, 5, "clientReplyStatus: transfer is DONE");
+ debugs(88, 5, "clientReplyStatus: transfer is DONE: " << done << flags.complete);
/* Ok we're finished, but how? */
const int64_t expectedBodySize =
return STREAM_UNPLANNED_COMPLETE;
}
- if (http->request->flags.proxyKeepalive) {
- debugs(88, 5, "clientReplyStatus: stream complete and can keepalive");
- return STREAM_COMPLETE;
- }
-
- debugs(88, 5, "clientReplyStatus: stream was not expected to complete!");
- return STREAM_UNPLANNED_COMPLETE;
+ debugs(88, 5, "clientReplyStatus: stream complete; keepalive=" <<
+ http->request->flags.proxyKeepalive);
+ return STREAM_COMPLETE;
}
// XXX: Should this be checked earlier? We could return above w/o checking.
buildReplyHeader();
}
+/// Safely disposes of an entry pointing to a cache hit that we do not want.
+/// We cannot just ignore the entry because it may be locking or otherwise
+/// holding an associated cache resource of some sort.
+void
+clientReplyContext::forgetHit()
+{
+ StoreEntry *e = http->storeEntry();
+ assert(e); // or we are not dealing with a hit
+ // We probably have not locked the entry earlier, unfortunately. We lock it
+ // now so that we can unlock two lines later (and trigger cleanup).
+ // Ideally, ClientHttpRequest::storeEntry() should lock/unlock, but it is
+ // used so inconsistently that simply adding locking there leads to bugs.
+ e->lock("clientReplyContext::forgetHit");
+ http->storeEntry(NULL);
+ e->unlock("clientReplyContext::forgetHit"); // may delete e
+}
+
void
clientReplyContext::identifyStoreObject()
{
if (NULL == http->storeEntry()) {
/** \li If no StoreEntry object is current assume this object isn't in the cache set MISS*/
- debugs(85, 3, "clientProcessRequest2: StoreEntry is NULL - MISS");
+ debugs(85, 3, "StoreEntry is NULL - MISS");
http->logType = LOG_TCP_MISS;
doGetMoreData();
return;
if (Config.onoff.offline) {
/** \li If we are running in offline mode set to HIT */
- debugs(85, 3, "clientProcessRequest2: offline HIT");
+ debugs(85, 3, "offline HIT " << *e);
http->logType = LOG_TCP_HIT;
doGetMoreData();
return;
if (http->redirect.status) {
/** \li If redirection status is True force this to be a MISS */
- debugs(85, 3, HERE << "REDIRECT status forced StoreEntry to NULL (no body on 3XX responses)");
- http->storeEntry(NULL);
+ debugs(85, 3, "REDIRECT status forced StoreEntry to NULL (no body on 3XX responses) " << *e);
+ forgetHit();
http->logType = LOG_TCP_REDIRECT;
doGetMoreData();
return;
}
if (!e->validToSend()) {
- debugs(85, 3, "clientProcessRequest2: !storeEntryValidToSend MISS" );
- http->storeEntry(NULL);
+ debugs(85, 3, "!storeEntryValidToSend MISS " << *e);
+ forgetHit();
http->logType = LOG_TCP_MISS;
doGetMoreData();
return;
if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) {
/* \li Special entries are always hits, no matter what the client says */
- debugs(85, 3, "clientProcessRequest2: ENTRY_SPECIAL HIT");
+ debugs(85, 3, "ENTRY_SPECIAL HIT " << *e);
http->logType = LOG_TCP_HIT;
doGetMoreData();
return;
}
if (r->flags.noCache) {
- debugs(85, 3, "clientProcessRequest2: no-cache REFRESH MISS");
- http->storeEntry(NULL);
+ debugs(85, 3, "no-cache REFRESH MISS " << *e);
+ forgetHit();
http->logType = LOG_TCP_CLIENT_REFRESH_MISS;
doGetMoreData();
return;
}
- debugs(85, 3, "clientProcessRequest2: default HIT");
+ debugs(85, 3, "default HIT " << *e);
http->logType = LOG_TCP_HIT;
doGetMoreData();
}
/* someone found the object in the cache for us */
StoreIOBuffer localTempBuffer;
- http->storeEntry()->lock();
+ http->storeEntry()->lock("clientReplyContext::doGetMoreData");
- if (http->storeEntry()->mem_obj == NULL) {
+ MemObject *mem_obj = http->storeEntry()->makeMemObject();
+ if (!mem_obj->hasUris()) {
/*
* This if-block exists because we don't want to clobber
* a preexiting mem_obj->method value if the mem_obj
* is a cache hit for a GET response, we want to keep
* the method as GET.
*/
- http->storeEntry()->createMemObject(storeId(), http->log_uri);
- http->storeEntry()->mem_obj->method = http->request->method;
+ mem_obj->setUris(storeId(), http->log_uri, http->request->method);
/**
* Here we can see if the object was
* created using URL or alternative StoreID from helper.
*/
- debugs(88, 3, "mem_obj->url: " << http->storeEntry()->mem_obj->url);
+ debugs(88, 3, "storeId: " << http->storeEntry()->mem_obj->storeId());
}
sc = storeClientListAdd(http->storeEntry(), this);
StoreEntry *e = storeCreateEntry(storeId(), http->log_uri, reqFlags, m);
+ // Make entry collapsable ASAP, to increase collapsing chances for others,
+ // TODO: every must-revalidate and similar request MUST reach the origin,
+ // but do we have to prohibit others from collapsing on that request?
+ if (Config.onoff.collapsed_forwarding && reqFlags.cachable &&
+ !reqFlags.needValidation &&
+ (m == Http::METHOD_GET || m == Http::METHOD_HEAD)) {
+ // make the entry available for future requests now
+ Store::Root().allowCollapsing(e, reqFlags, m);
+ }
+
sc = storeClientListAdd(e, this);
#if USE_DELAY_POOLS
void triggerInitialStoreRead();
void sendClientOldEntry();
void purgeAllCached();
+ void forgetHit();
+ bool blockedHit() const;
void sendBodyTooLargeError();
void sendPreconditionFailedError();
break;
case LFT_TIME_START: {
- int precision = fmt->widthMax >=0 ? fmt->widthMax :3;
- snprintf(tmp, sizeof(tmp), "%0*" PRId64 ".%0*d", fmt->zero && (fmt->widthMin - precision - 1 >= 0) ? fmt->widthMin - precision - 1 : 0, (int64_t)al->cache.start_time.tv_sec, precision, (int)(al->cache.start_time.tv_usec / fmt->divisor));
+ int precision = fmt->widthMax >=0 ? fmt->widthMax : 3;
+ snprintf(tmp, sizeof(tmp), "%0*" PRId64 ".%0*d", fmt->zero && (fmt->widthMin - precision - 1 >= 0) ? fmt->widthMin - precision - 1 : 0, static_cast<int64_t>(al->cache.start_time.tv_sec), precision, (int)(al->cache.start_time.tv_usec / fmt->divisor));
out = tmp;
}
- break;
+ break;
case LFT_TIME_TO_HANDLE_REQUEST:
outint = al->cache.msec;
debugs(9, 3, HERE);
if (code == 125 || (code == 150 && Comm::IsConnOpen(data.conn))) {
+ if (!originalRequest()->body_pipe) {
+ debugs(9, 3, "zero-size STOR?");
+ state = WRITING_DATA; // make ftpWriteTransferDone() responsible
+ dataComplete(); // XXX: keep in sync with doneSendingRequestBody()
+ return;
+ }
+
if (!startRequestBodyFlow()) { // register to receive body data
ftpFail(this);
return;
FtpStateData::completedListing()
{
assert(entry);
- entry->lock();
+ entry->lock("FtpStateData");
ErrorState ferr(ERR_DIR_LISTING, Http::scOkay, request);
ferr.ftp.listing = &listing;
ferr.ftp.cwd_msg = xstrdup(cwd_message.size()? cwd_message.termedBuf() : "");
entry->replaceHttpReply( ferr.BuildHttpReply() );
EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
entry->flush();
- entry->unlock();
+ entry->unlock("FtpStateData");
}
/// \ingroup ServerProtocolFTPInternal
* Authenticated requests can't be cached.
*/
e->release();
- } else if (EBIT_TEST(e->flags, ENTRY_CACHABLE) && !getCurrentOffset()) {
+ } else if (!EBIT_TEST(e->flags, RELEASE_REQUEST) && !getCurrentOffset()) {
e->setPublicKey();
} else {
e->release();