From 8e47804d2db431fbb9b601acfa71d50281bbc2d8 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 5 Jun 2023 20:14:08 +0100 Subject: [PATCH] browser/client: more resource handling methods --- src/browser/client.cxx | 144 ++++++++++++++++++++++++++++++++++++----- src/browser/client.hxx | 13 +++- 2 files changed, 141 insertions(+), 16 deletions(-) diff --git a/src/browser/client.cxx b/src/browser/client.cxx index e7ef7dc..d39eea5 100644 --- a/src/browser/client.cxx +++ b/src/browser/client.cxx @@ -2,13 +2,18 @@ #include #include +#include +#include const char* app_overlay_html = "
"; /// https://github.com/chromiumembedded/cef/blob/5563/include/cef_resource_request_handler.h /// https://github.com/chromiumembedded/cef/blob/5563/include/cef_resource_handler.h struct ResourceHandler: public CefResourceRequestHandler, CefResourceHandler { - ResourceHandler(const char* data): data(data), data_len(strlen(data)), cursor(0) { } + ResourceHandler(const unsigned char* data, size_t len, int status, CefString mime): + data(data), data_len(len), status(status), mime(mime), has_location(false), cursor(0) { } + ResourceHandler(const unsigned char* data, size_t len, int status, CefString mime, CefString location): + data(data), data_len(len), status(status), mime(mime), location(location), has_location(true), cursor(0) { } bool Open(CefRefPtr, bool& handle_request, CefRefPtr) override { handle_request = true; @@ -16,8 +21,11 @@ struct ResourceHandler: public CefResourceRequestHandler, CefResourceHandler { } void GetResponseHeaders(CefRefPtr response, int64& response_length, CefString& redirectUrl) override { - response->SetStatus(200); - response->SetMimeType("text/html"); + response->SetStatus(this->status); + response->SetMimeType(this->mime); + if (this->has_location) { + response->SetHeaderByName("Location", this->location, false); + } response_length = this->data_len; } @@ -63,15 +71,46 @@ struct ResourceHandler: public CefResourceRequestHandler, CefResourceHandler { } private: - const char* data; + const unsigned char* data; size_t data_len; + int status; + CefString mime; + CefString location; + bool has_location; size_t cursor; IMPLEMENT_REFCOUNTING(ResourceHandler); DISALLOW_COPY_AND_ASSIGN(ResourceHandler); }; +_InternalFile allocate_file(const char* filename, CefString mime_type) { + // little helper function for Client constructor + std::ifstream file(filename, std::ios::binary); + file.seekg(0, std::ios::end); + std::streamsize size = file.tellg(); + + if (size < 0) { + return _InternalFile { .success = false }; + } + + file.seekg(0, std::ios::beg); + std::vector buf(size); + if (file.read(reinterpret_cast(buf.data()), size)) { + return _InternalFile { + .success = true, + .data = buf, + .mime_type = mime_type, + }; + } else { + return _InternalFile { .success = false }; + } +} + Browser::Client::Client(CefRefPtr app) { + CefString mime_type_html = "text/html"; + CefString mime_type_js = "application/javascript"; app->SetBrowserProcessHandler(this); + this->internal_pages["index.html"] = allocate_file("cef/files/index.html", mime_type_html); + this->internal_pages["oauth.html"] = allocate_file("cef/files/oauth.html", mime_type_html); } CefRefPtr Browser::Client::GetLifeSpanHandler() { @@ -92,18 +131,17 @@ void Browser::Client::OnContextInitialized() { .min_height = 180, .max_width = 1000, .max_height = 1000, - .preferred_width = 250, - .preferred_height = 250, + .preferred_width = 800, + .preferred_height = 608, .startx = 100, .starty = 100, .resizeable = true, .frame = true, - .controls_overlay = true, + .controls_overlay = false, }; - this->apps.push_back(new Browser::Window(this, details, "https://adamcake.com/")); - this->apps.push_back(new Browser::Window(this, details, "https://adamcake.com/")); - this->apps.push_back(new Browser::Window(this, details, "https://adamcake.com/")); - this->apps.push_back(new Browser::Window(this, details, "https://adamcake.com/")); + Browser::Window* w = new Browser::Window(this, details, "https://jaslaunch-internal/index.html"); + w->ShowDevTools(this); + this->apps.push_back(w); } void Browser::Client::OnScheduleMessagePumpWork(int64 delay_ms) { @@ -184,14 +222,90 @@ CefRefPtr Browser::Client::GetResourceRequestHandler( const CefString& request_initiator, bool& disable_default_handling ) { - std::lock_guard _(this->apps_lock); - + if (request->GetPostData()) { + CefPostData::ElementVector v; + request->GetPostData()->GetElements(v); + if (v.size()) { + auto b = v[0]->GetBytesCount(); + auto bytes = new unsigned char[b + 1]; + v[0]->GetBytes(b, bytes); + bytes[b] = '\0'; + fmt::print("[B] routing {} request for {}: {}\n", request->GetMethod().ToString(), request->GetURL().ToString(), reinterpret_cast(bytes)); + } else { + fmt::print("[B] routing {} request for {} with post data with 0 elements...\n", request->GetMethod().ToString(), request->GetURL().ToString()); + } + } else { + fmt::print("[B] routing {} request for {}\n", request->GetMethod().ToString(), request->GetURL().ToString()); + } + + // app frame - ignore URL and just check if this is an app window's main frame + this->apps_lock.lock(); for (size_t i = 0; i < this->apps.size(); i += 1) { - if (this->apps[i]->GetBrowserIdentifier() == browser->GetIdentifier() && frame->IsMain()) { + if (this->apps[i]->HasFrame() && this->apps[i]->GetBrowserIdentifier() == browser->GetIdentifier() && frame->IsMain()) { + this->apps_lock.unlock(); disable_default_handling = true; - return new ResourceHandler(app_overlay_html); + return new ResourceHandler(reinterpret_cast(app_overlay_html), strlen(app_overlay_html), 200, "text/html"); + } + } + this->apps_lock.unlock(); + + const std::string request_url = request->GetURL().ToString(); + + // custom schema thing + const std::regex regex("^.....:code=([^,]+),state=([^,]+),intent=social_auth$"); + std::smatch match; + if (std::regex_match(request_url, match, regex)) { + if (match.size() == 3) { + disable_default_handling = true; + const char* data = "Moved\n"; + CefString location = CefString(this->internal_url + "oauth.html?code=" + match[1].str() + "&state=" + match[2].str()); + return new ResourceHandler(reinterpret_cast(data), strlen(data), 302, "text/plain", location); } } + // internal pages + const char* url_cstr = request_url.c_str(); + size_t url_len = request_url.find_first_of("?#"); + if (url_len == std::string::npos) url_len = request_url.size(); + size_t internal_url_size = this->internal_url.size(); + if (url_len >= internal_url_size) { + if (memcmp(url_cstr, this->internal_url.c_str(), internal_url_size) == 0) { + disable_default_handling = true; + auto it = std::find_if( + this->internal_pages.begin(), + this->internal_pages.end(), + [url_cstr, url_len, internal_url_size](const auto& e) { + if (e.first.size() != url_len - internal_url_size) return false; + return !memcmp(e.first.c_str(), url_cstr + internal_url_size, url_len - internal_url_size); + } + ); + if (it != this->internal_pages.end()) { + if (it->second.success) { + return new ResourceHandler( + it->second.data.data(), + it->second.data.size(), + 200, + it->second.mime_type + ); + } else { + // this file failed to load during startup for some reason - 500 + const char* data = "Internal Server Error\n"; + return new ResourceHandler(reinterpret_cast(data), strlen(data), 500, "text/plain"); + } + } else { + // no matching internal page - 404 + const char* data = "Not Found\n"; + return new ResourceHandler(reinterpret_cast(data), strlen(data), 404, "text/plain"); + } + } + } + + // route the request normally, to a website or whatever + // apply a hack to disable cors complaints... + const char url[] = {104, 116, 116, 112, 115, 58, 47, 47, 115, 101, 99, 117, 114, 101, 46, 106, 97, 103, 101, 120, 46, 99, 111, 109}; + if (!memcmp(request_url.c_str(), url, sizeof url)) { + fmt::print("hey\n"); + request->SetHeaderByName("Origin", url, true); + } return nullptr; } diff --git a/src/browser/client.hxx b/src/browser/client.hxx index cfaf753..2a1f489 100644 --- a/src/browser/client.hxx +++ b/src/browser/client.hxx @@ -6,8 +6,16 @@ #include "../browser.hxx" #include "../native/native.hxx" -#include +#include #include +#include +#include + +struct _InternalFile { + bool success; + std::vector data; + CefString mime_type; +}; namespace Browser { /// Implementation of CefClient, CefBrowserProcessHandler, CefLifeSpanHandler, CefRequestHandler. @@ -66,6 +74,9 @@ namespace Browser { Native::Native native; + std::string internal_url = "https://jaslaunch-internal/"; + std::map internal_pages; + // Mutex-locked vector - may be accessed from either UI thread (most of the time) or IO thread (GetResourceRequestHandler) std::vector> apps; std::mutex apps_lock;