Skip to content

Commit 6c115f3

Browse files
authored
Merge pull request #369 from etr/claude/review-pr-368-SXvkG
Add documentation and example for serving binary data from memory
2 parents 68bff78 + 6fa84e8 commit 6c115f3

File tree

4 files changed

+122
-2
lines changed

4 files changed

+122
-2
lines changed

ChangeLog

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
Version 0.20.0
22

3+
Added example and documentation for serving binary data from memory
4+
using string_response (addresses PR #368).
35
Added conditional compilation for basic auth (HAVE_BAUTH), mirroring
46
existing HAVE_DAUTH pattern for digest auth. Basic auth support
57
is auto-detected via AC_CHECK_LIB and can be disabled at build time.

README.md

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -807,7 +807,7 @@ You can also check this example on [github](https://github.com/etr/libhttpserver
807807
As seen in the documentation of [http_resource](#the-resource-object), every extensible method returns in output a `http_response` object. The webserver takes the responsibility to convert the `http_response` object you create into a response on the network.
808808

809809
There are 5 types of response that you can create - we will describe them here through their constructors:
810-
* _string_response(**const std::string&** content, **int** response_code = `200`, **const std::string&** content_type = `"text/plain"`):_ The most basic type of response. It uses the `content` string passed in construction as body of the HTTP response. 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.
810+
* _string_response(**const std::string&** content, **int** response_code = `200`, **const std::string&** content_type = `"text/plain"`):_ The most basic type of response. It uses the `content` string passed in construction as body of the HTTP response. 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. Note that `std::string` can hold arbitrary binary data (including null bytes), so `string_response` is also the right choice for serving binary content such as images directly from memory — simply set an appropriate `content_type` (e.g., `"image/png"`).
811811
* _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 file must be a regular file and exist on disk. Otherwise libhttpserver will return an error 500 (Internal Server Error). 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.
812812
* _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.
813813
* _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.
@@ -856,6 +856,41 @@ You will receive the message custom header in reply.
856856

857857
You can also check this example on [github](https://github.com/etr/libhttpserver/blob/master/examples/setting_headers.cpp).
858858

859+
### Serving binary data from memory
860+
`string_response` is not limited to text — it can serve arbitrary binary content directly from memory. This is useful when you have data in a buffer at runtime (e.g., from a camera, an image processing library, or a database) and want to serve it without writing to disk.
861+
862+
```cpp
863+
#include <httpserver.hpp>
864+
865+
using namespace httpserver;
866+
867+
class image_resource : public http_resource {
868+
public:
869+
std::shared_ptr<http_response> render_GET(const http_request&) {
870+
// binary_data could come from a camera capture, image library, etc.
871+
std::string binary_data = get_image_bytes_from_camera();
872+
873+
return std::make_shared<string_response>(
874+
std::move(binary_data), 200, "image/jpeg");
875+
}
876+
};
877+
878+
int main() {
879+
webserver ws = create_webserver(8080);
880+
881+
image_resource ir;
882+
ws.register_resource("/image", &ir);
883+
ws.start(true);
884+
885+
return 0;
886+
}
887+
```
888+
To test the above example, you could run the following command from a terminal:
889+
890+
curl -o image.jpg http://localhost:8080/image
891+
892+
You can also check the complete example on [github](https://github.com/etr/libhttpserver/blob/master/examples/binary_buffer_response.cpp).
893+
859894
[Back to TOC](#table-of-contents)
860895
861896
## IP Blacklisting and Whitelisting

examples/Makefile.am

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
LDADD = $(top_builddir)/src/libhttpserver.la
2020
AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/httpserver/
2121
METASOURCES = AUTO
22-
noinst_PROGRAMS = hello_world service minimal_hello_world custom_error allowing_disallowing_methods handlers hello_with_get_arg args_processing setting_headers custom_access_log minimal_https minimal_file_response minimal_deferred url_registration minimal_ip_ban benchmark_select benchmark_threads benchmark_nodelay deferred_with_accumulator file_upload file_upload_with_callback
22+
noinst_PROGRAMS = hello_world service minimal_hello_world custom_error allowing_disallowing_methods handlers hello_with_get_arg args_processing setting_headers custom_access_log minimal_https minimal_file_response minimal_deferred url_registration minimal_ip_ban benchmark_select benchmark_threads benchmark_nodelay deferred_with_accumulator file_upload file_upload_with_callback binary_buffer_response
2323

2424
hello_world_SOURCES = hello_world.cpp
2525
service_SOURCES = service.cpp
@@ -42,6 +42,7 @@ benchmark_threads_SOURCES = benchmark_threads.cpp
4242
benchmark_nodelay_SOURCES = benchmark_nodelay.cpp
4343
file_upload_SOURCES = file_upload.cpp
4444
file_upload_with_callback_SOURCES = file_upload_with_callback.cpp
45+
binary_buffer_response_SOURCES = binary_buffer_response.cpp
4546

4647
if HAVE_BAUTH
4748
noinst_PROGRAMS += basic_authentication centralized_authentication
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
This file is part of libhttpserver
3+
Copyright (C) 2011, 2012, 2013, 2014, 2015 Sebastiano Merlino
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
18+
USA
19+
*/
20+
21+
// This example demonstrates how to serve binary data (e.g., images) directly
22+
// from an in-memory buffer using string_response. Despite its name,
23+
// string_response works with arbitrary binary content because std::string can
24+
// hold any bytes, including null characters.
25+
//
26+
// This is useful when you generate or receive binary data at runtime (e.g.,
27+
// from a camera, an image library, or a database) and want to serve it over
28+
// HTTP without writing it to disk first.
29+
//
30+
// To test:
31+
// curl -o output.png http://localhost:8080/image
32+
33+
#include <memory>
34+
#include <string>
35+
#include <utility>
36+
37+
#include <httpserver.hpp>
38+
39+
// Generate a minimal valid 1x1 red PNG image in memory.
40+
// In a real application, this could come from a camera capture, image
41+
// processing library, database blob, etc.
42+
static std::string generate_png_data() {
43+
// Minimal 1x1 red pixel PNG (68 bytes)
44+
static const unsigned char png[] = {
45+
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, // PNG signature
46+
0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, // IHDR chunk
47+
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, // 1x1
48+
0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53, // 8-bit RGB
49+
0xde, 0x00, 0x00, 0x00, 0x0c, 0x49, 0x44, 0x41, // IDAT chunk
50+
0x54, 0x08, 0xd7, 0x63, 0xf8, 0xcf, 0xc0, 0x00, // compressed data
51+
0x00, 0x00, 0x03, 0x00, 0x01, 0x36, 0x28, 0x19,
52+
0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, // IEND chunk
53+
0x44, 0xae, 0x42, 0x60, 0x82
54+
};
55+
56+
return std::string(reinterpret_cast<const char*>(png), sizeof(png));
57+
}
58+
59+
class image_resource : public httpserver::http_resource {
60+
public:
61+
std::shared_ptr<httpserver::http_response> render_GET(const httpserver::http_request&) {
62+
// Build binary content as a std::string. The string can contain any
63+
// bytes — it is not limited to printable characters or null-terminated
64+
// C strings. The size is tracked internally by std::string::size().
65+
std::string image_data = generate_png_data();
66+
67+
// Use string_response with the appropriate content type. The response
68+
// will send the exact bytes contained in the string.
69+
return std::make_shared<httpserver::string_response>(
70+
std::move(image_data), 200, "image/png");
71+
}
72+
};
73+
74+
int main() {
75+
httpserver::webserver ws = httpserver::create_webserver(8080);
76+
77+
image_resource ir;
78+
ws.register_resource("/image", &ir);
79+
ws.start(true);
80+
81+
return 0;
82+
}

0 commit comments

Comments
 (0)