Change HTTPCallback::OnReceiveData to use UniqueBuffer
See: https://github.com/OpenTTD/OpenTTD/issues/11636
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
#define NETWORK_CORE_HTTP_H
|
#define NETWORK_CORE_HTTP_H
|
||||||
|
|
||||||
#include "tcp.h"
|
#include "tcp.h"
|
||||||
|
#include "../../src/core/alloc_type.hpp"
|
||||||
|
|
||||||
constexpr int HTTP_429_TOO_MANY_REQUESTS = 429;
|
constexpr int HTTP_429_TOO_MANY_REQUESTS = 429;
|
||||||
|
|
||||||
@@ -26,11 +27,11 @@ struct HTTPCallback {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* We're receiving data.
|
* We're receiving data.
|
||||||
* @param data the received data, nullptr when all data has been received. The implementation is responsible for freeing the data.
|
* @param data the received data, nullptr when all data has been received.
|
||||||
* @param length the amount of received data, 0 when all data has been received.
|
* @param length the amount of received data, 0 when all data has been received.
|
||||||
* @note When nullptr is sent the HTTP socket handler is closed/freed.
|
* @note When nullptr is sent the HTTP socket handler is closed/freed.
|
||||||
*/
|
*/
|
||||||
virtual void OnReceiveData(const char *data, size_t length) = 0;
|
virtual void OnReceiveData(UniqueBuffer<char> data) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if there is a request to cancel the transfer.
|
* Check if there is a request to cancel the transfer.
|
||||||
|
@@ -195,11 +195,11 @@ void HttpThread()
|
|||||||
HTTPThreadSafeCallback *callback = static_cast<HTTPThreadSafeCallback *>(userdata);
|
HTTPThreadSafeCallback *callback = static_cast<HTTPThreadSafeCallback *>(userdata);
|
||||||
|
|
||||||
/* Copy the buffer out of CURL. OnReceiveData() will free it when done. */
|
/* Copy the buffer out of CURL. OnReceiveData() will free it when done. */
|
||||||
char *buffer = size * nmemb == 0 ? nullptr : MallocT<char>(size * nmemb);
|
UniqueBuffer<char> buffer(size * nmemb);
|
||||||
if (buffer != nullptr) {
|
if (buffer != nullptr) {
|
||||||
memcpy(buffer, ptr, size * nmemb);
|
memcpy(buffer.get(), ptr, size * nmemb);
|
||||||
}
|
}
|
||||||
callback->OnReceiveData(buffer, size * nmemb);
|
callback->OnReceiveData(std::move(buffer));
|
||||||
|
|
||||||
return size * nmemb;
|
return size * nmemb;
|
||||||
});
|
});
|
||||||
@@ -223,7 +223,7 @@ void HttpThread()
|
|||||||
|
|
||||||
if (res == CURLE_OK) {
|
if (res == CURLE_OK) {
|
||||||
Debug(net, 1, "HTTP request succeeded");
|
Debug(net, 1, "HTTP request succeeded");
|
||||||
request->callback.OnReceiveData(nullptr, 0);
|
request->callback.OnReceiveData({});
|
||||||
} else {
|
} else {
|
||||||
long status_code = 0;
|
long status_code = 0;
|
||||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status_code);
|
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status_code);
|
||||||
|
@@ -24,11 +24,10 @@ private:
|
|||||||
/** Entries on the queue for later handling. */
|
/** Entries on the queue for later handling. */
|
||||||
class Callback {
|
class Callback {
|
||||||
public:
|
public:
|
||||||
Callback(const char *data, size_t length) : data(data), length(length), failure(false) {}
|
Callback(UniqueBuffer<char> data) : data(std::move(data)), failure(false) {}
|
||||||
Callback() : data(nullptr), length(0), failure(true) {}
|
Callback() : data({}), failure(true) {}
|
||||||
|
|
||||||
const char *data;
|
UniqueBuffer<char> data;
|
||||||
size_t length;
|
|
||||||
bool failure;
|
bool failure;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -45,10 +44,10 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Similar to HTTPCallback::OnReceiveData, but thread-safe.
|
* Similar to HTTPCallback::OnReceiveData, but thread-safe.
|
||||||
*/
|
*/
|
||||||
void OnReceiveData(const char *data, size_t length)
|
void OnReceiveData(UniqueBuffer<char> data)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(this->mutex);
|
std::lock_guard<std::mutex> lock(this->mutex);
|
||||||
this->queue.emplace_back(data, length);
|
this->queue.emplace_back(std::move(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,7 +65,7 @@ public:
|
|||||||
if (item.failure) {
|
if (item.failure) {
|
||||||
this->callback->OnFailure();
|
this->callback->OnFailure();
|
||||||
} else {
|
} else {
|
||||||
this->callback->OnReceiveData(item.data, item.length);
|
this->callback->OnReceiveData(std::move(item.data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,13 +100,6 @@ public:
|
|||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(this->mutex);
|
std::lock_guard<std::mutex> lock(this->mutex);
|
||||||
|
|
||||||
/* Free all data that was not handled. */
|
|
||||||
for (auto &item : this->queue) {
|
|
||||||
if (!item.failure) {
|
|
||||||
free(item.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
queue.clear();
|
queue.clear();
|
||||||
queue_cv.notify_all();
|
queue_cv.notify_all();
|
||||||
}
|
}
|
||||||
|
@@ -159,14 +159,14 @@ void NetworkHTTPRequest::WinHttpCallback(DWORD code, void *info, DWORD length)
|
|||||||
|
|
||||||
/* Next step: read the data in a temporary allocated buffer.
|
/* Next step: read the data in a temporary allocated buffer.
|
||||||
* The buffer will be free'd by OnReceiveData() in the next step. */
|
* The buffer will be free'd by OnReceiveData() in the next step. */
|
||||||
char *buffer = size == 0 ? nullptr : MallocT<char>(size);
|
char *buffer = size == 0 ? nullptr : new char[size];
|
||||||
WinHttpReadData(this->request, buffer, size, 0);
|
WinHttpReadData(this->request, buffer, size, 0);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
|
case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
|
||||||
Debug(net, 4, "HTTP callback: {} bytes", length);
|
Debug(net, 4, "HTTP callback: {} bytes", length);
|
||||||
|
|
||||||
this->callback.OnReceiveData(static_cast<char *>(info), length);
|
this->callback.OnReceiveData(UniqueBuffer<char>(std::unique_ptr<char[]>(static_cast<char *>(info)), length));
|
||||||
|
|
||||||
if (length == 0) {
|
if (length == 0) {
|
||||||
/* Next step: no more data available: request is finished. */
|
/* Next step: no more data available: request is finished. */
|
||||||
|
@@ -608,23 +608,19 @@ void ClientNetworkContentSocketHandler::OnFailure()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientNetworkContentSocketHandler::OnReceiveData(const char *data, size_t length)
|
void ClientNetworkContentSocketHandler::OnReceiveData(UniqueBuffer<char> data)
|
||||||
{
|
{
|
||||||
assert(data == nullptr || length != 0);
|
assert(data.get() == nullptr || data.size() != 0);
|
||||||
|
|
||||||
/* Ignore any latent data coming from a connection we closed. */
|
/* Ignore any latent data coming from a connection we closed. */
|
||||||
if (this->http_response_index == -2) {
|
if (this->http_response_index == -2) {
|
||||||
if (data != nullptr) {
|
|
||||||
free(data);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->http_response_index == -1) {
|
if (this->http_response_index == -1) {
|
||||||
if (data != nullptr) {
|
if (data != nullptr) {
|
||||||
/* Append the rest of the response. */
|
/* Append the rest of the response. */
|
||||||
this->http_response.insert(this->http_response.end(), data, data + length);
|
this->http_response.insert(this->http_response.end(), data.get(), data.get() + data.size());
|
||||||
free(data);
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
/* Make sure the response is properly terminated. */
|
/* Make sure the response is properly terminated. */
|
||||||
@@ -637,16 +633,15 @@ void ClientNetworkContentSocketHandler::OnReceiveData(const char *data, size_t l
|
|||||||
|
|
||||||
if (data != nullptr) {
|
if (data != nullptr) {
|
||||||
/* We have data, so write it to the file. */
|
/* We have data, so write it to the file. */
|
||||||
if (fwrite(data, 1, length, this->curFile) != length) {
|
if (fwrite(data.get(), 1, data.size(), this->curFile) != data.size()) {
|
||||||
/* Writing failed somehow, let try via the old method. */
|
/* Writing failed somehow, let try via the old method. */
|
||||||
this->OnFailure();
|
this->OnFailure();
|
||||||
} else {
|
} else {
|
||||||
/* Just received the data. */
|
/* Just received the data. */
|
||||||
this->OnDownloadProgress(this->curInfo, (int)length);
|
this->OnDownloadProgress(this->curInfo, (int)data.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Nothing more to do now. */
|
/* Nothing more to do now. */
|
||||||
free(data);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -97,7 +97,7 @@ protected:
|
|||||||
void OnDownloadComplete(ContentID cid) override;
|
void OnDownloadComplete(ContentID cid) override;
|
||||||
|
|
||||||
void OnFailure() override;
|
void OnFailure() override;
|
||||||
void OnReceiveData(const char *data, size_t length) override;
|
void OnReceiveData(UniqueBuffer<char> data) override;
|
||||||
bool IsCancelled() const override;
|
bool IsCancelled() const override;
|
||||||
|
|
||||||
bool BeforeDownload();
|
bool BeforeDownload();
|
||||||
|
@@ -389,12 +389,10 @@ void NetworkSurveyHandler::OnFailure()
|
|||||||
this->loaded.notify_all();
|
this->loaded.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkSurveyHandler::OnReceiveData(const char *data, size_t)
|
void NetworkSurveyHandler::OnReceiveData(UniqueBuffer<char> data)
|
||||||
{
|
{
|
||||||
if (data == nullptr) {
|
if (data == nullptr) {
|
||||||
Debug(net, 1, "Survey: survey results sent");
|
Debug(net, 1, "Survey: survey results sent");
|
||||||
this->loaded.notify_all();
|
this->loaded.notify_all();
|
||||||
} else {
|
|
||||||
free(data);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -20,7 +20,7 @@
|
|||||||
class NetworkSurveyHandler : public HTTPCallback {
|
class NetworkSurveyHandler : public HTTPCallback {
|
||||||
protected:
|
protected:
|
||||||
void OnFailure() override;
|
void OnFailure() override;
|
||||||
void OnReceiveData(const char *data, size_t length) override;
|
void OnReceiveData(UniqueBuffer<char> data) override;
|
||||||
bool IsCancelled() const override { return false; }
|
bool IsCancelled() const override { return false; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Reference in New Issue
Block a user