]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ICAP/ICAPClientRespmodPrecache.cc
Make Squid more robust in the event of unexpected ICAP server responses,
[thirdparty/squid.git] / src / ICAP / ICAPClientRespmodPrecache.cc
CommitLineData
774c051c 1#include "squid.h"
2#include "http.h"
3#include "MsgPipe.h"
4#include "MsgPipeData.h"
5#include "MsgPipeSource.h"
6#include "MsgPipeSink.h"
7#include "HttpRequest.h"
8#include "HttpReply.h"
bab98cf3 9#include "ICAPClientRespmodPrecache.h"
774c051c 10#include "ICAPClient.h"
11#include "ICAPServiceRep.h"
12
bab98cf3 13CBDATA_CLASS_INIT(ICAPClientRespmodPrecache);
774c051c 14
bab98cf3 15ICAPClientRespmodPrecache::ICAPClientRespmodPrecache(ICAPServiceRep::Pointer aService): service(aService), httpState(NULL), virgin(NULL), adapted(NULL)
774c051c 16{
bab98cf3 17 debug(93,5)("ICAPClientRespmodPrecache constructed, this=%p\n", this);
774c051c 18}
19
bab98cf3 20ICAPClientRespmodPrecache::~ICAPClientRespmodPrecache()
774c051c 21{
22 stop(notifyNone);
23 cbdataReferenceDone(httpState);
bab98cf3 24 debug(93,5)("ICAPClientRespmodPrecache destructed, this=%p\n", this);
774c051c 25
26 if (virgin != NULL)
27 freeVirgin();
28
29 if (adapted != NULL)
30 freeAdapted();
31
32 service = NULL;
33}
34
bab98cf3 35void ICAPClientRespmodPrecache::startRespMod(HttpStateData *anHttpState, HttpRequest *request, HttpReply *reply)
774c051c 36{
37 httpState = cbdataReference(anHttpState);
38
39 virgin = new MsgPipe("virgin"); // this is the place to create a refcount ptr
774c051c 40 virgin->source = this;
41 virgin->data = new MsgPipeData;
42 virgin->data->cause = requestLink(request);
43 virgin->data->header = reply;
44 virgin->data->body = new MemBuf;
45 virgin->data->body->init(ICAP::MsgPipeBufSizeMin, ICAP::MsgPipeBufSizeMax);
46
47 adapted = new MsgPipe("adapted");
774c051c 48 adapted->sink = this;
49#if ICAP_ANCHOR_LOOPBACK
50
51 adapted->data = new MsgPipeData;
52 adapted->data->cause = request; // should not hurt
53#else
54
55 ICAPInitXaction(service, virgin, adapted);
56#endif
57
58 virgin->sendSourceStart(); // we may have virgin data to provide
59 adapted->sendSinkNeed(); // we want adapted response, eventially
60}
61
bab98cf3 62void ICAPClientRespmodPrecache::sendMoreData(StoreIOBuffer buf)
774c051c 63{
bab98cf3 64 debug(93,5)("ICAPClientRespmodPrecache::sendMoreData() called\n");
774c051c 65 //buf.dump();
66 /*
67 * The caller is responsible for not giving us more data
68 * than will fit in body MemBuf. Caller should use
69 * potentialSpaceSize() to find out how much we can hold.
70 */
774c051c 71 virgin->data->body->append(buf.data, buf.length);
72 virgin->sendSourceProgress();
73}
74
75int
bab98cf3 76ICAPClientRespmodPrecache::potentialSpaceSize()
774c051c 77{
78 if (virgin == NULL)
79 return 0;
80
774c051c 81 return (int) virgin->data->body->potentialSpaceSize();
82}
83
84// HttpStateData says we have the entire HTTP message
bab98cf3 85void ICAPClientRespmodPrecache::doneSending()
774c051c 86{
bab98cf3 87 debug(93,5)("ICAPClientRespmodPrecache::doneSending() called\n");
774c051c 88
89#if ICAP_ANCHOR_LOOPBACK
90 /* simple assignments are not the right way to do this */
91 adapted->data->header = virgin->data->header;
92 adapted->data->body = virgin->data->body;
93 noteSourceFinish(adapted);
94 return;
95#else
96
774c051c 97 virgin->sendSourceFinish();
98#endif
99}
100
101// HttpStateData tells us to abort
bab98cf3 102void ICAPClientRespmodPrecache::ownerAbort()
774c051c 103{
bab98cf3 104 debug(93,5)("ICAPClientRespmodPrecache::ownerAbort() called\n");
774c051c 105 stop(notifyIcap);
106}
107
108// ICAP client needs more virgin response data
bab98cf3 109void ICAPClientRespmodPrecache::noteSinkNeed(MsgPipe *p)
774c051c 110{
bab98cf3 111 debug(93,5)("ICAPClientRespmodPrecache::noteSinkNeed() called\n");
774c051c 112
774c051c 113 if (virgin->data->body->potentialSpaceSize())
114 httpState->icapSpaceAvailable();
115}
116
117// ICAP client aborting
bab98cf3 118void ICAPClientRespmodPrecache::noteSinkAbort(MsgPipe *p)
774c051c 119{
bab98cf3 120 debug(93,5)("ICAPClientRespmodPrecache::noteSinkAbort() called\n");
774c051c 121 stop(notifyOwner);
122}
123
124// ICAP client starts sending adapted response
125// ICAP client has received new HTTP headers (if any) at this point
bab98cf3 126void ICAPClientRespmodPrecache::noteSourceStart(MsgPipe *p)
774c051c 127{
bab98cf3 128 debug(93,5)("ICAPClientRespmodPrecache::noteSourceStart() called\n");
774c051c 129
130 HttpReply *reply = dynamic_cast<HttpReply*>(adapted->data->header);
b559db5d 131 /*
132 * The ICAP reply MUST have a new HTTP reply header, or else
133 * it is an invalid ICAP message. Invalid ICAP messages should
134 * be handled prior to this point.
135 */
774c051c 136 assert(reply); // check that ICAP xaction created the right object
137 httpState->takeAdaptedHeaders(reply);
138
139 assert(reply == adapted->data->header);
140 adapted->data->header = NULL;
141
142 noteSourceProgress(p);
143}
144
145// ICAP client sends more data
bab98cf3 146void ICAPClientRespmodPrecache::noteSourceProgress(MsgPipe *p)
774c051c 147{
bab98cf3 148 debug(93,5)("ICAPClientRespmodPrecache::noteSourceProgress() called\n");
774c051c 149 //tell HttpStateData to store a fresh portion of the adapted response
150
774c051c 151 if (p->data->body->hasContent()) {
152 httpState->takeAdaptedBody(p->data->body);
153 }
154}
155
156// ICAP client is done sending adapted response
bab98cf3 157void ICAPClientRespmodPrecache::noteSourceFinish(MsgPipe *p)
774c051c 158{
bab98cf3 159 debug(93,5)("ICAPClientRespmodPrecache::noteSourceFinish() called\n");
774c051c 160 //tell HttpStateData that we expect no more response data
774c051c 161 httpState->doneAdapting();
162 stop(notifyNone);
163}
164
165// ICAP client is aborting
bab98cf3 166void ICAPClientRespmodPrecache::noteSourceAbort(MsgPipe *p)
774c051c 167{
bab98cf3 168 debug(93,5)("ICAPClientRespmodPrecache::noteSourceAbort() called\n");
774c051c 169 stop(notifyOwner);
170}
171
172// internal cleanup
bab98cf3 173void ICAPClientRespmodPrecache::stop(Notify notify)
774c051c 174{
175 if (virgin != NULL) {
774c051c 176 if (notify == notifyIcap)
177 virgin->sendSourceAbort();
178 else
179 virgin->source = NULL;
180
181 freeVirgin();
182 }
183
184 if (adapted != NULL) {
774c051c 185 if (notify == notifyIcap)
186 adapted->sendSinkAbort();
187 else
188 adapted->sink = NULL;
189
190 freeAdapted();
191 }
192
193 if (httpState) {
194 if (notify == notifyOwner)
195 // tell HttpStateData that we are aborting prematurely
196 httpState->abortAdapting();
197
198 cbdataReferenceDone(httpState);
199
200 // httpState is now NULL, will not call it any more
201 }
202}
203
bab98cf3 204void ICAPClientRespmodPrecache::freeVirgin()
774c051c 205{
206 requestUnlink(virgin->data->cause);
207 virgin->data->cause = NULL;
208 virgin->data->header = NULL;
774c051c 209 virgin = NULL; // refcounted
210}
211
bab98cf3 212void ICAPClientRespmodPrecache::freeAdapted()
774c051c 213{
214 /*
215 * Note on adapted->data->header. ICAPXaction-side created it
216 * but gave control of it to us. Normally we give it to
217 * HttpStateData::takeAdaptedHeader. If not, we have to
218 * make sure it gets deleted;
219 */
220
221 if (adapted->data->header != NULL) {
222 debug(93,3)("hey, adapted->data->header is still set!\n");
223 delete adapted->data->header;
224 adapted->data->header = NULL;
225 }
226
774c051c 227 adapted = NULL; // refcounted
228}