| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -601,10 +601,10 @@ There are 5 types of response that you can create - we will describe them here t | |||
| 601 | 601 | * _file_response(**const std::string&** filename, **int** response_code = `200`, **const std::string&** content_type = `"text/plain"`):_ Uses the `filename` passed in construction as pointer to a file on disk. The body of the HTTP response will be set using the content of the file. The other two optional parameters are the `response_code` and the `content_type`. You can find constant definition for the various response codes within the [http_utils](https://github.com/etr/libhttpserver/blob/master/src/httpserver/http_utils.hpp) library file. | |
| 602 | 602 | * _basic_auth_fail_response(**const std::string&** content, **const std::string&** realm = `""`, **int** response_code = `200`, **const std::string&** content_type = `"text/plain"`):_ A response in return to a failure during basic authentication. It allows to specify a `content` string as a message to send back to the client. The `realm` parameter should contain your realm of authentication (if any). The other two optional parameters are the `response_code` and the `content_type`. You can find constant definition for the various response codes within the [http_utils](https://github.com/etr/libhttpserver/blob/master/src/httpserver/http_utils.hpp) library file. | |
| 603 | 603 | * _digest_auth_fail_response(**const std::string&** content, **const std::string&** realm = `""`, **const std::string&** opaque = `""`, **bool** reload_nonce = `false`, **int** response_code = `200`, **const std::string&** content_type = `"text/plain"`):_ A response in return to a failure during digest authentication. It allows to specify a `content` string as a message to send back to the client. The `realm` parameter should contain your realm of authentication (if any). The `opaque` represents a value that gets passed to the client and expected to be passed again to the server as-is. This value can be a hexadecimal or base64 string. The `reload_nonce` parameter tells the server to reload the nonce (you should use the value returned by the `check_digest_auth` method on the `http_request`. The other two optional parameters are the `response_code` and the `content_type`. You can find constant definition for the various response codes within the [http_utils](https://github.com/etr/libhttpserver/blob/master/src/httpserver/http_utils.hpp) library file. | |
| 604 | - * _deferred_response(**ssize_t(*cycle_callback_ptr)(char*, size_t)** cycle_callback, **const std::string&** content = `""`, **int** response_code = `200`, **const std::string&** content_type = `"text/plain"`):_ A response that obtains additional content from a callback executed in a deferred way. It leaves the client in pending state (returning a `100 CONTINUE` message) and suspends the connection. Besides the callback, optionally, you can provide a `content` parameter that sets the initial message sent immediately to the client. The other two optional parameters are the `response_code` and the `content_type`. You can find constant definition for the various response codes within the [http_utils](https://github.com/etr/libhttpserver/blob/master/src/httpserver/http_utils.hpp) library file. To use `deferred_response` you need to have the `deferred` option active on your webserver (enabled by default). | ||
| 604 | + * _deferred_response(**ssize_t(*cycle_callback_ptr)(shared_ptr<T>, char*, size_t)** cycle_callback, **const std::string&** content = `""`, **int** response_code = `200`, **const std::string&** content_type = `"text/plain"`):_ A response that obtains additional content from a callback executed in a deferred way. It leaves the client in pending state (returning a `100 CONTINUE` message) and suspends the connection. Besides the callback, optionally, you can provide a `content` parameter that sets the initial message sent immediately to the client. The other two optional parameters are the `response_code` and the `content_type`. You can find constant definition for the various response codes within the [http_utils](https://github.com/etr/libhttpserver/blob/master/src/httpserver/http_utils.hpp) library file. To use `deferred_response` you need to have the `deferred` option active on your webserver (enabled by default). | ||
| 605 | 605 | * The `cycle_callback_ptr` has this shape: | |
| 606 | - _**ssize_t** cycle_callback(**char*** buf, **size_t** max_size)_. | ||
| 607 | - You are supposed to implement a function in this shape and provide it to the `deferred_repsonse` method. The webserver will provide a `char*` to the function. It is responsibility of the function to allocate it and fill its content. The method is supposed to respect the `max_size` parameter passed in input. The function must return a `ssize_t` value representing the actual size you filled the `buf` with. Any value different from `-1` will keep the resume the connection, deliver the content and suspend it again (with a `100 CONTINUE`). If the method returns `-1`, the webserver will complete the communication with the client and close the connection. | ||
| 606 | + _**ssize_t** cycle_callback(**shared_ptr<T> closure_data, char*** buf, **size_t** max_size)_. | ||
| 607 | + You are supposed to implement a function in this shape and provide it to the `deferred_repsonse` method. The webserver will provide a `char*` to the function. It is responsibility of the function to allocate it and fill its content. The method is supposed to respect the `max_size` parameter passed in input. The function must return a `ssize_t` value representing the actual size you filled the `buf` with. Any value different from `-1` will keep the resume the connection, deliver the content and suspend it again (with a `100 CONTINUE`). If the method returns `-1`, the webserver will complete the communication with the client and close the connection. You can also pass a `shared_ptr` pointing to a data object of your choice (this will be templetized with a class of your choice). The server will guarantee that this object is passed at each invocation of the method allowing the client code to use it as a memory buffer during computation. | ||
| 608 | 608 | ||
| 609 | 609 | ### Setting additional properties of the response | |
| 610 | 610 | The `http_response` class offers an additional set of methods to "decorate" your responses. This set of methods is: | |
@@ -825,36 +825,37 @@ You can also check this example on [github](https://github.com/etr/libhttpserver | |||
| 825 | 825 | ||
| 826 | 826 | #### Example of a deferred response through callback | |
| 827 | 827 | #include <httpserver.hpp> | |
| 828 | - | ||
| 828 | + | ||
| 829 | 829 | using namespace httpserver; | |
| 830 | - | ||
| 830 | + | ||
| 831 | 831 | static int counter = 0; | |
| 832 | - | ||
| 833 | - ssize_t test_callback (char* buf, size_t max) { | ||
| 832 | + | ||
| 833 | + ssize_t test_callback (std::shared_ptr<void> closure_data, char* buf, size_t max) { | ||
| 834 | 834 | if (counter == 2) { | |
| 835 | 835 | return -1; | |
| 836 | - } else { | ||
| 836 | + } | ||
| 837 | + else { | ||
| 837 | 838 | memset(buf, 0, max); | |
| 838 | 839 | strcat(buf, " test "); | |
| 839 | 840 | counter++; | |
| 840 | 841 | return std::string(buf).size(); | |
| 841 | 842 | } | |
| 842 | 843 | } | |
| 843 | - | ||
| 844 | + | ||
| 844 | 845 | class deferred_resource : public http_resource { | |
| 845 | - public: | ||
| 846 | - const std::shared_ptr<http_response> render_GET(const http_request& req) { | ||
| 847 | - return std::shared_ptr<deferred_response>(new deferred_response(test_callback, "cycle callback response")); | ||
| 848 | - } | ||
| 846 | + public: | ||
| 847 | + const std::shared_ptr<http_response> render_GET(const http_request& req) { | ||
| 848 | + return std::shared_ptr<deferred_response<void> >(new deferred_response<void>(test_callback, nullptr, "cycle callback response")); | ||
| 849 | + } | ||
| 849 | 850 | }; | |
| 850 | - | ||
| 851 | + | ||
| 851 | 852 | int main(int argc, char** argv) { | |
| 852 | 853 | webserver ws = create_webserver(8080); | |
| 853 | - | ||
| 854 | + | ||
| 854 | 855 | deferred_resource hwr; | |
| 855 | 856 | ws.register_resource("/hello", &hwr); | |
| 856 | 857 | ws.start(true); | |
| 857 | - | ||
| 858 | + | ||
| 858 | 859 | return 0; | |
| 859 | 860 | } | |
| 860 | 861 | ||
@@ -864,6 +865,63 @@ To test the above example, you can run the following command from a terminal: | |||
| 864 | 865 | ||
| 865 | 866 | You can also check this example on [github](https://github.com/etr/libhttpserver/blob/master/examples/minimal_deferred.cpp). | |
| 866 | 867 | ||
| 868 | + #### Example of a deferred response through callback (passing additional data along) | ||
| 869 | + #include <atomic> | ||
| 870 | + #include <httpserver.hpp> | ||
| 871 | + | ||
| 872 | + using namespace httpserver; | ||
| 873 | + | ||
| 874 | + std::atomic<int> counter; | ||
| 875 | + | ||
| 876 | + ssize_t test_callback (std::shared_ptr<std::atomic<int> > closure_data, char* buf, size_t max) { | ||
| 877 | + int reqid; | ||
| 878 | + if (closure_data == nullptr) { | ||
| 879 | + reqid = -1; | ||
| 880 | + } else { | ||
| 881 | + reqid = *closure_data; | ||
| 882 | + } | ||
| 883 | + | ||
| 884 | + // only first 5 connections can be established | ||
| 885 | + if (reqid >= 5) { | ||
| 886 | + return -1; | ||
| 887 | + } else { | ||
| 888 | + // respond corresponding request IDs to the clients | ||
| 889 | + std::string str = ""; | ||
| 890 | + str += std::to_string(reqid) + " "; | ||
| 891 | + memset(buf, 0, max); | ||
| 892 | + std::copy(str.begin(), str.end(), buf); | ||
| 893 | + | ||
| 894 | + // keep sending reqid | ||
| 895 | + sleep(1); | ||
| 896 | + | ||
| 897 | + return (ssize_t)max; | ||
| 898 | + } | ||
| 899 | + } | ||
| 900 | + | ||
| 901 | + class deferred_resource : public http_resource { | ||
| 902 | + public: | ||
| 903 | + const std::shared_ptr<http_response> render_GET(const http_request& req) { | ||
| 904 | + std::shared_ptr<std::atomic<int> > closure_data(new std::atomic<int>(counter++)); | ||
| 905 | + return std::shared_ptr<deferred_response<std::atomic<int> > >(new deferred_response<std::atomic<int> >(test_callback, closure_data, "cycle callback response")); | ||
| 906 | + } | ||
| 907 | + }; | ||
| 908 | + | ||
| 909 | + int main(int argc, char** argv) { | ||
| 910 | + webserver ws = create_webserver(8080); | ||
| 911 | + | ||
| 912 | + deferred_resource hwr; | ||
| 913 | + ws.register_resource("/hello", &hwr); | ||
| 914 | + ws.start(true); | ||
| 915 | + | ||
| 916 | + return 0; | ||
| 917 | + } | ||
| 918 | + | ||
| 919 | + To test the above example, you can run the following command from a terminal: | ||
| 920 | + | ||
| 921 | + curl -XGET -v localhost:8080/hello | ||
| 922 | + | ||
| 923 | + You can also check this example on [github](https://github.com/etr/libhttpserver/blob/master/examples/deferred_with_accumulator.cpp). | ||
| 924 | + | ||
| 867 | 925 | [Back to TOC](#table-of-contents) | |
| 868 | 926 | ||
| 869 | 927 | ## Copying | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -19,7 +19,7 @@ | |||
| 19 | 19 | LDADD = $(top_builddir)/src/libhttpserver.la | |
| 20 | 20 | AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/httpserver/ | |
| 21 | 21 | METASOURCES = AUTO | |
| 22 | - noinst_PROGRAMS = hello_world service minimal_hello_world custom_error allowing_disallowing_methods handlers hello_with_get_arg setting_headers custom_access_log basic_authentication digest_authentication minimal_https minimal_file_response minimal_deferred url_registration minimal_ip_ban benchmark_select benchmark_threads | ||
| 22 | + noinst_PROGRAMS = hello_world service minimal_hello_world custom_error allowing_disallowing_methods handlers hello_with_get_arg setting_headers custom_access_log basic_authentication digest_authentication minimal_https minimal_file_response minimal_deferred url_registration minimal_ip_ban benchmark_select benchmark_threads deferred_with_accumulator | ||
| 23 | 23 | ||
| 24 | 24 | hello_world_SOURCES = hello_world.cpp | |
| 25 | 25 | service_SOURCES = service.cpp | |
@@ -35,6 +35,7 @@ digest_authentication_SOURCES = digest_authentication.cpp | |||
| 35 | 35 | minimal_https_SOURCES = minimal_https.cpp | |
| 36 | 36 | minimal_file_response_SOURCES = minimal_file_response.cpp | |
| 37 | 37 | minimal_deferred_SOURCES = minimal_deferred.cpp | |
| 38 | + deferred_with_accumulator_SOURCES = deferred_with_accumulator.cpp | ||
| 38 | 39 | url_registration_SOURCES = url_registration.cpp | |
| 39 | 40 | minimal_ip_ban_SOURCES = minimal_ip_ban.cpp | |
| 40 | 41 | benchmark_select_SOURCES = benchmark_select.cpp | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -24,7 +24,7 @@ using namespace httpserver; | |||
| 24 | 24 | ||
| 25 | 25 | static int counter = 0; | |
| 26 | 26 | ||
| 27 | - ssize_t test_callback (char* buf, size_t max) { | ||
| 27 | + ssize_t test_callback (std::shared_ptr<void> closure_data, char* buf, size_t max) { | ||
| 28 | 28 | if (counter == 2) { | |
| 29 | 29 | return -1; | |
| 30 | 30 | } | |
@@ -39,7 +39,7 @@ ssize_t test_callback (char* buf, size_t max) { | |||
| 39 | 39 | class deferred_resource : public http_resource { | |
| 40 | 40 | public: | |
| 41 | 41 | const std::shared_ptr<http_response> render_GET(const http_request& req) { | |
| 42 | - return std::shared_ptr<deferred_response>(new deferred_response(test_callback, "cycle callback response")); | ||
| 42 | + return std::shared_ptr<deferred_response<void> >(new deferred_response<void>(test_callback, nullptr, "cycle callback response")); | ||
| 43 | 43 | } | |
| 44 | 44 | }; | |
| 45 | 45 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -28,44 +28,18 @@ namespace httpserver | |||
| 28 | 28 | namespace details | |
| 29 | 29 | { | |
| 30 | 30 | ||
| 31 | - ssize_t cb(void* cls, uint64_t pos, char* buf, size_t max) | ||
| 32 | - { | ||
| 33 | - ssize_t val = static_cast<deferred_response*>(cls)->cycle_callback(buf, max); | ||
| 34 | - if(val == -1) | ||
| 35 | - { | ||
| 36 | - static_cast<deferred_response*>(cls)->completed = true; | ||
| 37 | - } | ||
| 38 | - | ||
| 39 | - return val; | ||
| 40 | - } | ||
| 41 | - | ||
| 42 | - } | ||
| 43 | - | ||
| 44 | - MHD_Response* deferred_response::get_raw_response() | ||
| 31 | + MHD_Response* get_raw_response_helper(void* cls, bool completed, ssize_t (*cb)(void*, uint64_t, char*, size_t)) | ||
| 45 | 32 | { | |
| 46 | 33 | if(!completed) | |
| 47 | 34 | { | |
| 48 | - return MHD_create_response_from_callback( | ||
| 49 | - MHD_SIZE_UNKNOWN, | ||
| 50 | - 1024, | ||
| 51 | - &details::cb, | ||
| 52 | - this, | ||
| 53 | - NULL | ||
| 54 | - ); | ||
| 35 | + return MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, 1024, cb, cls, NULL); | ||
| 55 | 36 | } | |
| 56 | 37 | else | |
| 57 | 38 | { | |
| 58 | - return static_cast<string_response*>(this)->get_raw_response(); | ||
| 39 | + return static_cast<string_response*>(cls)->get_raw_response(); | ||
| 59 | 40 | } | |
| 60 | 41 | } | |
| 61 | 42 | ||
| 62 | - void deferred_response::decorate_response(MHD_Response* response) | ||
| 63 | - { | ||
| 64 | - if(completed) | ||
| 65 | - { | ||
| 66 | - static_cast<string_response*>(this)->decorate_response(response); | ||
| 67 | - } | ||
| 68 | 43 | } | |
| 69 | 44 | ||
| 70 | 45 | } | |
| 71 | - | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -25,43 +25,47 @@ | |||
| 25 | 25 | #ifndef _DEFERRED_RESPONSE_HPP_ | |
| 26 | 26 | #define _DEFERRED_RESPONSE_HPP_ | |
| 27 | 27 | ||
| 28 | + #include <memory> | ||
| 28 | 29 | #include "httpserver/string_response.hpp" | |
| 29 | 30 | ||
| 30 | 31 | namespace httpserver | |
| 31 | 32 | { | |
| 32 | 33 | ||
| 33 | 34 | namespace details | |
| 34 | 35 | { | |
| 35 | - ssize_t cb(void*, uint64_t, char*, size_t); | ||
| 36 | - }; | ||
| 37 | - | ||
| 38 | - typedef ssize_t(*cycle_callback_ptr)(char*, size_t); | ||
| 36 | + MHD_Response* get_raw_response_helper(void* cls, bool completed, ssize_t (*cb)(void*, uint64_t, char*, size_t)); | ||
| 37 | + } | ||
| 39 | 38 | ||
| 39 | + template <class T> | ||
| 40 | 40 | class deferred_response : public string_response | |
| 41 | 41 | { | |
| 42 | 42 | public: | |
| 43 | 43 | explicit deferred_response( | |
| 44 | - cycle_callback_ptr cycle_callback, | ||
| 44 | + ssize_t(*cycle_callback)(std::shared_ptr<T>, char*, size_t), | ||
| 45 | + std::shared_ptr<T> closure_data, | ||
| 45 | 46 | const std::string& content = "", | |
| 46 | 47 | int response_code = http::http_utils::http_ok, | |
| 47 | 48 | const std::string& content_type = http::http_utils::text_plain | |
| 48 | 49 | ): | |
| 49 | 50 | string_response(content, response_code, content_type), | |
| 50 | 51 | cycle_callback(cycle_callback), | |
| 52 | + closure_data(closure_data), | ||
| 51 | 53 | completed(false) | |
| 52 | 54 | { | |
| 53 | 55 | } | |
| 54 | 56 | ||
| 55 | 57 | deferred_response(const deferred_response& other): | |
| 56 | 58 | string_response(other), | |
| 57 | 59 | cycle_callback(other.cycle_callback), | |
| 60 | + closure_data(other.closure_data), | ||
| 58 | 61 | completed(other.completed) | |
| 59 | 62 | { | |
| 60 | 63 | } | |
| 61 | 64 | ||
| 62 | 65 | deferred_response(deferred_response&& other) noexcept: | |
| 63 | 66 | string_response(std::move(other)), | |
| 64 | 67 | cycle_callback(std::move(other.cycle_callback)), | |
| 68 | + closure_data(std::move(other.closure_data)), | ||
| 65 | 69 | completed(other.completed) | |
| 66 | 70 | { | |
| 67 | 71 | } | |
@@ -72,6 +76,7 @@ class deferred_response : public string_response | |||
| 72 | 76 | ||
| 73 | 77 | (string_response&) (*this) = b; | |
| 74 | 78 | this->cycle_callback = b.cycle_callback; | |
| 79 | + this->closure_data = b.closure_data; | ||
| 75 | 80 | this->completed = b.completed; | |
| 76 | 81 | ||
| 77 | 82 | return *this; | |
@@ -83,6 +88,7 @@ class deferred_response : public string_response | |||
| 83 | 88 | ||
| 84 | 89 | (string_response&) (*this) = std::move(b); | |
| 85 | 90 | this->cycle_callback = std::move(b.cycle_callback); | |
| 91 | + this->closure_data = std::move(b.closure_data); | ||
| 86 | 92 | this->completed = b.completed; | |
| 87 | 93 | ||
| 88 | 94 | return *this; | |
@@ -92,13 +98,35 @@ class deferred_response : public string_response | |||
| 92 | 98 | { | |
| 93 | 99 | } | |
| 94 | 100 | ||
| 95 | - MHD_Response* get_raw_response(); | ||
| 96 | - void decorate_response(MHD_Response* response); | ||
| 101 | + MHD_Response* get_raw_response() | ||
| 102 | + { | ||
| 103 | + return details::get_raw_response_helper((void*) this, completed, &(this->cb)); | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + void decorate_response(MHD_Response* response) | ||
| 107 | + { | ||
| 108 | + if(completed) | ||
| 109 | + { | ||
| 110 | + static_cast<string_response*>(this)->decorate_response(response); | ||
| 111 | + } | ||
| 112 | + } | ||
| 113 | + | ||
| 97 | 114 | private: | |
| 98 | - cycle_callback_ptr cycle_callback; | ||
| 115 | + ssize_t (*cycle_callback)(std::shared_ptr<T>, char*, size_t); | ||
| 116 | + std::shared_ptr<T> closure_data; | ||
| 99 | 117 | bool completed; | |
| 100 | 118 | ||
| 101 | - friend ssize_t details::cb(void* cls, uint64_t pos, char* buf, size_t max); | ||
| 119 | + static ssize_t cb(void* cls, uint64_t pos, char* buf, size_t max) | ||
| 120 | + { | ||
| 121 | + deferred_response<T>* dfr = static_cast<deferred_response<T>*>(cls); | ||
| 122 | + ssize_t val = dfr->cycle_callback(dfr->closure_data, buf, max); | ||
| 123 | + if(val == -1) | ||
| 124 | + { | ||
| 125 | + dfr->completed = true; | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + return val; | ||
| 129 | + } | ||
| 102 | 130 | }; | |
| 103 | 131 | ||
| 104 | 132 | } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments