From 0189e27fd98ad9a8ba9aacd1c5f715e56129167e Mon Sep 17 00:00:00 2001
From: George Hazan <george.hazan@gmail.com>
Date: Wed, 14 Jun 2023 16:23:38 +0300
Subject: Steam: old shitty perversion migrated to the kernel MHttpRequest

---
 protocols/Steam/src/api/app_info.h      |   6 +-
 protocols/Steam/src/api/authorization.h |  11 +-
 protocols/Steam/src/api/avatar.h        |   2 +-
 protocols/Steam/src/api/captcha.h       |   4 +-
 protocols/Steam/src/api/friend.h        |   6 +-
 protocols/Steam/src/api/friend_list.h   |  59 ++----
 protocols/Steam/src/api/history.h       |   8 +-
 protocols/Steam/src/api/login.h         |   8 +-
 protocols/Steam/src/api/message.h       |   8 +-
 protocols/Steam/src/api/pending.h       |  24 ++-
 protocols/Steam/src/api/poll.h          |   6 +-
 protocols/Steam/src/api/rsa_key.h       |   4 +-
 protocols/Steam/src/api/search.h        |   4 +-
 protocols/Steam/src/api/session.h       |   8 +-
 protocols/Steam/src/http_request.h      | 358 ++------------------------------
 protocols/Steam/src/steam_contacts.cpp  |  16 +-
 protocols/Steam/src/steam_login.cpp     |  12 +-
 protocols/Steam/src/steam_messages.cpp  |   2 +-
 protocols/Steam/src/steam_proto.h       |  25 +--
 protocols/Steam/src/steam_request.cpp   |  33 ++-
 protocols/Steam/src/steam_server.cpp    |   6 +-
 21 files changed, 135 insertions(+), 475 deletions(-)

(limited to 'protocols/Steam')

diff --git a/protocols/Steam/src/api/app_info.h b/protocols/Steam/src/api/app_info.h
index 7aeb26f9d4..b4c2618249 100644
--- a/protocols/Steam/src/api/app_info.h
+++ b/protocols/Steam/src/api/app_info.h
@@ -5,11 +5,9 @@ class GetAppInfoRequest : public HttpRequest
 {
 public:
 	GetAppInfoRequest(const char *token, const char *appIds) :
-		HttpRequest(HttpGet, STEAM_API_URL "/ISteamGameOAuth/GetAppInfo/v0001")
+		HttpRequest(REQUEST_GET, STEAM_API_URL "/ISteamGameOAuth/GetAppInfo/v0001")
 	{
-		Uri
-			<< CHAR_PARAM("access_token", token)
-			<< CHAR_PARAM("appIds", appIds);
+		this << CHAR_PARAM("access_token", token) << CHAR_PARAM("appIds", appIds);
 	}
 
 	//{
diff --git a/protocols/Steam/src/api/authorization.h b/protocols/Steam/src/api/authorization.h
index b2ba2639c0..fdaec9920d 100644
--- a/protocols/Steam/src/api/authorization.h
+++ b/protocols/Steam/src/api/authorization.h
@@ -5,15 +5,14 @@ class AuthorizationRequest : public HttpRequest
 {
 public:
 	AuthorizationRequest(const char *username, const char *password, const char *timestamp, const char *twoFactorCode, const char *guardCode, const char *guardId = "", const char *captchaId = "-1", const char *captchaText = "") :
-		HttpRequest(HttpPost, STEAM_WEB_URL "/mobilelogin/dologin/")
+		HttpRequest(REQUEST_POST, STEAM_WEB_URL "/mobilelogin/dologin/")
 	{
 		flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP;
 
-		Headers
-			<< CHAR_PARAM("Referer", STEAM_WEB_URL "/mobilelogin/dologin?oauth_client_id=3638BFB1&oauth_scope=read_profile%20write_profile%20read_client%20write_client")
-			<< CHAR_PARAM("Cookie", "mobileClientVersion=1291812;forceMobile=1;mobileClient=ios");
+		AddHeader("Referer", STEAM_WEB_URL "/mobilelogin/dologin?oauth_client_id=3638BFB1&oauth_scope=read_profile%20write_profile%20read_client%20write_client");
+		AddHeader("Cookie", "mobileClientVersion=1291812;forceMobile=1;mobileClient=ios");
 
-		Content = new FormUrlEncodedContent(this)
+		this 
 			<< CHAR_PARAM("oauth_client_id", "3638BFB1")
 			<< CHAR_PARAM("loginfriendlyname", "Miranda NG")
 			<< CHAR_PARAM("password", password)
@@ -24,7 +23,7 @@ public:
 			<< CHAR_PARAM("captchagid", captchaId)
 			<< CHAR_PARAM("captcha_text", captchaText)
 			<< CHAR_PARAM("rsatimestamp", timestamp)
-			<< BOOL_PARAM("rememberlogin", false)
+			<< INT_PARAM("rememberlogin", 0)
 			<< INT64_PARAM("donotcache", now());
 	}
 };
diff --git a/protocols/Steam/src/api/avatar.h b/protocols/Steam/src/api/avatar.h
index 521536550e..28e573d9d1 100644
--- a/protocols/Steam/src/api/avatar.h
+++ b/protocols/Steam/src/api/avatar.h
@@ -5,7 +5,7 @@ class GetAvatarRequest : public HttpRequest
 {
 public:
 	GetAvatarRequest(const char *url) :
-		HttpRequest(HttpGet, url)
+		HttpRequest(REQUEST_GET, url)
 	{
 		flags = NLHRF_HTTP11 | NLHRF_NODUMP;
 	}
diff --git a/protocols/Steam/src/api/captcha.h b/protocols/Steam/src/api/captcha.h
index 0b8ba9191a..a4bacb59f7 100644
--- a/protocols/Steam/src/api/captcha.h
+++ b/protocols/Steam/src/api/captcha.h
@@ -5,11 +5,11 @@ class GetCaptchaRequest : public HttpRequest
 {
 public:
 	GetCaptchaRequest(const char *captchaId) :
-		HttpRequest(HttpGet, STEAM_WEB_URL "/public/captcha.php")
+		HttpRequest(REQUEST_GET, STEAM_WEB_URL "/public/captcha.php")
 	{
 		flags = NLHRF_HTTP11 | NLHRF_NODUMP;
 
-		Uri << CHAR_PARAM("gid", captchaId);
+		this << CHAR_PARAM("gid", captchaId);
 	}
 };
 
diff --git a/protocols/Steam/src/api/friend.h b/protocols/Steam/src/api/friend.h
index 2f088a7e40..e6740e7151 100644
--- a/protocols/Steam/src/api/friend.h
+++ b/protocols/Steam/src/api/friend.h
@@ -5,11 +5,9 @@ class GetUserSummariesRequest : public HttpRequest
 {
 public:
 	GetUserSummariesRequest(CSteamProto *ppro, const char *steamIds) :
-		HttpRequest(HttpGet, STEAM_API_URL "/ISteamUserOAuth/GetUserSummaries/v0002")
+		HttpRequest(REQUEST_GET, STEAM_API_URL "/ISteamUserOAuth/GetUserSummaries/v0002")
 	{
-		Uri
-			<< CHAR_PARAM("access_token", ppro->getMStringA("TokenSecret"))
-			<< CHAR_PARAM("steamids", steamIds);
+		this << CHAR_PARAM("access_token", ppro->getMStringA("TokenSecret")) << CHAR_PARAM("steamids", steamIds);
 	}
 
 	//{
diff --git a/protocols/Steam/src/api/friend_list.h b/protocols/Steam/src/api/friend_list.h
index c291f14b85..359423d359 100644
--- a/protocols/Steam/src/api/friend_list.h
+++ b/protocols/Steam/src/api/friend_list.h
@@ -5,31 +5,17 @@ class GetFriendListRequest : public HttpRequest
 {
 public:
 	GetFriendListRequest(const char *token, const char *steamId, const char *relationship) :
-		HttpRequest(HttpGet, STEAM_API_URL "/ISteamUserOAuth/GetFriendList/v0001")
+		HttpRequest(REQUEST_GET, STEAM_API_URL "/ISteamUserOAuth/GetFriendList/v0001")
 	{
-		Uri
-			<< CHAR_PARAM("access_token", token)
-			<< CHAR_PARAM("steamid", steamId)
-			<< CHAR_PARAM("relationship", relationship);
+		this << CHAR_PARAM("access_token", token) << CHAR_PARAM("steamid", steamId) << CHAR_PARAM("relationship", relationship);
 	}
-
-	//{
-	//	"friends": [
-	//		{
-	//			"steamid": "XXXXXXXXXXXXXXXXX",
-	//			"relationship" : "friend",
-	//			"friend_since" : 1514314629
-	//		}
-	//	]
-	//}
-
 };
 
 class AddFriendRequest : public HttpRequest
 {
 public:
 	AddFriendRequest(const char *token, const char *sessionId, const char *steamId, const char *who) :
-		HttpRequest(HttpPost, STEAM_WEB_URL "/actions/AddFriendAjax")
+		HttpRequest(REQUEST_POST, STEAM_WEB_URL "/actions/AddFriendAjax")
 	{
 		char login[MAX_PATH];
 		mir_snprintf(login, "%s||oauth:%s", steamId, token);
@@ -37,25 +23,17 @@ public:
 		char cookie[MAX_PATH];
 		mir_snprintf(cookie, "steamLogin=%s;sessionid=%s;mobileClientVersion=1291812;forceMobile=1;mobileClient=ios", login, sessionId);
 
-		Headers << CHAR_PARAM("Cookie", cookie);
+		AddHeader("Cookie", cookie);
 
-		Content = new FormUrlEncodedContent(this)
-			<< CHAR_PARAM("sessionID", sessionId)
-			<< CHAR_PARAM("steamid", who);
+		this << CHAR_PARAM("sessionID", sessionId) << CHAR_PARAM("steamid", who);
 	}
-
-	// "true"
-
-	// {"invited":["XXXXXXXXXXXXXXXXX"], "success" : 1}
-
-	// {"failed_invites":["XXXXXXXXXXXXXXXXX"], "failed_invites_result" : [24], "success" : 1}
 };
 
 class BlockFriendRequest : public HttpRequest
 {
 public:
 	BlockFriendRequest(const char *token, const char *sessionId, const char *steamId, const char *who) :
-		HttpRequest(HttpPost, STEAM_WEB_URL "/actions/BlockUserAjax")
+		HttpRequest(REQUEST_POST, STEAM_WEB_URL "/actions/BlockUserAjax")
 	{
 		char login[MAX_PATH];
 		mir_snprintf(login, "%s||oauth:%s", steamId, token);
@@ -63,12 +41,9 @@ public:
 		char cookie[MAX_PATH];
 		mir_snprintf(cookie, "steamLogin=%s;sessionid=%s;mobileClientVersion=1291812;forceMobile=1;mobileClient=ios", login, sessionId);
 
-		Headers << CHAR_PARAM("Cookie", cookie);
+		AddHeader("Cookie", cookie);
 
-		Content = new FormUrlEncodedContent(this)
-			<< CHAR_PARAM("sessionID", sessionId)
-			<< CHAR_PARAM("steamid", who)
-			<< CHAR_PARAM("action", "ignore");
+		this << CHAR_PARAM("sessionID", sessionId) << CHAR_PARAM("steamid", who) << CHAR_PARAM("action", "ignore");
 	}
 };
 
@@ -76,7 +51,7 @@ class UnblockFriendRequest : public HttpRequest
 {
 public:
 	UnblockFriendRequest(const char *token, const char *sessionId, const char *steamId, const char *who) :
-		HttpRequest(HttpPost, STEAM_WEB_URL "/actions/BlockUserAjax")
+		HttpRequest(REQUEST_POST, STEAM_WEB_URL "/actions/BlockUserAjax")
 	{
 		char login[MAX_PATH];
 		mir_snprintf(login, "%s||oauth:%s", steamId, token);
@@ -84,13 +59,9 @@ public:
 		char cookie[MAX_PATH];
 		mir_snprintf(cookie, "steamLogin=%s;sessionid=%s;mobileClientVersion=1291812;forceMobile=1;mobileClient=ios", login, sessionId);
 
-		Headers << CHAR_PARAM("Cookie", cookie);
+		AddHeader("Cookie", cookie);
 
-		Content = new FormUrlEncodedContent(this)
-			<< CHAR_PARAM("sessionID", sessionId)
-			<< CHAR_PARAM("steamid", who)
-			<< CHAR_PARAM("action", "unignore")
-			<< INT_PARAM("block", 0);
+		this << CHAR_PARAM("sessionID", sessionId) << CHAR_PARAM("steamid", who) << CHAR_PARAM("action", "unignore") << INT_PARAM("block", 0);
 	}
 };
 
@@ -98,7 +69,7 @@ class RemoveFriendRequest : public HttpRequest
 {
 public:
 	RemoveFriendRequest(const char *token, const char *sessionId, const char *steamId, const char *who) :
-		HttpRequest(HttpPost, STEAM_WEB_URL "/actions/RemoveFriendAjax")
+		HttpRequest(REQUEST_POST, STEAM_WEB_URL "/actions/RemoveFriendAjax")
 	{
 		char login[MAX_PATH];
 		mir_snprintf(login, "%s||oauth:%s", steamId, token);
@@ -106,11 +77,9 @@ public:
 		char cookie[MAX_PATH];
 		mir_snprintf(cookie, "steamLogin=%s;sessionid=%s;mobileClientVersion=1291812;forceMobile=1;mobileClient=ios", login, sessionId);
 
-		Headers << CHAR_PARAM("Cookie", cookie);
+		AddHeader("Cookie", cookie);
 
-		Content = new FormUrlEncodedContent(this)
-			<< CHAR_PARAM("sessionID", sessionId)
-			<< CHAR_PARAM("steamid", who);
+		this << CHAR_PARAM("sessionID", sessionId) << CHAR_PARAM("steamid", who);
 	}
 };
 
diff --git a/protocols/Steam/src/api/history.h b/protocols/Steam/src/api/history.h
index decbea87f0..290f2310df 100644
--- a/protocols/Steam/src/api/history.h
+++ b/protocols/Steam/src/api/history.h
@@ -5,9 +5,9 @@ class GetConversationsRequest : public HttpRequest
 {
 public:
 	GetConversationsRequest(CSteamProto *ppro) :
-		HttpRequest(HttpGet, STEAM_API_URL "/IFriendMessagesService/GetActiveMessageSessions/v0001")
+		HttpRequest(REQUEST_GET, STEAM_API_URL "/IFriendMessagesService/GetActiveMessageSessions/v0001")
 	{
-		Uri << CHAR_PARAM("access_token", ppro->getMStringA("TokenSecret"));
+		this << CHAR_PARAM("access_token", ppro->getMStringA("TokenSecret"));
 	}
 
 	//{
@@ -30,9 +30,9 @@ class GetHistoryMessagesRequest : public HttpRequest
 {
 public:
 	GetHistoryMessagesRequest(const char *token, const char *steamId, const char *who, time_t since) :
-		HttpRequest(HttpGet, STEAM_API_URL "/IFriendMessagesService/GetRecentMessages/v0001")
+		HttpRequest(REQUEST_GET, STEAM_API_URL "/IFriendMessagesService/GetRecentMessages/v0001")
 	{
-		Uri
+		this
 			<< CHAR_PARAM("access_token", token)
 			<< CHAR_PARAM("steamid1", steamId)
 			<< CHAR_PARAM("steamid2", who)
diff --git a/protocols/Steam/src/api/login.h b/protocols/Steam/src/api/login.h
index e061d4236c..d9511c4752 100644
--- a/protocols/Steam/src/api/login.h
+++ b/protocols/Steam/src/api/login.h
@@ -5,12 +5,12 @@ class LogonRequest : public HttpRequest
 {
 public:
 	LogonRequest(const char *token) :
-		HttpRequest(HttpPost, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Logon/v0001")
+		HttpRequest(REQUEST_POST, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Logon/v0001")
 	{
 		char data[256];
 		mir_snprintf(data, "access_token=%s&ui_mode=web", token);
 
-		Content = new FormUrlEncodedContent(this)
+		this
 			<< CHAR_PARAM("access_token", token)
 			<< CHAR_PARAM("ui_mode", "web");
 	}
@@ -31,9 +31,9 @@ class LogoffRequest : public HttpRequest
 {
 public:
 	LogoffRequest(const char *token, const char *umqId) :
-		HttpRequest(HttpPost, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Logoff/v0001")
+		HttpRequest(REQUEST_POST, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Logoff/v0001")
 	{
-		Content = new FormUrlEncodedContent(this)
+		this
 			<< CHAR_PARAM("access_token", token)
 			<< CHAR_PARAM("umqid", umqId);
 	}
diff --git a/protocols/Steam/src/api/message.h b/protocols/Steam/src/api/message.h
index eee4c43b28..e07e70d959 100644
--- a/protocols/Steam/src/api/message.h
+++ b/protocols/Steam/src/api/message.h
@@ -5,9 +5,9 @@ class SendMessageRequest : public HttpRequest
 {
 public:
 	SendMessageRequest(const char *token, const char *umqId, const char *steamId, const char *text) :
-		HttpRequest(HttpPost, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Message/v0001")
+		HttpRequest(REQUEST_POST, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Message/v0001")
 	{
-		Content = new FormUrlEncodedContent(this)
+		this
 			<< CHAR_PARAM("access_token", token)
 			<< CHAR_PARAM("umqid", umqId)
 			<< CHAR_PARAM("steamid_dst", steamId)
@@ -20,9 +20,9 @@ class SendTypingRequest : public HttpRequest
 {
 public:
 	SendTypingRequest(const char *token, const char *umqId, const char *steamId) :
-		HttpRequest(HttpPost, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Message/v0001")
+		HttpRequest(REQUEST_POST, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Message/v0001")
 	{
-		Content = new FormUrlEncodedContent(this)
+		this
 			<< CHAR_PARAM("access_token", token)
 			<< CHAR_PARAM("umqid", umqId)
 			<< CHAR_PARAM("steamid_dst", steamId)
diff --git a/protocols/Steam/src/api/pending.h b/protocols/Steam/src/api/pending.h
index 9aeed4e182..b8e8e6e15f 100644
--- a/protocols/Steam/src/api/pending.h
+++ b/protocols/Steam/src/api/pending.h
@@ -5,15 +5,17 @@ class ApprovePendingRequest : public HttpRequest
 {
 public:
 	ApprovePendingRequest(const char *token, const char *sessionId, const char *steamId, const char *who) :
-		HttpRequest(HttpPost, FORMAT, STEAM_WEB_URL "/profiles/%s/home_process", steamId)
+		HttpRequest(REQUEST_POST, "")
 	{
+		m_szUrl.Format(STEAM_WEB_URL "/profiles/%s/home_process", steamId);
+
 		char cookie[MAX_PATH];
 		mir_snprintf(cookie, "steamLogin=%s||oauth:%s;sessionid=%s;mobileClientVersion=1291812;forceMobile=1;mobileClient=ios",
 			steamId, token, sessionId);
 
-		Headers << CHAR_PARAM("Cookie", cookie);
+		AddHeader("Cookie", cookie);
 
-		Content = new FormUrlEncodedContent(this)
+		this
 			<< CHAR_PARAM("sessionID", sessionId)
 			<< CHAR_PARAM("id", who)
 			<< CHAR_PARAM("perform", "accept")
@@ -28,15 +30,17 @@ class IgnorePendingRequest : public HttpRequest
 {
 public:
 	IgnorePendingRequest(const char *token, const char *sessionId, const char *steamId, const char *who) :
-		HttpRequest(HttpPost, FORMAT, STEAM_WEB_URL "/profiles/%s/home_process", steamId)
+		HttpRequest(REQUEST_POST, "")
 	{
+		m_szUrl.Format(STEAM_WEB_URL "/profiles/%s/home_process", steamId);
+
 		char cookie[MAX_PATH];
 		mir_snprintf(cookie, "steamLogin=%s||oauth:%s;sessionid=%s;mobileClientVersion=1291812;forceMobile=1;mobileClient=ios",
 			steamId, token, sessionId);
 
-		Headers << CHAR_PARAM("Cookie", cookie);
+		AddHeader("Cookie", cookie);
 
-		Content = new FormUrlEncodedContent(this)
+		this
 			<< CHAR_PARAM("sessionID", sessionId)
 			<< CHAR_PARAM("id", who)
 			<< CHAR_PARAM("perform", "ignore")
@@ -51,15 +55,17 @@ class BlockPendingRequest : public HttpRequest
 {
 public:
 	BlockPendingRequest(const char *token, const char *sessionId, const char *steamId, const char *who) :
-		HttpRequest(HttpPost, FORMAT, STEAM_WEB_URL "/profiles/%s/home_process", steamId)
+		HttpRequest(REQUEST_POST, "")
 	{
+		m_szUrl.Format(STEAM_WEB_URL "/profiles/%s/home_process", steamId);
+
 		char cookie[MAX_PATH];
 		mir_snprintf(cookie, "steamLogin=%s||oauth:%s;sessionid=%s;mobileClientVersion=1291812;forceMobile=1;mobileClient=ios",
 			steamId, token, sessionId);
 
-		Headers << CHAR_PARAM("Cookie", cookie);
+		AddHeader("Cookie", cookie);
 
-		Content = new FormUrlEncodedContent(this)
+		this
 			<< CHAR_PARAM("sessionID", sessionId)
 			<< CHAR_PARAM("id", who)
 			<< CHAR_PARAM("perform", "block")
diff --git a/protocols/Steam/src/api/poll.h b/protocols/Steam/src/api/poll.h
index a8f0ac3edb..9de2ed32d3 100644
--- a/protocols/Steam/src/api/poll.h
+++ b/protocols/Steam/src/api/poll.h
@@ -5,14 +5,14 @@ class PollRequest : public HttpRequest
 {
 public:
 	PollRequest(CSteamProto *ppro) :
-		HttpRequest(HttpPost, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Poll/v0001")
+		HttpRequest(REQUEST_POST, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Poll/v0001")
 	{
 		timeout = (STEAM_API_TIMEOUT + 5) * 1000;
 		// flags |= NLHRF_PERSISTENT;
 
-		Headers << CHAR_PARAM("Connection", "keep-alive");
+		AddHeader("Connection", "keep-alive");
 
-		Content = new FormUrlEncodedContent(this)
+		this
 			<< CHAR_PARAM("access_token", ppro->getMStringA("TokenSecret"))
 			<< CHAR_PARAM("umqid", ppro->getMStringA("UMQID"))
 			<< INT64_PARAM("message", ppro->getDword("MessageID"))
diff --git a/protocols/Steam/src/api/rsa_key.h b/protocols/Steam/src/api/rsa_key.h
index a0369f4db4..48c76e3e6d 100644
--- a/protocols/Steam/src/api/rsa_key.h
+++ b/protocols/Steam/src/api/rsa_key.h
@@ -5,11 +5,11 @@ class GetRsaKeyRequest : public HttpRequest
 {
 public:
 	GetRsaKeyRequest(const char *username) :
-		HttpRequest(HttpPost, STEAM_WEB_URL "/mobilelogin/getrsakey/")
+		HttpRequest(REQUEST_POST, STEAM_WEB_URL "/mobilelogin/getrsakey/")
 	{
 		flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP;
 
-		Content = new FormUrlEncodedContent(this)
+		this
 			<< CHAR_PARAM("username", username)
 			<< INT64_PARAM("donotcache", now());
 	}
diff --git a/protocols/Steam/src/api/search.h b/protocols/Steam/src/api/search.h
index 4484af4ba8..fd3c8a66f0 100644
--- a/protocols/Steam/src/api/search.h
+++ b/protocols/Steam/src/api/search.h
@@ -5,9 +5,9 @@ class SearchRequest : public HttpRequest
 {
 public:
 	SearchRequest(const char *token, const char *text, int offset = 0, int count = 30) :
-		HttpRequest(HttpGet, STEAM_API_URL "/ISteamUserOAuth/Search/v0001")
+		HttpRequest(REQUEST_GET, STEAM_API_URL "/ISteamUserOAuth/Search/v0001")
 	{
-		Uri
+		this
 			<< CHAR_PARAM("access_token", token)
 			<< CHAR_PARAM("keywords", text)
 			<< INT_PARAM("offset", offset)
diff --git a/protocols/Steam/src/api/session.h b/protocols/Steam/src/api/session.h
index dec2e0aa0a..00705c1b67 100644
--- a/protocols/Steam/src/api/session.h
+++ b/protocols/Steam/src/api/session.h
@@ -5,11 +5,11 @@ class GetSessionRequest : public HttpRequest
 {
 public:
 	GetSessionRequest(const char *token, const char *steamId, const char *cookie) :
-		HttpRequest(HttpPost, STEAM_WEB_URL "/mobileloginsucceeded")
+		HttpRequest(REQUEST_POST, STEAM_WEB_URL "/mobileloginsucceeded")
 	{
 		flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP;
 
-		Content = new FormUrlEncodedContent(this)
+		this
 			<< CHAR_PARAM("oauth_token", token)
 			<< CHAR_PARAM("steamid", steamId)
 			<< CHAR_PARAM("webcookie", cookie);
@@ -27,14 +27,14 @@ class GetSessionRequest2 : public HttpRequest
 {
 public:
 	GetSessionRequest2(const char *token, const char *steamId) :
-		HttpRequest(HttpGet, STEAM_WEB_URL "/mobilesettings/GetManifest/v0001")
+		HttpRequest(REQUEST_GET, STEAM_WEB_URL "/mobilesettings/GetManifest/v0001")
 	{
 		flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMPHEADERS;
 
 		char cookie[MAX_PATH];
 		mir_snprintf(cookie, "steamLogin=%s||oauth:%s", steamId, token);
 
-		Headers << CHAR_PARAM("Cookie", cookie);
+		AddHeader("Cookie", cookie);
 	}
 };
 
diff --git a/protocols/Steam/src/http_request.h b/protocols/Steam/src/http_request.h
index a8338ff60f..192eedd9ab 100644
--- a/protocols/Steam/src/http_request.h
+++ b/protocols/Steam/src/http_request.h
@@ -1,353 +1,13 @@
 #ifndef _HTTP_REQUEST_H_
 #define _HTTP_REQUEST_H_
 
-class HttpRequest;
-class HttpResponse;
-
-class HttpUri : private MNonCopyable
-{
-	friend class HttpRequest;
-
-private:
-	CMStringA m_uri;
-	NETLIBHTTPREQUEST *m_request;
-
-	HttpUri(NETLIBHTTPREQUEST *request, const char *uri)
-		: m_request(request), m_uri(uri)
-	{
-		if (m_request)
-			m_request->szUrl = m_uri.GetBuffer();
-	}
-
-	HttpUri(NETLIBHTTPREQUEST *request, const char *urlFormat, va_list args)
-		: m_request(request)
-	{
-		m_uri.AppendFormatV(urlFormat, args);
-		if (m_request)
-			m_request->szUrl = m_uri.GetBuffer();
-	}
-
-	~HttpUri()
-	{
-		if (m_request)
-			m_request->szUrl = NULL;
-	}
-
-	void FormatV(const char *urlFormat, va_list args)
-	{
-		m_uri.FormatV(urlFormat, args);
-		if (m_request)
-			m_request->szUrl = m_uri.GetBuffer();
-	}
-
-	void AppendFormat(const char *fmt, ...)
-	{
-		va_list args;
-		va_start(args, fmt);
-		m_uri += (m_uri.Find('?') == -1) ? '?' : '&';
-		m_uri.AppendFormatV(fmt, args);
-		va_end(args);
-
-		if (m_request)
-			m_request->szUrl = m_uri.GetBuffer();
-	}
-
-public:
-	operator const char*() const
-	{
-		return m_request
-			? m_request->szUrl
-			: NULL;
-	}
-
-	HttpUri &operator<<(const PARAM &param)
-	{
-		AppendFormat(param.szName);
-		return *this;
-	}
-
-	HttpUri &operator<<(const INT_PARAM &param)
-	{
-		AppendFormat("%s=%i", param.szName, param.iValue);
-		return *this;
-	}
-
-	HttpUri &operator<<(const INT64_PARAM &param)
-	{
-		AppendFormat("%s=%lld", param.szName, param.iValue);
-		return *this;
-	}
-
-	HttpUri &operator<<(const CHAR_PARAM &param)
-	{
-		AppendFormat("%s=%s", param.szName, mir_urlEncode(param.szValue).c_str());
-		return *this;
-	}
-};
-
-class HttpHeaders : private MNonCopyable
-{
-	friend class HttpContent;
-	friend class HttpRequest;
-	friend class HttpResponse;
-
-private:
-	NETLIBHTTPREQUEST *m_request;
-
-	HttpHeaders(NETLIBHTTPREQUEST *request)
-		: m_request(request)
-	{
-	}
-
-	void Set(LPCSTR szName)
-	{
-		Set(szName, "");
-	}
-
-	void Set(LPCSTR szName, LPCSTR szValue)
-	{
-		if (!m_request)
-			return;
-
-		m_request->headers = (NETLIBHTTPHEADER*)mir_realloc(m_request->headers,
-			sizeof(NETLIBHTTPHEADER)*(m_request->headersCount + 1));
-		m_request->headers[m_request->headersCount].szName = mir_strdup(szName);
-		m_request->headers[m_request->headersCount].szValue = mir_strdup(szValue);
-		m_request->headersCount++;
-	}
-
-public:
-	const NETLIBHTTPHEADER* operator[](size_t idx) const
-	{
-		return m_request
-			? &m_request->headers[idx]
-			: nullptr;
-	}
-
-	size_t size() const
-	{
-		return m_request
-			? m_request->headersCount
-			: 0;
-	}
-
-	const NETLIBHTTPHEADER* begin() const
-	{
-		return m_request->headers;
-	}
-
-	const NETLIBHTTPHEADER* end() const
-	{
-		return m_request->headers + m_request->headersCount;
-	}
-
-	HttpHeaders& operator<<(const PARAM &param)
-	{
-		Set(param.szName);
-		return *this;
-	}
-
-	HttpHeaders& operator<<(const CHAR_PARAM &param)
-	{
-		Set(param.szName, param.szValue);
-		return *this;
-	}
-};
-
-class HttpContent : private MNonCopyable
-{
-	friend class HttpRequest;
-	friend class HttpResponse;
-
-protected:
-	HttpHeaders Headers;
-	NETLIBHTTPREQUEST *m_request;
-
-	HttpContent(NETLIBHTTPREQUEST *request)
-		: Headers(request), m_request(request)
-	{
-	}
-
-	virtual ~HttpContent()
-	{
-		if (m_request) {
-			m_request->pData = nullptr;
-			m_request->dataLength = 0;
-		}
-	}
-
-public:
-	operator bool() const
-	{
-		return m_request && m_request->pData && m_request->dataLength;
-	}
-
-	operator const char*() const
-	{
-		return m_request
-			? m_request->pData
-			: nullptr;
-	}
-
-	operator const uint8_t*() const
-	{
-		return m_request
-			? (uint8_t*)m_request->pData
-			: nullptr;
-	}
-
-	const uint8_t* data() const
-	{
-		return this->operator const uint8_t*();
-	}
-
-	size_t size() const
-	{
-		return m_request ? m_request->dataLength : 0;
-	}
-};
-
-class FormUrlEncodedContent : public HttpContent
-{
-	friend FormUrlEncodedContent *operator<<(FormUrlEncodedContent *, const PARAM &);
-	friend FormUrlEncodedContent *operator<<(FormUrlEncodedContent *, const BOOL_PARAM &);
-	friend FormUrlEncodedContent *operator<<(FormUrlEncodedContent *, const INT_PARAM &);
-	friend FormUrlEncodedContent *operator<<(FormUrlEncodedContent *, const INT64_PARAM &);
-	friend FormUrlEncodedContent *operator<<(FormUrlEncodedContent *, const CHAR_PARAM &);
-
-private:
-	CMStringA m_content;
-
-	void AppendFormat(const char *fmt, ...)
-	{
-		va_list args;
-		va_start(args, fmt);
-		if (!m_content.IsEmpty())
-			m_content += '&';
-		m_content.AppendFormatV(fmt, args);
-		va_end(args);
-
-		if (m_request) {
-			m_request->pData = m_content.GetBuffer();
-			m_request->dataLength = m_content.GetLength();
-		}
-	}
-
-public:
-	FormUrlEncodedContent(NETLIBHTTPREQUEST *request)
-		: HttpContent(request)
-	{
-		Headers << CHAR_PARAM("Content-Type", "application/x-www-form-urlencoded");
-	}
-};
-
-__forceinline FormUrlEncodedContent* operator<<(FormUrlEncodedContent *content, const PARAM &param)
-{
-	content->AppendFormat(param.szName);
-	return content;
-}
-
-__forceinline FormUrlEncodedContent* operator<<(FormUrlEncodedContent *content, const BOOL_PARAM &param)
-{
-	content->AppendFormat("%s=%s", param.szName, param.bValue ? "true" : "false");
-	return content;
-}
-
-__forceinline FormUrlEncodedContent* operator<<(FormUrlEncodedContent *content, const INT_PARAM &param)
-{
-	content->AppendFormat("%s=%i", param.szName, param.iValue);
-	return content;
-}
-
-__forceinline FormUrlEncodedContent* operator<<(FormUrlEncodedContent *content, const INT64_PARAM &param)
-{
-	content->AppendFormat("%s=%lld", param.szName, param.iValue);
-	return content;
-}
-
-__forceinline FormUrlEncodedContent* operator<<(FormUrlEncodedContent *content, const CHAR_PARAM &param)
-{
-	content->AppendFormat("%s=%s", param.szName, mir_urlEncode(param.szValue).c_str());
-	return content;
-}
-
-enum HttpMethod
-{
-	HttpGet = 1,
-	HttpPost
-};
-
-class HttpRequest : public NETLIBHTTPREQUEST, public MZeroedObject
-{
-	friend class HttpUri;
-	friend class HttpHeaders;
-	friend class HttpContent;
-
-protected:
-	enum HttpRequestUrlFormat { FORMAT };
-
-public:
-	HttpUri Uri;
-	HttpHeaders Headers;
-	HttpContent *Content;
-
-	HttpRequest(HttpMethod method, const char *url)
-		: Uri(this, url), Headers(this), Content(nullptr)
-	{
-		cbSize = sizeof(NETLIBHTTPREQUEST);
-		requestType = method;
-		flags = NLHRF_HTTP11 | NLHRF_SSL;
-		timeout = 3000;
-
-		Content = new HttpContent(this);
-	}
-
-	HttpRequest(HttpMethod method, HttpRequestUrlFormat, const char *urlFormat, ...)
-		: Uri(this, urlFormat), Headers(this), Content(nullptr)
-	{
-		cbSize = sizeof(NETLIBHTTPREQUEST);
-		requestType = method;
-		flags = NLHRF_HTTP11 | NLHRF_SSL;
-		timeout = 5;
-
-		va_list formatArgs;
-		va_start(formatArgs, urlFormat);
-		Uri.FormatV(urlFormat, formatArgs);
-		va_end(formatArgs);
-
-		Content = new HttpContent(this);
-	}
-
-	~HttpRequest()
-	{
-		if (Content != nullptr) {
-			delete Content;
-			Content = nullptr;
-		}
-	}
-
-	operator NETLIBHTTPREQUEST*()
-	{
-		return this;
-	}
-};
-
 class HttpResponse
 {
-	friend class HttpRequest;
-
 	NETLIBHTTPREQUEST *m_response;
 
 public:
-	HttpRequest *Request;
-	HttpHeaders Headers;
-	HttpContent Content;
-
-	HttpResponse(HttpRequest *request, NETLIBHTTPREQUEST *response) :
-		Request(request),
-		m_response(response),
-		Headers(response),
-		Content(response)
+	HttpResponse(NETLIBHTTPREQUEST *response) :
+		m_response(response)
 	{
 	}
 
@@ -373,11 +33,23 @@ public:
 			m_response->resultCode <= HTTP_CODE_MULTI_STATUS;
 	}
 
+	char* data() const
+	{
+		return (m_response) ? m_response->pData : nullptr;
+	}
+
+	unsigned length() const
+	{
+		return (m_response) ? m_response->dataLength : 0;
+	}
+
+	LIST<NETLIBHTTPHEADER> Headers() const;
+
 	int GetStatusCode() const
 	{
 		if (m_response)
 			return m_response->resultCode;
-		return Request ? Request->resultCode : 0;
+		return 500;
 	}
 };
 
diff --git a/protocols/Steam/src/steam_contacts.cpp b/protocols/Steam/src/steam_contacts.cpp
index d4bc14bcc2..33764d2f82 100644
--- a/protocols/Steam/src/steam_contacts.cpp
+++ b/protocols/Steam/src/steam_contacts.cpp
@@ -491,7 +491,7 @@ void CSteamProto::OnGotAvatar(const HttpResponse &response, void *arg)
 
 	FILE *file = _wfopen(ai.filename, L"wb");
 	if (file) {
-		fwrite((const char *)response.Content, sizeof(char), response.Content.size(), file);
+		fwrite(response.data(), sizeof(char), response.length(), file);
 		fclose(file);
 
 		if (ai.hContact)
@@ -505,7 +505,7 @@ void CSteamProto::OnFriendAdded(const HttpResponse &response, void *arg)
 {
 	SendAuthParam *param = (SendAuthParam *)arg;
 
-	if (!response.IsSuccess() || mir_strcmp(response.Content, "true")) {
+	if (!response.IsSuccess() || mir_strcmp(response.data(), "true")) {
 
 		ptrW steamId(getWStringA(param->hContact, "SteamID"));
 		ptrW who(getWStringA(param->hContact, "Nick"));
@@ -515,7 +515,7 @@ void CSteamProto::OnFriendAdded(const HttpResponse &response, void *arg)
 		wchar_t message[MAX_PATH];
 		mir_snwprintf(message, L"Error adding friend %s", who.get());
 
-		JSONNode root = JSONNode::parse(response.Content);
+		JSONNode root = JSONNode::parse(response.data());
 		if (root) {
 			int success = root["success"].as_int();
 			if (success == 1) {
@@ -568,7 +568,7 @@ void CSteamProto::OnFriendBlocked(const HttpResponse &response, void *arg)
 {
 	ptrA steamId((char *)arg);
 
-	if (!response.IsSuccess() || mir_strcmp(response.Content, "true")) {
+	if (!response.IsSuccess() || mir_strcmp(response.data(), "true")) {
 		debugLogA(__FUNCTION__ ": failed to ignore friend %s", (char *)steamId);
 		return;
 	}
@@ -582,7 +582,7 @@ void CSteamProto::OnFriendUnblocked(const HttpResponse &response, void *arg)
 {
 	ptrA steamId((char *)arg);
 
-	if (!response.IsSuccess() || mir_strcmp(response.Content, "true")) {
+	if (!response.IsSuccess() || mir_strcmp(response.data(), "true")) {
 		debugLogA(__FUNCTION__ ": failed to unignore friend %s", (char *)steamId);
 		return;
 	}
@@ -596,7 +596,7 @@ void CSteamProto::OnFriendRemoved(const HttpResponse &response, void *arg)
 {
 	ptrA steamId((char *)arg);
 
-	if (!response.IsSuccess() || mir_strcmp(response.Content, "true")) {
+	if (!response.IsSuccess() || mir_strcmp(response.data(), "true")) {
 		debugLogA(__FUNCTION__ ": failed to remove friend %s", (char *)steamId);
 		return;
 	}
@@ -658,7 +658,7 @@ void CSteamProto::OnSearchResults(const HttpResponse &response, void *arg)
 		return;
 	}
 
-	JSONNode root = JSONNode::parse(response.Content);
+	JSONNode root = JSONNode::parse(response.data());
 	if (root.isnull()) {
 		ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_FAILED, searchType, 0);
 		debugLogA(__FUNCTION__ ": no data");
@@ -706,7 +706,7 @@ void CSteamProto::OnSearchByNameStarted(const HttpResponse &response, void *arg)
 		return;
 	}
 
-	JSONNode root = JSONNode::parse(response.Content);
+	JSONNode root = JSONNode::parse(response.data());
 	if (root.isnull()) {
 		ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_FAILED, (HANDLE)arg, 0);
 		debugLogA(__FUNCTION__ ": no data");
diff --git a/protocols/Steam/src/steam_login.cpp b/protocols/Steam/src/steam_login.cpp
index 0363f16930..32a418d848 100644
--- a/protocols/Steam/src/steam_login.cpp
+++ b/protocols/Steam/src/steam_login.cpp
@@ -114,7 +114,7 @@ void CSteamProto::OnGotCaptcha(const HttpResponse &response, void *arg)
 		return;
 	}
 
-	CSteamCaptchaDialog captchaDialog(this, response.Content, response.Content.size());
+	CSteamCaptchaDialog captchaDialog(this, (const uint8_t*)response.data(), response.length());
 	if (!captchaDialog.DoModal()) {
 		DeleteAuthSettings();
 		SetStatus(ID_STATUS_OFFLINE);
@@ -135,7 +135,7 @@ void CSteamProto::OnAuthorization(const HttpResponse &response, void *)
 		return;
 	}
 
-	JSONNode root = JSONNode::parse(response.Content);
+	JSONNode root = JSONNode::parse(response.data());
 	if (root.isnull()) {
 		SetStatus(ID_STATUS_OFFLINE);
 		return;
@@ -279,11 +279,11 @@ void CSteamProto::OnGotSession(const HttpResponse &response, void *)
 		return;
 	}
 
-	for (auto &header : response.Headers) {
-		if (mir_strcmpi(header.szName, "Set-Cookie"))
+	for (auto &header : response.Headers()) {
+		if (mir_strcmpi(header->szName, "Set-Cookie"))
 			continue;
 
-		std::string cookies = header.szValue;
+		std::string cookies = header->szValue;
 		size_t start = cookies.find("sessionid=") + 10;
 		size_t end = cookies.substr(start).find(';');
 		std::string sessionId = cookies.substr(start, end - start + 10);
@@ -329,7 +329,7 @@ void CSteamProto::OnLoggedOn(const HttpResponse &response, void *)
 		return;
 	}
 
-	JSONNode root = JSONNode::parse(response.Content);
+	JSONNode root = JSONNode::parse(response.data());
 	json_string error = root["error"].as_string();
 	if (error != "OK") {
 		// Probably expired TokenSecret
diff --git a/protocols/Steam/src/steam_messages.cpp b/protocols/Steam/src/steam_messages.cpp
index f90bba865c..11870d341b 100644
--- a/protocols/Steam/src/steam_messages.cpp
+++ b/protocols/Steam/src/steam_messages.cpp
@@ -30,7 +30,7 @@ void CSteamProto::OnMessageSent(const HttpResponse &response, void *arg)
 	time_t timestamp = NULL;
 
 	if (response) {
-		JSONNode root = JSONNode::parse(response.Content);
+		JSONNode root = JSONNode::parse(response.data());
 		const JSONNode &node = root["error"];
 		if (node)
 			error = node.as_string();
diff --git a/protocols/Steam/src/steam_proto.h b/protocols/Steam/src/steam_proto.h
index d72caba56f..74d3631fd8 100644
--- a/protocols/Steam/src/steam_proto.h
+++ b/protocols/Steam/src/steam_proto.h
@@ -5,6 +5,11 @@
 #define STEAM_SEARCH_BYNAME 1002
 #define STEAM_TYPING_TIME 10
 
+// Global settings for all accounts: hosts' list
+#define STEAM_MODULE "Steam"
+#define DBKEY_HOSTS_COUNT "HostsCount"
+#define DBKEY_HOSTS_DATE  "HostsDate"
+
 struct SendAuthParam
 {
 	MCONTACT hContact;
@@ -28,25 +33,9 @@ enum
 typedef void(CSteamProto::*HttpCallback)(const HttpResponse&, void*);
 typedef void(CSteamProto::*JsonCallback)(const JSONNode&, void*);
 
-struct RequestQueueItem
+struct HttpRequest : public MTHttpRequest<CSteamProto>
 {
-	HttpRequest *request;
-	HttpCallback httpCallback;
-	JsonCallback jsonCallback;
-	void *param;
-
-	RequestQueueItem(HttpRequest *request)
-		: request(request), httpCallback(nullptr), jsonCallback(nullptr), param(nullptr)
-	{
-	}
-	RequestQueueItem(HttpRequest *request, HttpCallback callback, void *param)
-		: request(request), httpCallback(callback), jsonCallback(nullptr), param(param)
-	{
-	}
-	RequestQueueItem(HttpRequest *request, JsonCallback callback, void *param)
-		: request(request), httpCallback(nullptr), jsonCallback(callback), param(param)
-	{
-	}
+	HttpRequest(int iRequestType, const char *pszUrl);
 };
 
 class CSteamProto : public PROTO<CSteamProto>
diff --git a/protocols/Steam/src/steam_request.cpp b/protocols/Steam/src/steam_request.cpp
index b4ddec0a65..5b23361c32 100644
--- a/protocols/Steam/src/steam_request.cpp
+++ b/protocols/Steam/src/steam_request.cpp
@@ -3,7 +3,7 @@
 bool CSteamProto::SendRequest(HttpRequest *request)
 {
 	NETLIBHTTPREQUEST *pResp = Netlib_HttpTransaction(m_hNetlibUser, request);
-	HttpResponse response(request, pResp);
+	HttpResponse response(pResp);
 	delete request;
 	return response.IsSuccess();
 }
@@ -11,7 +11,7 @@ bool CSteamProto::SendRequest(HttpRequest *request)
 bool CSteamProto::SendRequest(HttpRequest *request, HttpCallback callback, void *param)
 {
 	NETLIBHTTPREQUEST *pResp = Netlib_HttpTransaction(m_hNetlibUser, (NETLIBHTTPREQUEST*)request);
-	HttpResponse response(request, pResp);
+	HttpResponse response(pResp);
 	if (callback)
 		(this->*callback)(response, param);
 	delete request;
@@ -21,11 +21,36 @@ bool CSteamProto::SendRequest(HttpRequest *request, HttpCallback callback, void
 bool CSteamProto::SendRequest(HttpRequest *request, JsonCallback callback, void *param)
 {
 	NETLIBHTTPREQUEST *pResp = Netlib_HttpTransaction(m_hNetlibUser, (NETLIBHTTPREQUEST*)request);
-	HttpResponse response(request, pResp);
+	HttpResponse response(pResp);
 	if (callback) {
-		JSONNode root = JSONNode::parse(response.Content);
+		JSONNode root = JSONNode::parse(response.data());
 		(this->*callback)(root, param);
 	}
 	delete request;
 	return response.IsSuccess();
 }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// HttpRequest
+
+HttpRequest::HttpRequest(int iRequestType, const char *szUrl)
+{
+	requestType = iRequestType;
+	timeout = 30000;
+	if (szUrl)
+		m_szUrl = szUrl;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// HttpResponse
+
+LIST<NETLIBHTTPHEADER> HttpResponse::Headers() const
+{
+	LIST<NETLIBHTTPHEADER> ret(10);
+
+	if (m_response)
+		for (int i = 0; i < m_response->headersCount; i++)
+			ret.insert(&m_response->headers[i]);
+	
+	return ret;
+}
diff --git a/protocols/Steam/src/steam_server.cpp b/protocols/Steam/src/steam_server.cpp
index 56df3f0cc3..a93c7ae696 100644
--- a/protocols/Steam/src/steam_server.cpp
+++ b/protocols/Steam/src/steam_server.cpp
@@ -19,5 +19,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
 
 void __cdecl CSteamProto::ServerThread(void *)
 {
-
+	// load web socket servers first if needed
+	int iTimeDiff = db_get_dw(0, STEAM_MODULE, DBKEY_HOSTS_DATE);
+	if (!db_get_dw(0, STEAM_MODULE, DBKEY_HOSTS_COUNT) || time(0) - iTimeDiff > 3600 * 24 * 7) { // once a week
+		// if (!SendRequest())
+	}
 }
-- 
cgit v1.2.3