1 /* Copyright (c) 2013-2017 the Civetweb developers 2 * Copyright (c) 2013 No Face Press, LLC 3 * 4 * License http://opensource.org/licenses/mit-license.php MIT License 5 */ 6 7 #ifndef CIVETSERVER_HEADER_INCLUDED 8 #define CIVETSERVER_HEADER_INCLUDED 9 #ifdef __cplusplus 10 11 #include "civetweb.h" 12 #include <map> 13 #include <stdexcept> 14 #include <string> 15 #include <vector> 16 17 #ifndef CIVETWEB_CXX_API 18 #if defined(_WIN32) 19 #if defined(CIVETWEB_CXX_DLL_EXPORTS) 20 #define CIVETWEB_CXX_API __declspec(dllexport) 21 #elif defined(CIVETWEB_CXX_DLL_IMPORTS) 22 #define CIVETWEB_CXX_API __declspec(dllimport) 23 #else 24 #define CIVETWEB_CXX_API 25 #endif 26 #elif __GNUC__ >= 4 27 #define CIVETWEB_CXX_API __attribute__((visibility("default"))) 28 #else 29 #define CIVETWEB_CXX_API 30 #endif 31 #endif 32 33 // forward declaration 34 class CivetServer; 35 36 /** 37 * Exception class for thrown exceptions within the CivetHandler object. 38 */ 39 class CIVETWEB_CXX_API CivetException : public std::runtime_error 40 { 41 public: CivetException(const std::string & msg)42 CivetException(const std::string &msg) : std::runtime_error(msg) 43 { 44 } 45 }; 46 47 /** 48 * Basic interface for a URI request handler. Handlers implementations 49 * must be reentrant. 50 */ 51 class CIVETWEB_CXX_API CivetHandler 52 { 53 public: 54 /** 55 * Destructor 56 */ ~CivetHandler()57 virtual ~CivetHandler() 58 { 59 } 60 61 /** 62 * Callback method for GET request. 63 * 64 * @param server - the calling server 65 * @param conn - the connection information 66 * @returns true if implemented, false otherwise 67 */ 68 virtual bool handleGet(CivetServer *server, struct mg_connection *conn); 69 70 /** 71 * Callback method for POST request. 72 * 73 * @param server - the calling server 74 * @param conn - the connection information 75 * @returns true if implemented, false otherwise 76 */ 77 virtual bool handlePost(CivetServer *server, struct mg_connection *conn); 78 79 /** 80 * Callback method for HEAD request. 81 * 82 * @param server - the calling server 83 * @param conn - the connection information 84 * @returns true if implemented, false otherwise 85 */ 86 virtual bool handleHead(CivetServer *server, struct mg_connection *conn); 87 88 /** 89 * Callback method for PUT request. 90 * 91 * @param server - the calling server 92 * @param conn - the connection information 93 * @returns true if implemented, false otherwise 94 */ 95 virtual bool handlePut(CivetServer *server, struct mg_connection *conn); 96 97 /** 98 * Callback method for DELETE request. 99 * 100 * @param server - the calling server 101 * @param conn - the connection information 102 * @returns true if implemented, false otherwise 103 */ 104 virtual bool handleDelete(CivetServer *server, struct mg_connection *conn); 105 106 /** 107 * Callback method for OPTIONS request. 108 * 109 * @param server - the calling server 110 * @param conn - the connection information 111 * @returns true if implemented, false otherwise 112 */ 113 virtual bool handleOptions(CivetServer *server, struct mg_connection *conn); 114 115 /** 116 * Callback method for PATCH request. 117 * 118 * @param server - the calling server 119 * @param conn - the connection information 120 * @returns true if implemented, false otherwise 121 */ 122 virtual bool handlePatch(CivetServer *server, struct mg_connection *conn); 123 }; 124 125 /** 126 * Basic interface for a URI authorization handler. Handler implementations 127 * must be reentrant. 128 */ 129 class CIVETWEB_CXX_API CivetAuthHandler 130 { 131 public: 132 /** 133 * Destructor 134 */ ~CivetAuthHandler()135 virtual ~CivetAuthHandler() 136 { 137 } 138 139 /** 140 * Callback method for authorization requests. It is up the this handler 141 * to generate 401 responses if authorization fails. 142 * 143 * @param server - the calling server 144 * @param conn - the connection information 145 * @returns true if authorization succeeded, false otherwise 146 */ 147 virtual bool authorize(CivetServer *server, struct mg_connection *conn) = 0; 148 }; 149 150 /** 151 * Basic interface for a websocket handler. Handlers implementations 152 * must be reentrant. 153 */ 154 class CIVETWEB_CXX_API CivetWebSocketHandler 155 { 156 public: 157 /** 158 * Destructor 159 */ ~CivetWebSocketHandler()160 virtual ~CivetWebSocketHandler() 161 { 162 } 163 164 /** 165 * Callback method for when the client intends to establish a websocket 166 *connection, before websocket handshake. 167 * 168 * @param server - the calling server 169 * @param conn - the connection information 170 * @returns true to keep socket open, false to close it 171 */ 172 virtual bool handleConnection(CivetServer *server, 173 const struct mg_connection *conn); 174 175 /** 176 * Callback method for when websocket handshake is successfully completed, 177 *and connection is ready for data exchange. 178 * 179 * @param server - the calling server 180 * @param conn - the connection information 181 */ 182 virtual void handleReadyState(CivetServer *server, 183 struct mg_connection *conn); 184 185 /** 186 * Callback method for when a data frame has been received from the client. 187 * 188 * @param server - the calling server 189 * @param conn - the connection information 190 * @bits: first byte of the websocket frame, see websocket RFC at 191 *http://tools.ietf.org/html/rfc6455, section 5.2 192 * @data, data_len: payload, with mask (if any) already applied. 193 * @returns true to keep socket open, false to close it 194 */ 195 virtual bool handleData(CivetServer *server, 196 struct mg_connection *conn, 197 int bits, 198 char *data, 199 size_t data_len); 200 201 /** 202 * Callback method for when the connection is closed. 203 * 204 * @param server - the calling server 205 * @param conn - the connection information 206 */ 207 virtual void handleClose(CivetServer *server, 208 const struct mg_connection *conn); 209 }; 210 211 /** 212 * CivetCallbacks 213 * 214 * wrapper for mg_callbacks 215 */ 216 struct CIVETWEB_CXX_API CivetCallbacks : public mg_callbacks { 217 CivetCallbacks(); 218 }; 219 220 /** 221 * CivetServer 222 * 223 * Basic class for embedded web server. This has an URL mapping built-in. 224 */ 225 class CIVETWEB_CXX_API CivetServer 226 { 227 public: 228 /** 229 * Constructor 230 * 231 * This automatically starts the sever. 232 * It is good practice to call getContext() after this in case there 233 * were errors starting the server. 234 * 235 * Note: CivetServer should not be used as a static instance in a Windows 236 * DLL, since the constructor creates threads and the destructor joins 237 * them again (creating/joining threads should not be done in static 238 * constructors). 239 * 240 * @param options - the web server options. 241 * @param callbacks - optional web server callback methods. 242 * 243 * @throws CivetException 244 */ 245 CivetServer(const char **options, 246 const struct CivetCallbacks *callbacks = 0, 247 const void *UserContext = 0); 248 CivetServer(std::vector<std::string> options, 249 const struct CivetCallbacks *callbacks = 0, 250 const void *UserContext = 0); 251 252 /** 253 * Destructor 254 */ 255 virtual ~CivetServer(); 256 257 /** 258 * close() 259 * 260 * Stops server and frees resources. 261 */ 262 void close(); 263 264 /** 265 * getContext() 266 * 267 * @return the context or 0 if not running. 268 */ 269 const struct mg_context * getContext()270 getContext() const 271 { 272 return context; 273 } 274 275 /** 276 * addHandler(const std::string &, CivetHandler *) 277 * 278 * Adds a URI handler. If there is existing URI handler, it will 279 * be replaced with this one. 280 * 281 * URI's are ordered and prefix (REST) URI's are supported. 282 * 283 * @param uri - URI to match. 284 * @param handler - handler instance to use. 285 */ 286 void addHandler(const std::string &uri, CivetHandler *handler); 287 288 void addHandler(const std::string & uri,CivetHandler & handler)289 addHandler(const std::string &uri, CivetHandler &handler) 290 { 291 addHandler(uri, &handler); 292 } 293 294 /** 295 * addWebSocketHandler 296 * 297 * Adds a WebSocket handler for a specific URI. If there is existing URI 298 *handler, it will 299 * be replaced with this one. 300 * 301 * URI's are ordered and prefix (REST) URI's are supported. 302 * 303 * @param uri - URI to match. 304 * @param handler - handler instance to use. 305 */ 306 void addWebSocketHandler(const std::string &uri, 307 CivetWebSocketHandler *handler); 308 309 void addWebSocketHandler(const std::string & uri,CivetWebSocketHandler & handler)310 addWebSocketHandler(const std::string &uri, CivetWebSocketHandler &handler) 311 { 312 addWebSocketHandler(uri, &handler); 313 } 314 315 /** 316 * removeHandler(const std::string &) 317 * 318 * Removes a handler. 319 * 320 * @param uri - the exact URL used in addHandler(). 321 */ 322 void removeHandler(const std::string &uri); 323 324 /** 325 * removeWebSocketHandler(const std::string &) 326 * 327 * Removes a web socket handler. 328 * 329 * @param uri - the exact URL used in addWebSocketHandler(). 330 */ 331 void removeWebSocketHandler(const std::string &uri); 332 333 /** 334 * addAuthHandler(const std::string &, CivetAuthHandler *) 335 * 336 * Adds a URI authorization handler. If there is existing URI authorization 337 * handler, it will be replaced with this one. 338 * 339 * URI's are ordered and prefix (REST) URI's are supported. 340 * 341 * @param uri - URI to match. 342 * @param handler - authorization handler instance to use. 343 */ 344 void addAuthHandler(const std::string &uri, CivetAuthHandler *handler); 345 346 void addAuthHandler(const std::string & uri,CivetAuthHandler & handler)347 addAuthHandler(const std::string &uri, CivetAuthHandler &handler) 348 { 349 addAuthHandler(uri, &handler); 350 } 351 352 /** 353 * removeAuthHandler(const std::string &) 354 * 355 * Removes an authorization handler. 356 * 357 * @param uri - the exact URL used in addAuthHandler(). 358 */ 359 void removeAuthHandler(const std::string &uri); 360 361 /** 362 * getListeningPorts() 363 * 364 * Returns a list of ports that are listening 365 * 366 * @return A vector of ports 367 */ 368 369 std::vector<int> getListeningPorts(); 370 371 /** 372 * getListeningPorts() 373 * 374 * Variant of getListeningPorts() returning the full port information 375 * (protocol, SSL, ...) 376 * 377 * @return A vector of ports 378 */ 379 std::vector<struct mg_server_port> getListeningPortsFull(); 380 381 /** 382 * getCookie(struct mg_connection *conn, const std::string &cookieName, 383 * std::string &cookieValue) 384 * 385 * Puts the cookie value string that matches the cookie name in the 386 * cookieValue destination string. 387 * 388 * @param conn - the connection information 389 * @param cookieName - cookie name to get the value from 390 * @param cookieValue - cookie value is returned using this reference 391 * @returns the size of the cookie value string read. 392 */ 393 static int getCookie(struct mg_connection *conn, 394 const std::string &cookieName, 395 std::string &cookieValue); 396 397 /** 398 * getHeader(struct mg_connection *conn, const std::string &headerName) 399 * @param conn - the connection information 400 * @param headerName - header name to get the value from 401 * @returns a char array which contains the header value as string 402 */ 403 static const char *getHeader(struct mg_connection *conn, 404 const std::string &headerName); 405 406 /** 407 * getParam(struct mg_connection *conn, const char *, std::string &, size_t) 408 * 409 * Returns a query which contained in the supplied buffer. The 410 * occurrence value is a zero-based index of a particular key name. This 411 * should not be confused with the index over all of the keys. Note that 412 *this 413 * function assumes that parameters are sent as text in http query string 414 * format, which is the default for web forms. This function will work for 415 * html forms with method="GET" and method="POST" attributes. In other 416 *cases, 417 * you may use a getParam version that directly takes the data instead of 418 *the 419 * connection as a first argument. 420 * 421 * @param conn - parameters are read from the data sent through this 422 *connection 423 * @param name - the key to search for 424 * @param dst - the destination string 425 * @param occurrence - the occurrence of the selected name in the query (0 426 *based). 427 * @return true if key was found 428 */ 429 static bool getParam(struct mg_connection *conn, 430 const char *name, 431 std::string &dst, 432 size_t occurrence = 0); 433 434 /** 435 * getParam(const std::string &, const char *, std::string &, size_t) 436 * 437 * Returns a query parameter contained in the supplied buffer. The 438 * occurrence value is a zero-based index of a particular key name. This 439 * should not be confused with the index over all of the keys. 440 * 441 * @param data - the query string (text) 442 * @param name - the key to search for 443 * @param dst - the destination string 444 * @param occurrence - the occurrence of the selected name in the query (0 445 *based). 446 * @return true if key was found 447 */ 448 static bool 449 getParam(const std::string &data, 450 const char *name, 451 std::string &dst, 452 size_t occurrence = 0) 453 { 454 return getParam(data.c_str(), data.length(), name, dst, occurrence); 455 } 456 457 /** 458 * getParam(const char *, size_t, const char *, std::string &, size_t) 459 * 460 * Returns a query parameter contained in the supplied buffer. The 461 * occurrence value is a zero-based index of a particular key name. This 462 * should not be confused with the index over all of the keys. 463 * 464 * @param data the - query string (text) 465 * @param data_len - length of the query string 466 * @param name - the key to search for 467 * @param dst - the destination string 468 * @param occurrence - the occurrence of the selected name in the query (0 469 *based). 470 * @return true if key was found 471 */ 472 static bool getParam(const char *data, 473 size_t data_len, 474 const char *name, 475 std::string &dst, 476 size_t occurrence = 0); 477 478 /** 479 * getPostData(struct mg_connection *) 480 * 481 * Returns response body from a request made as POST. Since the 482 * connections map is protected, it can't be directly accessed. 483 * This uses string to store post data to handle big posts. 484 * 485 * @param conn - connection from which post data will be read 486 * @return Post data (empty if not available). 487 */ 488 static std::string getPostData(struct mg_connection *conn); 489 490 /** 491 * urlDecode(const std::string &, std::string &, bool) 492 * 493 * @param src - string to be decoded 494 * @param dst - destination string 495 * @param is_form_url_encoded - true if form url encoded 496 * form-url-encoded data differs from URI encoding in a way that it 497 * uses '+' as character for space, see RFC 1866 section 8.2.1 498 * http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt 499 */ 500 static void 501 urlDecode(const std::string &src, 502 std::string &dst, 503 bool is_form_url_encoded = true) 504 { 505 urlDecode(src.c_str(), src.length(), dst, is_form_url_encoded); 506 } 507 508 /** 509 * urlDecode(const char *, size_t, std::string &, bool) 510 * 511 * @param src - buffer to be decoded 512 * @param src_len - length of buffer to be decoded 513 * @param dst - destination string 514 * @param is_form_url_encoded - true if form url encoded 515 * form-url-encoded data differs from URI encoding in a way that it 516 * uses '+' as character for space, see RFC 1866 section 8.2.1 517 * http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt 518 */ 519 static void urlDecode(const char *src, 520 size_t src_len, 521 std::string &dst, 522 bool is_form_url_encoded = true); 523 524 /** 525 * urlDecode(const char *, std::string &, bool) 526 * 527 * @param src - buffer to be decoded (0 terminated) 528 * @param dst - destination string 529 * @param is_form_url_encoded true - if form url encoded 530 * form-url-encoded data differs from URI encoding in a way that it 531 * uses '+' as character for space, see RFC 1866 section 8.2.1 532 * http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt 533 */ 534 static void urlDecode(const char *src, 535 std::string &dst, 536 bool is_form_url_encoded = true); 537 538 /** 539 * urlEncode(const std::string &, std::string &, bool) 540 * 541 * @param src - buffer to be encoded 542 * @param dst - destination string 543 * @param append - true if string should not be cleared before encoding. 544 */ 545 static void 546 urlEncode(const std::string &src, std::string &dst, bool append = false) 547 { 548 urlEncode(src.c_str(), src.length(), dst, append); 549 } 550 551 /** 552 * urlEncode(const char *, size_t, std::string &, bool) 553 * 554 * @param src - buffer to be encoded (0 terminated) 555 * @param dst - destination string 556 * @param append - true if string should not be cleared before encoding. 557 */ 558 static void 559 urlEncode(const char *src, std::string &dst, bool append = false); 560 561 /** 562 * urlEncode(const char *, size_t, std::string &, bool) 563 * 564 * @param src - buffer to be encoded 565 * @param src_len - length of buffer to be decoded 566 * @param dst - destination string 567 * @param append - true if string should not be cleared before encoding. 568 */ 569 static void urlEncode(const char *src, 570 size_t src_len, 571 std::string &dst, 572 bool append = false); 573 574 // generic user context which can be set/read, 575 // the server does nothing with this apart from keep it. 576 const void * getUserContext()577 getUserContext() const 578 { 579 return UserContext; 580 } 581 582 protected: 583 class CivetConnection 584 { 585 public: 586 char *postData; 587 unsigned long postDataLen; 588 589 CivetConnection(); 590 ~CivetConnection(); 591 }; 592 593 struct mg_context *context; 594 std::map<struct mg_connection *, class CivetConnection> connections; 595 596 // generic user context which can be set/read, 597 // the server does nothing with this apart from keep it. 598 const void *UserContext; 599 600 private: 601 /** 602 * requestHandler(struct mg_connection *, void *cbdata) 603 * 604 * Handles the incoming request. 605 * 606 * @param conn - the connection information 607 * @param cbdata - pointer to the CivetHandler instance. 608 * @returns 0 if implemented, false otherwise 609 */ 610 static int requestHandler(struct mg_connection *conn, void *cbdata); 611 612 static int webSocketConnectionHandler(const struct mg_connection *conn, 613 void *cbdata); 614 static void webSocketReadyHandler(struct mg_connection *conn, void *cbdata); 615 static int webSocketDataHandler(struct mg_connection *conn, 616 int bits, 617 char *data, 618 size_t data_len, 619 void *cbdata); 620 static void webSocketCloseHandler(const struct mg_connection *conn, 621 void *cbdata); 622 /** 623 * authHandler(struct mg_connection *, void *cbdata) 624 * 625 * Handles the authorization requests. 626 * 627 * @param conn - the connection information 628 * @param cbdata - pointer to the CivetAuthHandler instance. 629 * @returns 1 if authorized, 0 otherwise 630 */ 631 static int authHandler(struct mg_connection *conn, void *cbdata); 632 633 /** 634 * closeHandler(struct mg_connection *) 635 * 636 * Handles closing a request (internal handler) 637 * 638 * @param conn - the connection information 639 */ 640 static void closeHandler(const struct mg_connection *conn); 641 642 /** 643 * Stores the user provided close handler 644 */ 645 void (*userCloseHandler)(const struct mg_connection *conn); 646 }; 647 648 #endif /* __cplusplus */ 649 #endif /* CIVETSERVER_HEADER_INCLUDED */ 650