http: Add timeout on no response.

Firewalls can cause this, by opening a connection but never responding.
This commit is contained in:
Unknown W. Brackets 2018-12-27 10:15:58 -08:00
parent 2dbdd73e5f
commit 359afb2d6b
5 changed files with 25 additions and 8 deletions

View File

@ -28,17 +28,20 @@ HTTPFileLoader::HTTPFileLoader(const std::string &filename)
void HTTPFileLoader::Prepare() {
std::call_once(preparedFlag_, [this](){
if (!client_.Resolve(url_.Host().c_str(), url_.Port())) {
// TODO: Should probably set some flag?
ERROR_LOG(LOADER, "HTTP request failed, unable to resolve: %s port %d", url_.Host().c_str(), url_.Port());
return;
}
client_.SetDataTimeout(20.0);
Connect();
if (!connected_) {
ERROR_LOG(LOADER, "HTTP request failed, failed to connect: %s port %d", url_.Host().c_str(), url_.Port());
return;
}
int err = client_.SendRequest("HEAD", url_.Resource().c_str());
if (err < 0) {
ERROR_LOG(LOADER, "HTTP request failed, failed to send request: %s port %d", url_.Host().c_str(), url_.Port());
Disconnect();
return;
}

View File

@ -146,8 +146,12 @@ bool Buffer::FlushToFile(const char *filename) {
return true;
}
bool Buffer::FlushSocket(uintptr_t sock) {
bool Buffer::FlushSocket(uintptr_t sock, double timeout) {
for (size_t pos = 0, end = data_.size(); pos < end; ) {
if (timeout >= 0.0 && !fd_util::WaitUntilReady(sock, timeout, true)) {
ELOG("FlushSocket timed out");
return false;
}
int sent = send(sock, &data_[pos], (int)(end - pos), MSG_NOSIGNAL);
if (sent < 0) {
ELOG("FlushSocket failed");
@ -156,7 +160,7 @@ bool Buffer::FlushSocket(uintptr_t sock) {
pos += sent;
// Buffer full, don't spin.
if (sent == 0) {
if (sent == 0 && timeout < 0.0) {
sleep_ms(1);
}
}

View File

@ -59,12 +59,12 @@ class Buffer {
// Simple I/O.
// Writes the entire buffer to the file descriptor. Also resets the
// size to zero. On failure, data remains in buffer and nothing is
// written.
// Writes the entire buffer to the file descriptor. Also resets the
// size to zero. On failure, data remains in buffer and nothing is
// written.
bool Flush(int fd);
bool FlushToFile(const char *filename);
bool FlushSocket(uintptr_t sock); // Windows portability
bool FlushSocket(uintptr_t sock, double timeout = -1.0); // Windows portability
bool ReadAll(int fd, int hintSize = 0);
bool ReadAllWithProgress(int fd, int knownSize, float *progress, bool *cancelled);

View File

@ -283,7 +283,7 @@ int Client::SendRequestWithData(const char *method, const char *resource, const
userAgent_,
otherHeaders ? otherHeaders : "");
buffer.Append(data);
bool flushed = buffer.FlushSocket(sock());
bool flushed = buffer.FlushSocket(sock(), dataTimeout_);
if (!flushed) {
return -1; // TODO error code.
}
@ -292,6 +292,10 @@ int Client::SendRequestWithData(const char *method, const char *resource, const
int Client::ReadResponseHeaders(Buffer *readbuf, std::vector<std::string> &responseHeaders, float *progress) {
// Snarf all the data we can into RAM. A little unsafe but hey.
if (dataTimeout_ >= 0.0 && fd_util::WaitUntilReady(sock(), dataTimeout_, false)) {
ELOG("HTTP headers timed out");
return -1;
}
if (readbuf->Read(sock(), 4096) < 0) {
ELOG("Failed to read HTTP headers :(");
return -1;

View File

@ -75,8 +75,14 @@ public:
// If your response contains a response, you must read it.
int ReadResponseEntity(Buffer *readbuf, const std::vector<std::string> &responseHeaders, Buffer *output, float *progress = nullptr, bool *cancelled = nullptr);
void SetDataTimeout(double t) {
dataTimeout_ = t;
}
protected:
const char *userAgent_;
const char *httpVersion_;
double dataTimeout_ = -1.0;
};
// Not particularly efficient, but hey - it's a background download, that's pretty cool :P