← Back to team overview

linuxdcpp-team team mailing list archive

[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 3257: HTTP downloads can go straight to a file

 

------------------------------------------------------------
revno: 3257
committer: poy <poy@xxxxxxxxxx>
branch nick: trunk
timestamp: Sat 2013-04-13 17:08:45 +0200
message:
  HTTP downloads can go straight to a file
modified:
  dcpp/Download.cpp
  dcpp/FavoriteManager.cpp
  dcpp/FavoriteManager.h
  dcpp/HttpConnection.cpp
  dcpp/HttpConnection.h
  dcpp/HttpConnectionListener.h
  dcpp/HttpManager.cpp
  dcpp/HttpManager.h
  dcpp/HttpManagerListener.h
  dcpp/ShareManager.cpp
  dcpp/SimpleXML.cpp
  dcpp/Streams.h
  dcpp/forward.h
  win32/AboutDlg.cpp
  win32/AboutDlg.h
  win32/MainWindow.cpp
  win32/MainWindow.h
  win32/TransferView.cpp
  win32/TransferView.h


--
lp:dcplusplus
https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk

Your team Dcplusplus-team is subscribed to branch lp:dcplusplus.
To unsubscribe from this branch go to https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk/+edit-subscription
=== modified file 'dcpp/Download.cpp'
--- dcpp/Download.cpp	2013-01-18 21:28:38 +0000
+++ dcpp/Download.cpp	2013-04-13 15:08:45 +0000
@@ -140,7 +140,7 @@
 		output.reset(new File(target, File::WRITE, File::OPEN | File::TRUNCATE | File::CREATE));
 		tempTarget = target;
 	} else if(getType() == Transfer::TYPE_PARTIAL_LIST) {
-		output.reset(new StringOutputStream(pfs));
+		output.reset(new StringRefOutputStream(pfs));
 	} else if(getType() == Transfer::TYPE_TREE) {
 		output.reset(new MerkleTreeOutputStream<TigerTree>(tt));
 	}

=== modified file 'dcpp/FavoriteManager.cpp'
--- dcpp/FavoriteManager.cpp	2013-04-12 21:10:13 +0000
+++ dcpp/FavoriteManager.cpp	2013-04-13 15:08:45 +0000
@@ -761,12 +761,12 @@
 	return lst;
 }
 
-void FavoriteManager::on(Added, HttpConnection* c) noexcept {
+void FavoriteManager::on(HttpManagerListener::Added, HttpConnection* c) noexcept {
 	if(c != this->c) { return; }
 	fire(FavoriteManagerListener::DownloadStarting(), c->getUrl());
 }
 
-void FavoriteManager::on(Failed, HttpConnection* c, const string& str) noexcept {
+void FavoriteManager::on(HttpManagerListener::Failed, HttpConnection* c, const string& str) noexcept {
 	if(c != this->c) { return; }
 	this->c = nullptr;
 	lastServer++;
@@ -776,14 +776,14 @@
 	}
 }
 
-void FavoriteManager::on(Complete, HttpConnection* c, const string& buf) noexcept {
+void FavoriteManager::on(HttpManagerListener::Complete, HttpConnection* c, OutputStream* stream) noexcept {
 	if(c != this->c) { return; }
 	this->c = nullptr;
 	bool parseSuccess = false;
 	if(useHttp) {
 		if(c->getMimeType() == "application/x-bzip2")
 			listType = TYPE_BZIP2;
-		parseSuccess = onHttpFinished(buf);
+		parseSuccess = onHttpFinished(static_cast<StringOutputStream*>(stream)->getString());
 	}	
 	running = false;
 	if(parseSuccess) {

=== modified file 'dcpp/FavoriteManager.h'
--- dcpp/FavoriteManager.h	2013-04-12 18:24:09 +0000
+++ dcpp/FavoriteManager.h	2013-04-13 15:08:45 +0000
@@ -160,9 +160,9 @@
 	void on(UserDisconnected, const UserPtr& user) noexcept;
 
 	// HttpManagerListener
-	void on(Added, HttpConnection*) noexcept;
-	void on(Failed, HttpConnection*, const string&) noexcept;
-	void on(Complete, HttpConnection*, const string&) noexcept;
+	void on(HttpManagerListener::Added, HttpConnection*) noexcept;
+	void on(HttpManagerListener::Failed, HttpConnection*, const string&) noexcept;
+	void on(HttpManagerListener::Complete, HttpConnection*, OutputStream*) noexcept;
 
 	bool onHttpFinished(const string& buf) noexcept;
 

=== modified file 'dcpp/HttpConnection.cpp'
--- dcpp/HttpConnection.cpp	2013-04-12 18:24:09 +0000
+++ dcpp/HttpConnection.cpp	2013-04-13 15:08:45 +0000
@@ -22,6 +22,7 @@
 #include "BufferedSocket.h"
 #include "format.h"
 #include "SettingsManager.h"
+#include "TimerManager.h"
 #include "version.h"
 
 namespace dcpp {
@@ -33,6 +34,9 @@
 port("80"),
 size(-1),
 done(0),
+speed(0),
+lastPos(0),
+lastTick(0),
 connState(CONN_UNKNOWN),
 coralizeState(coralize ? CST_DEFAULT : CST_NOCORALIZE),
 socket(0)
@@ -86,6 +90,10 @@
 
 	size = -1;
 	done = 0;
+	speed = 0;
+	lastPos = 0;
+	lastTick = GET_TICK();
+
 	connState = CONN_UNKNOWN;
 	connType = type;
 
@@ -147,6 +155,20 @@
 	socket = NULL;
 }
 
+void HttpConnection::updateSpeed() {
+	if(done > lastPos) {
+		auto tick = GET_TICK();
+
+		auto tickDelta = static_cast<double>(tick - lastTick);
+		if(tickDelta > 0) {
+			speed = static_cast<double>(done - lastPos) / tickDelta * 1000.0;
+		}
+
+		lastPos = done;
+		lastTick = tick;
+	}
+}
+
 void HttpConnection::on(BufferedSocketListener::Connected) noexcept {
 	dcassert(socket);
 	socket->write("GET " + file + " HTTP/1.1\r\n");
@@ -237,13 +259,12 @@
 			fire(HttpConnectionListener::Failed(), this, str(F_("Endless redirection loop (%1%)") % url));
 			return;
 		}
+
+		fire(HttpConnectionListener::Redirected(), this, location);
+
+		if(coralizeState != CST_NOCORALIZE)
+			coralizeState = CST_DEFAULT;
 		url = location;
-
-		fire(HttpConnectionListener::Redirected(), this);
-
-		if (coralizeState != CST_NOCORALIZE)
-			coralizeState = CST_DEFAULT;
-
 		download();
 
 	} else if(aLine[0] == 0x0d) {
@@ -297,8 +318,9 @@
 		return;
 	}
 
+	done += aLen;
+	updateSpeed();
 	fire(HttpConnectionListener::Data(), this, aBuf, aLen);
-	done += aLen;
 }
 
 } // namespace dcpp

=== modified file 'dcpp/HttpConnection.h'
--- dcpp/HttpConnection.h	2013-04-12 18:24:09 +0000
+++ dcpp/HttpConnection.h	2013-04-13 15:08:45 +0000
@@ -44,6 +44,7 @@
 
 	int64_t getSize() const { return size; }
 	int64_t getDone() const { return done; }
+	double getSpeed() const { return speed; }
 
 	bool coralized() const;
 
@@ -65,6 +66,11 @@
 	string mimeType;
 	int64_t size;
 	int64_t done;
+	double speed;
+
+	// counters to compute a best-effort speed
+	int64_t lastPos;
+	uint64_t lastTick;
 
 	ConnectionStates connState;
 	CoralizeStates coralizeState;
@@ -75,6 +81,8 @@
 	void prepareRequest(RequestType type);
 	void abortRequest(bool disconnect);
 
+	void updateSpeed();
+
 	// BufferedSocketListener
 	void on(Connected) noexcept;
 	void on(Line, const string&) noexcept;

=== modified file 'dcpp/HttpConnectionListener.h'
--- dcpp/HttpConnectionListener.h	2013-04-12 18:24:09 +0000
+++ dcpp/HttpConnectionListener.h	2013-04-13 15:08:45 +0000
@@ -42,7 +42,7 @@
 	virtual void on(Data, HttpConnection*, const uint8_t*, size_t) noexcept = 0;
 	virtual void on(Failed, HttpConnection*, const string&) noexcept = 0;
 	virtual void on(Complete, HttpConnection*) noexcept = 0;
-	virtual void on(Redirected, HttpConnection*) noexcept = 0;
+	virtual void on(Redirected, HttpConnection*, const string&) noexcept = 0;
 	virtual void on(Retried, HttpConnection*, bool) noexcept = 0;
 };
 

=== modified file 'dcpp/HttpManager.cpp'
--- dcpp/HttpManager.cpp	2013-04-12 21:10:13 +0000
+++ dcpp/HttpManager.cpp	2013-04-13 15:08:45 +0000
@@ -21,6 +21,7 @@
 
 #include "format.h"
 #include "HttpConnection.h"
+#include "Streams.h"
 
 namespace dcpp {
 
@@ -32,26 +33,28 @@
 	TimerManager::getInstance()->removeListener(this);
 }
 
-HttpConnection* HttpManager::download(string url) {
-	auto conn = makeConn(move(url));
+HttpConnection* HttpManager::download(string url, OutputStream* stream) {
+	auto conn = makeConn(move(url), stream);
 	conn->download();
 	return conn;
 }
 
-HttpConnection* HttpManager::download(string url, const StringMap& postData) {
-	auto conn = makeConn(move(url));
+HttpConnection* HttpManager::download(string url, const StringMap& postData, OutputStream* stream) {
+	auto conn = makeConn(move(url), stream);
 	conn->download(postData);
 	return conn;
 }
 
 void HttpManager::disconnect(const string& url) {
 	HttpConnection* c = nullptr;
+	OutputStream* stream;
 
 	{
 		Lock l(cs);
 		conns.erase(std::remove_if(conns.begin(), conns.end(), [&](const Conn& conn) -> bool {
 			if(conn.c->getUrl() == url) {
 				c = conn.c;
+				stream = conn.stream;
 				return true;
 			}
 			return false;
@@ -62,20 +65,21 @@
 		fire(HttpManagerListener::Failed(), c, _("Disconnected"));
 		fire(HttpManagerListener::Removed(), c);
 		delete c;
+		delete stream;
 	}
 }
 
 void HttpManager::shutdown() {
 	Lock l(cs);
-	for(auto& conn: conns) { delete conn.c; }
+	for(auto& conn: conns) { delete conn.c; delete conn.stream; }
 	conns.clear();
 }
 
-HttpConnection* HttpManager::makeConn(string&& url) {
+HttpConnection* HttpManager::makeConn(string&& url, OutputStream* stream) {
 	auto c = new HttpConnection();
 	{
 		Lock l(cs);
-		Conn conn { c, string(), 0 };
+		Conn conn { c, stream ? stream : new StringOutputStream(), 0 };
 		conns.push_back(move(conn));
 	}
 	c->addListener(this);
@@ -101,64 +105,56 @@
 void HttpManager::on(HttpConnectionListener::Data, HttpConnection* c, const uint8_t* data, size_t len) noexcept {
 	{
 		Lock l(cs);
-		auto& buf = findConn(c)->buf;
-		if(buf.empty() && c->getSize() != -1) {
-			buf.reserve(c->getSize());
-		}
-		buf.append(reinterpret_cast<const char*>(data), len);
+		findConn(c)->stream->write(data, len);
 	}
 	fire(HttpManagerListener::Updated(), c);
-	printf("size: %d\n", c->getSize());
 }
 
 void HttpManager::on(HttpConnectionListener::Failed, HttpConnection* c, const string& str) noexcept {
-	{
-		Lock l(cs);
-		findConn(c)->buf.clear();
-	}
 	fire(HttpManagerListener::Failed(), c, str);
 	removeLater(c);
 }
 
 void HttpManager::on(HttpConnectionListener::Complete, HttpConnection* c) noexcept {
-	string buf;
+	OutputStream* stream;
 	{
 		Lock l(cs);
-		buf = move(findConn(c)->buf);
+		stream = findConn(c)->stream;
 	}
-	fire(HttpManagerListener::Complete(), c, move(buf));
+	fire(HttpManagerListener::Complete(), c, stream);
 	removeLater(c);
 }
 
-void HttpManager::on(HttpConnectionListener::Redirected, HttpConnection* c) noexcept {
+void HttpManager::on(HttpConnectionListener::Redirected, HttpConnection* c, const string& redirect) noexcept {
 	fire(HttpManagerListener::Removed(), c);
+	c->setUrl(redirect);
 	fire(HttpManagerListener::Added(), c);
 }
 
 void HttpManager::on(HttpConnectionListener::Retried, HttpConnection* c, bool connected) noexcept {
 	if(connected) {
-		Lock l(cs);
-		findConn(c)->buf.clear();
+		/// @todo reset / redirect
 	}
 }
 
 void HttpManager::on(TimerManagerListener::Minute, uint64_t tick) noexcept {
-	vector<HttpConnection*> removed;
+	vector<pair<HttpConnection*, OutputStream*>> removed;
 
 	{
 		Lock l(cs);
 		conns.erase(std::remove_if(conns.begin(), conns.end(), [tick, &removed](const Conn& conn) -> bool {
 			if(conn.remove && tick > conn.remove) {
-				removed.push_back(conn.c);
+				removed.emplace_back(conn.c, conn.stream);
 				return true;
 			}
 			return false;
 		}), conns.end());
 	}
 
-	for(auto c: removed) {
-		fire(HttpManagerListener::Removed(), c);
-		delete c;
+	for(auto& rem: removed) {
+		fire(HttpManagerListener::Removed(), rem.first);
+		delete rem.first;
+		delete rem.second;
 	}
 }
 

=== modified file 'dcpp/HttpManager.h'
--- dcpp/HttpManager.h	2013-04-12 21:10:13 +0000
+++ dcpp/HttpManager.h	2013-04-13 15:08:45 +0000
@@ -41,22 +41,26 @@
 	private TimerManagerListener
 {
 public:
-	HttpConnection* download(string url);
-	HttpConnection* download(string url, const StringMap& postData);
+	/** Send a GET request to the designated url. If unspecified, the stream defaults to a
+	StringOutputStream. */
+	HttpConnection* download(string url, OutputStream* stream = nullptr);
+	/** Send a POST request to the designated url. If unspecified, the stream defaults to a
+	StringOutputStream. */
+	HttpConnection* download(string url, const StringMap& postData, OutputStream* stream = nullptr);
 
 	void disconnect(const string& url);
 
 	void shutdown();
 
 private:
-	struct Conn { HttpConnection* c; string buf; uint64_t remove; };
+	struct Conn { HttpConnection* c; OutputStream* stream; uint64_t remove; };
 
 	friend class Singleton<HttpManager>;
 
 	HttpManager();
 	virtual ~HttpManager();
 
-	HttpConnection* makeConn(string&& url);
+	HttpConnection* makeConn(string&& url, OutputStream* stream);
 	Conn* findConn(HttpConnection* c);
 	void removeLater(HttpConnection* c);
 
@@ -64,7 +68,7 @@
 	void on(HttpConnectionListener::Data, HttpConnection*, const uint8_t*, size_t) noexcept;
 	void on(HttpConnectionListener::Failed, HttpConnection*, const string&) noexcept;
 	void on(HttpConnectionListener::Complete, HttpConnection*) noexcept;
-	void on(HttpConnectionListener::Redirected, HttpConnection*) noexcept;
+	void on(HttpConnectionListener::Redirected, HttpConnection*, const string&) noexcept;
 	void on(HttpConnectionListener::Retried, HttpConnection*, bool) noexcept;
 
 	// TimerManagerListener

=== modified file 'dcpp/HttpManagerListener.h'
--- dcpp/HttpManagerListener.h	2013-04-12 18:24:09 +0000
+++ dcpp/HttpManagerListener.h	2013-04-13 15:08:45 +0000
@@ -42,7 +42,7 @@
 	virtual void on(Added, HttpConnection*) noexcept { }
 	virtual void on(Updated, HttpConnection*) noexcept { }
 	virtual void on(Failed, HttpConnection*, const string&) noexcept { }
-	virtual void on(Complete, HttpConnection*, const string&) noexcept { }
+	virtual void on(Complete, HttpConnection*, OutputStream*) noexcept { }
 	virtual void on(Removed, HttpConnection*) noexcept { }
 };
 

=== modified file 'dcpp/ShareManager.cpp'
--- dcpp/ShareManager.cpp	2013-02-14 16:25:20 +0000
+++ dcpp/ShareManager.cpp	2013-04-13 15:08:45 +0000
@@ -861,7 +861,7 @@
 	string xml = SimpleXML::utf8Header;
 	string tmp;
 	xml += "<FileListing Version=\"1\" CID=\"" + ClientManager::getInstance()->getMe()->getCID().toBase32() + "\" Base=\"" + SimpleXML::escape(dir, tmp, true) + "\" Generator=\"" APPNAME " " VERSIONSTRING "\">\r\n";
-	StringOutputStream sos(xml);
+	StringRefOutputStream sos(xml);
 	string indent = "\t";
 
 	Lock l(cs);

=== modified file 'dcpp/SimpleXML.cpp'
--- dcpp/SimpleXML.cpp	2013-01-18 21:28:38 +0000
+++ dcpp/SimpleXML.cpp	2013-04-13 15:08:45 +0000
@@ -200,10 +200,9 @@
 }
 
 string SimpleXML::toXML() {
-	string tmp;
-	StringOutputStream os(tmp);
+	StringOutputStream os;
 	toXML(&os);
-	return tmp;
+	return os.getString();
 }
 
 } // namespace dcpp

=== modified file 'dcpp/Streams.h'
--- dcpp/Streams.h	2013-02-14 16:25:20 +0000
+++ dcpp/Streams.h	2013-04-13 15:08:45 +0000
@@ -227,15 +227,35 @@
 
 class StringOutputStream : public OutputStream {
 public:
-	StringOutputStream(string& out) : str(out) { }
+	StringOutputStream() { }
 	virtual ~StringOutputStream() { }
 	using OutputStream::write;
 
 	virtual size_t flush() { return 0; }
 	virtual size_t write(const void* buf, size_t len) {
-		str.append((char*)buf, len);
-		return len;
-	}
+		str.append(reinterpret_cast<const char*>(buf), len);
+		return len;
+	}
+
+	string getString() { return move(str); }
+	string& stringRef() { return str; }
+
+private:
+	string str;
+};
+
+class StringRefOutputStream : public OutputStream {
+public:
+	StringRefOutputStream(string& out) : str(out) { }
+	virtual ~StringRefOutputStream() { }
+	using OutputStream::write;
+
+	virtual size_t flush() { return 0; }
+	virtual size_t write(const void* buf, size_t len) {
+		str.append(reinterpret_cast<const char*>(buf), len);
+		return len;
+	}
+
 private:
 	string& str;
 };

=== modified file 'dcpp/forward.h'
--- dcpp/forward.h	2013-04-12 18:24:09 +0000
+++ dcpp/forward.h	2013-04-13 15:08:45 +0000
@@ -95,6 +95,9 @@
 class Socket;
 class SocketException;
 
+class StringOutputStream;
+class StringRefOutputStream;
+
 class StringSearch;
 
 class Tagger;

=== modified file 'win32/AboutDlg.cpp'
--- win32/AboutDlg.cpp	2013-04-12 18:24:09 +0000
+++ win32/AboutDlg.cpp	2013-04-13 15:08:45 +0000
@@ -24,6 +24,7 @@
 #include <dcpp/HttpManager.h>
 #include <dcpp/SettingsManager.h>
 #include <dcpp/SimpleXML.h>
+#include <dcpp/Streams.h>
 #include <dcpp/version.h>
 
 #include <dwt/widgets/Grid.h>
@@ -195,7 +196,8 @@
 	callAsync([str, this] { completeDownload(false, str); });
 }
 
-void AboutDlg::on(HttpManagerListener::Complete, HttpConnection* c, const string& buf) noexcept {
+void AboutDlg::on(HttpManagerListener::Complete, HttpConnection* c, OutputStream* stream) noexcept {
 	if(c != this->c) { return; }
-	callAsync([buf, this] { completeDownload(true, buf); });
+	auto str = static_cast<StringOutputStream*>(stream)->getString();
+	callAsync([str, this] { completeDownload(true, str); });
 }

=== modified file 'win32/AboutDlg.h'
--- win32/AboutDlg.h	2013-04-12 18:24:09 +0000
+++ win32/AboutDlg.h	2013-04-13 15:08:45 +0000
@@ -54,7 +54,7 @@
 
 	// HttpManagerListener
 	void on(HttpManagerListener::Failed, HttpConnection*, const string&) noexcept;
-	void on(HttpManagerListener::Complete, HttpConnection*, const string&) noexcept;
+	void on(HttpManagerListener::Complete, HttpConnection*, OutputStream*) noexcept;
 };
 
 #endif // !defined(DCPLUSPLUS_WIN32_ABOUT_DLG_H)

=== modified file 'win32/MainWindow.cpp'
--- win32/MainWindow.cpp	2013-04-12 21:10:13 +0000
+++ win32/MainWindow.cpp	2013-04-13 15:08:45 +0000
@@ -1756,13 +1756,16 @@
 	}
 }
 
-void MainWindow::on(HttpManagerListener::Complete, HttpConnection* c, const string& buf) noexcept {
+void MainWindow::on(HttpManagerListener::Complete, HttpConnection* c, OutputStream* stream) noexcept {
 	if(c == conns[CONN_VERSION]) {
-		callAsync([buf, this] { completeVersionUpdate(true, buf); });
+		auto str = static_cast<StringOutputStream*>(stream)->getString();
+		callAsync([str, this] { completeVersionUpdate(true, str); });
 	} else if(c == conns[CONN_GEO_V6]) {
-		callAsync([buf, this] { completeGeoUpdate(true, true, buf); });
+		auto str = static_cast<StringOutputStream*>(stream)->getString();
+		callAsync([str, this] { completeGeoUpdate(true, true, str); });
 	} else if(c == conns[CONN_GEO_V4]) {
-		callAsync([buf, this] { completeGeoUpdate(false, true, buf); });
+		auto str = static_cast<StringOutputStream*>(stream)->getString();
+		callAsync([str, this] { completeGeoUpdate(false, true, str); });
 	}
 }
 

=== modified file 'win32/MainWindow.h'
--- win32/MainWindow.h	2013-04-12 18:24:09 +0000
+++ win32/MainWindow.h	2013-04-13 15:08:45 +0000
@@ -233,7 +233,7 @@
 
 	// HttpManagerListener
 	void on(HttpManagerListener::Failed, HttpConnection*, const string&) noexcept;
-	void on(HttpManagerListener::Complete, HttpConnection*, const string&) noexcept;
+	void on(HttpManagerListener::Complete, HttpConnection*, OutputStream*) noexcept;
 
 	// LogManagerListener
 	void on(LogManagerListener::Message, time_t t, const string& m) noexcept;

=== modified file 'win32/TransferView.cpp'
--- win32/TransferView.cpp	2013-04-12 21:10:13 +0000
+++ win32/TransferView.cpp	2013-04-13 15:08:45 +0000
@@ -397,8 +397,6 @@
 	columns[COLUMN_PATH] = Text::toT(url);
 	auto slash = columns[COLUMN_PATH].rfind('/');
 	columns[COLUMN_FILE] = slash != tstring::npos ? columns[COLUMN_PATH].substr(slash + 1) : columns[COLUMN_PATH];
-
-	columns[COLUMN_STATUS] = T_("Downloading");
 }
 
 void TransferView::HttpInfo::update(const UpdateInfo& ui) {
@@ -426,6 +424,21 @@
 			columns[COLUMN_SIZE].clear();
 		}
 	}
+
+	if(ui.updateMask & UpdateInfo::MASK_SPEED) {
+		speed = ui.speed;
+		columns[COLUMN_SPEED] = str(TF_("%1%/s") % Text::toT(Util::formatBytes(speed)));
+	}
+
+	if((ui.updateMask & UpdateInfo::MASK_STATUS) || (ui.updateMask & UpdateInfo::MASK_TRANSFERRED) || (ui.updateMask & UpdateInfo::MASK_SPEED)) {
+		if(status == STATUS_RUNNING && size > 0 && speed > 0) {
+			timeleft = static_cast<double>(size - transferred) / speed;
+			columns[COLUMN_TIMELEFT] = Text::toT(Util::formatSeconds(timeleft));
+		} else {
+			timeleft = 0;
+			columns[COLUMN_TIMELEFT].clear();
+		}
+	}
 }
 
 void TransferView::HttpInfo::disconnect() {
@@ -1028,6 +1041,7 @@
 void TransferView::on(HttpManagerListener::Added, HttpConnection* c) noexcept {
 	auto ui = makeHttpUI(c);
 	ui->setStatus(STATUS_RUNNING);
+	ui->setStatusString(T_("Downloading"));
 	ui->setTransferred(c->getDone(), c->getDone(), c->getSize());
 
 	addedConn(ui);
@@ -1036,6 +1050,7 @@
 void TransferView::on(HttpManagerListener::Updated, HttpConnection* c) noexcept {
 	auto ui = makeHttpUI(c);
 	ui->setTransferred(c->getDone(), c->getDone(), c->getSize());
+	ui->setSpeed(c->getSpeed());
 
 	updatedConn(ui);
 }
@@ -1049,10 +1064,10 @@
 	updatedConn(ui);
 }
 
-void TransferView::on(HttpManagerListener::Complete, HttpConnection* c, const string&) noexcept {
+void TransferView::on(HttpManagerListener::Complete, HttpConnection* c, OutputStream*) noexcept {
 	auto ui = makeHttpUI(c);
 	ui->setStatus(STATUS_WAITING);
-	ui->setStatusString(T_("Idle"));
+	ui->setStatusString(T_("Download finished"));
 	ui->setTransferred(c->getDone(), c->getDone(), c->getSize());
 
 	updatedConn(ui);

=== modified file 'win32/TransferView.h'
--- win32/TransferView.h	2013-04-12 21:10:13 +0000
+++ win32/TransferView.h	2013-04-13 15:08:45 +0000
@@ -180,7 +180,7 @@
 
 		UpdateInfo(const HintedUser& user, bool download, bool transferFailed = false) :
 			updateMask(0), user(user), download(download), transferFailed(transferFailed) { }
-		UpdateInfo(bool download) : download(download), transferFailed(false) { }
+		UpdateInfo(bool download) : updateMask(0), download(download), transferFailed(false) { }
 
 		uint32_t updateMask;
 
@@ -217,7 +217,7 @@
 		tstring country;
 
 		void setHttp() { updateMask |= MASK_HTTP; }
-		bool isHttp() const { return (updateMask & MASK_HTTP) == MASK_HTTP; }
+		bool isHttp() const { return updateMask & MASK_HTTP; }
 	};
 
 	typedef TypedTable<ItemInfo, false, dwt::TableTree> WidgetTransfers;
@@ -292,7 +292,7 @@
 	virtual void on(HttpManagerListener::Added, HttpConnection*) noexcept;
 	virtual void on(HttpManagerListener::Updated, HttpConnection*) noexcept;
 	virtual void on(HttpManagerListener::Failed, HttpConnection*, const string&) noexcept;
-	virtual void on(HttpManagerListener::Complete, HttpConnection*, const string&) noexcept;
+	virtual void on(HttpManagerListener::Complete, HttpConnection*, OutputStream*) noexcept;
 	virtual void on(HttpManagerListener::Removed, HttpConnection*) noexcept;
 
 	void addedConn(UpdateInfo* ui);