diff --git a/base/buffer.cpp b/base/buffer.cpp index 38900e0017..82a93d2ef1 100644 --- a/base/buffer.cpp +++ b/base/buffer.cpp @@ -175,11 +175,34 @@ bool Buffer::ReadAll(int fd) { return true; } -size_t Buffer::Read(int fd, size_t sz) { +bool Buffer::ReadAllWithProgress(int fd, int knownSize, float *progress) { + char buf[1024]; + int total = 0; + while (true) { + int retval = recv(fd, buf, sizeof(buf), 0); + if (retval == 0) { + return true; + } else if (retval < 0) { + ELOG("Error reading from buffer: %i", retval); + return false; + } + char *p = Append((size_t)retval); + memcpy(p, buf, retval); + total += retval; + *progress = (float)total / (float)knownSize; + ILOG("Progress: %f", *progress); + } + return true; +} + +int Buffer::Read(int fd, size_t sz) { char buf[1024]; int retval; size_t received = 0; while ((retval = recv(fd, buf, std::min(sz, sizeof(buf)), 0)) > 0) { + if (retval < 0) { + return retval; + } char *p = Append((size_t)retval); memcpy(p, buf, retval); sz -= retval; @@ -193,4 +216,4 @@ size_t Buffer::Read(int fd, size_t sz) { void Buffer::PeekAll(std::string *dest) { dest->resize(data_.size()); memcpy(&(*dest)[0], &data_[0], data_.size()); -} \ No newline at end of file +} diff --git a/base/buffer.h b/base/buffer.h index 0ebf7e3f2b..73fbe898fb 100644 --- a/base/buffer.h +++ b/base/buffer.h @@ -66,7 +66,11 @@ class Buffer { bool FlushSocket(uintptr_t sock); // Windows portability bool ReadAll(int fd); - size_t Read(int fd, size_t sz); + bool ReadAllWithProgress(int fd, int knownSize, float *progress); + + // < 0: error + // >= 0: number of bytes read + int Read(int fd, size_t sz); // Utilities. Try to avoid checking for size. size_t size() const { return data_.size(); } diff --git a/net/http_client.cpp b/net/http_client.cpp index 3c11e02cf6..31b3378ecf 100644 --- a/net/http_client.cpp +++ b/net/http_client.cpp @@ -121,7 +121,8 @@ Client::~Client() { #define USERAGENT "NATIVEAPP 1.0" -void DeChunk(Buffer *inbuffer, Buffer *outbuffer) { +void DeChunk(Buffer *inbuffer, Buffer *outbuffer, int contentLength, float *progress) { + int dechunkedBytes = 0; while (true) { std::string line; inbuffer->TakeLineCRLF(&line); @@ -138,13 +139,17 @@ void DeChunk(Buffer *inbuffer, Buffer *outbuffer) { inbuffer->clear(); return; } + dechunkedBytes += chunkSize; + if (progress && contentLength) { + *progress = (float)dechunkedBytes / contentLength; + } inbuffer->Skip(2); } } int Client::GET(const char *resource, Buffer *output, float *progress) { if (progress) { - *progress = 0; + *progress = 0.01f; } Buffer buffer; @@ -166,8 +171,10 @@ int Client::GET(const char *resource, Buffer *output, float *progress) { Buffer readbuf; // Snarf all the data we can into RAM. A little unsafe but hey. - if (!readbuf.ReadAll(sock())) + if (readbuf.Read(sock(), 4096) < 0) { + ELOG("Failed to read HTTP headers :("); return -1; + } // Grab the first header line that contains the http code. @@ -218,13 +225,23 @@ int Client::GET(const char *resource, Buffer *output, float *progress) { if (!contentLength && progress) { // Content length is unknown. // Set progress to 1% so it looks like something is happening... - *progress = 0.01f; + *progress = 0.1f; + } + + if (!contentLength) { + // No way to know how far along we are. Let's just not update the progress counter. + if (!readbuf.ReadAll(sock())) + return -1; + } else { + // Let's read in chunks, updating progress between each. + if (!readbuf.ReadAllWithProgress(sock(), contentLength, progress)) + return -1; } // output now contains the rest of the reply. Dechunk it. if (chunked) { // TODO: Turn this into a loop and update progress - DeChunk(&readbuf, output); + DeChunk(&readbuf, output, contentLength, progress); } else { // TODO: Turn this into a loop and update progress output->Append(readbuf); @@ -393,11 +410,18 @@ void Downloader::Update() { } } +std::vector Downloader::GetCurrentProgress() { + std::vector progress; + for (size_t i = 0; i < downloads_.size(); i++) { + progress.push_back(downloads_[i]->Progress()); + } + return progress; +} + void Downloader::CancelAll() { for (size_t i = 0; i < downloads_.size(); i++) { downloads_[i]->Cancel(); } } - } // http diff --git a/net/http_client.h b/net/http_client.h index bfd4ed0731..1074a9efdd 100644 --- a/net/http_client.h +++ b/net/http_client.h @@ -139,6 +139,8 @@ public: void Update(); void CancelAll(); + std::vector GetCurrentProgress(); + private: std::vector> downloads_; };