diff --git a/src/Format.cpp b/src/Format.cpp index 548546d8b..9a9d5c389 100644 --- a/src/Format.cpp +++ b/src/Format.cpp @@ -285,6 +285,19 @@ std::unique_ptr> format::PixelsToPNG(PlaneAdapter params; + + ByteString ToByteString() const; + }; + ByteString URLEncode(ByteString value); ByteString URLDecode(ByteString value); ByteString UnixtimeToDate(time_t unixtime, ByteString dateFomat = ByteString("%d %b %Y"), bool local = true); diff --git a/src/client/http/APIRequest.cpp b/src/client/http/APIRequest.cpp index 621d32766..4a25dff7e 100644 --- a/src/client/http/APIRequest.cpp +++ b/src/client/http/APIRequest.cpp @@ -5,23 +5,17 @@ namespace http { namespace { - ByteString MaybeAppendSession(APIRequest::AuthMode authMode, ByteString url) + format::Url &MaybeAppendSession(APIRequest::AuthMode authMode, format::Url &url) { if (auto user = Client::Ref().GetAuthUser(); user && authMode == APIRequest::authRequireAppendSession) { - // TODO: proper url builder >_> - auto appendChar = '?'; - if (url.find('?') != url.npos) - { - appendChar = '&'; - } - url = ByteString::Build(url, appendChar, "Key=", user->SessionKey);; + url.params["Key"] = user->SessionKey; } return url; } } - APIRequest::APIRequest(ByteString url, AuthMode authMode, bool newCheckStatus) : Request(MaybeAppendSession(authMode, url)), checkStatus(newCheckStatus) + APIRequest::APIRequest(format::Url url, AuthMode authMode, bool newCheckStatus) : Request(MaybeAppendSession(authMode, url).ToByteString()), checkStatus(newCheckStatus) { auto user = Client::Ref().GetAuthUser(); if ((authMode == authRequire || diff --git a/src/client/http/APIRequest.h b/src/client/http/APIRequest.h index 8e648923c..f040d32f9 100644 --- a/src/client/http/APIRequest.h +++ b/src/client/http/APIRequest.h @@ -1,6 +1,7 @@ #pragma once #include "Request.h" #include "common/String.h" +#include "Format.h" #include namespace http @@ -17,7 +18,7 @@ namespace http authUse, authOmit, }; - APIRequest(ByteString url, AuthMode authMode, bool newCheckStatus); + APIRequest(format::Url url, AuthMode authMode, bool newCheckStatus); Json::Value Finish(); }; diff --git a/src/client/http/AddCommentRequest.cpp b/src/client/http/AddCommentRequest.cpp index a5b5a79df..15bd9da94 100644 --- a/src/client/http/AddCommentRequest.cpp +++ b/src/client/http/AddCommentRequest.cpp @@ -5,7 +5,9 @@ namespace http { AddCommentRequest::AddCommentRequest(int saveID, String comment) : - APIRequest(ByteString::Build(SERVER, "/Browse/Comments.json?ID=", saveID), authRequire, true) + APIRequest({ ByteString::Build(SERVER, "/Browse/Comments.json"), { + { "ID", ByteString::Build(saveID) }, + } }, authRequire, true) { auto user = Client::Ref().GetAuthUser(); AddPostData(FormData{ diff --git a/src/client/http/AddTagRequest.cpp b/src/client/http/AddTagRequest.cpp index 7ce445a13..eab6c548b 100644 --- a/src/client/http/AddTagRequest.cpp +++ b/src/client/http/AddTagRequest.cpp @@ -4,7 +4,11 @@ namespace http { AddTagRequest::AddTagRequest(int saveID, ByteString tag) : - APIRequest(ByteString::Build(SERVER, "/Browse/EditTag.json?Op=add&ID=", saveID, "&Tag=", tag), authRequireAppendSession, true) + APIRequest({ ByteString::Build(SERVER, "/Browse/EditTag.json"), { + { "Op", "add" }, + { "ID", ByteString::Build(saveID) }, + { "Tag", tag } + } }, authRequireAppendSession, true) { } diff --git a/src/client/http/DeleteSaveRequest.cpp b/src/client/http/DeleteSaveRequest.cpp index 2a7e2f758..7e259e7ba 100644 --- a/src/client/http/DeleteSaveRequest.cpp +++ b/src/client/http/DeleteSaveRequest.cpp @@ -4,7 +4,10 @@ namespace http { DeleteSaveRequest::DeleteSaveRequest(int saveID) : - APIRequest(ByteString::Build(SERVER, "/Browse/Delete.json?ID=", saveID, "&Mode=Delete"), authRequireAppendSession, true) + APIRequest({ ByteString::Build(SERVER, "/Browse/Delete.json"), { + { "ID", ByteString::Build(saveID) }, + { "Mode", "Delete" }, + } }, authRequireAppendSession, true) { } diff --git a/src/client/http/ExecVoteRequest.cpp b/src/client/http/ExecVoteRequest.cpp index 2ac70c24f..60a37cb8a 100644 --- a/src/client/http/ExecVoteRequest.cpp +++ b/src/client/http/ExecVoteRequest.cpp @@ -5,7 +5,7 @@ namespace http { ExecVoteRequest::ExecVoteRequest(int saveID, int newDirection) : - APIRequest(ByteString::Build(SERVER, "/Vote.api"), authRequire, false), + APIRequest({ ByteString::Build(SERVER, "/Vote.api") }, authRequire, false), direction(newDirection) { auto user = Client::Ref().GetAuthUser(); diff --git a/src/client/http/FavouriteSaveRequest.cpp b/src/client/http/FavouriteSaveRequest.cpp index 4287ba832..f52fdfdd5 100644 --- a/src/client/http/FavouriteSaveRequest.cpp +++ b/src/client/http/FavouriteSaveRequest.cpp @@ -3,15 +3,15 @@ namespace http { - static ByteString Url(int saveID, bool favourite) + static format::Url Url(int saveID, bool favourite) { - ByteStringBuilder builder; - builder << SERVER << "/Browse/Favourite.json?ID=" << saveID; + format::Url url{ ByteString::Build(SERVER, "/Browse/Favourite.json") }; + url.params["ID"] = ByteString::Build(saveID); if (!favourite) { - builder << "&Mode=Remove"; + url.params["Mode"] = "Remove"; } - return builder.Build(); + return url; } FavouriteSaveRequest::FavouriteSaveRequest(int saveID, bool newFavourite) : diff --git a/src/client/http/GetCommentsRequest.cpp b/src/client/http/GetCommentsRequest.cpp index f1374cec4..5f00bb699 100644 --- a/src/client/http/GetCommentsRequest.cpp +++ b/src/client/http/GetCommentsRequest.cpp @@ -5,7 +5,11 @@ namespace http { GetCommentsRequest::GetCommentsRequest(int saveID, int start, int count) : - APIRequest(ByteString::Build(SERVER, "/Browse/Comments.json?ID=", saveID, "&Start=", start, "&Count=", count), authOmit, false) + APIRequest({ ByteString::Build(SERVER, "/Browse/Comments.json"), { + { "ID", ByteString::Build(saveID) }, + { "Start", ByteString::Build(start) }, + { "Count", ByteString::Build(count) }, + } }, authOmit, false) { } diff --git a/src/client/http/GetSaveRequest.cpp b/src/client/http/GetSaveRequest.cpp index e29dab8b6..d75a6eee9 100644 --- a/src/client/http/GetSaveRequest.cpp +++ b/src/client/http/GetSaveRequest.cpp @@ -2,22 +2,23 @@ #include "client/Client.h" #include "client/SaveInfo.h" #include "client/GameSave.h" +#include "Format.h" #include "Config.h" namespace http { - static ByteString Url(int saveID, int saveDate) + static format::Url Url(int saveID, int saveDate) { - ByteStringBuilder builder; - builder << SERVER << "/Browse/View.json?ID=" << saveID; + format::Url url{ ByteString::Build(SERVER, "/Browse/View.json") }; + url.params["ID"] = ByteString::Build(saveID); if (saveDate) { - builder << "&Date=" << saveDate; + url.params["Date"] = ByteString::Build(saveDate); } - return builder.Build(); + return url; } - GetSaveRequest::GetSaveRequest(int saveID, int saveDate) : Request(Url(saveID, saveDate)) + GetSaveRequest::GetSaveRequest(int saveID, int saveDate) : Request(Url(saveID, saveDate).ToByteString()) { auto user = Client::Ref().GetAuthUser(); if (user) diff --git a/src/client/http/GetUserInfoRequest.cpp b/src/client/http/GetUserInfoRequest.cpp index be67ee0f8..a8c3f1c04 100644 --- a/src/client/http/GetUserInfoRequest.cpp +++ b/src/client/http/GetUserInfoRequest.cpp @@ -5,7 +5,9 @@ namespace http { GetUserInfoRequest::GetUserInfoRequest(ByteString username) : - APIRequest(ByteString::Build(SERVER, "/User.json?Name=", username), authOmit, false) + APIRequest({ ByteString::Build(SERVER, "/User.json"), { + { "Name", username }, + } }, authOmit, false) { } diff --git a/src/client/http/LogoutRequest.cpp b/src/client/http/LogoutRequest.cpp index cfeef1752..a25f2134e 100644 --- a/src/client/http/LogoutRequest.cpp +++ b/src/client/http/LogoutRequest.cpp @@ -4,7 +4,7 @@ namespace http { LogoutRequest::LogoutRequest() : - APIRequest(ByteString::Build(SERVER, "/Logout.json"), authRequireAppendSession, true) + APIRequest({ ByteString::Build(SERVER, "/Logout.json") }, authRequireAppendSession, true) { } diff --git a/src/client/http/PublishSaveRequest.cpp b/src/client/http/PublishSaveRequest.cpp index e48afff13..640774a5a 100644 --- a/src/client/http/PublishSaveRequest.cpp +++ b/src/client/http/PublishSaveRequest.cpp @@ -4,7 +4,9 @@ namespace http { PublishSaveRequest::PublishSaveRequest(int saveID) : - APIRequest(ByteString::Build(SERVER, "/Browse/View.json?ID=", saveID), authRequireAppendSession, true) + APIRequest({ ByteString::Build(SERVER, "/Browse/View.json"), { + { "ID", ByteString::Build(saveID) }, + } }, authRequireAppendSession, true) { AddPostData(FormData{ { "ActionPublish", "bagels" }, diff --git a/src/client/http/RemoveTagRequest.cpp b/src/client/http/RemoveTagRequest.cpp index 249425f31..b205fcfc0 100644 --- a/src/client/http/RemoveTagRequest.cpp +++ b/src/client/http/RemoveTagRequest.cpp @@ -4,7 +4,11 @@ namespace http { RemoveTagRequest::RemoveTagRequest(int saveID, ByteString tag) : - APIRequest(ByteString::Build(SERVER, "/Browse/EditTag.json?Op=delete&ID=", saveID, "&Tag=", tag), authRequireAppendSession, true) + APIRequest({ ByteString::Build(SERVER, "/Browse/EditTag.json"), { + { "Op", "delete" }, + { "ID", ByteString::Build(saveID) }, + { "Tag", tag }, + } }, authRequireAppendSession, true) { } diff --git a/src/client/http/ReportSaveRequest.cpp b/src/client/http/ReportSaveRequest.cpp index b4be74cc5..17467389d 100644 --- a/src/client/http/ReportSaveRequest.cpp +++ b/src/client/http/ReportSaveRequest.cpp @@ -4,7 +4,9 @@ namespace http { ReportSaveRequest::ReportSaveRequest(int saveID, String message) : - APIRequest(ByteString::Build(SERVER, "/Browse/Report.json?ID=", saveID), authRequireAppendSession, true) + APIRequest({ ByteString::Build(SERVER, "/Browse/Report.json"), { + { "ID", ByteString::Build(saveID) }, + } }, authRequireAppendSession, true) { AddPostData(FormData{ { "Reason", message.ToUtf8() }, diff --git a/src/client/http/SaveUserInfoRequest.cpp b/src/client/http/SaveUserInfoRequest.cpp index 3629fb180..934c87cf2 100644 --- a/src/client/http/SaveUserInfoRequest.cpp +++ b/src/client/http/SaveUserInfoRequest.cpp @@ -4,7 +4,7 @@ namespace http { SaveUserInfoRequest::SaveUserInfoRequest(UserInfo info) : - APIRequest(ByteString::Build(SERVER, "/Profile.json"), authRequire, true) + APIRequest({ ByteString::Build(SERVER, "/Profile.json") }, authRequire, true) { AddPostData(FormData{ { "Location", info.location.ToUtf8() }, diff --git a/src/client/http/SearchSavesRequest.cpp b/src/client/http/SearchSavesRequest.cpp index b803606bb..4466f51d8 100644 --- a/src/client/http/SearchSavesRequest.cpp +++ b/src/client/http/SearchSavesRequest.cpp @@ -7,10 +7,11 @@ namespace http { - static ByteString Url(int start, int count, ByteString query, Period period, Sort sort, Category category) + static format::Url Url(int start, int count, ByteString query, Period period, Sort sort, Category category) { - ByteStringBuilder builder; - builder << SERVER << "/Browse.json?Start=" << start << "&Count=" << count; + format::Url url{ ByteString::Build(SERVER, "/Browse.json") }; + url.params["Start"] = ByteString::Build(start); + url.params["Count"] = ByteString::Build(count); auto appendToQuery = [&query](ByteString str) { if (query.size()) { @@ -63,7 +64,7 @@ namespace http switch (category) { case categoryFavourites: - builder << "&Category=Favourites"; + url.params["Category"] = "Favourites"; break; case categoryMyOwn: @@ -76,9 +77,9 @@ namespace http } if (query.size()) { - builder << "&Search_Query=" << format::URLEncode(query); + url.params["Search_Query"] = query; } - return builder.Build(); + return url; } SearchSavesRequest::SearchSavesRequest(int start, int count, ByteString query, Period period, Sort sort, Category category) : APIRequest(Url(start, count, query, period, sort, category), authUse, false) diff --git a/src/client/http/SearchTagsRequest.cpp b/src/client/http/SearchTagsRequest.cpp index 24d1b28ff..74e371af1 100644 --- a/src/client/http/SearchTagsRequest.cpp +++ b/src/client/http/SearchTagsRequest.cpp @@ -4,15 +4,16 @@ namespace http { - static ByteString Url(int start, int count, ByteString query) + static format::Url Url(int start, int count, ByteString query) { - ByteStringBuilder builder; - builder << SERVER << "/Browse/Tags.json?Start=" << start << "&Count=" << count; + format::Url url{ ByteString::Build(SERVER, "/Browse/Tags.json") }; + url.params["Start"] = ByteString::Build(start); + url.params["Count"] = ByteString::Build(count); if (query.size()) { - builder << "&Search_Query=" << format::URLEncode(query); + url.params["Search_Query"] = query; } - return builder.Build(); + return url; } SearchTagsRequest::SearchTagsRequest(int start, int count, ByteString query) : APIRequest(Url(start, count, query), authOmit, false) diff --git a/src/client/http/UnpublishSaveRequest.cpp b/src/client/http/UnpublishSaveRequest.cpp index 5a6a91cf8..725cfa5dc 100644 --- a/src/client/http/UnpublishSaveRequest.cpp +++ b/src/client/http/UnpublishSaveRequest.cpp @@ -4,7 +4,10 @@ namespace http { UnpublishSaveRequest::UnpublishSaveRequest(int saveID) : - APIRequest(ByteString::Build(SERVER, "/Browse/Delete.json?ID=", saveID, "&Mode=Unpublish"), authRequireAppendSession, true) + APIRequest({ ByteString::Build(SERVER, "/Browse/Delete.json"), { + { "ID", ByteString::Build(saveID) }, + { "Mode", "Unpublish" }, + } }, authRequireAppendSession, true) { } diff --git a/src/gui/search/SearchModel.cpp b/src/gui/search/SearchModel.cpp index 42fcf0392..09a212b1e 100644 --- a/src/gui/search/SearchModel.cpp +++ b/src/gui/search/SearchModel.cpp @@ -59,14 +59,6 @@ std::vector> SearchModel::EndSearchSaves() void SearchModel::BeginGetTags(int start, int count, String query) { lastError = ""; - ByteStringBuilder urlStream; - urlStream << SERVER << "/Browse/Tags.json?Start=" << start << "&Count=" << count; - if(query.length()) - { - urlStream << "&Search_Query="; - if(query.length()) - urlStream << format::URLEncode(query.ToUtf8()); - } getTags = std::make_unique(start, count, query.ToUtf8()); getTags->Start(); } diff --git a/src/lua/LuaHttp.cpp b/src/lua/LuaHttp.cpp index 6817c2cb9..dfd45c225 100644 --- a/src/lua/LuaHttp.cpp +++ b/src/lua/LuaHttp.cpp @@ -407,7 +407,10 @@ static int request(lua_State *L, bool isPost) static int getAuthToken(lua_State *L) { - return LuaHttp::RequestHandle::Make(L, ByteString::Build(SERVER, "/ExternalAuth.api?Action=Get&Audience=", format::URLEncode(tpt_lua_checkByteString(L, 1))), false, {}, LuaHttp::RequestHandle::getAuthToken, {}, {}); + return LuaHttp::RequestHandle::Make(L, format::Url{ ByteString::Build(SERVER, "/ExternalAuth.api"), { + { "Action", "Get" }, + { "Audience", tpt_lua_checkByteString(L, 1) }, + } }.ToByteString(), false, {}, LuaHttp::RequestHandle::getAuthToken, {}, {}); } static int get(lua_State *L) diff --git a/src/lua/LuaMisc.cpp b/src/lua/LuaMisc.cpp index 19fa5eacd..99f48703b 100644 --- a/src/lua/LuaMisc.cpp +++ b/src/lua/LuaMisc.cpp @@ -2,6 +2,7 @@ #include "client/http/Request.h" #include "common/platform/Platform.h" #include "compat_lua.h" +#include "Format.h" #include "Config.h" #include "gui/dialogues/ErrorMessage.h" #include "gui/dialogues/InformationMessage.h" @@ -39,7 +40,7 @@ static int installScriptManager(lua_State *L) new ErrorMessage("Script download", "You must run this function from the console"); return 0; } - lsi->scriptManagerDownload = std::make_unique(ByteString::Build("https://starcatcher.us/scripts/main.lua?get=1")); + lsi->scriptManagerDownload = std::make_unique(format::Url{ "https://starcatcher.us/scripts/main.lua", {{ "get", "1" }} }.ToByteString()); lsi->scriptManagerDownload->Start(); return 0; }