server/ev_server.cc
author Volker Birk <vb@pep-project.org>
Tue, 28 Jul 2020 18:37:10 +0200
changeset 1024 627cd00b19a3
parent 1007 f3c33b85c779
child 1025 65bd786c02c9
permissions -rw-r--r--
add message_cache functions
roker@883
     1
#include <pEp/webserver.hh>
roker@0
     2
roker@300
     3
#include "ev_server.hh"
roker@327
     4
#include "c_string.hh"
roker@344
     5
#include "prefix-config.hh"
roker@65
     6
#include "json-adapter.hh"
roker@0
     7
#include "function_map.hh"
roker@698
     8
#include "pEp-types.hh"
roker@0
     9
#include "json_rpc.hh"
roker@698
    10
#include "pEp-utils.hh"
roker@570
    11
#include "logger.hh"
roker@300
    12
#include "server_version.hh"
roker@0
    13
roker@0
    14
#include <pEp/message_api.h>
roker@142
    15
#include <pEp/blacklist.h>
roker@682
    16
#include <pEp/key_reset.h>
roker@142
    17
#include <pEp/openpgp_compat.h>
roker@685
    18
#include <pEp/message_api.h> // for get_binary_path()
dirk@109
    19
#include <pEp/mime.h>
roker@0
    20
roker@685
    21
// libpEpAdapter:
roker@895
    22
#include <pEp/Adapter.hh>
roker@685
    23
#include <pEp/status_to_string.hh>
roker@659
    24
#include <pEp/slurp.hh>
vb@1024
    25
#include <pEp/message_cache.hh>
roker@659
    26
roker@0
    27
#include <boost/filesystem.hpp>
roker@0
    28
#include "json_spirit/json_spirit_reader.h"
roker@0
    29
roker@739
    30
// HACK:
vb@957
    31
#ifndef JSON_ADAPTER_LIBRARY
roker@739
    32
#include "mini-adapter-impl.hh"
vb@957
    33
#else // JSON_ADAPTER_LIBRARY
vb@962
    34
#include <pEp/callback_dispatcher.hh>
vb@954
    35
#endif
roker@739
    36
roker@65
    37
roker@212
    38
namespace fs = boost::filesystem;
roker@212
    39
roker@344
    40
// compile-time default. might be overwritten in main() or before any ev_server function is called.
roker@344
    41
fs::path ev_server::path_to_html = fs::path(html_directory);
roker@89
    42
roker@344
    43
roker@344
    44
namespace {
roker@3
    45
roker@0
    46
roker@372
    47
std::string version_as_a_string()
roker@372
    48
{
roker@372
    49
	std::stringstream ss;
roker@372
    50
	ss << server_version();
roker@372
    51
	return ss.str();
roker@372
    52
}
roker@372
    53
roker@685
    54
std::string getBinaryPath()
roker@561
    55
{
roker@685
    56
	const char* gpg_path = nullptr;
roker@685
    57
	const auto status = get_binary_path( PEP_crypt_OpenPGP, &gpg_path);
roker@685
    58
	if(status == PEP_STATUS_OK && gpg_path)
roker@685
    59
	{
roker@685
    60
		return std::string(gpg_path);
roker@685
    61
	}
roker@685
    62
	
roker@685
    63
	throw std::runtime_error("getBinaryPath returns error: " + ::pEp::status_to_string(status) );
roker@561
    64
}
roker@561
    65
roker@561
    66
roker@0
    67
// these are the pEp functions that are callable by the client
roker@0
    68
const FunctionMap functions = {
claudio@620
    69
roker@681
    70
		// from message_api.h
roker@681
    71
		FP( "Message API", new Separator ),
roker@983
    72
		FP( "encrypt_message", new FuncPC<PEP_STATUS, In_Pep_Session, InOut<message*>, In<stringlist_t*>, Out<message*>, In<PEP_enc_format>, In<PEP_encrypt_flags_t>>( &encrypt_message ) ),
roker@983
    73
		FP( "encrypt_message_and_add_priv_key", new FuncPC<PEP_STATUS, In_Pep_Session,
roker@617
    74
			In<message*>, Out<message*>, In<c_string>, In<PEP_enc_format>, In<PEP_encrypt_flags_t>>( &encrypt_message_and_add_priv_key) ),
roker@983
    75
		FP( "encrypt_message_for_self", new FuncPC<PEP_STATUS, In_Pep_Session,
roker@455
    76
			In<pEp_identity*>, In<message*>, In<stringlist_t*>, Out<message*>, In<PEP_enc_format>, In<PEP_encrypt_flags_t>>( &encrypt_message_for_self ) ),
claudio@564
    77
roker@983
    78
		FP( "decrypt_message", new FuncPC<PEP_STATUS, In_Pep_Session, InOut<message*>, Out<message*>, InOutP<stringlist_t*>, Out<PEP_rating>, InOutP<PEP_decrypt_flags_t>>(  &decrypt_message ) ),
vb@1024
    79
		FP( "cache_decrypt_message", new FuncPC<PEP_STATUS, In_Pep_Session, InOut<message*>, Out<message*>, InOutP<stringlist_t*>, Out<PEP_rating>, InOutP<PEP_decrypt_flags_t>>(  &pEp::MessageCache::cache_decrypt_message) ),
roker@1007
    80
		FP( "get_key_rating_for_user", new FuncPC<PEP_STATUS, In_Pep_Session, In<c_string>, In<c_string>, Out<PEP_rating>>( &get_key_rating_for_user) ),
roker@0
    81
		
roker@793
    82
		// from mime.h
roker@793
    83
		FP( "MIME handling API", new Separator),
roker@836
    84
		FP( "mime_encode_message", new Func<PEP_STATUS, In<const message*>, In<bool>, Out<char*>, In<bool, ParamFlag::NoInput>>( &mime_encode_message )),
vb@1024
    85
		FP( "cache_mime_encode_message", new Func<PEP_STATUS, In<int>, In<const message*>, In<bool>, Out<char*>, In<bool, ParamFlag::NoInput>>( &pEp::MessageCache::cache_mime_encode_message)),
vb@1024
    86
        FP( "cache_release", new Func<PEP_STATUS, In<c_string>>( &pEp::MessageCache::cache_release )),
roker@836
    87
		FP( "mime_decode_message", new Func<PEP_STATUS, In<c_string>, InLength<>, Out<message*>, In<bool*, ParamFlag::NoInput>>( &mime_decode_message )),
roker@793
    88
		
roker@793
    89
		// from pEpEngine.h
roker@236
    90
		FP( "pEp Engine Core API", new Separator),
roker@521
    91
//		FP( "log_event",  new Func<PEP_STATUS, In_Pep_Session, In<c_string>, In<c_string>, In<c_string>, In<c_string>>( &log_event) ),
roker@1007
    92
		FP( "get_trustwords", new FuncPC<PEP_STATUS, In_Pep_Session, In<const pEp_identity*>, In<const pEp_identity*>, In<Language>, Out<char*>, Out<size_t>, In<bool>>( &get_trustwords) ),
roker@1007
    93
		FP( "re_evaluate_message_rating", new FuncPC<PEP_STATUS, In_Pep_Session, In<message *>, In<stringlist_t *>, In<PEP_rating>, Out<PEP_rating>>( &re_evaluate_message_rating ) ),
roker@1007
    94
		FP( "get_languagelist", new FuncPC<PEP_STATUS, In_Pep_Session, Out<char*>>( &get_languagelist) ),
roker@521
    95
//		FP( "get_phrase"      , new Func<PEP_STATUS, In_Pep_Session, In<Language>, In<int>, Out<char*>> ( &get_phrase) ),
roker@350
    96
//		FP( "get_engine_version", new Func<const char*> ( &get_engine_version) ),
roker@1007
    97
		FP( "is_pEp_user"     , new FuncPC<PEP_STATUS, In_Pep_Session, In<pEp_identity*>, Out<bool>>( &is_pEp_user) ),
roker@983
    98
roker@950
    99
		FP( "config_passive_mode", new FuncCache<void, In_Pep_Session, In<bool>>( "conf_p_m", &config_passive_mode) ),
roker@950
   100
		FP( "config_unencrypted_subject", new FuncCache<void, In_Pep_Session, In<bool>>( "conf_u_s", &config_unencrypted_subject) ),
roker@973
   101
// not defined in pEpEngine, yet:
roker@973
   102
//		FP( "config_use_only_own_private_keys", new FuncCache<void, In_Pep_Session, In<bool>>( "conf_uoopk", &config_use_only_own_private_keys) ),
roker@973
   103
		FP( "config_service_log" , new FuncCache<void, In_Pep_Session, In<bool>>( "conf_service_log", &config_service_log) ),
roker@973
   104
		FP( "config_cipher_suite", new FuncCache<void, In_Pep_Session, In<PEP_CIPHER_SUITE>>( "config_cipher_suite", &config_cipher_suite) ),
roker@979
   105
		FP( "config_passphrase",   new FuncCachePassphrase<void, In_Pep_Session, In<c_string>>( "config_passphrase" ) ),
roker@979
   106
		FP( "config_passphrase_for_new_keys",   new FuncCachePassphrase4NewKeys<void, In_Pep_Session, In<bool>, In<c_string>>( "config_passphrase4nk" ) ),
roker@25
   107
		
roker@236
   108
		FP( "Identity Management API", new Separator),
roker@1007
   109
		FP( "get_identity"       , new FuncPC<PEP_STATUS, In_Pep_Session, In<c_string>, In<c_string>, Out<pEp_identity*>>( &get_identity) ),
roker@1007
   110
		FP( "set_identity"       , new FuncPC<PEP_STATUS, In_Pep_Session, In<const pEp_identity*>> ( &set_identity) ),
roker@1007
   111
		FP( "mark_as_comprimized", new FuncPC<PEP_STATUS, In_Pep_Session, In<c_string>> ( &mark_as_compromized) ),
roker@1007
   112
		FP( "identity_rating"    , new FuncPC<PEP_STATUS, In_Pep_Session, In<pEp_identity*>, Out<PEP_rating>>( &identity_rating) ),
roker@1007
   113
		FP( "outgoing_message_rating", new FuncPC<PEP_STATUS, In_Pep_Session, In<message*>, Out<PEP_rating>>( &outgoing_message_rating) ),
roker@1007
   114
		FP( "outgoing_message_rating_preview", new FuncPC<PEP_STATUS, In_Pep_Session, In<message*>, Out<PEP_rating>>( &outgoing_message_rating_preview) ),
roker@1007
   115
		FP( "set_identity_flags"     , new FuncPC<PEP_STATUS, In_Pep_Session, InOut<pEp_identity*>, In<identity_flags_t>>( &set_identity_flags) ),
roker@1007
   116
		FP( "unset_identity_flags"   , new FuncPC<PEP_STATUS, In_Pep_Session, InOut<pEp_identity*>, In<identity_flags_t>>( &unset_identity_flags) ),
roker@22
   117
		
roker@236
   118
		FP( "Low level Key Management API", new Separator),
roker@1007
   119
		FP( "generate_keypair", new FuncPC<PEP_STATUS, In_Pep_Session, InOut<pEp_identity*>> ( &generate_keypair) ),
roker@1007
   120
		FP( "delete_keypair", new FuncPC<PEP_STATUS, In_Pep_Session, In<c_string>> ( &delete_keypair) ),
roker@1007
   121
		FP( "import_key"    , new FuncPC<PEP_STATUS, In_Pep_Session, In<binary_string>, InLength<>, Out<identity_list*>> ( &import_key) ),
roker@1007
   122
		FP( "export_key"    , new FuncPC<PEP_STATUS, In_Pep_Session, In<c_string>, Out<char*>, Out<std::size_t>> ( &export_key) ),
roker@1007
   123
		FP( "find_keys"     , new FuncPC<PEP_STATUS, In_Pep_Session, In<c_string>, Out<stringlist_t*>> ( &find_keys) ),
roker@1007
   124
		FP( "get_trust"     , new FuncPC<PEP_STATUS, In_Pep_Session, InOut<pEp_identity*>> ( &get_trust) ),
roker@1007
   125
		FP( "own_key_is_listed", new FuncPC<PEP_STATUS, In_Pep_Session, In<c_string>, Out<bool>> ( &own_key_is_listed) ),
roker@1007
   126
		FP( "own_identities_retrieve", new FuncPC<PEP_STATUS, In_Pep_Session, Out<identity_list*>>( &own_identities_retrieve ) ),
roker@1007
   127
		FP( "set_own_key", new FuncPC<PEP_STATUS, In_Pep_Session, InOut<pEp_identity*>, In<c_string>>( &set_own_key ) ),
roker@1007
   128
		FP( "key_reset_identity", new FuncPC<PEP_STATUS, In_Pep_Session, In<pEp_identity*>, In<c_string>>( &key_reset_identity) ),
roker@983
   129
		FP( "key_reset_user",     new FuncPC<PEP_STATUS, In_Pep_Session, In<c_string>     , In<c_string, ParamFlag::NullOkay>>( &key_reset_user) ),
roker@1007
   130
		FP( "key_reset_all_own_keys",  new FuncPC<PEP_STATUS, In_Pep_Session>( &key_reset_all_own_keys) ),
roker@22
   131
		
roker@1007
   132
		FP( "myself"        , new FuncPC<PEP_STATUS, In_Pep_Session, InOut<pEp_identity*>> ( &myself) ),
roker@1007
   133
		FP( "update_identity", new FuncPC<PEP_STATUS, In_Pep_Session, InOut<pEp_identity*>> ( &update_identity) ),
roker@142
   134
		
roker@1007
   135
		FP( "trust_personal_key", new FuncPC<PEP_STATUS, In_Pep_Session, In<pEp_identity*>>( &trust_personal_key) ),
roker@1007
   136
		FP( "trust_own_key",      new FuncPC<PEP_STATUS, In_Pep_Session, In<pEp_identity*>>( &trust_own_key) ),
roker@1007
   137
		FP( "key_mistrusted",     new FuncPC<PEP_STATUS, In_Pep_Session, In<pEp_identity*>>( &key_mistrusted) ),
roker@1007
   138
		FP( "key_reset_trust",    new FuncPC<PEP_STATUS, In_Pep_Session, In<pEp_identity*>>( &key_reset_trust) ),
roker@119
   139
		
roker@1007
   140
		FP( "least_trust"   , new FuncPC<PEP_STATUS, In_Pep_Session, In<c_string>, Out<PEP_comm_type>> ( &least_trust) ),
roker@1007
   141
		FP( "get_key_rating", new FuncPC<PEP_STATUS, In_Pep_Session, In<c_string>, Out<PEP_comm_type>> ( &get_key_rating) ),
roker@1007
   142
		FP( "renew_key"     , new FuncPC<PEP_STATUS, In_Pep_Session, In<c_string>, In<const timestamp*>> ( &renew_key) ),
roker@1007
   143
		FP( "revoke"        , new FuncPC<PEP_STATUS, In_Pep_Session, In<c_string>, In<c_string>> ( &revoke_key) ),
roker@1007
   144
		FP( "key_expired"   , new FuncPC<PEP_STATUS, In_Pep_Session, In<c_string>, In<time_t>, Out<bool>> ( &key_expired) ),
roker@3
   145
		
roker@236
   146
		FP( "from blacklist.h & OpenPGP_compat.h", new Separator),
roker@1007
   147
		FP( "blacklist_add"   , new FuncPC<PEP_STATUS, In_Pep_Session, In<c_string>> ( &blacklist_add) ),
roker@1007
   148
		FP( "blacklist_delete", new FuncPC<PEP_STATUS, In_Pep_Session, In<c_string>> ( &blacklist_delete) ),
roker@1007
   149
		FP( "blacklist_is_listed", new FuncPC<PEP_STATUS, In_Pep_Session, In<c_string>, Out<bool>> ( &blacklist_is_listed) ),
roker@1007
   150
		FP( "blacklist_retrieve" , new FuncPC<PEP_STATUS, In_Pep_Session, Out<stringlist_t*>> ( &blacklist_retrieve) ),
roker@1007
   151
		FP( "OpenPGP_list_keyinfo", new FuncPC<PEP_STATUS, In_Pep_Session, In<c_string>, Out<stringpair_list_t*>> ( &OpenPGP_list_keyinfo) ),
roker@142
   152
		
roker@236
   153
		FP( "Event Listener & Results", new Separator ),
roker@681
   154
		FP( "deliverHandshakeResult" , new Func<PEP_STATUS, In_Pep_Session, In<sync_handshake_result>, In<const identity_list*> > (&deliverHandshakeResult) ),
roker@917
   155
		// TODO: session_id shall be removed as soon as we find a way to make it automatic again.
roker@917
   156
		// 'std::this_thread::id'' as ID did not work as expected. :-(
roker@917
   157
//		FP( "pollForEvents"          , new Func<js::Array, In<JsonAdapter*,ParamFlag::NoInput>, In<unsigned>> (&JsonAdapter::pollForEvents) ),
roker@917
   158
		FP( "pollForEvents"          , new Func<js::Array, In<JsonAdapter*,ParamFlag::NoInput>, In<std::string>, In<unsigned>> (&JsonAdapter::pollForEvents2) ),
roker@906
   159
		FP( "create_session"         , new Func<std::string>(&JsonAdapter::create_session)),
roker@906
   160
		FP( "close_session"          , new Func<void, In<JsonAdapter*,ParamFlag::NoInput>, In<std::string>> (&JsonAdapter::close_session) ),
roker@81
   161
		
roker@739
   162
		FP( "Sync", new Separator ),
roker@1007
   163
		FP( "leave_device_group"       , new FuncPC<PEP_STATUS, In_Pep_Session> (&leave_device_group) ),
roker@1007
   164
		FP( "enable_identity_for_sync" , new FuncPC<PEP_STATUS, In_Pep_Session, InOut<pEp_identity*>> (&enable_identity_for_sync)),
roker@983
   165
		FP( "disable_identity_for_sync", new FuncPC<PEP_STATUS, In_Pep_Session, InOut<pEp_identity*>> (&disable_identity_for_sync)),
roker@983
   166
vb@959
   167
#ifndef JSON_ADAPTER_LIBRARY
roker@739
   168
		FP( "startSync", new Func<void> (&pEp::mini::startSync) ),
roker@739
   169
		FP( "stopSync" , new Func<void> (&pEp::mini::stopSync) ),
vb@954
   170
#else
vb@962
   171
		FP( "startSync", new Func<void> (&pEp::CallbackDispatcher::start_sync) ),
vb@962
   172
		FP( "stopSync" , new Func<void> (&pEp::CallbackDispatcher::stop_sync) ),
vb@954
   173
#endif
roker@3
   174
		// my own example function that does something useful. :-)
roker@236
   175
		FP( "Other", new Separator ),
roker@797
   176
		FP( "serverVersion", new Func<ServerVersion>( &server_version ) ),
roker@797
   177
		FP( "version",       new Func<std::string>( &version_as_a_string ) ),
roker@685
   178
		FP( "getBinaryPath", new Func<std::string>( &getBinaryPath ) ),
roker@863
   179
		FP( "testMessageToSend", new Func<PEP_STATUS, In<message*>> (&JsonAdapter::messageToSend) ),
roker@313
   180
roker@521
   181
		FP( "shutdown",  new Func<void, In<JsonAdapter*,ParamFlag::NoInput>>( &JsonAdapter::shutdown_now ) ),
roker@0
   182
	};
roker@506
   183
roker@506
   184
	bool add_sharks = false;
roker@506
   185
roker@344
   186
} // end of anonymous namespace
roker@0
   187
roker@344
   188
roker@899
   189
ev_server::ev_server(const std::string& address, unsigned short port, bool deliver_html, const std::string& base_url)
roker@899
   190
: pEp::Webserver(pEp::net::ip::address::from_string(address), port)
roker@892
   191
{
roker@892
   192
	this->add_url_handler(base_url + "callFunction", ev_server::OnApiRequest);
roker@892
   193
	if(deliver_html)
roker@892
   194
	{
roker@892
   195
		this->add_url_handler("/pEp_functions.js", ev_server::OnGetFunctions);
roker@892
   196
		this->add_generic_url_handler(ev_server::OnOtherRequest);
roker@892
   197
	}
roker@892
   198
}
roker@892
   199
roker@892
   200
roker@884
   201
pEp::Webserver::response ev_server::sendReplyString(const pEp::Webserver::request& req, const char* contentType, std::string&& outputText)
roker@0
   202
{
roker@885
   203
	Log() << Logger::Debug << "sendReplyString(): "
roker@884
   204
		<< ", contentType=" << (contentType ? "«" + std::string(contentType)+ "»" : "NULL")
roker@911
   205
		<< ", output.size()=«" << outputText.size() << "»"
roker@919
   206
		<< ", keep_alive=" << req.keep_alive() << ".";
roker@919
   207
	
roker@919
   208
	DEBUG_LOG(Log()) << "outputText=«" << outputText << "»";
roker@0
   209
	
roker@884
   210
	pEp::Webserver::response res{pEp::http::status::ok, req.version()};
roker@884
   211
	res.set(pEp::http::field::content_type, contentType);
roker@884
   212
	res.keep_alive(req.keep_alive());
roker@884
   213
	res.content_length(outputText.size());
roker@884
   214
	res.body() = std::move(outputText);
roker@884
   215
roker@884
   216
	return res;
roker@0
   217
}
roker@0
   218
roker@0
   219
roker@884
   220
pEp::Webserver::response ev_server::sendFile(const pEp::Webserver::request& req, const char* mimeType, const fs::path& fileName)
roker@0
   221
{
roker@168
   222
	// not the best for big files, but this server does not send big files. :-)
roker@884
   223
	std::string fileContent = pEp::slurp(fileName.string());
roker@884
   224
	return sendReplyString(req, mimeType, std::move(fileContent));
roker@0
   225
}
roker@0
   226
roker@0
   227
roker@0
   228
struct FileRequest
roker@0
   229
{
roker@884
   230
	const char* mimeType;
roker@212
   231
	fs::path    fileName;
roker@0
   232
};
roker@0
   233
roker@0
   234
// catch-all callback
roker@883
   235
pEp::Webserver::response ev_server::OnOtherRequest(boost::cmatch match, const pEp::Webserver::request& req)
roker@0
   236
{
roker@0
   237
	static const std::map<std::string, FileRequest > files =
roker@0
   238
		{
roker@212
   239
			{ "/"                , {"text/html"      , path_to_html / "index.html"            } },
roker@212
   240
			{ "/jquery.js"       , {"text/javascript", path_to_html / "jquery-2.2.0.min.js"   } },
roker@212
   241
			{ "/interactive.js"  , {"text/javascript", path_to_html / "interactive.js"        } },
roker@212
   242
			{ "/favicon.ico"     , {"image/vnd.microsoft.icon", path_to_html / "json-test.ico"} },
roker@0
   243
		};
roker@0
   244
	
roker@884
   245
	const std::string path = req.target().to_string(); // NB: is percent-encoded! does not relevant for the supported paths above.
roker@883
   246
	
roker@885
   247
	Log() << Logger::Debug << "** Request: [" << req.method_string().to_string() << "] " << "Path: [" + path + "]";
roker@0
   248
	
roker@393
   249
	try{
roker@883
   250
		const auto q = files.find(path);
roker@883
   251
		if(q != files.end()) // found in "files" map
roker@393
   252
		{
roker@570
   253
			Log() << Logger::Debug << "\t found file \"" << q->second.fileName.string() << "\", type=" << q->second.mimeType << ".\n";
roker@884
   254
			return sendFile( req, q->second.mimeType, q->second.fileName);
roker@393
   255
		}
roker@883
   256
		
roker@884
   257
		return pEp::Webserver::create_status_response(req, pEp::http::status::not_found);
roker@393
   258
	}
roker@393
   259
	catch(const std::runtime_error& e)
roker@0
   260
	{
roker@884
   261
		const std::string error_msg = "Internal error caused by path \"" + path + "\"";
roker@570
   262
		// Log e.what() to log file, but DON'T send it in HTTP error message
roker@570
   263
		// because it might contain sensitive information, e.g. local file paths etc.!
roker@570
   264
		Log() << Logger::Error << "OnOtherRequest: " << error_msg << ".  what:" << e.what();
roker@884
   265
		return pEp::Webserver::create_status_response(req, pEp::http::status::internal_server_error );
roker@0
   266
	}
roker@0
   267
};
roker@0
   268
roker@0
   269
roker@0
   270
// generate a JavaScript file containing the definition of all registered callable functions, see above.
roker@883
   271
pEp::Webserver::response ev_server::OnGetFunctions(boost::cmatch match, const pEp::Webserver::request& req)
roker@0
   272
{
roker@370
   273
	static const auto& version = server_version();
roker@16
   274
	static const std::string preamble =
roker@0
   275
		"var Direction = { In:1, Out:2, InOut:3 };\n"
roker@0
   276
		"var Type = {\n"
roker@0
   277
		"		Blob    : 10, // binary strings or 'array of octet'\n"
roker@0
   278
		"		String  : 20, // human-readable, NUL-terminated utf8-encoded strings\n"
roker@0
   279
		"		StringList: 25,\n"
roker@0
   280
		"		Message : 30,\n"
roker@0
   281
		"		PEP_color : 50,\n"
roker@0
   282
		"		PEP_enc_format: 51,\n"
roker@0
   283
		"		PEP_STATUS: 59,\n"
roker@0
   284
		"		Uint16  : 80,\n"
roker@0
   285
		"		Session : 90 // opaque type. only a special encoded 'handle' is used in JavaScript code\n"
roker@0
   286
		"	};\n"
roker@0
   287
		"\n"
roker@370
   288
		"var server_version_name = \"" + version.name + "\";\n"
roker@370
   289
		"var server_version = \"" + version.major_minor_patch() + "\";\n"
roker@506
   290
		"var add_sharks = " + (add_sharks?"true":"false") + ";\n"
roker@698
   291
		"var pEp_functions = ";
roker@0
   292
	
roker@0
   293
	js::Array jsonfunctions;
roker@0
   294
	for(const auto& f : functions)
roker@0
   295
	{
roker@0
   296
		js::Object o;
roker@0
   297
		o.emplace_back( "name", f.first );
roker@0
   298
		f.second->setJavaScriptSignature( o );
roker@0
   299
		jsonfunctions.push_back( o );
roker@0
   300
	}
roker@0
   301
	
roker@884
   302
	std::string output = preamble + js::write( jsonfunctions, js::pretty_print | js::raw_utf8 | js::single_line_arrays )
roker@0
   303
		+ ";\n"
roker@0
   304
		"\n"
roker@0
   305
		"// End of generated file.\n";
roker@0
   306
		
roker@884
   307
	return sendReplyString(req, "text/javascript", std::move(output));
roker@0
   308
}
roker@0
   309
roker@0
   310
roker@883
   311
pEp::Webserver::response ev_server::OnApiRequest(boost::cmatch match, const pEp::Webserver::request& req)
roker@0
   312
{
roker@570
   313
	Logger L( Log(), "OnApiReq");
roker@0
   314
roker@0
   315
	int request_id = -42;
roker@0
   316
	js::Object answer;
roker@59
   317
	js::Value p;
roker@0
   318
	
roker@0
   319
	try
roker@0
   320
	{
roker@0
   321
	
roker@884
   322
	JsonAdapter& ja = JsonAdapter::getInstance();
roker@877
   323
	
roker@884
   324
	const std::string data_string = req.body();
roker@884
   325
	if(!data_string.empty())
roker@0
   326
	{
roker@919
   327
#ifdef DEBUG_ENABLED
roker@919
   328
		L << Logger::Debug << "Data: «" << data_string  << "» (" << data_string.size() << " bytes).";
roker@919
   329
#else
roker@919
   330
		L << Logger::Debug << "Data.size=" << data_string.size() << ".";
roker@919
   331
#endif
roker@0
   332
		bool b = js::read( data_string, p);
roker@0
   333
		if(p.type() == js::obj_type)
roker@0
   334
		{
roker@0
   335
			const js::Object& request = p.get_obj();
roker@884
   336
			answer = call( functions, request, &ja );
roker@0
   337
		}else{
roker@919
   338
			const std::string error_msg = "request body is not a JSON object. js::read() returned" + std::to_string(b);
roker@570
   339
			L << Logger::Error << error_msg;
roker@570
   340
			answer = make_error( JSON_RPC::PARSE_ERROR, error_msg, js::Value{data_string}, 42 );
roker@0
   341
		}
roker@0
   342
	}else{
roker@884
   343
		answer = make_error( JSON_RPC::INTERNAL_ERROR, "ZERO size request", p, request_id );
roker@0
   344
	}
roker@0
   345
	
roker@0
   346
	}
roker@0
   347
	catch(const std::exception& e)
roker@0
   348
	{
roker@570
   349
		L << Logger::Error << "Exception: \"" << e.what() << "\"";
roker@0
   350
		answer = make_error( JSON_RPC::INTERNAL_ERROR, "Got a std::exception: \"" + std::string(e.what()) + "\"", p, request_id );
roker@0
   351
	}
roker@0
   352
roker@884
   353
	return sendReplyString(req, "text/plain", js::write(answer, js::raw_utf8));
roker@0
   354
};
roker@0
   355
roker@395
   356
roker@570
   357
Logger& ev_server::Log()
roker@395
   358
{
roker@570
   359
	static Logger L("evs");
roker@570
   360
	return L;
roker@395
   361
}
roker@395
   362
roker@395
   363
roker@506
   364
void ev_server::addSharks()
roker@506
   365
{
roker@506
   366
	add_sharks = true;
roker@506
   367
}
roker@895
   368
roker@895
   369
roker@895
   370
void ev_server::thread_init()
roker@895
   371
{
roker@895
   372
	// nothing to do, yet.
roker@895
   373
}
roker@895
   374
roker@895
   375
roker@895
   376
void ev_server::thread_done()
roker@895
   377
{
roker@895
   378
	JsonAdapter::getInstance().connection_close_cb();
roker@895
   379
	pEp::Adapter::session(pEp::Adapter::release);
roker@895
   380
}