diff --git a/Common/Net/HTTPServer.cpp b/Common/Net/HTTPServer.cpp index 8b46331755..5729bb34b1 100644 --- a/Common/Net/HTTPServer.cpp +++ b/Common/Net/HTTPServer.cpp @@ -335,7 +335,7 @@ void Server::HandleRequest(const ServerRequest &request) { } void Server::HandleRequestDefault(const ServerRequest &request) { - if (request.resource() == nullptr) { + if (request.resource().empty()) { fallback_(request); return; } diff --git a/Common/Net/HTTPServer.h b/Common/Net/HTTPServer.h index be655fca38..4f117069ae 100644 --- a/Common/Net/HTTPServer.h +++ b/Common/Net/HTTPServer.h @@ -30,7 +30,7 @@ public: ServerRequest(int fd); ~ServerRequest(); - const char *resource() const { + std::string_view resource() const { return header_.resource; } @@ -76,7 +76,7 @@ public: virtual ~Server(); typedef std::function UrlHandlerFunc; - typedef std::map UrlHandlerMap; + typedef std::map> UrlHandlerMap; // Runs forever, serving request. If you want to do something else than serve pages, // better put this on a thread. Returns false if failed to start serving, never diff --git a/Common/Thread/ThreadUtil.cpp b/Common/Thread/ThreadUtil.cpp index 3e7a809e8b..e6e9c7314a 100644 --- a/Common/Thread/ThreadUtil.cpp +++ b/Common/Thread/ThreadUtil.cpp @@ -211,6 +211,7 @@ void AssertCurrentThreadName(const char *threadName) { #ifdef TLS_SUPPORTED if (strcmp(curThreadName, threadName) != 0) { ERROR_LOG(Log::System, "Thread name assert failed: Expected %s, was %s", threadName, curThreadName); + _dbg_assert_msg_(false, "Thread name assert failed: Expected %s, was %s", threadName, curThreadName); } #endif } diff --git a/Core/Config.cpp b/Core/Config.cpp index 511e2fb370..7c6b4d4fe6 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -300,6 +300,7 @@ static const ConfigSetting generalSettings[] = { ConfigSetting("RemoteShareOnStartup", &g_Config.bRemoteShareOnStartup, false, CfgFlag::DEFAULT), ConfigSetting("RemoteISOSubdir", &g_Config.sRemoteISOSubdir, "/", CfgFlag::DEFAULT), ConfigSetting("RemoteDebuggerOnStartup", &g_Config.bRemoteDebuggerOnStartup, false, CfgFlag::DEFAULT), + ConfigSetting("RemoteDebuggerLocal", &g_Config.bRemoteDebuggerLocal, false, CfgFlag::DEFAULT), ConfigSetting("RemoteTab", &g_Config.bRemoteTab, false, CfgFlag::DEFAULT), ConfigSetting("RemoteISOSharedDir", &g_Config.sRemoteISOSharedDir, "", CfgFlag::DEFAULT), ConfigSetting("RemoteISOShareType", &g_Config.iRemoteISOShareType, (int)RemoteISOShareType::RECENT, CfgFlag::DEFAULT), diff --git a/Core/Config.h b/Core/Config.h index efd69c9288..d3e42c8bbc 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -125,7 +125,7 @@ public: bool bAutoSaveSymbolMap; bool bCompressSymbols; bool bCacheFullIsoInRam; - int iRemoteISOPort; + int iRemoteISOPort; // Also used for serving a local remote debugger. std::string sLastRemoteISOServer; int iLastRemoteISOPort; bool bRemoteISOManual; @@ -134,6 +134,7 @@ public: std::string sRemoteISOSharedDir; int iRemoteISOShareType; bool bRemoteDebuggerOnStartup; + bool bRemoteDebuggerLocal; bool bRemoteTab; bool bMemStickInserted; int iMemStickSizeGB; diff --git a/Core/WebServer.cpp b/Core/WebServer.cpp index 1b6fe10c65..0c46659e69 100644 --- a/Core/WebServer.cpp +++ b/Core/WebServer.cpp @@ -170,7 +170,7 @@ static std::string RemotePathForRecent(const std::string &filename) { return std::string(); } -static Path LocalFromRemotePath(const std::string &path) { +static Path LocalFromRemotePath(const std::string_view &path) { switch ((RemoteISOShareType)g_Config.iRemoteISOShareType) { case RemoteISOShareType::RECENT: for (const std::string &filename : g_recentFiles.GetRecentFiles()) { @@ -281,7 +281,7 @@ static void HandleListing(const http::ServerRequest &request) { { std::vector entries; - std::string resource = request.resource(); + std::string resource(request.resource()); Path localDir = LocalFromRemotePath(resource); File::GetFilesInDir(localDir, &entries); @@ -308,12 +308,13 @@ static void HandleListing(const http::ServerRequest &request) { static bool ServeDebuggerFile(const http::ServerRequest &request) { // Skip the slash at the start of the resource path. - const char *filename = request.resource() + 1; - if (strstr(filename, "..") != nullptr) + std::string_view filename = request.resource().substr(1); + if (filename.find("..") != std::string_view::npos) return false; size_t size; - uint8_t *data = g_VFS.ReadFile(filename, &size); + // TODO: ReadFile should take a string_view. + uint8_t *data = g_VFS.ReadFile(std::string(filename).c_str(), &size); if (!data) return false; @@ -351,10 +352,24 @@ static void HandleFallback(const http::ServerRequest &request) { AndroidJNIThreadContext jniContext; + if ((serverFlags & (int)WebServerFlags::DEBUGGER) != 0) { + if (request.resource() == "/debugger/") { + RedirectToDebugger(request); + return; + } + + // Actually serve debugger files. + if (startsWith(request.resource(), "/debugger/")) { + if (ServeDebuggerFile(request)) { + return; + } + } + } + if (serverFlags & (int)WebServerFlags::DISCS) { - std::string resource = request.resource(); + std::string_view resource = request.resource(); Path localPath = LocalFromRemotePath(resource); - INFO_LOG(Log::Loader, "Serving %s from %s", resource.c_str(), localPath.c_str()); + INFO_LOG(Log::Loader, "Serving %.*s from %s", (int)resource.size(), resource.data(), localPath.c_str()); if (!localPath.empty()) { if (File::IsDirectory(localPath)) { HandleListing(request); @@ -365,16 +380,6 @@ static void HandleFallback(const http::ServerRequest &request) { } } - if ((serverFlags & (int)WebServerFlags::DEBUGGER) != 0) { - if (!strcmp(request.resource(), "/debugger/")) { - RedirectToDebugger(request); - return; - } - - if (startsWith(request.resource(), "/debugger/") && ServeDebuggerFile(request)) - return; - } - static const std::string payload = "404 not found\r\n"; request.WriteHttpResponseHeader("1.0", 404, payload.size(), "text/plain"); request.Out()->Push(payload); @@ -410,7 +415,7 @@ static void ExecuteWebServer() { auto http = new http::Server(new NewThreadExecutor()); http->RegisterHandler("/", &HandleListing); - // This lists all the (current) recent ISOs. + // This lists all the (current) recent ISOs. It also handles the debugger, which is very ugly. http->SetFallbackHandler(&HandleFallback); http->RegisterHandler("/debugger", &ForwardDebuggerRequest); @@ -501,3 +506,7 @@ void ShutdownWebServer() { serverThread.join(); serverStatus = ServerStatus::STOPPED; } + +bool WebServerRunning(WebServerFlags flags) { + return RetrieveStatus() == ServerStatus::RUNNING && (serverFlags & (int)flags) != 0; +} diff --git a/Core/WebServer.h b/Core/WebServer.h index 0e9f6abe34..cd0d2cc3ec 100644 --- a/Core/WebServer.h +++ b/Core/WebServer.h @@ -32,6 +32,7 @@ bool StartWebServer(WebServerFlags flags); bool StopWebServer(WebServerFlags flags); bool WebServerStopping(WebServerFlags flags); bool WebServerStopped(WebServerFlags flags); +bool WebServerRunning(WebServerFlags flags); void ShutdownWebServer(); bool RemoteISOFileSupported(const std::string &filename); diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index a9df67251c..f1af96eba6 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -53,6 +53,7 @@ #include "Common/StringUtils.h" #include "Common/GPU/ShaderWriter.h" +#include "Core/WebServer.h" #include "Core/MemMap.h" #include "Core/Config.h" #include "Core/ConfigValues.h" @@ -156,10 +157,19 @@ void DevMenuScreen::CreatePopupContents(UI::ViewGroup *parent) { return UI::EVENT_DONE; }); - items->Add(new Choice(dev->T("Remote debugger")))->OnClick.Add([](UI::EventParams &e) { - System_LaunchUrl(LaunchUrlType::BROWSER_URL, "http://ppsspp-debugger.unknownbrackets.org/cpu"); // NOTE: https doesn't work - return UI::EVENT_DONE; - }); + if (WebServerRunning(WebServerFlags::DEBUGGER)) { + items->Add(new Choice(dev->T("Remote debugger")))->OnClick.Add([](UI::EventParams &e) { + int port = g_Config.iRemoteISOPort; // Also used for serving a local remote debugger. + if (g_Config.bRemoteDebuggerLocal) { + char uri[64]; + snprintf(uri, sizeof(uri), "http://localhost:%d/debugger/", port); + System_LaunchUrl(LaunchUrlType::BROWSER_URL, uri); + } else { + System_LaunchUrl(LaunchUrlType::BROWSER_URL, "http://ppsspp-debugger.unknownbrackets.org/cpu"); // NOTE: https doesn't work + } + return UI::EVENT_DONE; + }); + } items->Add(new Choice(sy->T("Developer Tools")))->OnClick.Handle(this, &DevMenuScreen::OnDeveloperTools); diff --git a/UI/DeveloperToolsScreen.cpp b/UI/DeveloperToolsScreen.cpp index 457b9708e5..ee4e363aa6 100644 --- a/UI/DeveloperToolsScreen.cpp +++ b/UI/DeveloperToolsScreen.cpp @@ -170,6 +170,9 @@ void DeveloperToolsScreen::CreateGeneralTab(UI::LinearLayout *list) { list->Add(allowDebugger)->OnClick.Handle(this, &DeveloperToolsScreen::OnRemoteDebugger); allowDebugger->SetEnabledPtr(&canAllowDebugger_); + CheckBox *localDebugger = list->Add(new CheckBox(&g_Config.bRemoteDebuggerLocal, dev->T("Use locally hosted debugger"))); + localDebugger->SetEnabledPtr(&allowDebugger_); + list->Add(new Choice(dev->T("GPI/GPO switches/LEDs")))->OnClick.Add([=](UI::EventParams &e) { screenManager()->push(new GPIGPOScreen(dev->T("GPI/GPO switches/LEDs"))); return UI::EVENT_DONE;