]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/Downloader.cc
Source Format Enforcement (#763)
[thirdparty/squid.git] / src / Downloader.cc
index de2dd9d6c658b2214a916bc7796eb004eebcbabd..ee5433b6581a5a5647763429807e8559b07900e7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
  *
  * Squid software is distributed under GPLv2+ license and includes
  * contributions from numerous individuals and organizations.
@@ -8,10 +8,11 @@
 
 #include "squid.h"
 #include "client_side.h"
-#include "client_side_request.h"
 #include "client_side_reply.h"
+#include "client_side_request.h"
 #include "ClientRequestContext.h"
 #include "Downloader.h"
+#include "fatal.h"
 #include "http/one/RequestParser.h"
 #include "http/Stream.h"
 
@@ -56,16 +57,34 @@ DownloaderContext::finished()
     http = nullptr;
 }
 
-Downloader::Downloader(SBuf &url, AsyncCall::Pointer &aCallback, unsigned int level):
+void
+Downloader::CbDialer::print(std::ostream &os) const
+{
+    os << " Http Status:" << status << Raw("body data", object.rawContent(), 64).hex();
+}
+
+Downloader::Downloader(SBuf &url, AsyncCall::Pointer &aCallback, const XactionInitiator initiator, unsigned int level):
     AsyncJob("Downloader"),
     url_(url),
     callback_(aCallback),
-    level_(level)
+    level_(level),
+    initiator_(initiator)
 {
 }
 
 Downloader::~Downloader()
 {
+    debugs(33, 6, this);
+}
+
+void
+Downloader::swanSong()
+{
+    debugs(33, 6, this);
+    if (context_) {
+        context_->finished();
+        context_ = nullptr;
+    }
 }
 
 bool
@@ -79,7 +98,7 @@ downloaderRecipient(clientStreamNode * node, ClientHttpRequest * http,
                     HttpReply * rep, StoreIOBuffer receivedData)
 {
     debugs(33, 6, MYNAME);
-     /* Test preconditions */
+    /* Test preconditions */
     assert(node);
 
     /* TODO: handle this rather than asserting
@@ -106,20 +125,18 @@ downloaderDetach(clientStreamNode * node, ClientHttpRequest * http)
 /// Initializes and starts the HTTP GET request to the remote server
 bool
 Downloader::buildRequest()
-{ 
+{
     const HttpRequestMethod method = Http::METHOD_GET;
 
-    char *uri = xstrdup(url_.c_str());
-    HttpRequest *const request = HttpRequest::CreateFromUrl(uri, method);
+    const MasterXaction::Pointer mx = new MasterXaction(initiator_);
+    auto * const request = HttpRequest::FromUrl(url_, mx, method);
     if (!request) {
         debugs(33, 5, "Invalid URI: " << url_);
-        xfree(uri);
         return false; //earlyError(...)
     }
     request->http_ver = Http::ProtocolVersion();
     request->header.putStr(Http::HdrType::HOST, request->url.host());
     request->header.putTime(Http::HdrType::DATE, squid_curtime);
-    request->flags.internalClient = true;
     request->client_addr.setNoAddr();
 #if FOLLOW_X_FORWARDED_FOR
     request->indirect_client_addr.setNoAddr();
@@ -134,11 +151,10 @@ Downloader::buildRequest()
            "\n----------");
 
     ClientHttpRequest *const http = new ClientHttpRequest(nullptr);
-    http->request = request;
-    HTTPMSGLOCK(http->request);
+    http->initRequest(request);
     http->req_sz = 0;
-    http->uri = uri;
-    setLogUri (http, urlCanonicalClean(request));
+    // XXX: performance regression. c_str() reallocates
+    http->uri = xstrdup(url_.c_str());
 
     context_ = new DownloaderContext(this, http);
     StoreIOBuffer tempBuffer;
@@ -192,11 +208,9 @@ Downloader::handleReply(clientStreamNode * node, ClientHttpRequest *http, HttpRe
         return;
     }
 
-    if (receivedData.length) {
-        object_.append(receivedData.data, receivedData.length);
-        http->out.size += receivedData.length;
-        http->out.offset += receivedData.length;
-    }
+    object_.append(receivedData.data, receivedData.length);
+    http->out.size += receivedData.length;
+    http->out.offset += receivedData.length;
 
     switch (clientStreamStatus(node, http)) {
     case STREAM_NONE: {
@@ -207,7 +221,7 @@ Downloader::handleReply(clientStreamNode * node, ClientHttpRequest *http, HttpRe
         tempBuffer.length = HTTP_REQBUF_SZ;
         clientStreamRead(node, http, tempBuffer);
     }
-        break;
+    break;
     case STREAM_COMPLETE:
         debugs(33, 3, "Object data transfer successfully complete");
         callBack(Http::scOkay);
@@ -229,12 +243,6 @@ void
 Downloader::downloadFinished()
 {
     debugs(33, 7, this);
-    // We cannot delay http destruction until refcounting deletes 
-    // DownloaderContext. The http object destruction will cause 
-    // clientStream cleanup and will release the refcount to context_
-    // object hold by clientStream structures.
-    context_->finished();
-    context_ = nullptr;
     Must(done());
 }
 
@@ -243,20 +251,18 @@ Downloader::downloadFinished()
 void
 Downloader::callBack(Http::StatusCode const statusCode)
 {
-     CbDialer *dialer = dynamic_cast<CbDialer*>(callback_->getDialer());
-     Must(dialer);
-     dialer->status = statusCode;
-     if (statusCode == Http::scOkay)
-         dialer->object = object_;
-     ScheduleCallHere(callback_);
-     callback_ = nullptr;
-
-     // Calling deleteThis method here to finish Downloader
-     // may result to squid crash.
-     // This method called by handleReply method which maybe called
-     // by ClientHttpRequest::doCallouts. The doCallouts after this object
-     // deleted, may operate on non valid objects.
-     // Schedule an async call here just to force squid to delete this object.
-     CallJobHere(33, 7, CbcPointer<Downloader>(this), Downloader, downloadFinished);
+    CbDialer *dialer = dynamic_cast<CbDialer*>(callback_->getDialer());
+    Must(dialer);
+    dialer->status = statusCode;
+    if (statusCode == Http::scOkay)
+        dialer->object = object_;
+    ScheduleCallHere(callback_);
+    callback_ = nullptr;
+
+    // We cannot deleteThis() because we may be called synchronously from
+    // doCallouts() via handleReply() (XXX), and doCallouts() may crash if we
+    // disappear. Instead, schedule an async call now so that later, when the
+    // call firing code discovers a done() job, it deletes us.
+    CallJobHere(33, 7, CbcPointer<Downloader>(this), Downloader, downloadFinished);
 }