53 void Send(
const void *buf,
int len)
override
84 if (longpoll) num_avail++;
86 if ((num_avail <= 0.1 * engine->GetNumThreads()) || (num_avail <= 2)) {
87 const char *cfg = engine->
IsWebGui() ?
"WebGui.HttpThreads parameter in rootrc" :
"thrds=N parameter in config URL";
88 const char *place = longpoll ?
"TCivetweb::LongpollHandler" :
"TCivetweb::WebSocketHandler";
89 ::Error(place,
"Only %d threads are available, reject connection request for %s. Increase %s, now it is %d", num_avail, uri, cfg, engine->
GetNumThreads());
111 auto arg = std::make_shared<THttpCallArg>();
112 arg->SetPathAndFileName(request_info->
local_uri);
115 arg->SetMethod(
"WS_CONNECT");
122 return execres && !arg->Is404() ? 0 : 1;
140 auto arg = std::make_shared<THttpCallArg>();
141 arg->SetPathAndFileName(request_info->
local_uri);
143 arg->SetMethod(
"WS_READY");
169 auto arg = std::make_shared<THttpCallArg>();
170 arg->SetPathAndFileName(request_info->
local_uri);
173 arg->SetMethod(
"WS_CLOSE");
192 int fin = code & 0x80, opcode = code & 0x0F;
195 enum { OP_CONTINUE = 0, OP_TEXT = 1, OP_BINARY = 2, OP_CLOSE = 8 };
198 if (fin && (opcode == OP_CLOSE)) {
210 if ((opcode != OP_CONTINUE) && (opcode != OP_TEXT) && (opcode != OP_BINARY)) {
235 auto arg = std::make_shared<THttpCallArg>();
236 arg->SetPathAndFileName(request_info->
local_uri);
239 arg->SetMethod(
"WS_DATA");
247 arg->SetPostData(std::string(
data,
len));
268 if ((
gDebug > 0) || (strstr(message,
"cannot bind to") != 0))
269 fprintf(stderr,
"Error in <TCivetweb::Log> %s\n", message);
292 if (strcmp(arg->GetFileName(),
"root.longpoll") != 0)
295 const char *
q = arg->GetQuery();
299 if ((strstr(
q,
"raw_connect") !=
q) && (strstr(
q,
"txt_connect") !=
q))
320 auto arg = std::make_shared<THttpCallArg>();
333 arg->SetContent(std::move(buf));
337 arg->AddNoCacheHeader();
344 arg->SetPathAndFileName(request_info->
local_uri);
355 arg->SetRequestHeader(header);
365 arg->SetPostData(std::move(buf));
370 cont.
Append(
"<title>Civetweb echo</title>");
371 cont.
Append(
"<h1>Civetweb echo</h1>\n");
373 static int count = 0;
381 if (arg->GetUserName())
384 cont.
Append(
"</pre><p>\n");
386 cont.
Append(
"Environment:<br/>\n<pre>\n");
390 cont.
Append(
"</pre><p>\n");
392 arg->SetContentType(
"text/html");
394 arg->SetContent(cont);
404 if (!execres || arg->Is404()) {
405 std::string hdr = arg->FillHttpHeader(
"HTTP/1.1");
407 }
else if (arg->IsFile()) {
408 filename = (
const char *)arg->GetContent();
412 auto hFile = CreateFile(
filename.Data(),
417 FILE_ATTRIBUTE_NORMAL,
423 auto dwRet = GetFinalPathNameByHandle( hFile, Path,
BUFSIZE, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS );
426 if (dwRet > 4 && Path[0] ==
'\\' && Path[1] ==
'\\' && Path[2] ==
'?' && Path[3] ==
'\\')
443 switch (arg->GetZipping()) {
446 if (arg->GetContentLength() < 10000)
break;
463 arg->CompressWithGzip();
465 std::string hdr = arg->FillHttpHeader(
"HTTP/1.1");
468 if (arg->GetContentLength() > 0)
469 mg_write(conn, arg->GetContent(), (
size_t)arg->GetContentLength());
515 :
THttpEngine(
"civetweb",
"compact embedded http server"),
516 fOnlySecured(only_secured)
534 if ((
gDebug > 0) || (strstr(message,
"cannot bind to") != 0))
535 Error(
"Log",
"%s", message);
545 std::lock_guard<std::mutex> guard(
fMutex);
554 std::lock_guard<std::mutex> guard(
fMutex);
599 websocket_timeout =
"300000",
600 dir_listening =
"no",
606 Int_t socket_mode = 0700;
607 bool use_ws =
kTRUE, is_socket =
false;
615 is_socket = *args ==
'x';
617 while ((*args != 0) && (*args !=
'?') && (is_socket || (*args !=
'/')))
623 while ((*args != 0) && (*args !=
'?'))
652 auth_domain = adomain;
660 websocket_timeout.Format(
"%d", wtmout * 1000);
675 if (dls && (!strcmp(dls,
"no") || !strcmp(dls,
"yes")))
680 socket_mode = std::stoi(smode,
nullptr, *smode==
'0' ? 8 : 10);
683 sport =
TString(
"127.0.0.1:") + sport;
687 if (addr && strlen(addr))
688 sport =
TString(addr) +
":" + sport;
714 const char *options[30];
717 Info(
"Create",
"Starting HTTP server on port %s", sport.
Data());
719 options[op++] =
"listening_ports";
720 options[op++] = sport.
Data();
721 options[op++] =
"num_threads";
722 options[op++] = num_threads.Data();
725 options[op++] =
"websocket_timeout_ms";
726 options[op++] = websocket_timeout.Data();
729 if ((auth_file.Length() > 0) && (auth_domain.Length() > 0)) {
730 options[op++] =
"global_auth_file";
731 options[op++] = auth_file.Data();
732 options[op++] =
"authentication_domain";
733 options[op++] = auth_domain.Data();
735 options[op++] =
"enable_auth_domain_check";
736 options[op++] =
"no";
739 if (log_file.Length() > 0) {
740 options[op++] =
"error_log_file";
741 options[op++] = log_file.Data();
744 if (ssl_cert.Length() > 0) {
745 options[op++] =
"ssl_certificate";
746 options[op++] = ssl_cert.Data();
748 Error(
"Create",
"No SSL certificate file configured");
751 if (max_age.Length() > 0) {
752 options[op++] =
"static_file_max_age";
753 options[op++] = max_age.Data();
758 options[op++] =
"access_control_allow_origin";
763 options[op++] =
"access_control_allow_credentials";
773 options[op++] =
"enable_directory_listing";
774 options[op++] = dir_listening.Data();
776 options[op++] =
nullptr;
779 if (is_socket && !sport.
Contains(
","))
795 if (is_socket && !sport.
Contains(
","))
int websocket_connect_handler(const struct mg_connection *conn, void *)
static int begin_request_handler(struct mg_connection *conn, void *)
static int log_message_handler(const struct mg_connection *conn, const char *message)
int websocket_data_handler(struct mg_connection *conn, int code, char *data, size_t len, void *)
void websocket_close_handler(const struct mg_connection *conn, void *)
Bool_t CheckEngineThreads(TCivetweb *engine, const char *uri, Bool_t longpoll)
Check if engine has enough threads to process connect to new websocket handle.
void websocket_ready_handler(struct mg_connection *conn, void *)
Bool_t IsBadLongPollConnect(TCivetweb *engine, const std::shared_ptr< THttpCallArg > &arg)
Returns kTRUE in case of longpoll connection request - or at least looks like that.
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
#define INVALID_HANDLE_VALUE
R__EXTERN TSystem * gSystem
int mg_printf(struct mg_connection *conn, const char *fmt,...)
void mg_send_file(struct mg_connection *conn, const char *path)
struct mg_context * mg_start(const struct mg_callbacks *callbacks, void *user_data, const char **options)
void mg_set_websocket_handler(struct mg_context *ctx, const char *uri, mg_websocket_connect_handler connect_handler, mg_websocket_ready_handler ready_handler, mg_websocket_data_handler data_handler, mg_websocket_close_handler close_handler, void *cbdata)
void mg_send_mime_file(struct mg_connection *conn, const char *path, const char *mime_type)
const char * mg_get_header(const struct mg_connection *conn, const char *name)
int mg_write(struct mg_connection *conn, const void *buf, size_t len)
const struct mg_request_info * mg_get_request_info(const struct mg_connection *conn)
void mg_set_user_connection_data(const struct mg_connection *const_conn, void *data)
void * mg_get_user_connection_data(const struct mg_connection *conn)
int mg_read(struct mg_connection *conn, void *buf, size_t len)
void mg_set_request_handler(struct mg_context *ctx, const char *uri, mg_request_handler handler, void *cbdata)
struct mg_context * mg_get_context(const struct mg_connection *conn)
void mg_stop(struct mg_context *ctx)
void * mg_get_user_data(const struct mg_context *ctx)
int mg_websocket_write(struct mg_connection *conn, int opcode, const char *data, size_t data_len)
@ MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE
@ MG_WEBSOCKET_OPCODE_BINARY
@ MG_WEBSOCKET_OPCODE_TEXT
struct mg_connection * fWSconn
UInt_t GetId() const override
void SendCharStar(const char *str) override
Envelope for sending string via the websocket.
void ClearHandle(Bool_t terminate) override
Bool_t SupportSendThrd() const override
True websocket requires extra thread to parallelize sending.
~TCivetwebWSEngine() override=default
void SendHeader(const char *hdr, const void *buf, int len) override
Special method to send binary data with text header For normal websocket it is two separated operatio...
void Send(const void *buf, int len) override
TCivetwebWSEngine(struct mg_connection *conn)
THttpEngine implementation, based on civetweb embedded server.
Int_t fNumThreads
! number of configured threads
Int_t fNumActiveThreads
! number of active threads - used in request and websocket handling
struct mg_context * fCtx
! civetweb context
std::mutex fMutex
! mutex to read/write fNumActiveThreads
Bool_t fWinSymLinks
! resolve symbolic links on Windows
Bool_t IsTerminating() const
const char * GetTopName() const
TCivetweb(Bool_t only_secured=kFALSE)
constructor
Int_t fMaxAge
! max-age parameter
Int_t ProcessLog(const char *message)
process civetweb log message, can be used to detect critical errors
TString fTopName
! name of top item
Int_t GetNumAvailableThreads()
Returns number of actively used threads.
Bool_t fTerminating
! server doing shutdown and not react on requests
Bool_t Create(const char *args) override
Creates embedded civetweb server.
Int_t ChangeNumActiveThrerads(int cnt=0)
Returns number of actively used threads.
Int_t GetNumThreads() const
Bool_t IsDebugMode() const
virtual ~TCivetweb()
destructor
Bool_t IsWinSymLinks() const
Bool_t fWebGui
! if server used for webgui
Bool_t fDebug
! debug mode
struct mg_callbacks fCallbacks
! call-back table for civetweb webserver
Abstract class for implementing http protocol for THttpServer.
THttpServer * GetServer() const
Returns pointer to THttpServer associated with engine.
Online http server for arbitrary ROOT application.
Bool_t IsFileRequested(const char *uri, TString &res) const
Check if file is requested, thread safe.
const char * GetCors() const
Returns specified CORS domain.
Bool_t ExecuteWS(std::shared_ptr< THttpCallArg > &arg, Bool_t external_thrd=kFALSE, Bool_t wait_process=kFALSE)
Execute WS request.
Bool_t ExecuteHttp(std::shared_ptr< THttpCallArg > arg)
Execute HTTP request.
void SetCorsCredentials(const std::string &value="true")
Enable/disable usage Access-Control-Allow-Credentials response header.
void SetCors(const std::string &domain="*")
Enable CORS header to ProcessRequests() responses Specified location (typically "*") add as "Access-C...
const char * GetCorsCredentials() const
Returns specified CORS credentials value - if any.
static char * ReadFileContent(const char *filename, Int_t &len)
Reads content of file from the disk.
static const char * GetMimeType(const char *path)
Guess mime type base on file extension.
Internal instance used to exchange WS functionality between THttpServer and THttpWSHandler.
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Int_t Atoi() const
Return integer value of string.
const char * Data() const
UInt_t Hash(ECaseCompare cmp=kExact) const
Return hash value.
TString & Append(const char *cs)
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
virtual int Chmod(const char *file, UInt_t mode)
Set the file permission bits. Returns -1 in case or error, 0 otherwise.
virtual int Unlink(const char *name)
Unlink, i.e.
This class represents a WWW compatible URL.
const char * GetValueFromOptions(const char *key) const
Return a value for a given key from the URL options.
Int_t GetIntValueFromOptions(const char *key) const
Return a value for a given key from the URL options as an Int_t, a missing key returns -1.
void ParseOptions() const
Parse URL options into a key/value map.
Bool_t HasOption(const char *key) const
Returns true if the given key appears in the URL options list.
TEngineHolder(TCivetweb *engine)
int(* log_message)(const struct mg_connection *, const char *message)
struct mg_header http_headers[(64)]
const char * request_method
const char * query_string