/* * Copyright (C) 1996-2023 The Squid Software Foundation and contributors * * Squid software is distributed under GPLv2+ license and includes * contributions from numerous individuals and organizations. * Please see the COPYING and CONTRIBUTORS files for details. */ #ifndef SQUID_SRC_CLIENT_SIDE_REPLY_H #define SQUID_SRC_CLIENT_SIDE_REPLY_H #include "acl/forward.h" #include "client_side_request.h" #include "ip/forward.h" #include "RequestFlags.h" #include "StoreClient.h" class ErrorState; /* XXX make static method */ class clientReplyContext : public RefCountable, public StoreClient { CBDATA_CLASS(clientReplyContext); public: static STCB CacheHit; static STCB HandleIMSReply; static STCB SendMoreData; clientReplyContext(ClientHttpRequest *); ~clientReplyContext() override; void saveState(); void restoreState(); void purgeRequest (); void doGetMoreData(); void identifyStoreObject(); void identifyFoundObject(StoreEntry *entry, const char *detail); int storeOKTransferDone() const; int storeNotOKTransferDone() const; /// replaces current response store entry with the given one void setReplyToStoreEntry(StoreEntry *e, const char *reason); /// builds error using clientBuildError() and calls setReplyToError() below void setReplyToError(err_type, Http::StatusCode, char const *, const ConnStateData *, HttpRequest *, const char *, #if USE_AUTH Auth::UserRequest::Pointer); #else void * unused); #endif /// creates a store entry for the reply and appends err to it void setReplyToError(const HttpRequestMethod& method, ErrorState *err); /// creates a store entry for the reply and appends error reply to it void setReplyToReply(HttpReply *reply); void createStoreEntry(const HttpRequestMethod& m, RequestFlags flags); void removeStoreReference(store_client ** scp, StoreEntry ** ep); void removeClientStoreReference(store_client **scp, ClientHttpRequest *http); void startError(ErrorState * err); void processExpired(); clientStream_status_t replyStatus(); void processMiss(); void traceReply(); const char *storeId() const { return (http->store_id.size() > 0 ? http->store_id.termedBuf() : http->uri); } Http::StatusCode purgeStatus; /* StoreClient API */ LogTags *loggingTags() const override; ClientHttpRequest *http; store_client *sc; /* The store_client we're using */ /// Buffer dedicated to receiving storeClientCopy() responses to generated /// revalidation requests. These requests cannot use next()->readBuffer /// because the latter keeps the contents of the stale HTTP response during /// revalidation. sendClientOldEntry() uses that contents. char tempbuf[HTTP_REQBUF_SZ]; struct Flags { Flags() : storelogiccomplete(0), complete(0), headersSent(false) {} unsigned storelogiccomplete:1; unsigned complete:1; ///< we have read all we can from upstream bool headersSent; } flags; clientStreamNode *ourNode; /* This will go away if/when this file gets refactored some more */ private: /* StoreClient API */ void fillChecklist(ACLFilledChecklist &) const override; clientStreamNode *getNextNode() const; void makeThisHead(); bool errorInStream(const StoreIOBuffer &result) const; bool matchesStreamBodyBuffer(const StoreIOBuffer &) const; void sendStreamError(StoreIOBuffer const &result); void pushStreamData(const StoreIOBuffer &); clientStreamNode * next() const; HttpReply *reply; void processReplyAccess(); static ACLCB ProcessReplyAccessResult; void processReplyAccessResult(const Acl::Answer &accessAllowed); void cloneReply(); void buildReplyHeader (); bool alwaysAllowResponse(Http::StatusCode sline) const; int checkTransferDone(); void processOnlyIfCachedMiss(); bool processConditional(); void noteStreamBufferredBytes(const StoreIOBuffer &); void cacheHit(StoreIOBuffer result); void handleIMSReply(StoreIOBuffer result); void sendMoreData(StoreIOBuffer result); void triggerInitialStoreRead(STCB = SendMoreData); void requestMoreBodyFromStore(); void sendClientOldEntry(); void purgeAllCached(); /// attempts to release the cached entry /// \returns whether the entry was released bool purgeEntry(StoreEntry &, const Http::MethodType, const char *descriptionPrefix = ""); /// releases both cached GET and HEAD entries void purgeDoPurge(); void forgetHit(); bool blockedHit() const; const char *storeLookupString(bool found) const { return found ? "match" : "mismatch"; } void detailStoreLookup(const char *detail); void sendBodyTooLargeError(); void sendPreconditionFailedError(); void sendNotModified(); void sendNotModifiedOrPreconditionFailedError(); void sendClientUpstreamResponse(const StoreIOBuffer &upstreamResponse); /// Reduces a chance of an accidental direct storeClientCopy() call that /// (should but) forgets to invalidate our lastStreamBufferedBytes. This /// function is not defined; decltype() syntax prohibits "= delete", but /// function usage will trigger deprecation warnings and linking errors. static decltype(::storeClientCopy) storeClientCopy [[deprecated]]; /// Classification of the initial Store lookup. /// This very first lookup happens without the Vary-driven key augmentation. /// TODO: Exclude internal Store match bans from the "mismatch" category. const char *firstStoreLookup_ = nullptr; /* (stale) cache hit information preserved during IMS revalidation */ StoreEntry *old_entry; store_client *old_sc; time_t old_lastmod; String old_etag; bool deleting; typedef enum { crNone = 0, ///< collapsed revalidation is not allowed for this context crInitiator, ///< we initiated collapsed revalidation request crSlave ///< we collapsed on the existing revalidation request } CollapsedRevalidation; CollapsedRevalidation collapsedRevalidation; /// HTTP response body bytes stored in our Client Stream buffer (if any) StoreIOBuffer lastStreamBufferedBytes; // TODO: Remove after moving the meat of this function into a method. friend CSR clientGetMoreData; }; // TODO: move to SideAgent parent, when we have one void purgeEntriesByUrl(HttpRequest *, const char *); #endif /* SQUID_SRC_CLIENT_SIDE_REPLY_H */