]> git.ipfire.org Git - thirdparty/squid.git/blame - src/clientStream.cc
Source Maintenance: enforce #include statement block ordering
[thirdparty/squid.git] / src / clientStream.cc
CommitLineData
edce4d98 1
2/*
edce4d98 3 * DEBUG: section 87 Client-side Stream routines.
4 * AUTHOR: Robert Collins
5 *
6 * SQUID Web Proxy Cache http://www.squid-cache.org/
7 * ----------------------------------------------------------
8 *
9 * Squid is the result of efforts by numerous individuals from
10 * the Internet community; see the CONTRIBUTORS file for full
11 * details. Many organizations have provided support for Squid's
12 * development; see the SPONSORS file for full details. Squid is
13 * Copyrighted (C) 2001 by the Regents of the University of
14 * California; see the COPYRIGHT file for full details. Squid
15 * incorporates software developed and/or copyrighted by other
16 * sources; see the CREDITS file for full details.
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
26ac0430 22 *
edce4d98 23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
26ac0430 27 *
edce4d98 28 * You should have received a copy of the GNU General Public License
e6ccf245 29 * along with thisObject program; if not, write to the Free Software
edce4d98 30 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
31 *
32 */
33
582c2af2 34#include "squid.h"
63be0a78 35#include "clientStream.h"
36#include "HttpReply.h"
37#include "HttpRequest.h"
38#include "client_side_request.h"
39
40/**
41 \defgroup ClientStreamInternal Client Streams Internals
42 \ingroup ClientStreamAPI
43 \par
edce4d98 44 * A client Stream is a uni directional pipe, with the usual non-blocking
45 * asynchronous approach present elsewhere in squid.
46 *
63be0a78 47 \par
edce4d98 48 * Each pipe node has a data push function, and a data request function.
49 * This limits flexability - the data flow is no longer assembled at each
26ac0430 50 * step.
edce4d98 51 *
63be0a78 52 \par
edce4d98 53 * An alternative approach is to pass each node in the pipe the call-
26ac0430
AJ
54 * back to use on each IO call. This allows the callbacks to be changed
55 * very easily by a participating node, but requires more maintenance
56 * in each node (store the callback to the most recent IO request in
57 * the nodes context.) Such an approach also prevents dynamically
edce4d98 58 * changing the pipeline from outside without an additional interface
59 * method to extract the callback and context from the next node.
60 *
63be0a78 61 \par
edce4d98 62 * One important characteristic of the stream is that the readfunc
63 * on the terminating node, and the callback on the first node
64 * will be NULL, and never used.
edce4d98 65 *
63be0a78 66 \section QuickNotes Quick Notes
67 \par
edce4d98 68 * Each node including the HEAD of the clientStream has a cbdataReference
69 * held by the stream. Freeing the stream then removes that reference
63be0a78 70 * and cbdataFree()'s every node.
26ac0430 71 * Any node with other References, and all nodes downstream will only
edce4d98 72 * free when those references are released.
26ac0430 73 * Stream nodes MAY hold references to the data member of the node.
edce4d98 74 *
63be0a78 75 \par
26ac0430 76 * Specifically - on creation no reference is made.
edce4d98 77 * If you pass a data variable to a node, give it an initial reference.
78 * If the data member is non-null on FREE, cbdataFree WILL be called.
79 * This you must never call cbdataFree on your own context without
80 * explicitly setting the stream node data member to NULL and
81 * cbdataReferenceDone'ing it.
82 *
63be0a78 83 \par
edce4d98 84 * No data member may hold a reference to it's stream node.
85 * The stream guarantees that DETACH will be called before
86 * freeing the node, alowing data members to cleanup.
26ac0430 87 *
63be0a78 88 \par
edce4d98 89 * If a node's data holds a reference to something that needs to
90 * free the stream a circular reference list will occur.
91 * This results no data being freed until that reference is removed.
e6ccf245 92 * One way to accomplish thisObject is to explicitly remove the
edce4d98 93 * data from your own node before freeing the stream.
94 *
63be0a78 95 \code
96 mycontext = thisObject->data;
97 thisObject->data = NULL;
98 clientStreamFree (thisObject->head);
99 mycontext = NULL;
100 return;
101 \endcode
102 *
103 \todo rather than each node undeleting the next, have a clientStreamDelete that walks the list.
edce4d98 104 */
105
63be0a78 106/// \ingroup ClientStreamInternal
107CBDATA_TYPE(clientStreamNode);
108
edce4d98 109/* Local functions */
110static FREE clientStreamFree;
111
63be0a78 112/// \ingroup ClientStreamInternal
edce4d98 113clientStreamNode *
114clientStreamNew(CSR * readfunc, CSCB * callback, CSD * detach, CSS * status,
0655fa4d 115 ClientStreamData data)
edce4d98 116{
117 clientStreamNode *temp;
118 CBDATA_INIT_TYPE_FREECB(clientStreamNode, clientStreamFree);
119 temp = cbdataAlloc(clientStreamNode);
120 temp->readfunc = readfunc;
121 temp->callback = callback;
122 temp->detach = detach;
123 temp->status = status;
124 temp->data = data;
125 return temp;
126}
127
63be0a78 128/**
129 \ingroup ClientStreamInternal
edce4d98 130 * Initialise a client Stream.
131 * list is the stream
132 * func is the read function for the head
133 * callback is the callback for the tail
134 * tailbuf and taillen are the initial buffer and length for the tail.
135 */
136void
137clientStreamInit(dlink_list * list, CSR * func, CSD * rdetach, CSS * readstatus,
0655fa4d 138 ClientStreamData readdata, CSCB * callback, CSD * cdetach, ClientStreamData callbackdata,
62e76326 139 StoreIOBuffer tailBuffer)
edce4d98 140{
141 clientStreamNode *temp = clientStreamNew(func, NULL, rdetach, readstatus,
62e76326 142 readdata);
7e6b941f 143 dlinkAdd(cbdataReference(temp), &temp->node, list);
edce4d98 144 temp->head = list;
145 clientStreamInsertHead(list, NULL, callback, cdetach, NULL, callbackdata);
e6ccf245 146 temp = (clientStreamNode *)list->tail->data;
c8be6d7b 147 temp->readBuffer = tailBuffer;
edce4d98 148}
149
63be0a78 150/**
151 \ingroup ClientStreamInternal
edce4d98 152 * Doesn't actually insert at head. Instead it inserts one *after*
153 * head. This is because HEAD is a special node, as is tail
154 * This function is not suitable for inserting the real HEAD.
edce4d98 155 */
156void
157clientStreamInsertHead(dlink_list * list, CSR * func, CSCB * callback,
0655fa4d 158 CSD * detach, CSS * status, ClientStreamData data)
edce4d98 159{
edce4d98 160
161 /* test preconditions */
162 assert(list != NULL);
163 assert(list->head);
0655fa4d 164 clientStreamNode *temp = clientStreamNew(func, callback, detach, status, data);
edce4d98 165 temp->head = list;
bf8fe701 166 debugs(87, 3, "clientStreamInsertHead: Inserted node " << temp <<
167 " with data " << data.getRaw() << " after head");
43ae1d95 168
169 if (list->head->next)
170 temp->readBuffer = ((clientStreamNode *)list->head->next->data)->readBuffer;
171
7e6b941f 172 dlinkAddAfter(cbdataReference(temp), &temp->node, list->head, list);
edce4d98 173}
174
63be0a78 175// API
edce4d98 176void
59a1efb2 177clientStreamCallback(clientStreamNode * thisObject, ClientHttpRequest * http,
62e76326 178 HttpReply * rep, StoreIOBuffer replyBuffer)
edce4d98 179{
180 clientStreamNode *next;
e6ccf245 181 assert(thisObject && http && thisObject->node.next);
182 next = thisObject->next();
edce4d98 183
26ac0430 184 debugs(87, 3, "clientStreamCallback: Calling " << next->callback << " with cbdata " <<
bf8fe701 185 next->data.getRaw() << " from node " << thisObject);
c8be6d7b 186 next->callback(next, http, rep, replyBuffer);
edce4d98 187}
188
63be0a78 189/**
190 \ingroup ClientStreamInternal
edce4d98 191 * Call the previous node in the chain to read some data
63be0a78 192 *
193 \param thisObject ??
194 \param http ??
195 \param readBuffer ??
edce4d98 196 */
197void
59a1efb2 198clientStreamRead(clientStreamNode * thisObject, ClientHttpRequest * http,
62e76326 199 StoreIOBuffer readBuffer)
edce4d98 200{
201 /* place the parameters on the 'stack' */
202 clientStreamNode *prev;
e6ccf245 203 assert(thisObject && http && thisObject->prev());
204 prev = thisObject->prev();
edce4d98 205
bf8fe701 206 debugs(87, 3, "clientStreamRead: Calling " << prev->readfunc <<
207 " with cbdata " << prev->data.getRaw() << " from node " << thisObject);
e6ccf245 208 thisObject->readBuffer = readBuffer;
edce4d98 209 prev->readfunc(prev, http);
210}
211
63be0a78 212/**
213 \ingroup ClientStreamInternal
edce4d98 214 * Detach from the stream - only allowed for terminal members
63be0a78 215 *
216 \param thisObject ??
217 \param http ??
edce4d98 218 */
219void
59a1efb2 220clientStreamDetach(clientStreamNode * thisObject, ClientHttpRequest * http)
edce4d98 221{
e6ccf245 222 clientStreamNode *temp = thisObject;
edce4d98 223
e6ccf245 224 assert(thisObject->node.next == NULL);
bf8fe701 225 debugs(87, 3, "clientStreamDetach: Detaching node " << thisObject);
e6ccf245 226 /* And clean up thisObject node */
edce4d98 227 /* ESI TODO: push refcount class through to head */
0655fa4d 228 clientStreamNode *prev = NULL;
229
230 if (thisObject->prev())
231 prev = cbdataReference(thisObject->prev());
232
233 thisObject->removeFromStream();
234
edce4d98 235 cbdataReferenceDone(temp);
0655fa4d 236
e6ccf245 237 cbdataFree(thisObject);
0655fa4d 238
edce4d98 239 /* and tell the prev that the detach has occured */
240 /*
e6ccf245 241 * We do it in thisObject order so that the detaching node is always
edce4d98 242 * at the end of the list
243 */
62e76326 244
edce4d98 245 if (prev) {
bf8fe701 246 debugs(87, 3, "clientStreamDetach: Calling " << prev->detach << " with cbdata " << prev->data.getRaw());
0655fa4d 247
248 if (cbdataReferenceValid(prev))
249 prev->detach(prev, http);
250
251 cbdataReferenceDone(prev);
edce4d98 252 }
253}
254
63be0a78 255/**
256 \ingroup ClientStreamInternal
edce4d98 257 * Abort the stream - detach every node in the pipeline.
63be0a78 258 *
259 \param thisObject ??
260 \param http ??
edce4d98 261 */
262void
59a1efb2 263clientStreamAbort(clientStreamNode * thisObject, ClientHttpRequest * http)
edce4d98 264{
265 dlink_list *list;
266
e6ccf245 267 assert(thisObject != NULL);
edce4d98 268 assert(http != NULL);
e6ccf245 269 list = thisObject->head;
bf8fe701 270 debugs(87, 3, "clientStreamAbort: Aborting stream with tail " << list->tail);
62e76326 271
edce4d98 272 if (list->tail) {
62e76326 273 clientStreamDetach((clientStreamNode *)list->tail->data, http);
edce4d98 274 }
275}
276
63be0a78 277/**
278 \ingroup ClientStreamInternal
279 * Call the upstream node to find it's status
280 *
281 \param thisObject ??
282 \param http ??
edce4d98 283 */
284clientStream_status_t
59a1efb2 285clientStreamStatus(clientStreamNode * thisObject, ClientHttpRequest * http)
edce4d98 286{
287 clientStreamNode *prev;
e6ccf245 288 assert(thisObject && http && thisObject->node.prev);
289 prev = (clientStreamNode *)thisObject->node.prev->data;
edce4d98 290 return prev->status(prev, http);
291}
292
293/* Local function bodies */
63be0a78 294
0655fa4d 295void
296clientStreamNode::removeFromStream()
297{
298 if (head)
299 dlinkDelete(&node, head);
300
301 head = NULL;
302}
303
63be0a78 304/// \ingroup ClientStreamInternal
edce4d98 305void
306clientStreamFree(void *foo)
307{
e6ccf245 308 clientStreamNode *thisObject = (clientStreamNode *)foo;
edce4d98 309
bf8fe701 310 debugs(87, 3, "Freeing clientStreamNode " << thisObject);
62e76326 311
0655fa4d 312 thisObject->removeFromStream();
313 thisObject->data = NULL;
edce4d98 314}
e6ccf245 315
43ae1d95 316clientStreamNode *
317clientStreamNode::prev() const
e6ccf245 318{
319 if (node.prev)
43ae1d95 320 return (clientStreamNode *)node.prev->data;
e6ccf245 321 else
62e76326 322 return NULL;
e6ccf245 323}
324
43ae1d95 325clientStreamNode *
326clientStreamNode::next() const
e6ccf245 327{
328 if (node.next)
43ae1d95 329 return (clientStreamNode *)node.next->data;
e6ccf245 330 else
62e76326 331 return NULL;
e6ccf245 332}