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