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