HttpServerUtil.qm.dox.h
// -*- mode: c++; indent-tabs-mode: nil -*-
// @file HttpServerUtil.qm HTTP server base code
/* HttpServerUtil.qm Copyright (C) 2014 - 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 {
const HttpServerVersion = "0.3.11.1";
const HttpServerString = sprintf("Qore-HTTP-Server/%s", HttpServerVersion);
const DefaultTimeout = 30s; // recvs timeout after 30 seconds
const ReadTimeout = DefaultTimeout;
const HttpCodes = (
// 100s: Informational
"100": "Continue",
"101": "Switching Protocols",
// RFC 2518: WebDAV
"102": "Processing",
// 200s: Success
"200": "OK",
"201": "Created",
"202": "Accepted",
"203": "Non-Authoritative Information",
"204": "No Content",
"205": "Reset Content",
"206": "Partial Content",
// RFC 4918: WebDAV: The message body that follows is an XML message and can contain a number of separate response codes, depending on how many sub-requests were made
"207": "Multi-Status",
// RFC 5842: WebDAV: The members of a DAV binding have already been enumerated in a previous reply to this request, and are not being included again
"208": "Already Reported",
// RFC 3229
"226": "IM Used",
// 300s: Redirection
"300": "Multiple Choices",
"301": "Moved Permanently",
"302": "Found",
"303": "See Other",
"304": "Not Modified",
"305": "Use Proxy",
//"306": "(Reserved)",
"307": "Temporary Redirect",
// 400s: Client Errors
"400": "Bad Request",
"401": "Unauthorized",
"402": "Payment Required",
"403": "Forbidden",
"404": "Not Found",
"405": "Method Not Allowed",
"406": "Not Acceptable",
"407": "Proxy Authentication Required",
"408": "Request Timeout",
"409": "Conflict",
"410": "Gone",
"411": "Length Required",
"412": "Precondition Failed",
"413": "Request Entity Too Large",
"414": "Request-URI Too Long",
"415": "Unsupported Media Type",
"416": "Requested Range Not Satisfiable",
"417": "Expectation Failed",
// RFC 2324: http://tools.ietf.org/html/rfc2324
"418": "I'm a teapot",
// Returned by the Twitter Search and Trends API when the client is being rate limited
"420": "Enhance Yextern Calm",
// RFC 4918: WebDAV: The request was well-formed but was unable to be followed due to semantic errors
"422": "Unprocessable Entity",
// RFC 4918: WebDAV: The resource that is being accessed is locked
"423": "Locked",
// RFC 4918: WebDAV: The request failed due to failure of a previous request (e.g. a PROPPATCH)
"424": "Failed Dependency",
// Internet draft: Defined in drafts of "WebDAV Advanced Collections Protocol", but not present in "Web Distributed Authoring and Versioning (WebDAV) Ordered Collections Protocol"
"425": "Unordered Collection",
// RFC 2817: The client should switch to a different protocol such as TLS/1.0
"426": "Upgrade Required",
// RFC 6585: The origin server requires the request to be conditional. Intended to prevent "the 'lost update' problem, where a client GETs a resource's state, modifies it, and PUTs it back to the server, when meanwhile a third party has modified the state on the server, leading to a conflict."
"428": "Precondition Required",
// RFC 6585: The user has sent too many requests in a given amount of time. Intended for use with rate limiting schemes
"429": "Too Many Requests",
// RFC 6585
"431": "Request Header Fields Too Large",
// 500s: Server Errors
"500": "Internal Server Error",
"501": "Not Implemented",
"502": "Bad Gateway",
"503": "Service Unavailable",
"504": "Gateway Timeout",
"505": "HTTP Version Not Supported",
"509": "Bandwidth Limit Exceeded",
// RFC 2774: Further extensions to the request are required for the server to fulfill it
"510": "Not Extended",
// RFC 6585: The client needs to authenticate to gain network access. Intended for use by intercepting proxies used to control access to the network (e.g. "captive portals" used to require agreement to Terms of Service before granting full Internet access via a Wi-Fi hotspot)
"511": "Network Authentication Required",
);
const LP_LOGPARAMS = 1 << 16;
const LP_LEVELMASK = LP_LOGPARAMS - 1;
public struct HttpResponseInfo {
int code;
*data body;
softbool close = False;
*hash hdr;
bool reply_sent = False;
string log;
string errlog;
};
public struct HttpHandlerResponseInfo {
int code;
auto body;
softbool close = False;
*hash hdr;
bool reply_sent = False;
string log;
string errlog;
};
string http_get_url_from_bind(softstring bind, *string host);
hash<Util::UriQueryInfo> parse_uri_query(string path);
nothing http_set_reply_headers(Socket s, hash cx, reference rv, *string server_string);
string http_mask_data(string msg);
};
class HttpServer::AbstractLogger {
public:
abstract log(string fmt);
abstract logError(string fmt);
logArgs(*softlist args);
logErrorArgs(*softlist args);
};
class HttpServer::HttpListenerInterface : public HttpServer::AbstractLogger {
public:
abstract addUserThreadContext(hash uctx);
abstract auto removeUserThreadContext(*string k);
};
class HttpServer::AbstractAuthenticator {
public:
bool requiresAuthentication();
string getRealm();
authenticate(string user, string pass = "");
authenticateByIP(string ip, reference<string> user);
private:
hash getAuthHeader();
public:
private:
hash<HttpResponseInfo> do401(string msg = "Authentication is required to access this server");
public:
*hash<HttpResponseInfo> authenticateRequest(HttpListenerInterface listener, hash hdr, reference<hash> cx);
};
class HttpServer::PermissiveAuthenticator : public HttpServer::AbstractAuthenticator {
public:
*hash<HttpResponseInfo> authenticateRequest(HttpListenerInterface listener, hash hdr, reference<hash> cx);
};
class HttpServer::AbstractStreamRequest {
public:
private:
public:
private :
HttpListenerInterface listener;
AbstractHttpRequestHandler handler;
Socket s;
hash cx;
hash hdr;
auto body;
timeout timeout_ms = HttpServer::DefaultTimeout;
public:
constructor(HttpListenerInterface n_listener, AbstractHttpRequestHandler n_handler, Socket n_s, hash n_cx, hash n_hdr, auto n_body);
hash<HttpHandlerResponseInfo> handleRequest();
private:
hash<HttpHandlerResponseInfo> sendResponse();
public:
private:
hash<HttpHandlerResponseInfo> getResponseHeaderMessage();
public:
private:
nothing recv(hash v);
public:
private:
auto send();
public:
private:
logChunk(bool send, int size);
public:
private:
hash<HttpResponseInfo> getResponseHeaderMessageImpl();
public:
private:
nothing recvImpl(hash v);
public:
private:
auto sendImpl();
public:
};
class HttpServer::AbstractHttpRequestHandler {
public:
public :
*AbstractAuthenticator auth;
bool decompress = True;
bool decompress_to_string = True;
bool stream;
timeout timeout_ms = HttpServer::DefaultTimeout;
const NotificationThreadKey = "_AHRH_pc";
const PersistenceThreadKey = "_AHRH_p";
public:
constructor(*AbstractAuthenticator n_auth, softbool n_stream = False);
bool isPersistent();
setPersistent(bool p = True);
notifyClosed(*code c);
string maskData(string msg);
static staticNotificationCleanup();
static staticPersistenceCleanup();
nothing persistentClosed();
private:
nothing checkPersistent(hash cx, hash hdr);
public:
hash<HttpResponseInfo> handleRequest(hash cx, hash hdr, *data body);
hash<HttpResponseInfo> handleRequest(HttpListenerInterface listener, Socket s, hash cx, hash hdr, *data body);
private:
AbstractStreamRequest getStreamRequestImpl(HttpListenerInterface listener, Socket s, hash cx, hash hdr, *data body);
public:
static data decodeBody(string ce, binary body, *string enc);
static binary encodeBody(string ce, data body);
*data getMessageBody(Socket s, hash hdr, *data body, bool decode = True);
static *string getLogMessage(hash cx, hash api, reference params, *reference<string> args);
*hash saveThreadLocalData();
restoreThreadLocalData(*hash data);
static hash<HttpResponseInfo> makeResponse(int code, string fmt);
static hash<HttpResponseInfo> makeResponse(hash hdr, int code, string fmt);
static hash<HttpResponseInfo> makeResponse(int code, *data body, *hash hdr);
static hash<HttpResponseInfo> make400(string fmt);
static hash<HttpResponseInfo> make400(hash hdr, string fmt);
static hash<HttpResponseInfo> make501(string fmt);
static hash<HttpResponseInfo> make501(hash hdr, string fmt);
static hash<HttpResponseInfo> redirect(hash cx, hash hdr, string path);
};
class HttpServer::AbstractUrlHandler : public HttpServer::AbstractHttpRequestHandler {
public:
public :
string url_root;
public:
constructor(string n_url_root, *AbstractAuthenticator auth) ;
string getRelativePath(string path);
};
class HttpServer::AbstractHttpSocketHandler : public HttpServer::AbstractHttpRequestHandler {
public:
private :
bool stop = False;
hash lh;
hash lsh;
Mutex m();
public:
constructor(*AbstractAuthenticator auth) ;
start(softstring lid, hash cx, hash hdr, Socket s);
stop(softstring lid);
stop();
abstract hash handleRequest(hash cx, hash hdr, *data b);
private:
abstract startImpl(softstring lid, hash cx, hash hdr, Socket s);
public:
private:
stopImpl(string lid);
public:
private:
stopImpl();
public:
};
HttpServer::HttpResponseInfo::close
softbool close
set this key to True if the connection should be unconditionally closed when the handler returns ...
Definition: HttpServerUtil.qm.dox.h:223
HttpServer::HttpResponseInfo::reply_sent
bool reply_sent
this key can be set to True if the reply has already been sent (by a chunked callback for example) ...
Definition: HttpServerUtil.qm.dox.h:229
sprintf
string sprintf(string fmt,...)
HttpServer::AbstractStreamRequest::hdr
hash hdr
a hash of request headers
Definition: HttpServerUtil.qm.dox.h:469
HttpServer::ReadTimeout
const ReadTimeout
read timeout in ms
Definition: HttpServerUtil.qm.dox.h:99
HttpServer::HttpCodes
const HttpCodes
map of HTTP result codes and text messages
Definition: HttpServerUtil.qm.dox.h:102
HttpServer::AbstractStreamRequest
abstract class for streaming HTTP chunked requests/responses
Definition: HttpServerUtil.qm.dox.h:452
HttpServer::LP_LOGPARAMS
const LP_LOGPARAMS
bit for logging argument
Definition: HttpServerUtil.qm.dox.h:208
HttpServer::AbstractHttpRequestHandler
abstract class that all HTTP request handler objects must inherit from
Definition: HttpServerUtil.qm.dox.h:608
HttpServer::PermissiveAuthenticator
class providing automatic authentication for all requests
Definition: HttpServerUtil.qm.dox.h:420
HttpServer::AbstractHttpRequestHandler::auth
*AbstractAuthenticator auth
the optional AbstractAuthenticator for requests to this handler
Definition: HttpServerUtil.qm.dox.h:613
HttpServer::AbstractHttpSocketHandler::lh
hash lh
hash of listener references; this is to stop all connections associated with a particular listener ...
Definition: HttpServerUtil.qm.dox.h:818
HttpServer::HttpResponseInfo::hdr
*hash hdr
set this key to a hash of extra header information to be returned with the response ...
Definition: HttpServerUtil.qm.dox.h:226
True
const True
HttpServer::HttpListenerInterface
this abstract class defines the public interface of the private HttpListener class defined in the Htt...
Definition: HttpServerUtil.qm.dox.h:331
HttpServer::http_mask_data
string http_mask_data(string msg)
this function can be used to mask data in log messages
HttpServer::AbstractStreamRequest::handler
AbstractHttpRequestHandler handler
the request handler for the request
Definition: HttpServerUtil.qm.dox.h:463
HttpServer::HttpResponseInfo::errlog
string errlog
a string can be returned here which will be logged in the HTTP server&#39;s error log file (if any) ...
Definition: HttpServerUtil.qm.dox.h:235
binary
binary binary()
HttpServer::AbstractHttpRequestHandler::stream
bool stream
if the handler supports streaming requests/responses with chunked data
Definition: HttpServerUtil.qm.dox.h:622
HttpServer::HttpHandlerResponseInfo::errlog
string errlog
a string can be returned here which will be logged in the HTTP server&#39;s error log file (if any) ...
Definition: HttpServerUtil.qm.dox.h:259
False
const False
HttpServer::http_get_url_from_bind
string http_get_url_from_bind(softstring bind, *string host)
returns a complete URL from a bind address
HttpServer::AbstractAuthenticator
abstract base class for external authentication
Definition: HttpServerUtil.qm.dox.h:348
HttpServer::AbstractStreamRequest::cx
hash cx
the call context variable
Definition: HttpServerUtil.qm.dox.h:467
HttpServer::AbstractStreamRequest::s
Socket s
the Socket object for the response
Definition: HttpServerUtil.qm.dox.h:465
HttpServer::HttpServerVersion
const HttpServerVersion
version of the HttpServer&#39;s implementation
Definition: HttpServerUtil.qm.dox.h:90
HttpServer::HttpResponseInfo::body
*data body
the message body to return in the response; if this key is returned, then the reply is sent immediate...
Definition: HttpServerUtil.qm.dox.h:220
HttpServer::HttpHandlerResponseInfo::hdr
*hash hdr
set this key to a hash of extra header information to be returned with the response ...
Definition: HttpServerUtil.qm.dox.h:250
HttpServer::AbstractStreamRequest::listener
HttpListenerInterface listener
an HttpListenerInterface object for the listener serving the request for logging purposes ...
Definition: HttpServerUtil.qm.dox.h:461
HttpServer::AbstractLogger
this abstract class defines the interface for classes that provide logging methods ...
Definition: HttpServerUtil.qm.dox.h:304
HttpServer::AbstractStreamRequest::body
auto body
any message body given in a non-chunked request; could already be deserialized
Definition: HttpServerUtil.qm.dox.h:471
HttpServer::HttpHandlerResponseInfo::code
int code
the HTTP return code (see HttpServer::HttpCodes for possible values)
Definition: HttpServerUtil.qm.dox.h:241
HttpServer::DefaultTimeout
const DefaultTimeout
default timeout in ms
Definition: HttpServerUtil.qm.dox.h:96
HttpServer::HttpHandlerResponseInfo::log
string log
a string can be returned here which will be logged in the HTTP server&#39;s log file (if any) ...
Definition: HttpServerUtil.qm.dox.h:256
HttpServer::HttpResponseInfo::code
int code
the HTTP return code (see HttpServer::HttpCodes for possible values)
Definition: HttpServerUtil.qm.dox.h:217
HttpServer::AbstractHttpSocketHandler
abstract class that all HTTP dedicated socket handler objects must inherit from
Definition: HttpServerUtil.qm.dox.h:810
HttpServer::AbstractUrlHandler
abstract class for HTTP request handlers anchored at a specific URL
Definition: HttpServerUtil.qm.dox.h:786
HttpServer::HttpHandlerResponseInfo
the return value of HTTP handler methods with potentially unserialized message bodies ...
Definition: HttpServerUtil.qm.dox.h:239
HttpServer::parse_uri_query
hash< Util::UriQueryInfo > parse_uri_query(string path)
parses a URI path for a arguments and a method; where the method is the part of the path before the f...
HttpServer::LP_LEVELMASK
const LP_LEVELMASK
mask for the log level
Definition: HttpServerUtil.qm.dox.h:211
HttpServer::HttpServerString
const HttpServerString
default HTTP server string
Definition: HttpServerUtil.qm.dox.h:93
HttpServer
the main namespace for the HttpServer and HttpServerUtil modules
Definition: HttpServerUtil.qm.dox.h:88
HttpServer::HttpResponseInfo
the return value of HTTP handler methods where any message body has been serialized for sending over ...
Definition: HttpServerUtil.qm.dox.h:215
HttpServer::http_set_reply_headers
nothing http_set_reply_headers(Socket s, hash cx, reference rv, *string server_string)
helper function for setting HTTP response headers
hash
hash hash(object obj)
HttpServer::AbstractUrlHandler::url_root
string url_root
root part of URL for matching requests
Definition: HttpServerUtil.qm.dox.h:791
HttpServer::HttpHandlerResponseInfo::body
auto body
the message body to return in the response; for higher-level handlers this can be any data type that ...
Definition: HttpServerUtil.qm.dox.h:244
HttpServer::AbstractHttpSocketHandler::lsh
hash lsh
hash of listener stop flags
Definition: HttpServerUtil.qm.dox.h:821
HttpServer::HttpResponseInfo::log
string log
a string can be returned here which will be logged in the HTTP server&#39;s log file (if any) ...
Definition: HttpServerUtil.qm.dox.h:232