libcex  1.0.0
Modern C++11 embedded webserver library
core.hpp
Go to the documentation of this file.
1 //*************************************************************************
2 // File core.hpp
3 // Date 24.04.2018
4 // Copyright (c) 2018-2019 by Patrick Fial
5 //-------------------------------------------------------------------------
6 // cex Library core definitions
7 //*************************************************************************
8 
9 #ifndef __CORE_HPP__
10 #define __CORE_HPP__
11 
14 //***************************************************************************
15 // includes
16 //***************************************************************************
17 
18 #include <evhtp/evhtp.h>
19 #include <event2/thread.h>
20 
21 #include <thread>
22 #include <condition_variable>
23 #include <mutex>
24 #include <string>
25 #include <vector>
26 #include <regex>
27 
28 #include <plist.hpp>
29 #include <cex/cex_config.h>
30 
31 #define IO_BUFFER_SIZE 128*1024
32 
33 namespace cex
34 {
35 
36 //***************************************************************************
37 // definitions
38 //***************************************************************************
39 
40 enum ReturnValues
41 {
42  na= -1,
43  fail= na,
44  yes= 1,
45  no= 0,
46  success= 0,
47  done= 0
48 };
49 
53 enum Method
54 {
55  unknownMethod= na,
56 
57  methodGET, // 0 /*!< HTTP GET method */
58  methodHEAD, // 1
59  methodPOST, // 2
60  methodPUT, // 3MaMa
61  methodDELETE, // 4
62  methodOPTIONS, // 5
63  methodTRACE, // 6
64  methodCONNECT, // 7
65  methodPATCH, // 8
66  methodMKCOL, // 9
67  methodCOPY, // 10
68  methodMOVE, // 11
69  methodPROPFIND, // 12
70  methodPROPPATCH, // 13
71  methodLOCK, // 14
72  methodUNLOCK, // 15
73 
74  nMethods
75 };
76 
81 {
82  unknownProtocol= na,
83 
84  protocol10, // 0
85  protocol11, // 1
86 
87  nProtocols
88 };
89 
90 class Request;
91 class Response;
92 
94 const char* getLibraryVersion();
95 
96 //***************************************************************************
97 // types
98 //***************************************************************************
99 
100 typedef std::shared_ptr<Request> ReqPtr;
101 typedef std::shared_ptr<Response> ResPtr;
102 
108 typedef std::function<void(Request* req, Response* res, std::function<void()> next)> MiddlewareFunction;
109 
122 typedef std::function<void(Request* req, const char* data, size_t len)> UploadFunction;
123 
129 typedef std::function<bool(const char* name, const char* value)> PairCallbackFunction;
130 
131 typedef std::pair<std::string,bool> MimeType;
132 typedef std::unordered_map<std::string, MimeType> MimeTypes;
133 typedef std::unique_ptr<std::thread, std::function<void(std::thread* t)>> ThreadPtr;
134 typedef std::unique_ptr<event_base, std::function<void(event_base*)>> EventBasePtr;
135 
136 //***************************************************************************
137 // class Request
138 //***************************************************************************
172 class Request
173 {
174  friend class Server;
175  friend class Response;
176  friend class Middleware;
177 
178  public:
179 
183  Request(evhtp_request* req);
184 
185  // base request info
186 
187  Method getMethod();
189  int getPort();
190  const char* getHost();
191  const char* getUrl();
192  const char* getPath();
193  const char* getFile();
195  const char* getMiddlewarePath();
197  // HTTP header related
198 
203 
206  const char* get(const char* name);
207 
208  // URL query parameter related
209 
214 
217  const char* getQueryParam(const char* name);
218 
219  // request body
220 
221  const char* getBody();
222  size_t getBodyLength();
224  // CEX properties (sessionId, sslClientCert, ...)
225 
235 
236  private:
237 
238  void parse();
239 
240  static int keyValueIteratorCb(evhtp_kv_t * kv, void * arg);
241 
242  evhtp_request* req;
243  evhtp_path_t* uri;
244  evhtp_authority_t* authority;
245 
246  int evhtp_method;
247  int port;
248  std::string host;
249  Method method;
250  Protocol protocol;
251  std::string middlewarePath;
252  std::vector<char> body;
253 };
254 
255 //***************************************************************************
256 // class Response
257 //***************************************************************************
275 class Response
276 {
277  public:
278 
280  enum State
281  {
284  };
285 
290  enum Flags
291  {
292  fNoFlags= 0x0000,
293 
294  fCompression= 0x000F,
295  fCompressGZip= 0x0001,
297  };
298 
302  Response(evhtp_request* req);
303 
308  void set(const char* name, const char* value);
309 
314  void set(const char* name, int value);
315 
320  int end(const char* string, int status);
321 
327  int end(const char* buffer, size_t bufLen, int status);
328 
332  int end(int status);
333 
341  int stream(int status, std::istream* stream);
342 
347  bool isState(State aState) { return state == aState; }
348 
352  bool isDone() { return isState(stDone); }
353 
357  bool isPending() { return !isState(stDone); }
358 
361  void setFlags(int newFlags) { flags= newFlags; }
362 
364  int getFlags() { return flags; };
365 
366  private:
367 
368  static evhtp_res sendChunk(evhtp_connection_t* conn, void* arg);
369 
370  evhtp_request* req;
371  State state;
372  int flags;
373 };
374 
375 //***************************************************************************
376 // class Middleware
377 //***************************************************************************
384 {
385  friend class Server;
386 
387  public:
388 
390  enum Flags
391  {
392  fMatchContain= 0x001,
393  fMatchCompare= 0x002,
394  fMatchRegex= 0x004,
395  fMatching= 0x00F
396  };
397 
399  enum Type
400  {
403  };
404 
410  Middleware(const char* path, MiddlewareFunction func, int method= na, int flags= fMatchContain);
411  Middleware(const char* path, UploadFunction func, int method= na, int flags= fMatchContain);
412 
413  bool match(Request* req);
414  const char* getPath() { return path.c_str(); }
415 
416  private:
417 
418  int type;
419  int method;
420  int flags;
421  std::regex rep;
422  std::string path;
423  MiddlewareFunction func;
424  UploadFunction uploadFunc;
425 };
426 
427 //***************************************************************************
428 // class Server
429 //***************************************************************************
434 class Server
435 {
436  public:
437 
442  struct Context
443  {
444  Context(evhtp_request_t* request, Server* serv)
445  : req(new Request(request)), res(new Response(request)), serv(serv) {}
446 
447  ReqPtr req;
448  ResPtr res;
449  Server* serv;
450  };
451 
458  struct Config
459  {
460  Config();
461  Config(Config& other);
462  virtual ~Config();
463 
464  int port;
465  std::string address;
467  bool compress;
473  bool sslEnabled;
476 #ifdef CEX_WITH_SSL
477  int sslVerifyMode;
478  evhtp_ssl_cfg_t* sslConfig;
479 #endif
480  };
481 
483  Server();
484 
488  Server(Config& config);
489  virtual ~Server();
490 
491  // server
492 
496  int listen(bool block= true);
497 
503  int listen(std::string address, int port, bool block= true);
504 
506  int stop();
507 
508  // router
509 
511  void reset() { middleWares.clear(); }
512 
517  void use(MiddlewareFunction func);
518 
525  void use(const char* path, MiddlewareFunction func, int flags= Middleware::fMatchContain);
526 
531  void get(MiddlewareFunction func);
532 
539  void get(const char* path, MiddlewareFunction func, int flags= Middleware::fMatchContain);
540 
545  void put(MiddlewareFunction func);
546 
553  void put(const char* path, MiddlewareFunction func, int flags= Middleware::fMatchContain);
554 
559  void post(MiddlewareFunction func);
560 
567  void post(const char* path, MiddlewareFunction func, int flags= Middleware::fMatchContain);
568 
573  void head(MiddlewareFunction func);
574 
581  void head(const char* path, MiddlewareFunction func, int flags= Middleware::fMatchContain);
582 
587  void del(MiddlewareFunction func);
588 
595  void del(const char* path, MiddlewareFunction func, int flags= Middleware::fMatchContain);
596 
601  void connect(MiddlewareFunction func);
602 
609  void connect(const char* path, MiddlewareFunction func, int flags= Middleware::fMatchContain);
610 
615  void options(MiddlewareFunction func);
616 
623  void options(const char* path, MiddlewareFunction func, int flags= Middleware::fMatchContain);
624 
625 
630  void trace(MiddlewareFunction func);
631 
638  void trace(const char* path, MiddlewareFunction func, int flags= Middleware::fMatchContain);
639 
644  void patch(MiddlewareFunction func);
645 
652  void patch(const char* path, MiddlewareFunction func, int flags= Middleware::fMatchContain);
653 
654  // WEBDAV HTTP methods
655 
660  void mkcol(MiddlewareFunction func);
661 
668  void mkcol(const char* path, MiddlewareFunction func, int flags= Middleware::fMatchContain);
669 
674  void copy(MiddlewareFunction func);
675 
682  void copy(const char* path, MiddlewareFunction func, int flags= Middleware::fMatchContain);
683 
688  void move(MiddlewareFunction func);
689 
696  void move(const char* path, MiddlewareFunction func, int flags= Middleware::fMatchContain);
697 
702  void propfind(MiddlewareFunction func);
703 
710  void propfind(const char* path, MiddlewareFunction func, int flags= Middleware::fMatchContain);
711 
716  void proppatch(MiddlewareFunction func);
717 
724  void proppatch(const char* path, MiddlewareFunction func, int flags= Middleware::fMatchContain);
725 
730  void lock(MiddlewareFunction func);
731 
738  void lock(const char* path, MiddlewareFunction func, int flags= Middleware::fMatchContain);
739 
744  void unlock(MiddlewareFunction func);
745 
752  void unlock(const char* path, MiddlewareFunction func, int flags= Middleware::fMatchContain);
753 
754  // upload hooks to catch file uploads w/ streaming
755 
761  void uploads(UploadFunction func);
762 
770  void uploads(const char* path, UploadFunction func, Method method= methodPOST, int flags= Middleware::fMatchContain);
771 
772  // tools
773 
774  static MimeTypes* getMimeTypes() { return mimeTypes.get(); }
775  static void registerMimeType(const char* ext, const char* mime, bool binary);
776 
777  // SSL/TLS
778 
779 #ifdef CEX_WITH_SSL
780  void setSslOption(const char* option, const char* value);
781  void getSslClientInfo(Request* req);
782 #endif
783 
784  static void libraryInit();
785 
786  private:
787 
788  int start(bool block);
789 
790  static int initMimeTypes();
791 
792  static void handleRequest(evhtp_request* req, void* arg);
793  static evhtp_res handleHeaders(evhtp_request_t* request, evhtp_headers_t* hdr, void* arg);
794  static evhtp_res handleBody(evhtp_request_t* req, struct evbuffer* buf, void* arg);
795  static evhtp_res handleFinished(evhtp_request_t* req, void* arg);
796 
797 #ifdef CEX_WITH_SSL
798  static int verifyCert(int ok, X509_STORE_CTX* store);
799 #endif
800 
801  // members
802 
803  std::vector<std::unique_ptr<Middleware>> middleWares;
804  std::vector<std::unique_ptr<Middleware>> uploadWares;
805 
806  Config serverConfig;
807 
808  // server control
809 
810  EventBasePtr eventBase;
811  ThreadPtr backgroundThread;
812  std::mutex startMutex;
813  std::condition_variable startCond;
814  bool startSignaled;
815  bool started;
816 
817  // global/static stuff
818 
819  static bool initialized;
820  static std::mutex initMutex;
821  static std::unique_ptr<MimeTypes> mimeTypes;
822 };
823 
824 //***************************************************************************
825 } // namespace cex
826 
827 #endif // __CORE_HPP_
int getFlags()
Returns the currently set flags of the response object.
Definition: core.hpp:364
bool sslEnabled
Flag indicating whether or not SSL is enabled on the listener (default: false).
Definition: core.hpp:473
Protocol
Enumeration of available HTTP versions (HTTP 1.0 or HTTP 1.1)
Definition: core.hpp:80
bool parseSslInfo
Flag indicating whether or not SSL client info shall be parsed for each request (default: true).
Definition: core.hpp:470
int stop()
Stops the listener. If it was started within a background thread, the background thread is terminated...
Definition: server.cc:222
void uploads(UploadFunction func)
Attaches a special middleware function which receives request body data uploads in chunks.
Definition: server.cc:424
Definition: core.hpp:282
Definition: core.hpp:283
Definition: core.hpp:392
int port
HTTP/HTTPS listener port of the server.
Definition: core.hpp:464
int listen(bool block=true)
Starts the server with listener on address and port specified in the server Config struct.
Definition: server.cc:87
void setFlags(int newFlags)
Sets the response object flags.
Definition: core.hpp:361
void propfind(MiddlewareFunction func)
Attaches a middleware function for HTTP WEBDAV PROPFIND requests.
Definition: server.cc:382
Internal helper struct for handling libevhtp callback functions.
Definition: core.hpp:442
Protocol getProtocol()
Returns the HTTP protocol version (1.0 or 1.1)
Definition: request.cc:121
bool isDone()
Checks if state of the response is stDone.
Definition: core.hpp:352
State
State of the response.
Definition: core.hpp:280
Definition: core.hpp:296
int getPort()
Returns the port, if present in the URI.
Definition: request.cc:111
bool isPending()
Checks if state of the response is not stDone.
Definition: core.hpp:357
Serves as interface to the response which will be sent to the client. Contains functions for modifyin...
Definition: core.hpp:275
void head(MiddlewareFunction func)
Attaches a middleware function for HTTP HEAD requests.
Definition: server.cc:291
Response(evhtp_request *req)
Constructs a new Response object.
Definition: response.cc:27
const char * getBody()
Definition: request.cc:101
const char * getQueryParam(const char *name)
Returns the value of a URL query parameter.
Definition: request.cc:61
void move(MiddlewareFunction func)
Attaches a middleware function for WEBDAV MOVE requests.
Definition: server.cc:372
Structure transporting all configuration options of the embedded server. Note that certain middleware...
Definition: core.hpp:458
Method getMethod()
Returns the request's HTTP method.
Definition: request.cc:116
Definition: core.hpp:295
size_t getBodyLength()
Definition: request.cc:106
void lock(MiddlewareFunction func)
Attaches a middleware function for WEBDAV LOCK requests.
Definition: server.cc:402
void put(MiddlewareFunction func)
Attaches a middleware function for HTTP PUT requests.
Definition: server.cc:271
Definition: core.hpp:393
Represents a single middleware.
Definition: core.hpp:383
const char * getUrl()
Returns the full URL of the request.
Definition: request.cc:131
void set(const char *name, const char *value)
Sets a HTTP header to a given value.
Definition: response.cc:33
void mkcol(MiddlewareFunction func)
Attaches a middleware function for WEBDAV MKCOL requests.
Definition: server.cc:352
void get(MiddlewareFunction func)
Attaches a middleware function for HTTP GET requests.
Definition: server.cc:261
void eachQueryParam(PairCallbackFunction cb)
Iterates all URL query parameters of the request with the given callback function.
Definition: request.cc:75
std::function< void(Request *req, const char *data, size_t len)> UploadFunction
A function which is called by an upload Middleware when an incoming request matches.
Definition: core.hpp:122
int stream(int status, std::istream *stream)
Streams a response to the client with the supplied HTTP code.
Definition: response.cc:110
Flags
Flags for controlling the path matching behaviour.
Definition: core.hpp:390
const char * getMiddlewarePath()
Definition: request.cc:146
Method
Enumeration of available HTTP methods.
Definition: core.hpp:53
std::function< void(Request *req, Response *res, std::function< void()> next)> MiddlewareFunction
A function which is called by a standard Middleware when an incoming request matches.
Definition: core.hpp:108
const char * getFile()
Returns the file-portion of the URL of the request.
Definition: request.cc:141
std::function< bool(const char *name, const char *value)> PairCallbackFunction
A callback function which receives a name and a value parameter.
Definition: core.hpp:129
void copy(MiddlewareFunction func)
Attaches a middleware function for WEBDAV COPY requests.
Definition: server.cc:362
Implementation of a simple propertylist based on std::unordered_map
Definition: core.hpp:401
bool compress
Globally enable compression of outgoing responses (default: true).
Definition: core.hpp:467
bool isState(State aState)
Queries the state of the response.
Definition: core.hpp:347
Server()
Constructs a new server with the default config.
Definition: server.cc:49
void trace(MiddlewareFunction func)
Attaches a middleware function for HTTP TRACE requests.
Definition: server.cc:331
void options(MiddlewareFunction func)
Attaches a middleware function for HTTP OPTIONS requests.
Definition: server.cc:321
int threadCount
Controls the number of worker threads the server is going to use (default: 4).
Definition: core.hpp:474
void proppatch(MiddlewareFunction func)
Attaches a middleware function for WEBDAV PROPPATCH requests.
Definition: server.cc:392
const char * get(const char *name)
Returns the value of a HTTP header.
Definition: request.cc:37
void connect(MiddlewareFunction func)
Attaches a middleware function for HTTP CONNECT requests.
Definition: server.cc:311
Contains the current request and all of its preparsed properties.
Definition: core.hpp:172
void unlock(MiddlewareFunction func)
Attaches a middleware function for WEBDAV UNLOCK requests.
Definition: server.cc:412
PropertyList properties
A list of properties of the current request.
Definition: core.hpp:234
void eachHeader(PairCallbackFunction cb)
Iterates all HTTP headers of the request with the given callback function.
Definition: request.cc:49
Type
Type of middleware.
Definition: core.hpp:399
const char * getHost()
Returns the hostname of the request.
Definition: request.cc:126
void reset()
Removes all attached middlewares.
Definition: core.hpp:511
A simple list of properties implemented using std::unordered_map
Definition: plist.hpp:76
int end(const char *string, int status)
Sends a response to the client with the supplied HTTP code and payload text.
Definition: response.cc:58
void patch(MiddlewareFunction func)
Attaches a middleware function for HTTP PATCH requests.
Definition: server.cc:341
Core class of the embedded webserver. Manages a single HTTP/HTTPS listener and performs routing as de...
Definition: core.hpp:434
void post(MiddlewareFunction func)
Attaches a middleware function for HTTP POST requests.
Definition: server.cc:281
Flags
Flags describing features of the response. Currently this affects only compression.
Definition: core.hpp:290
Middleware(const char *path, MiddlewareFunction func, int method=na, int flags=fMatchContain)
Constructs a new middleware with the given parameters.
Definition: middleware.cc:27
void del(MiddlewareFunction func)
Attaches a middleware function for HTTP DEL requests.
Definition: server.cc:301
void use(MiddlewareFunction func)
Attaches a middleware function with no conditions.
Definition: server.cc:243
Definition: core.hpp:402
Request(evhtp_request *req)
Constructs a new Response object.
Definition: request.cc:27
Definition: core.hpp:394
const char * getPath()
Returns the path-portion of the URL of the request.
Definition: request.cc:136
std::string address
Bind address of the server.
Definition: core.hpp:465