Qore HttpServerUtil Module Reference  0.3.11.1
HttpServerUtil.qm.dox.h
1 // -*- mode: c++; indent-tabs-mode: nil -*-
2 // @file HttpServerUtil.qm HTTP server base code
3 
4 /* HttpServerUtil.qm Copyright (C) 2014 - 2016 David Nichols
5 
6  Permission is hereby granted, free of charge, to any person obtaining a
7  copy of this software and associated documentation files (the "Software"),
8  to deal in the Software without restriction, including without limitation
9  the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  and/or sell copies of the Software, and to permit persons to whom the
11  Software is furnished to do so, subject to the following conditions:
12 
13  The above copyright notice and this permission notice shall be included in
14  all copies or substantial portions of the Software.
15 
16  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  DEALINGS IN THE SOFTWARE.
23 */
24 
25 // need mime definitions
26 
27 
28 
74 
79 namespace HttpServer {
81  const HttpServerVersion = "0.3.11.1";
82 
84  const HttpServerString = sprintf("Qore-HTTP-Server/%s", HttpServerVersion);
85 
87  const DefaultTimeout = 30s; // recvs timeout after 30 seconds
88 
91 
93  const HttpCodes = (
94  // 100s: Informational
95  "100": "Continue",
96  "101": "Switching Protocols",
97 
98  // RFC 2518: WebDAV
99  "102": "Processing",
100 
101  // 200s: Success
102  "200": "OK",
103  "201": "Created",
104  "202": "Accepted",
105  "203": "Non-Authoritative Information",
106  "204": "No Content",
107  "205": "Reset Content",
108  "206": "Partial Content",
109 
110  // 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
111  "207": "Multi-Status",
112 
113  // 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
114  "208": "Already Reported",
115 
116  // RFC 3229
117  "226": "IM Used",
118 
119  // 300s: Redirection
120  "300": "Multiple Choices",
121  "301": "Moved Permanently",
122  "302": "Found",
123  "303": "See Other",
124  "304": "Not Modified",
125  "305": "Use Proxy",
126  //"306": "(Reserved)",
127  "307": "Temporary Redirect",
128 
129  // 400s: Client Errors
130  "400": "Bad Request",
131  "401": "Unauthorized",
132  "402": "Payment Required",
133  "403": "Forbidden",
134  "404": "Not Found",
135  "405": "Method Not Allowed",
136  "406": "Not Acceptable",
137  "407": "Proxy Authentication Required",
138  "408": "Request Timeout",
139  "409": "Conflict",
140  "410": "Gone",
141  "411": "Length Required",
142  "412": "Precondition Failed",
143  "413": "Request Entity Too Large",
144  "414": "Request-URI Too Long",
145  "415": "Unsupported Media Type",
146  "416": "Requested Range Not Satisfiable",
147  "417": "Expectation Failed",
148 
149  // RFC 2324: http://tools.ietf.org/html/rfc2324
150  "418": "I'm a teapot",
151 
152  // Returned by the Twitter Search and Trends API when the client is being rate limited
153  "420": "Enhance Yextern Calm",
154 
155  // RFC 4918: WebDAV: The request was well-formed but was unable to be followed due to semantic errors
156  "422": "Unprocessable Entity",
157 
158  // RFC 4918: WebDAV: The resource that is being accessed is locked
159  "423": "Locked",
160 
161  // RFC 4918: WebDAV: The request failed due to failure of a previous request (e.g. a PROPPATCH)
162  "424": "Failed Dependency",
163 
164  // Internet draft: Defined in drafts of "WebDAV Advanced Collections Protocol", but not present in "Web Distributed Authoring and Versioning (WebDAV) Ordered Collections Protocol"
165  "425": "Unordered Collection",
166 
167  // RFC 2817: The client should switch to a different protocol such as TLS/1.0
168  "426": "Upgrade Required",
169 
170  // 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."
171  "428": "Precondition Required",
172 
173  // RFC 6585: The user has sent too many requests in a given amount of time. Intended for use with rate limiting schemes
174  "429": "Too Many Requests",
175 
176  // RFC 6585
177  "431": "Request Header Fields Too Large",
178 
179  // 500s: Server Errors
180  "500": "Internal Server Error",
181  "501": "Not Implemented",
182  "502": "Bad Gateway",
183  "503": "Service Unavailable",
184  "504": "Gateway Timeout",
185  "505": "HTTP Version Not Supported",
186  "509": "Bandwidth Limit Exceeded",
187 
188  // RFC 2774: Further extensions to the request are required for the server to fulfill it
189  "510": "Not Extended",
190 
191  // 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)
192  "511": "Network Authentication Required",
193  );
194 
198  const LP_LOGPARAMS = 1 << 16;
200 
204 
206 
209  string http_get_url_from_bind(softstring bind, *string host);
210 
211 
213 
221  hash parse_uri_query(string path);
222 
223 
225  nothing http_set_reply_headers(Socket s, hash cx, reference rv, *string server_string);
226 
227 };
228 
231 
232 public:
234 
236  abstract log(string fmt);
237 
239 
241  abstract logError(string fmt);
242 
244 
246  logArgs(*softlist args);
247 
248 
250 
252  logErrorArgs(*softlist args);
253 
254 };
255 
258 
259 public:
261 
263  abstract addUserThreadContext(hash uctx);
264 
266 
268  abstract any removeUserThreadContext(*string k);
269 };
270 
272 
275 
276 public:
278 
280  bool requiresAuthentication();
281 
282 
284 
286  string getRealm();
287 
288 
290 
296  authenticate(string user, string pass = "");
297 
298 
300 
306  authenticateByIP(string ip, reference user);
307 
308 
309  private hash getAuthHeader();
310 
311 
312  private hash do401(string msg = "Authentication is required to access this server");
313 
314 
316 
325  *hash authenticateRequest(HttpListenerInterface listener, hash hdr, reference cx);
326 
327 };
328 
331 
332 public:
334 
340  *hash authenticateRequest(HttpListenerInterface listener, hash hdr, reference cx);
341 
342 };
343 
345 
354 
355 public:
356 private:
357 
358 public:
359 
360  private :
366  Socket s;
372  any body;
375 
376 public:
377 
379 
389  constructor(HttpListenerInterface n_listener, AbstractHttpRequestHandler n_handler, Socket n_s, hash n_cx, hash n_hdr, any n_body);
390 
391 
394 
395 
397 
402  private hash sendResponse();
403 
404 
406 
415  private hash getResponseHeaderMessage();
416 
417 
419 
421  private nothing recv(hash v);
422 
423 
425  private any send();
426 
427 
428  private logChunk(bool send, int size);
429 
430 
432 
444 
445 
447 
456  private nothing recvImpl(hash v);
457 
458 
460 
463  private any sendImpl();
464 
465 };
466 
468 
476 
477 public:
478  public :
481 
483  bool decompress = True;
484 
487 
489  bool stream;
490 
493 
495  const NotificationThreadKey = "_AHRH_pc";
496 
498  const PersistenceThreadKey = "_AHRH_p";
499 
500 public:
501 
503 
506  constructor(*AbstractAuthenticator n_auth, softbool n_stream = False);
507 
508 
510  bool isPersistent();
511 
512 
514  setPersistent(bool p = True);
515 
516 
518  notifyClosed(*code c);
519 
520 
522  static staticNotificationCleanup();
523 
525  static staticPersistenceCleanup();
526 
528  nothing persistentClosed();
529 
530 
532  private nothing checkPersistent(hash cx, hash hdr);
533 
534 
536 
560  hash handleRequest(hash cx, hash hdr, *data body);
561 
562 
564  hash handleRequest(HttpListenerInterface listener, Socket s, hash cx, hash hdr, *data body);
565 
566 
568  private AbstractStreamRequest getStreamRequestImpl(HttpListenerInterface listener, Socket s, hash cx, hash hdr, *data body);
569 
570 
572  static data decodeBody(string ce, binary body, *string enc);
573 
575  static binary encodeBody(string ce, data body);
576 
578  *data getMessageBody(Socket s, hash hdr, *data body, bool decode = True);
579 
580 
582 
589  static *string getLogMessage(hash cx, hash api, reference params, *reference args);
590 
592 
595 
596 
598 
601 
602 
604  static hash makeResponse(int code, string fmt);
605 
607  static hash makeResponse(hash hdr, int code, string fmt);
608 
610  static hash makeResponse(int code, *data body, *hash hdr);
611 
613  static hash make400(string fmt);
614 
616  static hash make400(hash hdr, string fmt);
617 
619  static hash make501(string fmt);
620 
622  static hash make501(hash hdr, string fmt);
623 
625  static hash redirect(hash cx, hash hdr, string path);
626 };
627 
630 
631 public:
632  public :
634  string url_root;
635 
636 public:
637 
639 
642  constructor(string n_url_root, *AbstractAuthenticator auth) ;
643 
644 
646  string getRelativePath(string path);
647 
648 };
649 
651 
654 
655 public:
656  private :
658  bool stop = False;
659 
662 
665 
667  Mutex m();
668 
669 public:
670 
672 
675 
676 
678 
693  start(softstring lid, hash cx, hash hdr, Socket s);
694 
695 
697 
701  stop(softstring lid);
702 
703 
705 
707  stop();
708 
709 
711 
738  abstract hash handleRequest(hash cx, hash hdr, *data b);
739 
741 
756  private abstract startImpl(softstring lid, hash cx, hash hdr, Socket s);
757 
759 
761  private stopImpl(string lid);
762 
763 
765  private stopImpl();
766 
767 };
string sprintf(string fmt,...)
logErrorArgs(*softlist args)
calls logError() with the given args
hash hdr
a hash of request headers
Definition: HttpServerUtil.qm.dox.h:370
private nothing recvImpl(hash v)
callback method for receiving chunked data; the default implementation in this base class does nothin...
const ReadTimeout
read timeout in ms
Definition: HttpServerUtil.qm.dox.h:90
const HttpCodes
map of HTTP result codes and text messages
Definition: HttpServerUtil.qm.dox.h:93
abstract class for streaming HTTP chunked requests/responses
Definition: HttpServerUtil.qm.dox.h:353
abstract hash handleRequest(hash cx, hash hdr, *data b)
called by the HTTP server to handle incoming HTTP requests
const LP_LOGPARAMS
bit for logging argument
Definition: HttpServerUtil.qm.dox.h:199
string getRealm()
returns the authentication realm as a string
abstract class that all HTTP request handler objects must inherit from
Definition: HttpServerUtil.qm.dox.h:475
class providing automatic authentication for all requests
Definition: HttpServerUtil.qm.dox.h:330
*AbstractAuthenticator auth
the optional AbstractAuthenticator for requests to this handler
Definition: HttpServerUtil.qm.dox.h:480
abstract log(string fmt)
called to log information to the registered log code
hash lh
hash of listener references; this is to stop all connections associated with a particular listener ...
Definition: HttpServerUtil.qm.dox.h:661
const True
start(softstring lid, hash cx, hash hdr, Socket s)
called from the HTTP server after the handleRequest() method indicates that a dedicated connection sh...
string getRelativePath(string path)
returns the relative path anchored from the url_root if possible; URI query arguments are stripped of...
this abstract class defines the public interface of the private HttpListener class defined in the Htt...
Definition: HttpServerUtil.qm.dox.h:257
*hash authenticateRequest(HttpListenerInterface listener, hash hdr, reference cx)
primary method called to authenticate each request
*data getMessageBody(Socket s, hash hdr, *data body, bool decode=True)
optionally retrieves and post-processes any message body
private hash sendResponse()
called to either create the response hash or send a chunked response directly
AbstractHttpRequestHandler handler
the request handler for the request
Definition: HttpServerUtil.qm.dox.h:364
bool decompress
if POSTed data should be decompressed automatically if there is content-encoding
Definition: HttpServerUtil.qm.dox.h:483
abstract private startImpl(softstring lid, hash cx, hash hdr, Socket s)
called from the HTTP server after the handleRequest() method indicates that a dedicated connection sh...
constructor(HttpListenerInterface n_listener, AbstractHttpRequestHandler n_handler, Socket n_s, hash n_cx, hash n_hdr, any n_body)
creates the object with the given attributes
private hash getResponseHeaderMessageImpl()
this method should return the response message description hash
binary binary()
bool stream
if the handler supports streaming requests/responses with chunked data
Definition: HttpServerUtil.qm.dox.h:489
constructor(string n_url_root, *AbstractAuthenticator auth)
creates the object based on the URL root and optional authenticator
Mutex m()
listener reference hash mutex
private stopImpl()
called from the HTTP server when the socket should be closed due to an external request; the start() ...
static hash make501(string fmt)
creates a hash for an HTTP 501 error response with the response message body as a string ...
const False
bool requiresAuthentication()
called to check if the connection requires authentication
notifyClosed(*code c)
calls the argument when the persistent connection is closed
string http_get_url_from_bind(softstring bind, *string host)
returns a complete URL from a bind address
abstract base class for external authentication
Definition: HttpServerUtil.qm.dox.h:274
abstract any removeUserThreadContext(*string k)
removes the given key from the "uctx" context key; if no argument is provided, then the "uctx" contex...
static staticNotificationCleanup()
removes the thread-local data key in case the object is destroyed in another thread ...
static hash makeResponse(int code, string fmt)
creates a hash for an HTTP response with the response code and the response message body as a formatt...
static hash make400(string fmt)
creates a hash for an HTTP 400 error response with the response message body as a string ...
restoreThreadLocalData(*hash data)
called after handleRequest() with any data returned from saveThreadData()
private nothing recv(hash v)
this is the primary callback for receiving chunked data; data will be logged, and then recvImpl() is ...
timeout timeout_ms
send and receive timeout
Definition: HttpServerUtil.qm.dox.h:374
stop()
called from the HTTP server when the socket should be closed due to an external request; the start() ...
hash cx
the call context variable
Definition: HttpServerUtil.qm.dox.h:368
Socket s
the Socket object for the response
Definition: HttpServerUtil.qm.dox.h:366
private any sendImpl()
callback method for sending chunked data; the default implementation in this base class does nothing ...
const HttpServerVersion
version of the HttpServer's implementation
Definition: HttpServerUtil.qm.dox.h:81
static staticPersistenceCleanup()
removes the thread-local data key in case the object is destroyed in another thread ...
constructor(*AbstractAuthenticator auth)
create the object optionally with the given AbstractAuthenticator
*hash authenticateRequest(HttpListenerInterface listener, hash hdr, reference cx)
primary method called to authenticate each request
hash 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...
HttpListenerInterface listener
an HttpListenerInterface object for the listener serving the request for logging purposes ...
Definition: HttpServerUtil.qm.dox.h:362
static binary encodeBody(string ce, data body)
encodes a message body with content-encoding
static *string getLogMessage(hash cx, hash api, reference params, *reference args)
helper method for handling log messages
this abstract class defines the interface for classes that provide logging methods ...
Definition: HttpServerUtil.qm.dox.h:230
abstract addUserThreadContext(hash uctx)
adds user-defined data to be returned in the "uctx" context key when serving requests from this liste...
const DefaultTimeout
default timeout in ms
Definition: HttpServerUtil.qm.dox.h:87
private any send()
this is the primary callback for sending chunked responses; first sendImpl() is called to get the raw...
abstract class that all HTTP dedicated socket handler objects must inherit from
Definition: HttpServerUtil.qm.dox.h:653
abstract class for HTTP request handlers anchored at a specific URL
Definition: HttpServerUtil.qm.dox.h:629
static data decodeBody(string ce, binary body, *string enc)
decodes a message body with content-encoding
hash handleRequest(hash cx, hash hdr, *data body)
will be called when a request is received that should be directed to the handler
const LP_LEVELMASK
mask for the log level
Definition: HttpServerUtil.qm.dox.h:202
private hash getResponseHeaderMessage()
this method returns the response message description hash by calling getResponseHeaderMessageImpl() ...
constructor(*AbstractAuthenticator n_auth, softbool n_stream=False)
create the object optionally with the given AbstractAuthenticator
const HttpServerString
default HTTP server string
Definition: HttpServerUtil.qm.dox.h:84
timeout timeout_ms
send and receive socket timeout in milliseconds
Definition: HttpServerUtil.qm.dox.h:492
bool decompress_to_string
if automatically decompressed POSTed data should be converted to a string (if False, then it will be decompressed to a binary)
Definition: HttpServerUtil.qm.dox.h:486
hash handleRequest()
handles the request
authenticate(string user, string pass="")
called to authenticate a user for a connection
the main namespace for the HttpServer and HttpServerUtil modules
Definition: HttpServerUtil.qm.dox.h:79
setPersistent(bool p=True)
called externally to notify the handler that the connection will be persistent
const NotificationThreadKey
thread-local key string for notification callbacks
Definition: HttpServerUtil.qm.dox.h:495
abstract logError(string fmt)
called to log error information to the registered error log code
*hash saveThreadLocalData()
called before handleRequest() any data returned here will be given to restoreThreadLocalData() after ...
private AbstractStreamRequest getStreamRequestImpl(HttpListenerInterface listener, Socket s, hash cx, hash hdr, *data body)
returns the AbstractStreamRequest object for handling chunked requests
logArgs(*softlist args)
calls log() with the given args
nothing http_set_reply_headers(Socket s, hash cx, reference rv, *string server_string)
helper function for setting HTTP response headers
authenticateByIP(string ip, reference user)
called when the connection requires authentication, but no authentication credentials were supplied...
hash hash(object obj)
string url_root
root part of URL for matching requests
Definition: HttpServerUtil.qm.dox.h:634
nothing persistentClosed()
called externally when a persistent connection is closed
static hash redirect(hash cx, hash hdr, string path)
generates a redirect hash for the given path
const PersistenceThreadKey
thread-local key string for the persistent flag
Definition: HttpServerUtil.qm.dox.h:498
hash lsh
hash of listener stop flags
Definition: HttpServerUtil.qm.dox.h:664
any body
any message body given in a non-chunked request; could already be deserialized
Definition: HttpServerUtil.qm.dox.h:372
bool isPersistent()
returns True if the current connection is persistent, False if not
private nothing checkPersistent(hash cx, hash hdr)
this method will throw an exception if a persistent connection cannot be granted