635                hash<auto> 
cx, hash<auto> 
hdr, 
auto body)
 
  637                    cx + (exists 
body ? {
'deserialized': True} : NOTHING), 
hdr, 
body);
 
  763                Socket s, *list<string> cl, 
string mn, hash<auto> cx, *hash<auto> args) {
 
  764            if (!args && cx.body.typeCode() == NT_HASH);
 
  771            string astr = rh.
maskData(sprintf(
"%y", args));
 
  772            rh.
logDebug(
"REST DBG: class %y: dispatching method %y args: %s", 
name(), mn, astr);
 
  777        private hash<HttpServer::HttpHandlerResponseInfo> 
dispatchStream(HttpListenerInterface listener,
 
  778                RestHandler rh, Socket s, 
string mn, *hash<auto> ah, hash<auto> cx) {
 
  779            string sn = 
"stream" + mn[0].upr() + mn.substr(1);
 
  782                rsh = call_object_method_args(self, sn, (cx, ah));
 
  783            } 
catch (hash<ExceptionInfo> ex) {
 
  784                if (ex.err == 
"METHOD-DOES-NOT-EXIST" && ex.desc.find(sn) != -1) {
 
  785                    if (cx.hdr.
"transfer-encoding" == 
"chunked")
 
  788                    return cast<hash<HttpHandlerResponseInfo>>(
dispatch(rh, mn, ah, cx));
 
  790                string desc = !cx.debug
 
  791                    ? sprintf(
"%s: %s: %s", get_ex_pos(ex), ex.err, ex.desc)
 
  792                    : get_exception_string(ex);
 
  793                rh.
logDebug(
"REST DBG: class %y: stream method %y: %s", 
name(), sn, desc);
 
  797                RestStreamRequest req(rsh, listener, rh, s, cx, cx.hdr, cx.hdr.
"content-length" ? cx.body : NOTHING);
 
  799            } 
catch (hash<ExceptionInfo> ex) {
 
  802                    # issue #4291: handle errors here correctly 
  805                    } 
catch (hash<ExceptionInfo> ex1) {
 
  806                        rh.
logError(
"cannot register error %s: %s with stream handler: %s: %s", ex.err, ex.desc,
 
  810                string desc = !cx.debug
 
  811                    ? sprintf(
"%s: %s: %s", get_ex_pos(ex), ex.err, ex.desc)
 
  812                    : get_exception_string(ex);
 
  813                rh.
logDebug(
"REST DBG: class %y: stream method %y: %s", 
name(), sn, desc);
 
  843                return cast<hash<HttpHandlerResponseInfo>>(call_object_method_args(self, mn, (cx, ah)));
 
  844            } 
catch (hash<ExceptionInfo> ex) {
 
  845                if (ex.err == 
"METHOD-DOES-NOT-EXIST") {
 
  847                    string astr = rh.
maskData(sprintf(
"%y", ah));
 
  848                    rh.
logError(
"DISPATCH-ERROR: cannot dispatch to unimplemented method %y: class %y, args: %s", mn,
 
  850                    # see if alternate methods would work 
  855                        string nmn = mh.value + cx.rest_method;
 
  856                        if (self.hasCallableMethod(nmn)) {
 
  857                            if (mh.key == cx.hdr.method) {
 
  867                                "not implement method %y", 
name(), self.className(),
 
  868                                cx.orig_method ? cx.orig_method : mn));
 
  870                        string ml = foldl $1 + 
"," + $2, hl;
 
  871                        string desc = sprintf(
"HTTP method %s is unimplemented in REST class %y (%s)", cx.hdr.method,
 
  872                            name(), self.className());
 
  874                            desc += sprintf(
" REST method %y", cx.orig_method);
 
  875                        desc += sprintf(
", available methods: %s", ml);
 
  876                        return cast<hash<HttpHandlerResponseInfo>>(
 
  881                string desc = !cx.debug
 
  882                    ? sprintf(
"%s: %s: %s", get_ex_pos(ex), ex.err, ex.desc)
 
  883                    : get_exception_string(ex);
 
  884                rh.
logDebug(
"REST DBG: class %y: method %y: %s", 
name(), mn, desc);
 
  904         hash<HttpServer::HttpHandlerResponseInfo> 
unknownSubClassError(
string cls_name, hash<auto> cx, *hash<auto> ah);
 
  942            const Err501 = 
new hash<HttpResponseInfo>({
 
  944                "body": 
"not implemented",
 
  953                "OPTIONS": 
"options",
 
 1054        hash<HttpResponseInfo> 
handleRequest(HttpListenerInterface listener, Socket s, hash<auto> cx, hash<auto> hdr,
 
 1062            string path = cx.url.path ?? 
"";
 
 1064            removeRootPath(\path);
 
 1066            hash<RestRequestServerInfo> req;
 
 1069                    string bstr = maskData(b.typeCode() == NT_STRING ? trim(b) : sprintf(
"%y", b));
 
 1070                    logDebug(
"REST DBG: body: %s", bstr);
 
 1073                req = validator.
parseRequest(hdr.method, path, body, \hdr);
 
 1074            } 
catch (hash<ExceptionInfo> ex) {
 
 1075                logDebug(
"REST DBG: %s", get_exception_string(ex));
 
 1077                if (ex.err == 
"INVALID-ENCODING" 
 1078                    || ex.err == 
"ENCODING-CONVERSION-ERROR" 
 1079                    || ex.err == 
"DESERIALIZATION-ERROR" 
 1080                    || ex.err == 
"SCHEMA-VALIDATION-ERROR")
 
 1081                    return AbstractHttpRequestHandler::makeResponse(400, sprintf(
"%s: %s", ex.err, ex.desc),
 
 1082                        errorResponseHeaders(cx));
 
 1083                if (ex.err == 
"INVALID-METHOD") {
 
 1084                    string ml = (foldl $1 + 
"," + $2, ex.arg) ?? 
"";
 
 1085                    return AbstractHttpRequestHandler::makeResponse(405, sprintf(
"HTTP method %y is not supported " 
 1086                        "with URI path %y; supported methods: %s", hdr.method, path, ml ?* 
"<none>"),
 
 1087                        errorResponseHeaders(cx) + {
"Allow": ml});
 
 1093            hash<auto> ah = path ? {
 
 1095                "params": req.query,
 
 1113            if (body.typeCode() == NT_HASH);
 
 1116            if (!Methods.(hdr.method))
 
 1117                return AbstractHttpRequestHandler::make400(
"unsupported HTTP method %y given in REST call %y",
 
 1123 else if (body.action);
 
 1125                mn = Methods.(hdr.method);
 
 1128            cx.rest_action_method = mn;
 
 1132                splice ah.method, 0, 1;
 
 1140            *
string astr = hdr.accept;
 
 1145                # it is assumed that the client accepts all media types 
 1152            cx += {
"hdr": hdr, 
"body": body, 
"aih": aih};
 
 1155            hash<HttpHandlerResponseInfo> rv;
 
 1158                rv = dispatchRequest(listener, s, cl, mn, path, cx, args);
 
 1159            } 
catch (hash<ExceptionInfo> ex) {
 
 1160                string desc = !cx.debug
 
 1161                    ? sprintf(
"%s: %s: %s", get_ex_pos(ex), ex.err, ex.desc)
 
 1162                    : get_exception_string(ex);
 
 1165                rv = returnRestException(ex);
 
 1168            if (!rv.reply_sent);
 
 1173            return cast<hash<HttpResponseInfo>>(rv);
 
 1185        private hash<HttpHandlerResponseInfo> 
dispatchRequest(HttpListenerInterface listener, Socket s,
 
 1186                *list<string> class_list, 
string method_name, 
string path, hash<auto> cx, *hash<auto> args) {
 
 1190            *
string cls = shift class_list;
 
 1197                    # ind an action method instead 
 1198                    if (!class_list && !args.action) {
 
 1199                        string mname = sprintf(
"%s%s%s", method_name, cls[0].upr(), cls[1..]);
 
 1200                        if (self.hasCallableMethod(mname)) {
 
 1202                            method_name = mname;
 
 1207                        return unknownSubClassError(cls, cx, args);
 
 1214            return rcls.
handleRequest(listener, self, s, class_list, method_name, cx, args);
 
 1233        hash<auto> 
get(hash<auto> cx, *hash<auto> ah);
 
 1267          static hash<HttpHandlerResponseInfo> 
make200(
string fmt);
 
 1270          static hash<HttpHandlerResponseInfo> 
make200(hash<auto> hdr, 
string fmt);
 
 1273          static hash<HttpHandlerResponseInfo> 
make400(
string fmt);
 
 1276          static hash<HttpHandlerResponseInfo> 
make400(hash<auto> hdr, 
string fmt);
 
 1279          static hash<HttpHandlerResponseInfo> 
makeResponse(
int code, 
auto body, *hash<auto> hdr);
 
 1282          static hash<HttpHandlerResponseInfo> 
make500(
string fmt);
 
 1285          static hash<HttpHandlerResponseInfo> 
make500(hash<auto> hdr, 
string fmt);
 
 1288          static hash<HttpHandlerResponseInfo> 
make501(
string fmt);
 
 1291          static hash<HttpHandlerResponseInfo> 
make501(hash<auto> hdr, 
string fmt);
 
 1298class DummyListenerInterface : 
public HttpListenerInterface {
 
 1301        addUserThreadContext(hash<auto> uctx);
 
 1304        auto removeUserThreadContext(*
string k);
 
 1310        logError(
string fmt);
 
static hash< HttpResponseInfo > makeResponse(hash< auto > hdr, int code, binary body)
 
*data getMessageBody(Socket s, hash< auto > hdr, *data body, bool decode=True)
 
string maskData(string msg)
 
constructor(HttpListenerInterface listener, AbstractHttpRequestHandler handler, Socket s, hash< auto > cx, hash< auto > hdr, auto body)
 
AbstractHttpRequestHandler handler
 
hash< HttpHandlerResponseInfo > handleRequest()
 
HttpListenerInterface listener
 
the base abstract class for REST handler classes
Definition: RestHandler.qm.dox.h:686
 
hash< HttpServer::HttpHandlerResponseInfo > unknownSubClassError(string cls_name, hash< auto > cx, *hash< auto > ah)
returns a 404 Not Found response when a request tries to access an unknown subclass
 
private hash< HttpServer::HttpHandlerResponseInfo > dispatch(RestHandler rh, string mn, *hash< auto > ah, hash< auto > cx)
this method is called to dispatch requests on the given object
Definition: RestHandler.qm.dox.h:840
 
abstract string name()
this provides the name of the REST class
 
private hash< HttpServer::HttpHandlerResponseInfo > dispatchStream(HttpListenerInterface listener, RestHandler rh, Socket s, string mn, *hash< auto > ah, hash< auto > cx)
this method is called to dispatch streamed requests on the given object
Definition: RestHandler.qm.dox.h:777
 
hash< HttpServer::HttpHandlerResponseInfo > handleRequest(HttpListenerInterface listener, RestHandler rh, Socket s, *list< string > cl, string mn, hash< auto > cx, *hash< auto > args)
this method is called by the RestHandler class to match the right object with incoming requests
Definition: RestHandler.qm.dox.h:762
 
addClass(AbstractRestClass cls)
adds a REST class to the handler
 
*AbstractRestClass subClassImpl(string name, hash< auto > cx, *hash< auto > args)
this method will be called to find a sub-class (ie with GET /invoices/1 - if this class represents "i...
 
*hash< string, bool > doGetPossibleSubClasses(hash< auto > cx, *hash< auto > ah)
returns a set of possible subclasses for a particular request
 
hash< string, AbstractRestClass > class_hash
class hash: name -> AbstractRestClass
Definition: RestHandler.qm.dox.h:690
 
*AbstractRestClass subClass(string name, hash< auto > cx, *hash< auto > args)
this method will be called to find a sub-class (ie with GET /invoices/1 - if this class represents "i...
 
const RestBasicMethodSet
set of REST class method names based on basic HTTP methods
Definition: RestHandler.qm.dox.h:693
 
the base abstract class for REST stream request handlers
Definition: RestHandler.qm.dox.h:484
 
hash< auto > rhdr
headers to add in the response
Definition: RestHandler.qm.dox.h:500
 
auto send()
this method provides the callback method for sending chunked data by calling sendImpl()
 
abstract auto sendImpl()
abstract callback method for sending chunked data
 
hash< auto > cx
call context hash
Definition: RestHandler.qm.dox.h:491
 
nothing recv(hash< auto > v)
this method provides the callback method for receiving chunked data by calling recvImpl()
 
constructor(hash< auto > n_cx, *hash< auto > n_ah)
creates the object with the given arguments
 
*int getTimeout()
returns the timeout in milliseconds or NOTHING if no timeout is set
 
*hash< auto > ah
call argument hash
Definition: RestHandler.qm.dox.h:497
 
hash< HttpServer::HttpHandlerResponseInfo > getResponseHeaderMessage()
this method returns the response message description hash by calling getResponseHeaderMessageImpl()
 
bool isPersistent()
returns True if the connection is persistent; this method in the base class returns False by default
 
abstract hash< auto > getResponseHeaderMessageImpl()
this method should return the response message description hash
 
*int timeout_ms
socket I/O timeout in milliseconds
Definition: RestHandler.qm.dox.h:503
 
setTimeout(timeout n_timeout_ms)
sets the internal socket I/O timeout value in ms
 
streamError(hash< auto > n_ex)
registers stream errors in the send operation with the stream handler if no error is already present
 
*hash< auto > ex
if an exception is raised in a callback then the exception hash is saved here
Definition: RestHandler.qm.dox.h:494
 
*code getPersistentClosedNotification()
returns a callable value in case a persistent connection is in progress; NOTHING if not; this method ...
 
abstract nothing recvImpl(hash< auto > v)
abstract callback method for receiving chunked data
 
auto handleExternalRequest(string method, string path, *hash< auto > body, hash< auto > cx={})
processes REST API calls outside the HTTP server
 
responseSerializationError(hash< auto > cx, *hash< auto > aih, hash< auto > rv)
default implementation is empty
 
static hash< HttpHandlerResponseInfo > make500(hash< auto > hdr, string fmt)
creates a hash for an HTTP 500 error response with the response message body as a string
 
const Methods
supported HTTP methods
Definition: RestHandler.qm.dox.h:948
 
RestSchemaValidator::AbstractRestSchemaValidator validator
REST schema validator.
Definition: RestHandler.qm.dox.h:962
 
removeRootPath(reference< string > path)
default implementation is empty
 
hash< HttpResponseInfo > handleRequest(HttpListenerInterface listener, Socket s, hash< auto > cx, hash< auto > hdr, *data b)
called by the HTTP server to handle incoming HTTP requests
Definition: RestHandler.qm.dox.h:1054
 
static hash< HttpHandlerResponseInfo > make501(hash< auto > hdr, string fmt)
creates a hash for an HTTP 501 error response with the response message body as a string
 
static hash< HttpHandlerResponseInfo > make200(hash< auto > hdr, string fmt)
creates a hash for an HTTP 200 OK error response with the response message body as a string
 
logInfo(string fmt)
This method is called with informational log messages.
 
checkExceptionSerializable(reference< hash< ExceptionInfo > > ex)
Recursively ensure that exception arguments are serializable.
 
static hash< HttpHandlerResponseInfo > make501(string fmt)
creates a hash for an HTTP 501 error response with the response message body as a string
 
private hash< HttpHandlerResponseInfo > dispatchRequest(HttpListenerInterface listener, Socket s, *list< string > class_list, string method_name, string path, hash< auto > cx, *hash< auto > args)
Dispatches the request and returns the response.
Definition: RestHandler.qm.dox.h:1185
 
static hash< HttpHandlerResponseInfo > makeResponse(int code, auto body, *hash< auto > hdr)
creates a hash for an HTTP response with the response code and a literal response message body
 
hash< HttpHandlerResponseInfo > returnRestException(hash< ExceptionInfo > ex)
method that determines how exceptions handling REST requests are returned
 
logError(string fmt)
This method is called with error log messages.
 
constructor(*HttpServer::AbstractAuthenticator auth, RestSchemaValidator::AbstractRestSchemaValidator validator=new NullRestSchemaValidator())
create the object optionally with the given HttpServer::AbstractAuthenticator
 
constructor(Logger::Logger logger, *HttpServer::AbstractAuthenticator auth, RestSchemaValidator::AbstractRestSchemaValidator validator=new NullRestSchemaValidator(logger))
create the object optionally with the given Logger and authenticator
 
static hash< HttpHandlerResponseInfo > make400(hash< auto > hdr, string fmt)
creates a hash for an HTTP 400 error response with the response message body as a string
 
logDebug(string fmt)
This method is called with debug log messages.
 
string name()
returns the name of the root REST class
 
*hash< auto > errorResponseHeaders(hash< auto > cx)
Retrieves headers for an error response.
 
setLogger(Logger::Logger logger)
Sets a new logger.
 
hash< auto > get(hash< auto > cx, *hash< auto > ah)
default get handler for the base handler class
 
static hash< HttpHandlerResponseInfo > make500(string fmt)
creates a hash for an HTTP 500 error response with the response message body as a string
 
Logger::Logger logger
logger
Definition: RestHandler.qm.dox.h:959
 
static hash< HttpHandlerResponseInfo > make200(string fmt)
creates a hash for an HTTP 200 OK error response with the response message body as a string
 
requestDeserializationError(hash< auto > hdr, hash< auto > cx, string body)
default implementation is empty
 
static hash< HttpHandlerResponseInfo > make400(string fmt)
creates a hash for an HTTP 400 error response with the response message body as a string
 
the base class for handling HTTP chunked requests and responses within the RestHandler infrastructure
Definition: RestHandler.qm.dox.h:623
 
nothing recvImpl(hash< auto > v)
callback method for receiving chunked data; this calls RestHandler::AbstractRestStreamRequestHandler:...
 
hash< HttpServer::HttpHandlerResponseInfo > getResponseHeaderMessageImpl()
 
constructor(RestHandler::AbstractRestStreamRequestHandler n_stream, HttpServer::HttpListenerInterface listener, HttpServer::AbstractHttpRequestHandler handler, Socket s, hash< auto > cx, hash< auto > hdr, auto body) destructor()
creates the object with the given attributes
 
auto sendImpl()
callback method for sending chunked data; this calls RestHandler::AbstractRestStreamRequestHandler::s...
 
hash< RestRequestServerInfo > parseRequest(string method, string path, *data http_body, reference< hash< auto > > headers)
 
the RestHandler namespace contains all the objects in the RestHandler module
Definition: RestHandler.qm.dox.h:475