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