HttpServer.qm.dox.h
// -*- mode: c++; indent-tabs-mode: nil -*-
// @file HttpServer.qm HTTP multi-threaded server module definition
/* HttpServer.qm Copyright (C) 2012 - 2017 Qore Technologies, s.r.o.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
// need mime definitions
namespace HttpServer {
string get_exception_string(hash ex);
};
// class containing handler info
class HttpServer::HandlerInfo {
public:
public :
string name;
HttpServer::AbstractHttpRequestHandler obj;
string path;
bool isregex;
// content type hash
hash ch;
*list shdr;
public:
constructor(string n_name, HttpServer::AbstractHttpRequestHandler n_obj, string n_path, bool n_isregex = True, *softlist n_content, *softlist n_shdr);
bool matchContentType(string ct);
int matchRequest(hash hdr, int score);
};
// class to implement handler-handling (private)
class HttpServer::HttpHandlerList {
public:
public :
hash handlers;
TreeMap treeMap();
public:
/*
private static checkSpecialHeaders(reference sh) {
foreach auto h in (\sh) {
if (h.typeCode() != NT_STRING)
throw "SETHANDLER-ERROR", sprintf("entry %d in the special header list is not a string; type: %s", $#, h.type());
# make sure header is in lower case for matching
h = tolower(h);
}
}
*/
setHandler(string name, string path, bool isregex = True, *softlist content, HttpServer::AbstractHttpRequestHandler obj, *softlist special_headers);
// matches a handler to the request
*HandlerInfo findHandler(hash hdr, reference<int> score, bool finalv = False, *reference<string> root_path);
bool empty();
int size();
};
// class containing dynamic handler info
class HttpServer::DynamicHandlerInfo : public HttpServer::HandlerInfo {
public:
public :
Counter counter();
public:
constructor(string name, HttpServer::AbstractHttpRequestHandler obj, string path, bool isregex = True, *softlist content, *softlist shdr) ;
};
// maintains the request count for dynamic handlers (private)
class HttpServer::DynamicHandlerHelper {
public:
private:
public:
private :
Counter c;
public:
constructor(Counter n_c);
destructor();
};
// for dynamic handler-handling (private)
class HttpServer::DynamicHttpHandlerList : public HttpServer::HttpHandlerList {
public:
private :
RWLock dhl();
public:
setHandler(string name, string path, bool isregex, *softlist content_type, HttpServer::AbstractHttpRequestHandler obj, *softlist special_headers);
removeHandler(string name);
*DynamicHandlerInfo findHandler(hash hdr, reference<int> score, reference<DynamicHandlerHelper> dhh, *reference<string> root_path);
};
class HttpServer::HttpServer : public HttpServer::AbstractLogger {
public:
public :
const Version = HttpServer::HttpServerVersion;
const ReadTimeout = HttpServer::ReadTimeout; // recvs timeout after 30 seconds
const PollTimeout = 5000; // check for exit every 5 seconds while waiting
// logging options
const LP_LOGPARAMS = HttpServer::LP_LOGPARAMS;
const LP_LEVELMASK = HttpServer::LP_LEVELMASK;
const AIFlags = AI_PASSIVE | AI_ADDRCONFIG;
const HttpMethods = (
"HEAD": True,
"POST": True,
"PUT": True,
"DELETE": True,
"GET": True,
"OPTIONS": True,
"PATCH": True,
//"TRACE": True,
//"CONNECT": True,
);
const HttpCodes = HttpServer::HttpCodes;
const ContentEncodings = (
"gzip": "gzip",
"deflate": "deflate",
"bzip2": "bzip2",
"x-gzip": "gzip",
"x-deflate": "deflate",
"x-bzip2": "bzip2",
);
const DefaultIdleThreads = 10;
const CompressionThreshold = 1024;
const LLO_RECV_HEADERS = (1 << 0);
const LLO_RECV_BODY = (1 << 1);
const LLO_SEND_HEADERS = (1 << 2);
const LLO_SEND_BODY = (1 << 3);
public:
private :
*code logfunc;
*code errlogfunc;
// for masking HTTP request log msgs
*code maskfunc;
// quit server flag
bool exit = False;
// if True then verbose exception info will be logged
bool debug;
Sequence seqSessions();
Sequence seqListeners();
bool stopped = False;
// permanent handlers; these handlers are never removed
HttpHandlerList handlers();
// default handler
hash defaultHandler;
// hash of listeners keyed by listener ID
hash listeners;
// map of bind addresses to listener IDs
hash smap;
// map of listener names to listener IDs
hash nmap;
// listener Gate
Gate lm();
// running listener counter
Counter c();
// dynamic handlers
DynamicHttpHandlerList dhandlers();
// connection thread pool
ThreadPool threadPool(-1, DefaultIdleThreads);
// other misc response headers
hash hdr;
// override message body encoding if none is received from the sender; http://tools.ietf.org/html/rfc2616#section-3.7.1 states that it must be iso-8850-1
*string override_encoding;
string http_server_string;
public:
constructor(*code n_logfunc, *code n_errlogfunc, bool n_dbg = False, string n_name = HttpServer::HttpServerString, hash n_hdr = ("X-Powered-By": "Qore/" + Qore::VersionString));
destructor();
static string getHttpServerVersionString();
setDefaultTextEncoding(string enc);
string getDefaultTextEncoding();
final list addListenersWithHandler(string hname, HttpServer::AbstractHttpRequestHandler handler, hash lp, *code logger, *code errorlogger, *code stopc, *string name, int family = AF_UNSPEC);
final list addListeners(string bind, hash lp, *code logger, *code errorlogger, *code stopc, *string name, int family = AF_UNSPEC);
hash addListener(softstring sock, *string cert_path, *string key_path, *string name, int family = AF_UNSPEC, *string pwd);
softlist addListeners(softstring sock, *string cert_path, *string key_path, *string name, int family = AF_UNSPEC, *string pwd);
list addINETListeners(*string node, softstring service, *string cert_path, *string key_path, *string name, int family = AF_UNSPEC, *string pwd);
copy();
hash getListeners();
hash getListenerInfo(softint id);
hash getListenerInfoName(string name);
int getListenerCount();
stopNoWait();
waitStop();
listenerStarted(int id, hash sinfo);
// only called from the listeners - do not call externally
listenerStopped(HttpListener l);
stop();
stopListener(softstring bind);
stopListenerID(softint id);
int getListenerTID(softint id);
setDefaultHandler(string name, HttpServer::AbstractHttpRequestHandler obj);
setHandler(string name, string path, *softlist content_type, HttpServer::AbstractHttpRequestHandler obj, *softlist special_headers, bool isregex = True);
setDynamicHandler(string name, string path, *softlist content_type, HttpServer::AbstractHttpRequestHandler obj, *softlist special_headers, bool isregex = True);
setHandler(string name, HttpServer::AbstractUrlHandler obj);
setDynamicHandler(string name, HttpServer::AbstractUrlHandler obj);
addHandlerToListener(softstring bind, string name, string path, *softlist content_type, HttpServer::AbstractHttpRequestHandler obj, *softlist special_headers, bool isregex = True);
addHandlerToListenerID(softint id, string name, string path, *softlist content_type, HttpServer::AbstractHttpRequestHandler obj, *softlist special_headers, bool isregex = True);
addHandlerToListener(softstring bind, string name, HttpServer::AbstractUrlHandler obj);
addHandlerToListenerID(softint id, string name, HttpServer::AbstractUrlHandler obj);
setListenerLogOptions(softstring bind, softint code);
setListenerLogOptionsID(softint id, softint code);
int getListenerLogOptions(softstring bind);
int getListenerLogOptionsID(softint id);
removeDynamicHandler(string name);
log(string fmt);
logError(string fmt);
sendHttpError(HttpListener listener, hash cx, Socket s, int code, string msg, *hash extra_hdrs, *string encoding);
string maskData(string msg);
setMaskCode(code maskfunc);
static string getURLFromBind(softstring bind, *string host);
setDebug(bool dbg = True);
bool getDebug();
startConnection(code c);
private:
int getListenerIdFromBindUnlocked(string bind);
public:
private:
setListenerLogOptionsUnlocked(softstring id, int code);
public:
private:
int getListenerLogOptionsUnlocked(softstring id);
public:
static nothing setReplyHeaders(Socket s, hash cx, reference<hash> rv);
// don't reimplement this method; fix/enhance it in the module
private:
final HttpListener addListenerIntern(*string node, *softstring service, *Qore::SSLCertificate cert, *Qore::SSLPrivateKey key, *hash hi, *code logger, *code errorlogger, *code stopc, *string name, int family = AF_UNSPEC);
public:
// don't reimplement this method; fix/enhance it in the module
private:
static final hash getSSLObjects(string cert_path, *string key_path, *string pwd);
public:
// don't reimplement this method; fix/enhance it in the module
private:
final list addINETListenersIntern(*string node, softstring service, *hash sd, *hash lp, *code logger, *code errorlogger, *code stopc, *string name, int family = AF_UNSPEC);
public:
// don't reimplement this method; fix/enhance it in the module
private:
final hash<HttpResponseInfo> noHandlerError(hash cx, hash hdr, auto body);
public:
// handles an incoming request - do not call externally; this method is called by the listeners when a request is received
// don't reimplement this method; fix/enhance it in the module
final handleRequest(HttpListener listener, Socket s, reference<hash> cx, hash hdr, hash hh, *data body, bool head = False, HttpPersistentHandlerInfo phi);
// sends a reply to a request
// don't reimplement this method; fix/enhance it in the module
final sendReply(HttpListener listener, Socket s, HttpServer::AbstractHttpRequestHandler handler, hash rv, reference<hash> cx, hash hdr, bool head);
};
class HttpServer::HttpPersistentHandlerInfo {
public:
public :
*DynamicHandlerHelper dhh;
*HttpServer::AbstractHttpRequestHandler handler;
public:
destructor();
assign(*DynamicHandlerHelper n_dhh, HttpServer::AbstractHttpRequestHandler n_handler);
clear();
};
class HttpServer::HttpListener : public Qore::Socket,public HttpServer::HttpListenerInterface {
public:
private :
HttpServer serv;
Sequence ss;
*SSLCertificate cert;
*SSLPrivateKey key;
bool ssl = False;
auto socket;
hash socket_info;
// connection counter
Counter cThreads();
bool exit = False;
bool stopped = False;
int id;
// socket handler hash
hash shh;
// mutex
Mutex m();
// code references to external logging functions
*code logger;
*code errorlogger;
// stop notification closure
*code stopc;
string name;
// log recv headers flag
bool log_recv_headers = False;
// log recv body flag
bool log_recv_body = False;
// log send headers flag
bool log_send_headers = False;
// log send body flag
bool log_send_body = False;
const PollInterval = 1s;
const ListenQueue = 100;
const BodyLogLimit = 40;
public:
public :
// TID of the background listener thread
int tid;
// listener-specific handlers
HttpHandlerList handlers();
// default handler info
*HandlerInfo defaultHandler;
public:
// params: server, id, session ID sequence object, socket, rbac obj, [cert, key]
constructor(HttpServer n_server, int n_id, Sequence n_ss, *string n_node, *softstring n_service, *Qore::SSLCertificate n_cert, *Qore::SSLPrivateKey n_key, *hash n_hi, *code n_logger, *code n_errorlogger, *code n_stopc, string n_name, int n_family = AF_UNSPEC);
addHandlers(hash hi);
setDefaultHandler(string name);
copy();
destructor();
logRecvHeaders(softbool flag = True);
logRecvBody(softbool flag = True);
logSendHeaders(softbool flag = True);
logSendBody(softbool flag = True);
hash getLogOptions();
string getName();
auto getAddress();
int getID();
bool isSecure();
hash getInfo();
auto removeUserThreadContext(*string k);
addUserThreadContext(hash uctx);
stopNoWait();
stop();
logResponse(hash cx, int code, *data body, *hash hdr);
logResponse(hash cx, hash rv);
log(string fmt);
logError(string fmt);
private:
mainThread();
public:
// thread for handling communication per connection
private:
connectionThread(Socket s);
public:
bool registerDedicatedSocket(softstring id, HttpServer::AbstractHttpSocketHandler h);
removeDedicatedSocket(softstring id, HttpServer::AbstractHttpSocketHandler h);
};
AF_UNSPEC
const AF_UNSPEC
HttpServer::ReadTimeout
const ReadTimeout
HttpServer::get_exception_string
string get_exception_string(hash ex)
returns a multi-line string from the exception hash argument suitable for logging or output on the co...
HttpServer::HttpCodes
const HttpCodes
HttpServer::LP_LOGPARAMS
const LP_LOGPARAMS
HttpServer::AbstractHttpRequestHandler
HttpServer::HttpServer::ReadTimeout
const ReadTimeout
default read timeout in ms
Definition: HttpServer.qm.dox.h:382
Qore::Socket
True
const True
HttpServer::HttpListenerInterface
False
const False
list
list list(...)
HttpServer::HttpServerVersion
const HttpServerVersion
exit
nothing exit(softint rc=0)
Qore::SSLPrivateKey
HttpServer::AbstractLogger
HttpServer::AbstractHttpSocketHandler
HttpServer::AbstractUrlHandler
Qore::SSLCertificate
HttpServer::LP_LEVELMASK
const LP_LEVELMASK
HttpServer::HttpServerString
const HttpServerString
HttpServer::HttpServer
The HttpServer class implements a multithreaded HTTP server.
Definition: HttpServer.qm.dox.h:375
HttpServer
the main namespace for the HttpServer module
HttpServer::HttpListener
this class implements the listeners for the HttpServer class
Definition: HttpServer.qm.dox.h:973
Qore::VersionString
const VersionString
hash
hash hash(object obj)
AI_ADDRCONFIG
const AI_ADDRCONFIG
HttpServer::HttpServer::HttpCodes
const HttpCodes
map of HTTP result codes and text messages
Definition: HttpServer.qm.dox.h:407
AI_PASSIVE
const AI_PASSIVE