2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 #ifndef SQUID_SRC_STORECLIENT_H
10 #define SQUID_SRC_STORECLIENT_H
12 #include "acl/ChecklistFiller.h"
13 #include "base/AsyncCall.h"
14 #include "base/forward.h"
16 #include "store/ParsingBuffer.h"
17 #include "StoreIOBuffer.h"
18 #include "StoreIOState.h"
20 /// A storeClientCopy() callback function.
22 /// Upon storeClientCopy() success, StoreIOBuffer::flags.error is zero, and
23 /// * HTTP response headers (if any) are available via MemObject::freshestReply();
24 /// * HTTP response body bytes (if any) are available via StoreIOBuffer.
26 /// STCB callbacks may use response semantics to detect certain EOF conditions.
27 /// Callbacks that expect HTTP headers may call store_client::atEof(). Similar
28 /// to clientStreamCallback() callbacks, callbacks dedicated to receiving HTTP
29 /// bodies may use zero StoreIOBuffer::length as an EOF condition.
31 /// Errors are indicated by setting StoreIOBuffer flags.error.
32 using STCB
= void (void *, StoreIOBuffer
);
35 class ACLFilledChecklist
;
38 // TODO: Merge store_client into StoreClient.
39 /// a storeGetPublic*() caller
40 class StoreClient
: public Acl::ChecklistFiller
44 ~StoreClient () override
{}
46 /// \return LogTags (if the class logs transactions) or nil (otherwise)
47 virtual LogTags
*loggingTags() const = 0;
50 /// \returns whether the caller must collapse on the given entry
51 /// Before returning true, updates common collapsing-related stats.
52 /// See also: StoreEntry::hittingRequiresCollapsing().
53 bool startCollapsingOn(const StoreEntry
&, const bool doingRevalidation
) const;
55 // These methods only interpret Squid configuration. Their allowances are
56 // provisional -- other factors may prevent collapsed forwarding. The first
57 // two exist primarily to distinguish two major CF cases in callers code.
58 /// whether Squid configuration allows us to become a CF initiator
59 bool mayInitiateCollapsing() const { return onCollapsingPath(); }
60 /// whether Squid configuration allows collapsing for this transaction
61 bool onCollapsingPath() const;
63 /// whether startCollapsingOn() was called and returned true
64 mutable bool didCollapse
= false;
71 /* keep track each client receiving data from that particular StoreEntry */
75 CBDATA_CLASS(store_client
);
78 explicit store_client(StoreEntry
*);
81 /// the client will not use HTTP response bytes with lower offsets (if any)
82 auto discardableHttpEnd() const { return discardableHttpEnd_
; }
86 /// React to the end of reading the response from disk. There will be no
87 /// more readHeader() and readBody() callbacks for the current storeRead()
88 /// swapin after this notification.
89 void noteSwapInDone(bool error
);
91 void doCopy (StoreEntry
*e
);
92 void readHeader(const char *buf
, ssize_t len
);
93 void readBody(const char *buf
, ssize_t len
);
95 /// Request StoreIOBuffer-described response data via an asynchronous STCB
96 /// callback. At most one outstanding request is allowed per store_client.
97 void copy(StoreEntry
*, StoreIOBuffer
, STCB
*, void *);
99 void dumpStats(MemBuf
* output
, int clientNumber
) const;
101 // TODO: When STCB gets a dedicated Answer type, move this info there.
102 /// Whether the last successful storeClientCopy() answer was known to
103 /// contain the last body bytes of the HTTP response
104 /// \retval true requesting bytes at higher offsets is futile
106 bool atEof() const { return atEof_
; }
108 #if STORE_CLIENT_LIST_DEBUG
113 StoreEntry
*entry
; /* ptr to the parent StoreEntry, argh! */
114 StoreIOState::Pointer swapin_sio
;
117 /// whether we are expecting a response to be swapped in from disk
118 /// (i.e. whether async storeRead() is currently in progress)
119 // TODO: a better name reflecting the 'in' scope of the flag
120 bool disk_io_pending
;
122 /// whether the store_client::doCopy()-initiated STCB sequence is
123 /// currently in progress
130 /// The maximum number of bytes the Store client can read/copy next without
131 /// overflowing its buffer and without violating delay pool limits. Store
132 /// I/O is not rate-limited, but we assume that the same number of bytes may
133 /// be read from the Squid-to-server connection that may be rate-limited.
134 int bytesWanted() const;
136 void setDelayId(DelayId delay_id
);
142 bool moreToRead() const;
143 bool canReadFromMemory() const;
144 bool answeredOnce() const { return answers
>= 1; }
145 bool sendingHttpHeaders() const;
146 int64_t nextHttpReadOffset() const;
149 void scheduleDiskRead();
150 void readFromMemory();
153 void handleBodyFromDisk();
154 void maybeWriteFromDiskToMemory(const StoreIOBuffer
&);
156 bool parseHttpHeadersFromDisk();
157 bool tryParsingHttpHeaders();
158 void skipHttpHeadersFromDisk();
161 void callback(ssize_t
);
162 void noteCopiedBytes(size_t);
164 void finishCallback();
165 static void FinishCallback(store_client
*);
173 /// Storage and metadata associated with the current copy() request. Ought
174 /// to be ignored when not answering a copy() request.
175 /// * copyInto.offset is the requested HTTP response body offset;
176 /// * copyInto.data is the client-owned, client-provided result buffer;
177 /// * copyInto.length is the size of the .data result buffer;
178 /// * copyInto.flags are unused by this class.
179 StoreIOBuffer copyInto
;
181 // TODO: Convert to uint64_t after fixing mem_hdr::endOffset() and friends.
182 /// \copydoc discardableHttpEnd()
183 int64_t discardableHttpEnd_
= 0;
185 /// the total number of finishCallback() calls
188 /// Accumulates raw bytes read from Store while answering the current copy()
189 /// request. Buffer contents depends on the source and parsing stage; it may
190 /// hold (parts of) swap metadata, HTTP response headers, and/or HTTP
191 /// response body bytes.
192 std::optional
<Store::ParsingBuffer
> parsingBuffer
;
194 StoreIOBuffer lastDiskRead
; ///< buffer used for the last storeRead() call
196 /* Until we finish stuffing code into store_client */
201 Callback() = default;
203 Callback (STCB
*, void *);
205 /// Whether the copy() answer is needed/expected (by the client) and has
206 /// not been computed (by us). False during (asynchronous) answer
207 /// delivery to the STCB callback_handler.
208 bool pending() const;
210 STCB
*callback_handler
= nullptr; ///< where to deliver the answer
211 CallbackData cbData
; ///< the first STCB callback parameter
212 CodeContextPointer codeContext
; ///< Store client context
214 /// a scheduled asynchronous finishCallback() call (or nil)
215 AsyncCall::Pointer notifier
;
219 /// Asynchronously read HTTP response headers and/or body bytes from Store.
221 /// The requested zero-based HTTP body offset is specified via the
222 /// StoreIOBuffer::offset field. The first call (for a given store_client
223 /// object) must specify zero offset.
225 /// The requested HTTP body portion size is specified via the
226 /// StoreIOBuffer::length field. The function may return fewer body bytes.
228 /// See STCB for result delivery details.
229 void storeClientCopy(store_client
*, StoreEntry
*, StoreIOBuffer
, STCB
*, void *);
231 store_client
* storeClientListAdd(StoreEntry
* e
, void *data
);
232 int storeUnregister(store_client
* sc
, StoreEntry
* e
, void *data
);
233 int storePendingNClients(const StoreEntry
* e
);
234 int storeClientIsThisAClient(store_client
* sc
, void *someClient
);
236 #endif /* SQUID_SRC_STORECLIENT_H */