]> git.ipfire.org Git - thirdparty/squid.git/blame - src/Downloader.cc
fix SrvBio::serverCertificates call now called SrvBio::serverCertificatesIfAny
[thirdparty/squid.git] / src / Downloader.cc
CommitLineData
55369ae6
AR
1#include "squid.h"
2#include "client_side.h"
3#include "client_side_request.h"
4#include "client_side_reply.h"
5#include "Downloader.h"
6#include "http/one/RequestParser.h"
54fb1cbf 7#include "http/Stream.h"
55369ae6
AR
8
9CBDATA_CLASS_INIT(Downloader);
10
4e526b93 11Downloader::Downloader(SBuf &url, const MasterXaction::Pointer &xact, AsyncCall::Pointer &aCallback, unsigned int level):
55369ae6
AR
12 AsyncJob("Downloader"),
13 ConnStateData(xact),
14 url_(url),
15 callback(aCallback),
4e526b93
CT
16 status(Http::scNone),
17 level_(level)
55369ae6 18{
7b4984f7 19 transferProtocol = AnyP::ProtocolVersion(AnyP::PROTO_HTTP,1,1);
55369ae6
AR
20}
21
22Downloader::~Downloader()
23{
24 debugs(33 , 2, "Downloader Finished");
25}
26
27void
28Downloader::callException(const std::exception &e)
29{
30 debugs(33 , 2, "Downloader caught:" << e.what());
31 AsyncJob::callException(e);
32}
33
34bool
35Downloader::doneAll() const
36{
37 return (!callback || callback->canceled()) && AsyncJob::doneAll();
38}
39
40void
41Downloader::start()
42{
43 BodyProducer::start();
44 HttpControlMsgSink::start();
54fb1cbf 45 if (Http::Stream *context = parseOneRequest()) {
55369ae6
AR
46 context->registerWithConn();
47 processParsedRequest(context);
48
49 /**/
50 if (context->flags.deferred) {
d3b1bee6 51 if (context != context->http->getConn()->pipeline.front().getRaw())
55369ae6
AR
52 context->deferRecipientForLater(context->deferredparams.node, context->deferredparams.rep, context->deferredparams.queuedBuffer);
53 else
54 context->http->getConn()->handleReply(context->deferredparams.rep, context->deferredparams.queuedBuffer);
55 }
56 /**/
57
58 }
59
60}
61
62void
63Downloader::noteMoreBodySpaceAvailable(BodyPipe::Pointer)
64{
65 // This method required only if we need to support uploading data to server
66 // Currently only GET requests are supported
67 assert(0);
68}
69
70void
71Downloader::noteBodyConsumerAborted(BodyPipe::Pointer)
72{
73 // This method required only if we need to support uploading data to server
74 // Currently only GET requests are supported
75 assert(0);
76}
77
54fb1cbf 78Http::Stream *
55369ae6
AR
79Downloader::parseOneRequest()
80{
81 const HttpRequestMethod method = Http::METHOD_GET;
82
83 char *uri = strdup(url_.c_str());
524a2eee 84 HttpRequest *const request = HttpRequest::CreateFromUrl(uri, method);
55369ae6
AR
85 if (!request) {
86 debugs(33, 5, "Invalid FTP URL: " << uri);
87 safe_free(uri);
88 return NULL; //earlyError(...)
89 }
90 request->http_ver = Http::ProtocolVersion();
91 request->header.putStr(Http::HdrType::HOST, request->url.host());
92 request->header.putTime(Http::HdrType::DATE, squid_curtime);
93
94 ClientHttpRequest *const http = new ClientHttpRequest(this);
95 http->request = request;
96 HTTPMSGLOCK(http->request);
97 http->req_sz = 0;
98 http->uri = uri;
99
54fb1cbf 100 Http::Stream *const context = new Http::Stream(NULL, http);
55369ae6
AR
101 StoreIOBuffer tempBuffer;
102 tempBuffer.data = context->reqbuf;
103 tempBuffer.length = HTTP_REQBUF_SZ;
104
105 ClientStreamData newServer = new clientReplyContext(http);
106 ClientStreamData newClient = context;
107 clientStreamInit(&http->client_stream, clientGetMoreData, clientReplyDetach,
108 clientReplyStatus, newServer, clientSocketRecipient,
109 clientSocketDetach, newClient, tempBuffer);
110
111 context->flags.parsed_ok = 1;
112 return context;
113}
114
115void
54fb1cbf 116Downloader::processParsedRequest(Http::Stream *context)
55369ae6
AR
117{
118 Must(context != NULL);
d3b1bee6 119 Must(pipeline.nrequests == 1);
55369ae6
AR
120
121 ClientHttpRequest *const http = context->http;
122 assert(http != NULL);
123
124 debugs(33, 4, "forwarding request to server side");
125 assert(http->storeEntry() == NULL);
126 clientProcessRequest(this, Http1::RequestParserPointer(), context);
127}
128
129time_t
130Downloader::idleTimeout() const
131{
132 // No need to be implemented for connection-less ConnStateData object.
133 assert(0);
134 return 0;
135}
136
137void
d3b1bee6 138Downloader::writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call)
55369ae6
AR
139{
140}
141
142void
143Downloader::handleReply(HttpReply *reply, StoreIOBuffer receivedData)
144{
54fb1cbf 145 Http::StreamPointer context = pipeline.front();
55369ae6 146 bool existingContent = reply ? reply->content_length : 0;
d3b1bee6 147 bool exceedSize = (context->startOfOutput() && existingContent > -1 && (size_t)existingContent > MaxObjectSize) ||
6cae08c9 148 ((object.length() + receivedData.length) > MaxObjectSize);
55369ae6
AR
149
150 if (exceedSize) {
151 status = Http::scInternalServerError;
152 callBack();
153 return;
154 }
155
156 debugs(33, 4, "Received " << receivedData.length <<
157 " object data, offset: " << receivedData.offset <<
158 " error flag:" << receivedData.flags.error);
159
160 if (receivedData.length > 0) {
161 object.append(receivedData.data, receivedData.length);
d3b1bee6
CT
162 context->http->out.size += receivedData.length;
163 context->noteSentBodyBytes(receivedData.length);
55369ae6
AR
164 }
165
d3b1bee6 166 switch (context->socketState()) {
55369ae6
AR
167 case STREAM_NONE:
168 debugs(33, 3, "Get more data");
d3b1bee6 169 context->pullData();
55369ae6
AR
170 break;
171 case STREAM_COMPLETE:
172 debugs(33, 3, "Object data transfer successfully complete");
173 status = Http::scOkay;
174 callBack();
175 break;
176 case STREAM_UNPLANNED_COMPLETE:
177 debugs(33, 3, "Object data transfer failed: STREAM_UNPLANNED_COMPLETE");
178 status = Http::scInternalServerError;
179 callBack();
180 break;
181 case STREAM_FAILED:
182 debugs(33, 3, "Object data transfer failed: STREAM_FAILED");
183 status = Http::scInternalServerError;
184 callBack();
185 break;
186 default:
187 fatal("unreachable code");
188 }
189}
190
191void
192Downloader::downloadFinished()
193{
194 debugs(33, 3, "fake call, to just delete the Downloader");
195
196 // Not really needed. Squid will delete this object because "doneAll" is true.
197 //deleteThis("completed");
198}
199
200void
201Downloader::callBack()
202{
203 CbDialer *dialer = dynamic_cast<CbDialer*>(callback->getDialer());
204 Must(dialer);
205 dialer->status = status;
206 if (status == Http::scOkay)
207 dialer->object = object;
208 ScheduleCallHere(callback);
209 callback = NULL;
210 // Calling deleteThis method here to finish Downloader
211 // may result to squid crash.
212 // This method called by handleReply method which maybe called
213 // by ClientHttpRequest::doCallouts. The doCallouts after this object deleted
214 // may operate on non valid objects.
215 // Schedule a fake call here just to force squid to delete this object
216 CallJobHere(33, 7, CbcPointer<Downloader>(this), Downloader, downloadFinished);
217}
218
219bool
220Downloader::isOpen() const
221{
222 return cbdataReferenceValid(this) && // XXX: checking "this" in a method
223 callback != NULL;
224}