From 97bd4b196b5b5ef908c21582a5cfc51bd0611e35 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 27 Feb 2026 19:41:39 +0000 Subject: [PATCH 1/2] Add documentation and example for serving binary data from memory The existing string_response already supports binary content (std::string can hold arbitrary bytes), but this was not documented or demonstrated anywhere. This gap caused users to believe a new response type was needed (see PR #368). - Add a note to the README's string_response description clarifying binary data support - Add a new "Serving binary data from memory" section with inline example - Add examples/binary_buffer_response.cpp as a complete, buildable example that serves a PNG image from an in-memory buffer - Register the new example in examples/Makefile.am https://claude.ai/code/session_01S3BvBrSoNvUhpYTyhPYCjJ --- README.md | 37 ++++++++++++- examples/Makefile.am | 3 +- examples/binary_buffer_response.cpp | 81 +++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 examples/binary_buffer_response.cpp diff --git a/README.md b/README.md index a70ff849..b9d96f37 100644 --- a/README.md +++ b/README.md @@ -807,7 +807,7 @@ You can also check this example on [github](https://github.com/etr/libhttpserver 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. There are 5 types of response that you can create - we will describe them here through their constructors: -* _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. +* _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"`). * _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. * _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. * _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. You can also check this example on [github](https://github.com/etr/libhttpserver/blob/master/examples/setting_headers.cpp). +### Serving binary data from memory +`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. + +```cpp + #include + + using namespace httpserver; + + class image_resource : public http_resource { + public: + std::shared_ptr render_GET(const http_request&) { + // binary_data could come from a camera capture, image library, etc. + std::string binary_data = get_image_bytes_from_camera(); + + return std::make_shared( + std::move(binary_data), 200, "image/jpeg"); + } + }; + + int main() { + webserver ws = create_webserver(8080); + + image_resource ir; + ws.register_resource("/image", &ir); + ws.start(true); + + return 0; + } +``` +To test the above example, you could run the following command from a terminal: + + curl -o image.jpg http://localhost:8080/image + +You can also check the complete example on [github](https://github.com/etr/libhttpserver/blob/master/examples/binary_buffer_response.cpp). + [Back to TOC](#table-of-contents) ## IP Blacklisting and Whitelisting diff --git a/examples/Makefile.am b/examples/Makefile.am index c04e0acf..148fa944 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -19,7 +19,7 @@ LDADD = $(top_builddir)/src/libhttpserver.la AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/httpserver/ METASOURCES = AUTO -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 +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 hello_world_SOURCES = hello_world.cpp service_SOURCES = service.cpp @@ -42,6 +42,7 @@ benchmark_threads_SOURCES = benchmark_threads.cpp benchmark_nodelay_SOURCES = benchmark_nodelay.cpp file_upload_SOURCES = file_upload.cpp file_upload_with_callback_SOURCES = file_upload_with_callback.cpp +binary_buffer_response_SOURCES = binary_buffer_response.cpp if HAVE_BAUTH noinst_PROGRAMS += basic_authentication centralized_authentication diff --git a/examples/binary_buffer_response.cpp b/examples/binary_buffer_response.cpp new file mode 100644 index 00000000..17060137 --- /dev/null +++ b/examples/binary_buffer_response.cpp @@ -0,0 +1,81 @@ +/* + This file is part of libhttpserver + Copyright (C) 2011, 2012, 2013, 2014, 2015 Sebastiano Merlino + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + USA +*/ + +// This example demonstrates how to serve binary data (e.g., images) directly +// from an in-memory buffer using string_response. Despite its name, +// string_response works with arbitrary binary content because std::string can +// hold any bytes, including null characters. +// +// This is useful when you generate or receive binary data at runtime (e.g., +// from a camera, an image library, or a database) and want to serve it over +// HTTP without writing it to disk first. +// +// To test: +// curl -o output.png http://localhost:8080/image + +#include +#include + +#include + +// Generate a minimal valid 1x1 red PNG image in memory. +// In a real application, this could come from a camera capture, image +// processing library, database blob, etc. +static std::string generate_png_data() { + // Minimal 1x1 red pixel PNG (68 bytes) + static const unsigned char png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, // PNG signature + 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, // IHDR chunk + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, // 1x1 + 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53, // 8-bit RGB + 0xde, 0x00, 0x00, 0x00, 0x0c, 0x49, 0x44, 0x41, // IDAT chunk + 0x54, 0x08, 0xd7, 0x63, 0xf8, 0xcf, 0xc0, 0x00, // compressed data + 0x00, 0x00, 0x03, 0x00, 0x01, 0x36, 0x28, 0x19, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, // IEND chunk + 0x44, 0xae, 0x42, 0x60, 0x82 + }; + + return std::string(reinterpret_cast(png), sizeof(png)); +} + +class image_resource : public httpserver::http_resource { + public: + std::shared_ptr render_GET(const httpserver::http_request&) { + // Build binary content as a std::string. The string can contain any + // bytes — it is not limited to printable characters or null-terminated + // C strings. The size is tracked internally by std::string::size(). + std::string image_data = generate_png_data(); + + // Use string_response with the appropriate content type. The response + // will send the exact bytes contained in the string. + return std::make_shared( + std::move(image_data), 200, "image/png"); + } +}; + +int main() { + httpserver::webserver ws = httpserver::create_webserver(8080); + + image_resource ir; + ws.register_resource("/image", &ir); + ws.start(true); + + return 0; +} From 6fa84e836d490a2ee83f0b8b78553fc3e1032ac4 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 27 Feb 2026 22:13:38 +0000 Subject: [PATCH 2/2] Fix CI: add ChangeLog entry and missing include Add ChangeLog entry for the binary buffer example to satisfy the ChangeLog Check workflow. Add missing #include for std::move to fix cpplint warning. https://claude.ai/code/session_01S3BvBrSoNvUhpYTyhPYCjJ --- ChangeLog | 2 ++ examples/binary_buffer_response.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/ChangeLog b/ChangeLog index 7bb0aefb..6e9532e3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ Version 0.20.0 + Added example and documentation for serving binary data from memory + using string_response (addresses PR #368). Added conditional compilation for basic auth (HAVE_BAUTH), mirroring existing HAVE_DAUTH pattern for digest auth. Basic auth support is auto-detected via AC_CHECK_LIB and can be disabled at build time. diff --git a/examples/binary_buffer_response.cpp b/examples/binary_buffer_response.cpp index 17060137..19559cfc 100644 --- a/examples/binary_buffer_response.cpp +++ b/examples/binary_buffer_response.cpp @@ -32,6 +32,7 @@ #include #include +#include #include