Merge JSON-156 into default. Release_2.2.0-RC1
authorJorg Knobloch
Tue, 13 Oct 2020 21:15:54 +0200
changeset 107591121b279901
parent 1071 7b4bb2fd9e73
parent 1074 edb2c787f799
child 1076 808f087bb28a
Merge JSON-156 into default.
     1.1 --- a/server/context.cc	Fri Oct 09 10:56:35 2020 +0200
     1.2 +++ b/server/context.cc	Tue Oct 13 21:15:54 2020 +0200
     1.3 @@ -22,7 +22,7 @@
     1.4  // Cache a certain function call. See JSON-155.
     1.5  void Context::cache(const std::string& func_name, const std::function<void(PEP_SESSION)>& fn)
     1.6  {
     1.7 -	ja->cache(func_name, fn);
     1.8 +	ja->cache(client_id(), func_name, fn);
     1.9  }
    1.10  
    1.11  
     2.1 --- a/server/context.hh	Fri Oct 09 10:56:35 2020 +0200
     2.2 +++ b/server/context.hh	Tue Oct 13 21:15:54 2020 +0200
     2.3 @@ -12,11 +12,15 @@
     2.4  class Context
     2.5  {
     2.6  public:
     2.7 -	Context(JsonAdapterBase* _ja) : ja{_ja} {}
     2.8 +	Context(JsonAdapterBase* _ja, const std::string& _cid)
     2.9 +	: ja{_ja}, cid{_cid}
    2.10 +	{}
    2.11  	
    2.12  	Context(const Context&) = delete;
    2.13  	void operator=(const Context&) = delete;
    2.14  	
    2.15 +	const std::string& client_id() const { return cid; }
    2.16 +	
    2.17  	// delegate call to the 'ja' member
    2.18  	bool verify_security_token(const std::string& token) const ;
    2.19  	
    2.20 @@ -29,11 +33,11 @@
    2.21  	// KISS: at the moment only "size_t" objects are supported.
    2.22  	void store(int position, size_t value);
    2.23  	size_t retrieve(int position);
    2.24 -	void clear();
    2.25  
    2.26  private:
    2.27  	std::map<int, size_t> obj_store;
    2.28  	JsonAdapterBase* ja;
    2.29 +	const std::string& cid;
    2.30  };
    2.31  
    2.32  #endif // JSON_ADAPTER_CONTEXT_HH
     3.1 --- a/server/json-adapter.cc	Fri Oct 09 10:56:35 2020 +0200
     3.2 +++ b/server/json-adapter.cc	Tue Oct 13 21:15:54 2020 +0200
     3.3 @@ -100,6 +100,8 @@
     3.4  	bool        ignore_session_error = false;
     3.5  	bool        deliver_html = true;
     3.6  	
     3.7 +	int  client_session_timeout = 7*60; // in seconds
     3.8 +	
     3.9  	explicit Internal()
    3.10  	: Log("JAI")
    3.11  	{}
    3.12 @@ -152,15 +154,15 @@
    3.13  };
    3.14  
    3.15  
    3.16 -PEP_SESSION JsonAdapter::getSessionForThread()
    3.17 +PEP_SESSION JsonAdapter::getSessionForThread(const std::string& client_id)
    3.18  {
    3.19 -	const auto id = std::this_thread::get_id();
    3.20 -	return JsonAdapter::getInstance().i->session_registry->get(id);
    3.21 +	const auto thread_id = std::this_thread::get_id();
    3.22 +	return JsonAdapter::getInstance().i->session_registry->get(thread_id, client_id);
    3.23  }
    3.24  
    3.25  
    3.26 -In_Pep_Session::In_Pep_Session(const js::Value& v, Context*, unsigned)
    3.27 -: Base( JsonAdapter::getSessionForThread() )
    3.28 +In_Pep_Session::In_Pep_Session(const js::Value& v, Context* ctx, unsigned)
    3.29 +: Base( JsonAdapter::getSessionForThread(ctx->client_id()) )
    3.30  {}
    3.31  
    3.32  
    3.33 @@ -244,11 +246,19 @@
    3.34  }
    3.35  
    3.36  
    3.37 +JsonAdapter& JsonAdapter::set_client_session_timeout(int timeout_seconds)
    3.38 +{
    3.39 +	check_guard();
    3.40 +	i->client_session_timeout = timeout_seconds;
    3.41 +	return *this;
    3.42 +}
    3.43 +
    3.44 +
    3.45  void JsonAdapter::prepare_run(const std::string& address, unsigned start_port, unsigned end_port, ::messageToSend_t messageToSend)
    3.46  {
    3.47  	check_guard();
    3.48  	// delayed after constructor, so virtual functions are working:
    3.49 -	i->session_registry.reset(new SessionRegistry(messageToSend ? messageToSend : this->getMessageToSend(), this->getInjectSyncEvent()));
    3.50 +	i->session_registry.reset(new SessionRegistry(messageToSend ? messageToSend : this->getMessageToSend(), this->getInjectSyncEvent(), i->client_session_timeout));
    3.51  	
    3.52  	for(unsigned short port = start_port; port<=end_port; ++port)
    3.53  	{
    3.54 @@ -355,9 +365,9 @@
    3.55  }
    3.56  
    3.57  
    3.58 -void JsonAdapter::cache(const std::string& fn_name, const std::function<void(PEP_SESSION)>& func)
    3.59 +void JsonAdapter::cache(const std::string& client_id, const std::string& fn_name, const std::function<void(PEP_SESSION)>& func)
    3.60  {
    3.61 -	i->session_registry->add_to_cache(fn_name, func);
    3.62 +	i->session_registry->add_to_cache(client_id, fn_name, func);
    3.63  }
    3.64  
    3.65  
     4.1 --- a/server/json-adapter.hh	Fri Oct 09 10:56:35 2020 +0200
     4.2 +++ b/server/json-adapter.hh	Tue Oct 13 21:15:54 2020 +0200
     4.3 @@ -21,7 +21,7 @@
     4.4  	virtual bool verify_security_token(const std::string& s) const = 0;
     4.5  	
     4.6  	// Cache a certain function call. See JSON-155.
     4.7 -	virtual void cache(const std::string& fn_name, const std::function<void(PEP_SESSION)>& func) = 0;
     4.8 +	virtual void cache(const std::string& client_id, const std::string& fn_name, const std::function<void(PEP_SESSION)>& func) = 0;
     4.9  };
    4.10  
    4.11  
    4.12 @@ -51,6 +51,9 @@
    4.13  	// if called with "false" the JSON Adpapter would no longer deliver HTML and JavaScript files, only handle JSON-RPC requests
    4.14  	JsonAdapter& deliver_html(bool _deliver_html);
    4.15  	
    4.16 +	// sets the timeout to drop client's config cache
    4.17 +	JsonAdapter& set_client_session_timeout(int timeout_seconds);
    4.18 +	
    4.19  	// look for a free port to listen on and set the given configuration
    4.20  	void prepare_run(const std::string& address, unsigned start_port, unsigned end_port, ::messageToSend_t messageToSend);
    4.21  
    4.22 @@ -87,14 +90,14 @@
    4.23  	// returns 'true' if 's' is the security token created by the function above.
    4.24  	virtual bool verify_security_token(const std::string& s) const override;
    4.25  	
    4.26 -	virtual void cache(const std::string& fn_name, const std::function<void(PEP_SESSION)>& func) override;
    4.27 +	virtual void cache(const std::string& client_id, const std::string& fn_name, const std::function<void(PEP_SESSION)>& func) override;
    4.28  	
    4.29  	// returns the version of the JsonAdapter
    4.30  	static
    4.31  	ServerVersion version();
    4.32  	
    4.33  	// returns the PEP_SESSION registered for the current thread
    4.34 -	static PEP_SESSION getSessionForThread();
    4.35 +	static PEP_SESSION getSessionForThread(const std::string& client_id);
    4.36  	
    4.37  	static PEP_STATUS messageToSend(message* msg);
    4.38  	static PEP_STATUS notifyHandshake(pEp_identity* self, pEp_identity* partner, sync_handshake_signal signal);
     5.1 --- a/server/json_rpc.cc	Fri Oct 09 10:56:35 2020 +0200
     5.2 +++ b/server/json_rpc.cc	Tue Oct 13 21:15:54 2020 +0200
     5.3 @@ -131,7 +131,7 @@
     5.4  		DEBUG_OUT(L, "method_name=\"" + method_name + "\"\n"
     5.5  					"params=" + js::write(params) );
     5.6  		
     5.7 -		Context context{ja};
     5.8 +		Context context{ja, client_id_s};
     5.9  		const js::Value result = fn->second->call(p, &context);
    5.10  		DEBUG_OUT(L, "result=" + js::write(result, js::raw_utf8) );
    5.11  		
     6.1 --- a/server/mini-adapter-main.cc	Fri Oct 09 10:56:35 2020 +0200
     6.2 +++ b/server/mini-adapter-main.cc	Tue Oct 13 21:15:54 2020 +0200
     6.3 @@ -27,6 +27,7 @@
     6.4  bool ignore_missing_session = false;
     6.5  bool add_sharks = false;
     6.6  bool no_html    = false;
     6.7 +int  client_session_timeout = 7*60; // in secondds
     6.8  
     6.9  uintptr_t status_handle = 0;
    6.10  
    6.11 @@ -76,6 +77,7 @@
    6.12  		("ignore-missing-session", po::bool_switch(&ignore_missing_session), "Ignore when no PEP_SESSION can be created.")
    6.13  		("add-sharks", po::bool_switch(&add_sharks), "Add sharks to the JSON Adapter.")
    6.14  		("no-html"   , po::bool_switch(&no_html   ), "Don't deliver HTML and JavaScript files, only accept JSON-RPC calls.")
    6.15 +		("client-timeout", po::value<int>(&client_session_timeout)->default_value(client_session_timeout), "Drop cached client session config after this timeout (in seconds).")
    6.16  #ifdef _WIN32
    6.17  		((STATUS_HANDLE), po::value<uintptr_t>(&status_handle)->default_value(0), "Status file handle, for internal use.")
    6.18  #endif
    6.19 @@ -144,6 +146,7 @@
    6.20  	JsonAdapter& ja = pEp::mini::Adapter::createInstance();
    6.21  	ja.ignore_session_errors( ignore_missing_session)
    6.22  	  .deliver_html( !no_html )
    6.23 +	  .set_client_session_timeout(client_session_timeout)
    6.24  	  ;
    6.25  	/*
    6.26  	 * FIXME: why are exceptions risen after the instantiation of JsonAdapter
     7.1 --- a/server/server_version.cc	Fri Oct 09 10:56:35 2020 +0200
     7.2 +++ b/server/server_version.cc	Tue Oct 13 21:15:54 2020 +0200
     7.3 @@ -76,7 +76,8 @@
     7.4  //	"(42) Gotha"; // JSON-152: 2-parameter version of pollForEvents().
     7.5  //	"(43) Wandersleben"; // JSON-153 passphrase support. *sigh*
     7.6  //	"(44) Neudietendorf"; // replace my own sync thread code by libpEpAdapter's implementation.
     7.7 -	"(45) Kreuz Erfurt"; // fix of context-saved function parameters that would cause trouble when >1 request is processed in parallel.
     7.8 +//	"(45) Kreuz Erfurt"; // fix of context-saved function parameters that would cause trouble when >1 request is processed in parallel.
     7.9 +	"(46) Erfurt-West";  // JSON-156: delete client cached values after timeout.
    7.10  
    7.11  } // end of anonymous namespace
    7.12  ////////////////////////////////////////////////////////////////////////////
     8.1 --- a/server/session_registry.cc	Fri Oct 09 10:56:35 2020 +0200
     8.2 +++ b/server/session_registry.cc	Tue Oct 13 21:15:54 2020 +0200
     8.3 @@ -6,10 +6,12 @@
     8.4  
     8.5  
     8.6  // creates a PEP_SESSION if none yet exists for the given thread
     8.7 -PEP_SESSION SessionRegistry::get(std::thread::id tid)
     8.8 +PEP_SESSION SessionRegistry::get(std::thread::id tid, const std::string& client_id)
     8.9  {
    8.10  	Lock L(_mtx);
    8.11  	
    8.12 +	update_last_use(client_id);
    8.13 +	
    8.14  	auto q = m.find(tid);
    8.15  	if(q != m.end())
    8.16  	{
    8.17 @@ -24,8 +26,10 @@
    8.18  		throw std::runtime_error("init() fails: " + pEp::status_to_string(status) );
    8.19  	}
    8.20  	m[tid] = session;
    8.21 -	Log.debug("Apply %zu cached config values to new session.", cache.size());
    8.22 -	for(const auto& e : cache)
    8.23 +	
    8.24 +	const auto& cache_for_client = cache[client_id];
    8.25 +	Log.debug("Apply %zu cached config values for client_id \"%s\" to new session.", cache_for_client.size(), client_id.c_str());
    8.26 +	for(const auto& e : cache_for_client)
    8.27  	{
    8.28  		Log.debug("\t %s", e.first.c_str());
    8.29  		e.second(session);
    8.30 @@ -62,11 +66,12 @@
    8.31  }
    8.32  
    8.33  
    8.34 -void SessionRegistry::add_to_cache(const std::string& fn_name, const std::function<void(PEP_SESSION)>& func)
    8.35 +void SessionRegistry::add_to_cache(const std::string& client_id, const std::string& fn_name, const std::function<void(PEP_SESSION)>& func)
    8.36  {
    8.37  	Lock L(_mtx);
    8.38 -	Log.debug("add_to_cache(\"%s\")", fn_name.c_str());
    8.39 -	cache[fn_name] = func;
    8.40 +	Log.debug("add_to_cache(\"%s\", \"%s\")", client_id.c_str(), fn_name.c_str());
    8.41 +	cache[client_id][fn_name] = func;
    8.42 +	update_last_use(client_id);
    8.43  }
    8.44  
    8.45  
    8.46 @@ -81,3 +86,23 @@
    8.47  	}
    8.48  	return ss.str();
    8.49  }
    8.50 +
    8.51 +
    8.52 +void SessionRegistry::update_last_use(const std::string& client_id)
    8.53 +{
    8.54 +	const auto now = std::chrono::system_clock::now();
    8.55 +	const auto too_old = now - std::chrono::seconds(client_timeout);
    8.56 +	last_use[client_id] = now;
    8.57 +	
    8.58 +	// TODO: replace by C++20 std::erase_if()
    8.59 +	for(auto q = last_use.begin(); q != last_use.end(); /* no increment here */ )
    8.60 +	{
    8.61 +		if(q->second < too_old)
    8.62 +		{
    8.63 +			cache.erase( q->first );
    8.64 +			q = last_use.erase(q);
    8.65 +		}else{
    8.66 +			++q;
    8.67 +		}
    8.68 +	}
    8.69 +}
     9.1 --- a/server/session_registry.hh	Fri Oct 09 10:56:35 2020 +0200
     9.2 +++ b/server/session_registry.hh	Tue Oct 13 21:15:54 2020 +0200
     9.3 @@ -1,6 +1,7 @@
     9.4  #ifndef JSON_ADAPTER_SESSION_REGISTRY_HH
     9.5  #define JSON_ADAPTER_SESSION_REGISTRY_HH
     9.6  
     9.7 +#include <chrono>
     9.8  #include <map>
     9.9  #include <mutex>
    9.10  #include <thread>
    9.11 @@ -11,14 +12,15 @@
    9.12  class SessionRegistry
    9.13  {
    9.14  public:
    9.15 -	SessionRegistry(messageToSend_t _mts, inject_sync_event_t _ise)
    9.16 +	SessionRegistry(messageToSend_t _mts, inject_sync_event_t _ise, int _client_timeout)
    9.17  	: mts{_mts}
    9.18  	, ise{_ise}
    9.19  	, Log{"SR"}
    9.20 +	, client_timeout{_client_timeout} // in seconds
    9.21  	{}
    9.22  	
    9.23  	// calls "init" for the given thread if no PEP_SESSION exists, yet for the given thread
    9.24 -	PEP_SESSION get(std::thread::id tid = std::this_thread::get_id());
    9.25 +	PEP_SESSION get(std::thread::id tid, const std::string& client_id);
    9.26  	void     remove(std::thread::id tid = std::this_thread::get_id());
    9.27  	
    9.28  	std::size_t  size() const { return m.size();  }
    9.29 @@ -28,7 +30,7 @@
    9.30  	// on each stored session.
    9.31  	void for_each(void(*function)(PEP_SESSION));
    9.32  	
    9.33 -	void add_to_cache(const std::string& fn_name, const std::function<void(PEP_SESSION)>& func);
    9.34 +	void add_to_cache(const std::string& client_id, const std::string& fn_name, const std::function<void(PEP_SESSION)>& func);
    9.35  	
    9.36  	std::string to_string() const;
    9.37  	
    9.38 @@ -36,12 +38,23 @@
    9.39  	std::map<std::thread::id, PEP_SESSION> m;
    9.40  	messageToSend_t      mts;
    9.41  	inject_sync_event_t  ise;
    9.42 -	Logger Log;
    9.43 -	std::map<std::string, std::function<void(PEP_SESSION)>> cache;
    9.44 +	Logger               Log;
    9.45 +	int       client_timeout; // in seconds
    9.46 +	
    9.47 +	// function name -> functor
    9.48 +	typedef
    9.49 +	std::map<std::string, std::function<void(PEP_SESSION)>> cache_per_client_t;
    9.50 +	
    9.51 +	// key=client_id
    9.52 +	std::map<std::string, cache_per_client_t> cache;
    9.53 +	
    9.54 +	std::map<std::string, std::chrono::time_point<std::chrono::system_clock> > last_use;
    9.55  	
    9.56  	typedef std::recursive_mutex     Mutex;
    9.57  	typedef std::unique_lock<Mutex>  Lock;
    9.58  	mutable Mutex  _mtx;
    9.59 +	
    9.60 +	void update_last_use(const std::string& client_id);
    9.61  };
    9.62  
    9.63  #endif // JSON_ADAPTER_SESSION_REGISTRY_HH
    10.1 --- a/server/unittest_rpc.cc	Fri Oct 09 10:56:35 2020 +0200
    10.2 +++ b/server/unittest_rpc.cc	Tue Oct 13 21:15:54 2020 +0200
    10.3 @@ -30,7 +30,7 @@
    10.4  public:
    10.5  	virtual bool verify_security_token(const std::string& token) const override { return true; }
    10.6  	
    10.7 -	virtual void cache(const std::string& func_name, const std::function<void(PEP_SESSION)>& fn) override
    10.8 +	virtual void cache(const std::string& client_id, const std::string& func_name, const std::function<void(PEP_SESSION)>& fn) override
    10.9  	{
   10.10  		// do nothing
   10.11  	}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/server/unittest_string.cc	Tue Oct 13 21:15:54 2020 +0200
    11.3 @@ -0,0 +1,41 @@
    11.4 +#include <gtest/gtest.h>
    11.5 +
    11.6 +#include <pEp/constant_time_algo.hh>
    11.7 +
    11.8 +namespace {
    11.9 +
   11.10 +const char nullo[4] = {0,0,0,0};
   11.11 +const char null_x[4] = { '\0', 'X', '\0', '\n' };
   11.12 +
   11.13 +const std::vector<std::string> testValuesInput =
   11.14 +	{
   11.15 +		{ ""                   },  // always start with the simple case ;-)
   11.16 +		{ "123"                },  // some ASCII digits. Still easy.
   11.17 +		{ "\n\\\b"             },  // backslash escapes for ASCII and control chars
   11.18 +		{ "äöü\x80\x7f"        },  // also with some non-ASCII chars
   11.19 +		
   11.20 +		{ std::string(nullo, nullo+1)   },  // Yeah, 1 NUL byte
   11.21 +		{ std::string(nullo, nullo+2)   },  // Yeah, 2 NUL bytes
   11.22 +		{ std::string(null_x, null_x+4) },  // guess what...
   11.23 +		
   11.24 +		{ "EOF" }
   11.25 +	};
   11.26 +
   11.27 +}
   11.28 +
   11.29 +
   11.30 +class StringCompareTest : public ::testing::TestWithParam<std::string>
   11.31 +{
   11.32 +	// intentionally left blank for now.
   11.33 +};
   11.34 +
   11.35 +INSTANTIATE_TEST_CASE_P(StringcompareTestInstance, StringCompareTest, testing::ValuesIn(testValuesInput) );
   11.36 +
   11.37 +
   11.38 +TEST_P( StringCompareTest, Equal )
   11.39 +{
   11.40 +	const auto param = GetParam();
   11.41 +	EXPECT_TRUE( pEp::constant_time_equal(param, param) );
   11.42 +	EXPECT_FALSE( pEp::constant_time_equal(param, "€") );
   11.43 +	EXPECT_FALSE( pEp::constant_time_equal("@@@", param) );
   11.44 +}