aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-04-13 02:55:36 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-04-13 02:55:36 +0800
commitc29cdb831b7586bb8421ca48e9e78a3a2183aca7 (patch)
tree6e7dd7e14f53541ee885a20047c7d2290aaa8b7e /src
parent24c36f5250e4c2b4232186ba3d17f949d70f5de2 (diff)
downloadrwebbrowser-c29cdb831b7586bb8421ca48e9e78a3a2183aca7.tar.gz
rwebbrowser-c29cdb831b7586bb8421ca48e9e78a3a2183aca7.tar.xz
feat: implement persistent cookie storage and migrate configuration files to ~/.ricochet directory
Diffstat (limited to 'src')
-rw-r--r--src/core/browser.cc14
-rw-r--r--src/net/http_client.cc47
2 files changed, 59 insertions, 2 deletions
diff --git a/src/core/browser.cc b/src/core/browser.cc
index e9f1fce..03c34bc 100644
--- a/src/core/browser.cc
+++ b/src/core/browser.cc
@@ -23,10 +23,12 @@
#include "ricochet/render/renderer.hh"
#include "ricochet/tui/terminal.hh"
#include <cstddef>
+#include <cstdlib>
#include <exception>
#include <fstream>
#include <iostream>
#include <ranges>
+#include <sys/stat.h>
namespace ricochet::core {
@@ -47,6 +49,14 @@ struct HttpRequest
namespace {
+std::string get_config_path( const std::string& filename )
+{
+ const char* home = std::getenv( "HOME" ); // NOLINT(concurrency-mt-unsafe)
+ const std::string dir = ( home != nullptr ) ? std::string( home ) + "/.ricochet" : ".ricochet";
+ static_cast<void>( mkdir( dir.c_str(), 0755 ) );
+ return dir + "/" + filename;
+}
+
std::string extract_title( const parser::DomNode& root_node )
{
std::vector<const parser::DomNode*> stack;
@@ -93,7 +103,7 @@ void save_bookmark( const std::string& title, // NOLINT(bugprone-easily-swappabl
if ( url == "ricochet://bookmarks" ) {
return;
}
- std::ofstream file( "bookmarks.txt", std::ios::app );
+ std::ofstream file( get_config_path( "bookmarks.txt" ), std::ios::app );
if ( !file.is_open() ) {
return;
}
@@ -112,7 +122,7 @@ void save_bookmark( const std::string& title, // NOLINT(bugprone-easily-swappabl
std::string generate_bookmarks_html()
{
- std::ifstream file( "bookmarks.txt" );
+ std::ifstream file( get_config_path( "bookmarks.txt" ) );
std::string html = "<html><head><title>My Bookmarks</title></head><body><h1>Saved Bookmarks</h1><ul>";
if ( !file.is_open() ) {
html += "<li>No bookmarks found. Press 'b' on any page to add one!</li>";
diff --git a/src/net/http_client.cc b/src/net/http_client.cc
index bbc5d17..5a56ac3 100644
--- a/src/net/http_client.cc
+++ b/src/net/http_client.cc
@@ -23,9 +23,12 @@
#include "ricochet/net/sys/socket.hh"
#include <cstddef>
+#include <cstdlib>
#include <format>
+#include <fstream>
#include <string>
#include <string_view>
+#include <sys/stat.h>
#include <unordered_map>
namespace ricochet::net {
@@ -163,15 +166,55 @@ std::string extract_redirect_url( const std::string& raw_response, bool is_https
return "";
}
+std::string get_config_path( const std::string& filename )
+{
+ const char* home = std::getenv( "HOME" ); // NOLINT(concurrency-mt-unsafe)
+ const std::string dir = ( home != nullptr ) ? std::string( home ) + "/.ricochet" : ".ricochet";
+ static_cast<void>( mkdir( dir.c_str(), 0755 ) );
+ return dir + "/" + filename;
+}
+
+void load_cookies_from_file( std::unordered_map<std::string, std::string>& jar )
+{
+ std::ifstream file( get_config_path( "cookies.txt" ) );
+ if ( !file.is_open() ) {
+ return;
+ }
+ std::string line;
+ while ( std::getline( file, line ) ) {
+ const std::size_t tab_pos = line.find( '\t' );
+ if ( tab_pos != std::string::npos ) {
+ jar[line.substr( 0, tab_pos )] = line.substr( tab_pos + 1 );
+ }
+ }
+}
+
std::unordered_map<std::string, std::string>& get_cookie_jar()
{
static std::unordered_map<std::string, std::string> jar;
+ static bool initialized = false;
+ if ( !initialized ) {
+ load_cookies_from_file( jar );
+ initialized = true;
+ }
return jar;
}
+void save_cookies_to_file( const std::unordered_map<std::string, std::string>& jar )
+{
+ std::ofstream file( get_config_path( "cookies.txt" ), std::ios::trunc );
+ if ( !file.is_open() ) {
+ return;
+ }
+ for ( const auto& [k, v] : jar ) {
+ file << k << '\t' << v << '\n';
+ }
+}
+
void update_cookies( const std::string& raw_response )
{
std::size_t pos = 0;
+ bool updated = false;
while ( ( pos = raw_response.find( "Set-Cookie: ", pos ) ) != std::string::npos ) {
pos += 12;
const std::size_t end_pos = raw_response.find( '\r', pos );
@@ -189,8 +232,12 @@ void update_cookies( const std::string& raw_response )
const std::string key = cookie_pair.substr( 0, eq_pos );
const std::string val = cookie_pair.substr( eq_pos + 1 );
get_cookie_jar()[key] = val;
+ updated = true;
}
}
+ if ( updated ) {
+ save_cookies_to_file( get_cookie_jar() );
+ }
}
std::string build_cookie_header()