]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) 1996-2020 The Squid Software Foundation and contributors | |
3 | * | |
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. | |
7 | */ | |
8 | ||
9 | #ifndef SQUID_CLIENTSTREAM_H | |
10 | #define SQUID_CLIENTSTREAM_H | |
11 | ||
12 | #include "base/RefCount.h" | |
13 | #include "clientStreamForward.h" | |
14 | #include "dlink.h" | |
15 | #include "StoreIOBuffer.h" | |
16 | ||
17 | /** | |
18 | \defgroup ClientStreamAPI Client Streams API | |
19 | \ingroup Components | |
20 | \section ClientStreamIntroduction Introduction | |
21 | \par | |
22 | * A ClientStream implements a unidirectional, non-blocking, | |
23 | * pull pipeline. They allow code to be inserted into the | |
24 | * reply logic on an as-needed basis. For instance, | |
25 | * transfer-encoding logic is only needed when sending a | |
26 | * HTTP/1.1 reply. | |
27 | * | |
28 | \par | |
29 | * Each node consists of four methods - read, callback, detach, and status, | |
30 | * along with the stream housekeeping variables (a dlink node and pointer | |
31 | * to the head of the list), context data for the node, and read request | |
32 | * parameters - readbuf, readlen and readoff (in the body). | |
33 | * | |
34 | \par | |
35 | * clientStream is the basic unit for scheduling, and the clientStreamRead() | |
36 | * and clientStreamCallback() calls allow for deferred scheduled activity if | |
37 | * desired. | |
38 | * | |
39 | \section OperationTheory Theory on stream operation | |
40 | \par | |
41 | \li Something creates a pipeline. At a minimum it needs a head with a | |
42 | * status method and a read method, and a tail with a callback method | |
43 | * and a valid initial read request. | |
44 | \li Other nodes may be added into the pipeline. | |
45 | \li The tail-1th node's read method is called. | |
46 | * | |
47 | \par | |
48 | * For each node going up the pipeline, the node either: | |
49 | \li satisfies the read request, or | |
50 | \li inserts a new node above it and calls clientStreamRead(), or | |
51 | \li calls clientStreamRead() | |
52 | \todo DOCS: make the above list nested. | |
53 | * | |
54 | \par | |
55 | * There is no requirement for the Read parameters from different | |
56 | * nodes to have any correspondence, as long as the callbacks provided are | |
57 | * correct. | |
58 | * | |
59 | \section WhatsInANode Whats in a node | |
60 | * | |
61 | \todo ClientStreams: These details should really be codified as a class which all ClientStream nodes inherit from. | |
62 | * | |
63 | \par Each node must have: | |
64 | \li read method - to allow loose coupling in the pipeline. (The reader may | |
65 | therefore change if the pipeline is altered, even mid-flow). | |
66 | \li callback method - likewise. | |
67 | \li status method - likewise. | |
68 | \li detach method - used to ensure all resources are cleaned up properly. | |
69 | \li dlink head pointer - to allow list inserts and deletes from within a node. | |
70 | \li context data - to allow the called back nodes to maintain their private information. | |
71 | \li read request parameters - For two reasons: | |
72 | \li To allow a node to determine the requested data offset, length and target buffer dynamically. Again, this is to promote loose coupling. | |
73 | \li Because of the callback nature of squid, every node would have to keep these parameters in their context anyway, so this reduces programmer overhead. | |
74 | */ | |
75 | ||
76 | class clientStreamNode | |
77 | { | |
78 | CBDATA_CLASS(clientStreamNode); | |
79 | ||
80 | public: | |
81 | clientStreamNode(CSR * aReadfunc, CSCB * aCallback, CSD * aDetach, CSS * aStatus, ClientStreamData); | |
82 | ~clientStreamNode(); | |
83 | ||
84 | clientStreamNode *prev() const; | |
85 | clientStreamNode *next() const; | |
86 | void removeFromStream(); | |
87 | ||
88 | dlink_node node; | |
89 | dlink_list *head; /* sucks I know, but hey, the interface is limited */ | |
90 | CSR *readfunc; | |
91 | CSCB *callback; | |
92 | CSD *detach; /* tell this node the next one downstream wants no more data */ | |
93 | CSS *status; | |
94 | ClientStreamData data; /* Context for the node */ | |
95 | StoreIOBuffer readBuffer; /* what, where and how much this node wants */ | |
96 | }; | |
97 | ||
98 | /// \ingroup ClientStreamAPI | |
99 | void clientStreamInit(dlink_list *, CSR *, CSD *, CSS *, ClientStreamData, CSCB *, CSD *, ClientStreamData, StoreIOBuffer tailBuffer); | |
100 | ||
101 | /// \ingroup ClientStreamAPI | |
102 | void clientStreamInsertHead(dlink_list *, CSR *, CSCB *, CSD *, CSS *, ClientStreamData); | |
103 | ||
104 | /** | |
105 | \ingroup ClientStreamAPI | |
106 | * | |
107 | * Call back the next node the in chain with it's requested data. | |
108 | * Return data to the next node in the stream. | |
109 | * The data may be returned immediately, or may be delayed for a later scheduling cycle. | |
110 | * | |
111 | \param thisObject 'this' reference for the client stream | |
112 | \param http Superset of request data, being winnowed down over time. MUST NOT be NULL. | |
113 | \param rep Not NULL on the first call back only. Ownership is passed down the pipeline. | |
114 | Each node may alter the reply if appropriate. | |
115 | \param replyBuffer - buffer, length - where and how much. | |
116 | */ | |
117 | void clientStreamCallback(clientStreamNode *thisObject, ClientHttpRequest *http, HttpReply *rep, StoreIOBuffer replyBuffer); | |
118 | ||
119 | /** | |
120 | \ingroup ClientStreamAPI | |
121 | * | |
122 | * Triggers a read of data that satisfies the httpClientRequest | |
123 | * metainformation and (if appropriate) the offset,length and buffer | |
124 | * parameters. | |
125 | * | |
126 | \param thisObject 'this' reference for the client stream | |
127 | \param http Superset of request data, being winnowed down over time. MUST NOT be NULL. | |
128 | \param readBuffer - offset, length, buffer - what, how much and where. | |
129 | */ | |
130 | void clientStreamRead(clientStreamNode *thisObject, ClientHttpRequest *http, StoreIOBuffer readBuffer); | |
131 | ||
132 | /** | |
133 | \ingroup ClientStreamAPI | |
134 | * | |
135 | * Removes this node from a clientStream. The stream infrastructure handles the removal. | |
136 | * This node MUST have cleaned up all context data, UNLESS scheduled callbacks will take care of that. | |
137 | * Informs the prev node in the list of this nodes detachment. | |
138 | * | |
139 | \param thisObject 'this' reference for the client stream | |
140 | \param http MUST NOT be NULL. | |
141 | */ | |
142 | void clientStreamDetach(clientStreamNode *thisObject, ClientHttpRequest *http); | |
143 | ||
144 | /** | |
145 | \ingroup ClientStreamAPI | |
146 | * | |
147 | * Detachs the tail of the stream. CURRENTLY DOES NOT clean up the tail node data - | |
148 | * this must be done separately. Thus Abort may ONLY be called by the tail node. | |
149 | * | |
150 | \param thisObject 'this' reference for the client stream | |
151 | \param http MUST NOT be NULL. | |
152 | */ | |
153 | void clientStreamAbort(clientStreamNode *thisObject, ClientHttpRequest *http); | |
154 | ||
155 | /** | |
156 | \ingroup ClientStreamAPI | |
157 | * | |
158 | * Allows nodes to query the upstream nodes for : | |
159 | \li stream ABORTS - request cancelled for some reason. upstream will not accept further reads(). | |
160 | \li stream COMPLETION - upstream has completed and will not accept further reads(). | |
161 | \li stream UNPLANNED COMPLETION - upstream has completed, but not at a pre-planned location (used for keepalive checking), and will not accept further reads(). | |
162 | \li stream NONE - no special status, further reads permitted. | |
163 | * | |
164 | \param thisObject 'this' reference for the client stream | |
165 | \param http MUST NOT be NULL. | |
166 | */ | |
167 | clientStream_status_t clientStreamStatus(clientStreamNode *thisObject, ClientHttpRequest *http); | |
168 | ||
169 | #endif /* SQUID_CLIENTSTREAM_H */ | |
170 |