httpp 0.4.0__tar.gz → 0.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. {httpp-0.4.0 → httpp-0.5.0}/.github/workflows/cmake.yml +2 -2
  2. {httpp-0.4.0 → httpp-0.5.0}/.github/workflows/orchestrator.yml +1 -0
  3. {httpp-0.4.0 → httpp-0.5.0}/.github/workflows/wheels.yml +1 -1
  4. httpp-0.5.0/CMakeLists.txt +173 -0
  5. {httpp-0.4.0 → httpp-0.5.0}/PKG-INFO +17 -12
  6. {httpp-0.4.0 → httpp-0.5.0}/README.md +16 -11
  7. httpp-0.5.0/include/httpp/client.hpp +114 -0
  8. {httpp-0.4.0 → httpp-0.5.0}/include/httpp/curl.hpp +12 -12
  9. {httpp-0.4.0 → httpp-0.5.0}/include/httpp/curl_compat.h +16 -8
  10. {httpp-0.4.0 → httpp-0.5.0}/include/httpp/download.hpp +8 -8
  11. httpp-0.5.0/include/httpp/export.hpp +26 -0
  12. {httpp-0.4.0 → httpp-0.5.0}/include/httpp/progress.hpp +16 -12
  13. {httpp-0.4.0 → httpp-0.5.0}/include/httpp/server.hpp +12 -12
  14. {httpp-0.4.0 → httpp-0.5.0}/include/httpp/url.hpp +2 -2
  15. {httpp-0.4.0 → httpp-0.5.0}/include/httpp.h +1 -2
  16. {httpp-0.4.0 → httpp-0.5.0}/pyproject.toml +5 -1
  17. {httpp-0.4.0 → httpp-0.5.0}/requirements-dev.txt +2 -0
  18. {httpp-0.4.0 → httpp-0.5.0}/src/bindings/python/CMakeLists.txt +9 -4
  19. {httpp-0.4.0 → httpp-0.5.0}/src/bindings/python/httpp/__init__.py +10 -3
  20. {httpp-0.4.0 → httpp-0.5.0}/src/bindings/python/httpp/__main__.py +46 -3
  21. {httpp-0.4.0 → httpp-0.5.0}/src/bindings/python/httpp_cy.pyx +36 -9
  22. httpp-0.5.0/src/core/client.cpp +172 -0
  23. {httpp-0.4.0 → httpp-0.5.0}/src/core/curl_compat.cpp +26 -4
  24. {httpp-0.4.0 → httpp-0.5.0}/src/core/download.cpp +4 -4
  25. httpp-0.5.0/src/core/internal/httplib_common.hpp +36 -0
  26. {httpp-0.4.0 → httpp-0.5.0}/tests/cmake/consumer_project/main.cpp +5 -5
  27. httpp-0.5.0/tests/cpp/test_client_request.cpp +111 -0
  28. httpp-0.4.0/CMakeLists.txt +0 -107
  29. httpp-0.4.0/include/httpp/client.hpp +0 -44
  30. httpp-0.4.0/include/httpp/export.hpp +0 -15
  31. httpp-0.4.0/src/core/client.cpp +0 -57
  32. {httpp-0.4.0 → httpp-0.5.0}/.github/workflows/release_template.md +0 -0
  33. {httpp-0.4.0 → httpp-0.5.0}/.gitignore +0 -0
  34. {httpp-0.4.0 → httpp-0.5.0}/.gitmodules +0 -0
  35. {httpp-0.4.0 → httpp-0.5.0}/LICENSE.txt +0 -0
  36. {httpp-0.4.0 → httpp-0.5.0}/cmake/DynamicVersion.cmake +0 -0
  37. {httpp-0.4.0 → httpp-0.5.0}/cmake/FindCython.cmake +0 -0
  38. {httpp-0.4.0 → httpp-0.5.0}/cmake/Optimize.cmake +0 -0
  39. {httpp-0.4.0 → httpp-0.5.0}/cmake/Startup.cmake +0 -0
  40. {httpp-0.4.0 → httpp-0.5.0}/cmake/UseCython.cmake +0 -0
  41. {httpp-0.4.0 → httpp-0.5.0}/cmake/httppConfig.cmake.in +0 -0
  42. {httpp-0.4.0 → httpp-0.5.0}/docs/index.rst +0 -0
  43. {httpp-0.4.0 → httpp-0.5.0}/examples/find_httpp_via_python/CMakeLists.txt +0 -0
  44. {httpp-0.4.0 → httpp-0.5.0}/examples/find_httpp_via_python/main.cpp +0 -0
  45. {httpp-0.4.0 → httpp-0.5.0}/src/core/curl.cpp +0 -0
  46. {httpp-0.4.0 → httpp-0.5.0}/src/core/progress.cpp +0 -0
  47. {httpp-0.4.0 → httpp-0.5.0}/src/core/server.cpp +0 -0
  48. {httpp-0.4.0 → httpp-0.5.0}/src/core/url.cpp +0 -0
  49. {httpp-0.4.0 → httpp-0.5.0}/src/third_party/README.md +0 -0
  50. {httpp-0.4.0 → httpp-0.5.0}/src/third_party/cpp-httplib/httplib.h +0 -0
  51. {httpp-0.4.0 → httpp-0.5.0}/src/third_party/indicators/indicators.hpp +0 -0
  52. {httpp-0.4.0 → httpp-0.5.0}/tests/CMakeLists.txt +0 -0
  53. {httpp-0.4.0 → httpp-0.5.0}/tests/cmake/CMakeLists.txt +0 -0
  54. {httpp-0.4.0 → httpp-0.5.0}/tests/cmake/consumer_project/CMakeLists.txt +0 -0
  55. {httpp-0.4.0 → httpp-0.5.0}/tests/cmake/run_consumer_test.cmake +0 -0
  56. {httpp-0.4.0 → httpp-0.5.0}/tests/cpp/CMakeLists.txt +0 -0
  57. {httpp-0.4.0 → httpp-0.5.0}/tests/cpp/test_client.cpp +0 -0
  58. {httpp-0.4.0 → httpp-0.5.0}/tests/cpp/test_curl.cpp +0 -0
  59. {httpp-0.4.0 → httpp-0.5.0}/tests/cpp/test_curl_compat.cpp +0 -0
  60. {httpp-0.4.0 → httpp-0.5.0}/tests/cpp/test_download.cpp +0 -0
  61. {httpp-0.4.0 → httpp-0.5.0}/tests/cpp/test_progress.cpp +0 -0
  62. {httpp-0.4.0 → httpp-0.5.0}/tests/cpp/test_server.cpp +0 -0
  63. {httpp-0.4.0 → httpp-0.5.0}/tests/cpp/test_url.cpp +0 -0
  64. {httpp-0.4.0 → httpp-0.5.0}/tests/python/CMakeLists.txt +0 -0
  65. {httpp-0.4.0 → httpp-0.5.0}/tests/python/test_httpp_basic.py +0 -0
  66. {httpp-0.4.0 → httpp-0.5.0}/tests/utest/utest.h +0 -0
  67. {httpp-0.4.0 → httpp-0.5.0}/tests/utest/utest_main.cxx +0 -0
  68. {httpp-0.4.0 → httpp-0.5.0}/version.py +0 -0
@@ -18,7 +18,7 @@ jobs:
18
18
  - name: Checkout repository
19
19
  uses: actions/checkout@v6
20
20
  with:
21
- submodules: true
21
+ submodules: recursive
22
22
 
23
23
  - name: Set up Python
24
24
  uses: actions/setup-python@v6
@@ -53,7 +53,7 @@ jobs:
53
53
  - name: Checkout repository
54
54
  uses: actions/checkout@v6
55
55
  with:
56
- submodules: true
56
+ submodules: recursive
57
57
 
58
58
  - name: Setup cmake
59
59
  uses: jwlawson/actions-setup-cmake@v2
@@ -79,6 +79,7 @@ jobs:
79
79
  prerelease: ${{ needs.init.outputs.is_tag == 'false' }}
80
80
  token: ${{ secrets.GITHUB_TOKEN }}
81
81
  files: dist/*
82
+ generate_release_notes: true
82
83
 
83
84
  - name: Publishing to PyPi
84
85
  uses: pypa/gh-action-pypi-publish@release/v1
@@ -50,7 +50,7 @@ jobs:
50
50
  steps:
51
51
  - uses: actions/checkout@v6
52
52
  with:
53
- submodules: true
53
+ submodules: recursive
54
54
 
55
55
  - name: Build wheels
56
56
  uses: pypa/cibuildwheel@v3.4.1
@@ -0,0 +1,173 @@
1
+ cmake_minimum_required(VERSION 3.21)
2
+
3
+ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
4
+ include(DynamicVersion)
5
+
6
+ extract_version_string(
7
+ HEADER_FILE ${CMAKE_CURRENT_LIST_DIR}/include/httpp.h
8
+ VERSION_PREFIX HTTPP_
9
+ OUTPUT_VAR PROJECT_VERSION
10
+ )
11
+
12
+ project(httpp LANGUAGES CXX VERSION ${PROJECT_VERSION})
13
+ message(STATUS "Project: ${PROJECT_NAME}@v${PROJECT_VERSION}")
14
+ include(Startup)
15
+
16
+ set(CMAKE_CXX_STANDARD 17)
17
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
18
+ set(CMAKE_CXX_EXTENSIONS OFF)
19
+
20
+ include(Optimize)
21
+
22
+ # Project options
23
+ option(HTTPP_BUILD_TESTS "Build tests" ${PROJECT_IS_TOP_LEVEL})
24
+ option(HTTPP_BUILD_PYTHON "Build Python bindings" ${PROJECT_IS_TOP_LEVEL})
25
+
26
+ set(HTTPP_SOURCE_DIR ${PROJECT_SOURCE_DIR})
27
+
28
+ # --- httpp C++ core ---
29
+ # httplib.h is vendored at src/third_party/cpp-httplib (a real committed
30
+ # file, no system package). mbedtls is a git submodule at
31
+ # src/third_party/mbedtls (also built from source, no system package).
32
+ # Both are included only from src/core/*.cpp, never from a public
33
+ # include/httpp/*.hpp header, and are compiled with hidden visibility so
34
+ # they never leak into the httpp .so/.a's public symbols.
35
+ file(GLOB HTTPP_CORE_SOURCES ${PROJECT_SOURCE_DIR}/src/core/*.cpp)
36
+
37
+ # liburlparser (git submodule, built from source — no system package) does
38
+ # the real URL parsing (scheme/host/port/path, IPv4/IPv6, PSL-aware). It is
39
+ # linked PRIVATE into httpp_core, same as cpp-httplib: consumers of
40
+ # <httpp/url.hpp> see only httpp::url, never urlparser::url directly.
41
+ set(BUILD_PYTHON OFF CACHE BOOL "" FORCE)
42
+ # Needed so liburlparser's static lib can be linked into httpp's shared
43
+ # lib / the Cython extension module (which are themselves PIC).
44
+ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
45
+ add_subdirectory(${PROJECT_SOURCE_DIR}/src/third_party/liburlparser)
46
+
47
+ # mbedtls (TLS support for HTTPS, via cpp-httplib's CPPHTTPLIB_MBEDTLS_SUPPORT).
48
+ set(ENABLE_PROGRAMS OFF CACHE BOOL "" FORCE)
49
+ set(ENABLE_TESTING OFF CACHE BOOL "" FORCE)
50
+ set(MBEDTLS_FATAL_WARNINGS OFF CACHE BOOL "" FORCE)
51
+ set(USE_STATIC_MBEDTLS_LIBRARY ON CACHE BOOL "" FORCE)
52
+ set(USE_SHARED_MBEDTLS_LIBRARY OFF CACHE BOOL "" FORCE)
53
+ # mbedtls's codegen'd sources (library/error.c,
54
+ # tf-psa-crypto/core/psa_crypto_driver_wrappers_no_static.c, etc.) must
55
+ # exist on disk before add_subdirectory() below runs. mbedtls generates
56
+ # them itself via its own GEN_FILES option on Linux/macOS, but defaults
57
+ # GEN_FILES OFF on any Windows host (assuming a release tarball with these
58
+ # files already bundled). We build mbedtls from a git submodule, which
59
+ # never has them on any platform, so we generate them ourselves here,
60
+ # unconditionally, using mbedtls's own official scripts — the approach
61
+ # mbedtls's maintainers recommend: https://github.com/Mbed-TLS/mbedtls/issues/10678.
62
+ # Requires Python 3 and Perl on PATH (both are already required to build
63
+ # mbedtls from a git checkout, per its own documentation).
64
+ set(_httpp_mbedtls_dir ${PROJECT_SOURCE_DIR}/src/third_party/mbedtls)
65
+ find_package(Python3 COMPONENTS Interpreter REQUIRED)
66
+ execute_process(
67
+ COMMAND ${Python3_EXECUTABLE} framework/scripts/make_generated_files.py
68
+ WORKING_DIRECTORY ${_httpp_mbedtls_dir}/tf-psa-crypto
69
+ RESULT_VARIABLE _httpp_mbedtls_gen_result
70
+ )
71
+ if(NOT _httpp_mbedtls_gen_result EQUAL 0)
72
+ message(FATAL_ERROR "Failed to generate tf-psa-crypto sources (exit ${_httpp_mbedtls_gen_result})")
73
+ endif()
74
+ execute_process(
75
+ COMMAND ${Python3_EXECUTABLE} scripts/make_generated_files.py
76
+ WORKING_DIRECTORY ${_httpp_mbedtls_dir}
77
+ RESULT_VARIABLE _httpp_mbedtls_gen_result
78
+ )
79
+ if(NOT _httpp_mbedtls_gen_result EQUAL 0)
80
+ message(FATAL_ERROR "Failed to generate mbedtls sources (exit ${_httpp_mbedtls_gen_result})")
81
+ endif()
82
+ # mbedtls's own install() rules are unconditional unless this is forced ON
83
+ # (its "am I a subproject" auto-detection doesn't reliably suppress them);
84
+ # httpp links it in statically and never re-exports its headers/libs, so
85
+ # nothing from mbedtls itself belongs in the installed wheel.
86
+ set(DISABLE_PACKAGE_CONFIG_AND_INSTALL ON CACHE BOOL "" FORCE)
87
+ add_subdirectory(${PROJECT_SOURCE_DIR}/src/third_party/mbedtls)
88
+
89
+ add_library(httpp_core SHARED ${HTTPP_CORE_SOURCES})
90
+ add_library(httpp::core ALIAS httpp_core)
91
+
92
+ # Windows/MSVC dllexport-vs-dllimport: HTTPP_API (include/httpp/export.hpp)
93
+ # resolves to __declspec(dllexport) only when HTTPP_BUILDING_DLL is defined.
94
+ # It must be defined while compiling httpp_core's OWN translation units
95
+ # (client.cpp/server.cpp/url.cpp) so the public classes are actually
96
+ # exported from httpp_core.dll — and must NOT be defined for anyone
97
+ # consuming the already-built DLL (they need dllimport instead), hence
98
+ # PRIVATE, not PUBLIC/INTERFACE.
99
+ target_compile_definitions(httpp_core PRIVATE HTTPP_BUILDING_DLL)
100
+
101
+ set_target_properties(httpp_core PROPERTIES
102
+ POSITION_INDEPENDENT_CODE ON
103
+ CXX_VISIBILITY_PRESET hidden
104
+ VISIBILITY_INLINES_HIDDEN ON
105
+ MACOSX_RPATH ON
106
+ INSTALL_NAME_DIR "@rpath"
107
+ )
108
+
109
+ target_include_directories(httpp_core
110
+ PUBLIC
111
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
112
+ $<INSTALL_INTERFACE:httpp/include>
113
+ )
114
+ # SYSTEM: these are vendored/third-party headers we don't control (cpp-httplib,
115
+ # indicators, etc.). Marking them SYSTEM tells the compiler their own internal
116
+ # warnings (e.g. indicators.hpp's narrowing-conversion C4244/C4267 on MSVC)
117
+ # aren't ours to fix and shouldn't surface under our own -Wall/-Wextra/-W4
118
+ # below — without patching vendored code to silence its own warnings.
119
+ target_include_directories(httpp_core SYSTEM PRIVATE
120
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/third_party/cpp-httplib
121
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/third_party
122
+ )
123
+
124
+ find_package(Threads REQUIRED)
125
+ target_link_libraries(httpp_core PUBLIC Threads::Threads)
126
+ target_link_libraries(httpp_core PRIVATE url::base)
127
+
128
+ # HTTPS support: mbedtls is linked PRIVATE and CPPHTTPLIB_MBEDTLS_SUPPORT is
129
+ # only ever defined in src/core/internal/httplib_common.hpp (never in a
130
+ # public header), so consumers of httpp never need mbedtls on their own
131
+ # include/link path — see that file for the shared httplib.h include.
132
+ target_link_libraries(httpp_core PRIVATE mbedtls mbedx509)
133
+ target_compile_definitions(httpp_core PRIVATE CPPHTTPLIB_MBEDTLS_SUPPORT)
134
+
135
+ # macOS: cpp-httplib (src/third_party/cpp-httplib/httplib.h) reads the
136
+ # system trust store via the Keychain APIs (CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN),
137
+ # which pulls in CoreFoundation/Security symbols (e.g. SecTrustSettingsCopyCertificates).
138
+ # These aren't linked by default and must be added explicitly, or the final
139
+ # link of libhttpp_core.dylib fails with "symbol(s) not found for architecture".
140
+ if(APPLE)
141
+ find_library(COREFOUNDATION_LIBRARY CoreFoundation REQUIRED)
142
+ find_library(SECURITY_LIBRARY Security REQUIRED)
143
+ target_link_libraries(httpp_core PRIVATE ${COREFOUNDATION_LIBRARY} ${SECURITY_LIBRARY})
144
+ endif()
145
+
146
+ target_compile_options(httpp_core PRIVATE
147
+ $<$<CXX_COMPILER_ID:MSVC>:/W4 /EHsc>
148
+ $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Wextra -Wpedantic>
149
+ )
150
+
151
+ apply_optimization_flags(httpp_core)
152
+
153
+ if(HTTPP_BUILD_PYTHON OR DEFINED SKBUILD)
154
+ set(PYTHON_INSTALL_DIR ${CMAKE_BINARY_DIR}/python/install)
155
+ add_subdirectory(${PROJECT_SOURCE_DIR}/src/bindings/python)
156
+ if(DEFINED SKBUILD)
157
+ return()
158
+ endif()
159
+ endif()
160
+
161
+ # Installation
162
+ install(TARGETS httpp_core
163
+ ARCHIVE DESTINATION lib
164
+ LIBRARY DESTINATION lib
165
+ )
166
+ install(DIRECTORY include DESTINATION .)
167
+
168
+ # Tests
169
+ if(HTTPP_BUILD_TESTS)
170
+ enable_testing()
171
+ set(CMAKE_CTEST_ARGUMENTS "--output-on-failure" "-V")
172
+ add_subdirectory(${PROJECT_SOURCE_DIR}/tests)
173
+ endif()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: httpp
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: A Cython project with scikit-build
5
5
  Author-Email: Mohammad Raziei <mohammadraziei1375@gmail.com>
6
6
  License: MIT
@@ -61,7 +61,7 @@ pip install httpp
61
61
  ### Python
62
62
 
63
63
  ```python
64
- from httpp import Client, Server, DownloadFile, CurlRequest
64
+ from httpp import Client, Server, DownloadFile, Request
65
65
 
66
66
  # client
67
67
  res = Client.fetch("http://example.com/")
@@ -76,7 +76,7 @@ srv.listen("0.0.0.0", 8000)
76
76
  DownloadFile("http://example.com/big.zip").output("big.zip").run()
77
77
 
78
78
  # a small curl-flavored request builder
79
- res = CurlRequest("http://example.com/api").method("POST").data("a=1").run()
79
+ res = Request("http://example.com/api").method("POST").data("a=1").run()
80
80
  ```
81
81
 
82
82
  ### CLI
@@ -105,7 +105,7 @@ srv.listen("0.0.0.0", 8000);
105
105
 
106
106
  httpp::download_file("http://example.com/f.zip").output("f.zip").run();
107
107
 
108
- auto res2 = httpp::curl::request("http://example.com/api")
108
+ auto res2 = httpp::client::request("http://example.com/api")
109
109
  .method("POST")
110
110
  .header("X-Token", "abc")
111
111
  .data("a=1")
@@ -162,17 +162,22 @@ ctest --test-dir build --output-on-failure # C++, Python, and CMake-integratio
162
162
 
163
163
  ## Status
164
164
 
165
- - [x] `httpp::client` — GET requests; `.fetch(url)` parses a full URL in one call
165
+ - [x] `httpp::client` — GET requests (with optional headers), response
166
+ headers (`res.header("Content-Type")`); `.fetch(url)` parses a full
167
+ URL in one call. HTTP **and HTTPS** (mbedtls-backed).
166
168
  - [x] `httpp::server` — route handlers, static directory serving
167
- - [x] `httpp::curl` — a small curl-flavored fluent request builder (method/headers/data)
168
- - [x] `httpp::download_file` — fluent download builder with a terminal progress bar
169
- (sync `.run()` and async `.run_async()`)
169
+ - [x] `httpp::client::request` — a small curl-flavored fluent request
170
+ builder (method/headers/data/timeout/redirects), also over HTTPS
171
+ - [x] `httpp::download_file` — fluent download builder with a terminal
172
+ progress bar (sync `.run()` and async `.run_async()`)
170
173
  - [x] `httpp::progress` — `bar` (tqdm-like) and `range` (trange-like)
171
174
  - [x] `httpp/curl_compat.h` — a `curl_easy_*` C API subset for migrating
172
- existing libcurl code, built directly on `httpp::curl::request`
173
- - [x] CLI — `server`, `download`, `curl`, `install`/`uninstall`
174
- - [x] Python bindings for `Client`, `Server`, `DownloadFile`, `CurlRequest`
175
- - [ ] HTTPS
175
+ existing libcurl code, including response headers
176
+ (`CURLOPT_HEADERFUNCTION`) and `CURLINFO_CONTENT_TYPE`, built
177
+ directly on `httpp::client::request`
178
+ - [x] CLI — `server`, `download`, `curl`, `install`/`uninstall`, `path`
179
+ (`httpp --cmake-dir` / `httpp path --include-dir`, etc.)
180
+ - [x] Python bindings for `Client`, `Server`, `DownloadFile`, `Request`
176
181
  - [ ] Route handlers from Python (directory serving works today; custom
177
182
  routes are C++-only for now)
178
183
 
@@ -36,7 +36,7 @@ pip install httpp
36
36
  ### Python
37
37
 
38
38
  ```python
39
- from httpp import Client, Server, DownloadFile, CurlRequest
39
+ from httpp import Client, Server, DownloadFile, Request
40
40
 
41
41
  # client
42
42
  res = Client.fetch("http://example.com/")
@@ -51,7 +51,7 @@ srv.listen("0.0.0.0", 8000)
51
51
  DownloadFile("http://example.com/big.zip").output("big.zip").run()
52
52
 
53
53
  # a small curl-flavored request builder
54
- res = CurlRequest("http://example.com/api").method("POST").data("a=1").run()
54
+ res = Request("http://example.com/api").method("POST").data("a=1").run()
55
55
  ```
56
56
 
57
57
  ### CLI
@@ -80,7 +80,7 @@ srv.listen("0.0.0.0", 8000);
80
80
 
81
81
  httpp::download_file("http://example.com/f.zip").output("f.zip").run();
82
82
 
83
- auto res2 = httpp::curl::request("http://example.com/api")
83
+ auto res2 = httpp::client::request("http://example.com/api")
84
84
  .method("POST")
85
85
  .header("X-Token", "abc")
86
86
  .data("a=1")
@@ -137,17 +137,22 @@ ctest --test-dir build --output-on-failure # C++, Python, and CMake-integratio
137
137
 
138
138
  ## Status
139
139
 
140
- - [x] `httpp::client` — GET requests; `.fetch(url)` parses a full URL in one call
140
+ - [x] `httpp::client` — GET requests (with optional headers), response
141
+ headers (`res.header("Content-Type")`); `.fetch(url)` parses a full
142
+ URL in one call. HTTP **and HTTPS** (mbedtls-backed).
141
143
  - [x] `httpp::server` — route handlers, static directory serving
142
- - [x] `httpp::curl` — a small curl-flavored fluent request builder (method/headers/data)
143
- - [x] `httpp::download_file` — fluent download builder with a terminal progress bar
144
- (sync `.run()` and async `.run_async()`)
144
+ - [x] `httpp::client::request` — a small curl-flavored fluent request
145
+ builder (method/headers/data/timeout/redirects), also over HTTPS
146
+ - [x] `httpp::download_file` — fluent download builder with a terminal
147
+ progress bar (sync `.run()` and async `.run_async()`)
145
148
  - [x] `httpp::progress` — `bar` (tqdm-like) and `range` (trange-like)
146
149
  - [x] `httpp/curl_compat.h` — a `curl_easy_*` C API subset for migrating
147
- existing libcurl code, built directly on `httpp::curl::request`
148
- - [x] CLI — `server`, `download`, `curl`, `install`/`uninstall`
149
- - [x] Python bindings for `Client`, `Server`, `DownloadFile`, `CurlRequest`
150
- - [ ] HTTPS
150
+ existing libcurl code, including response headers
151
+ (`CURLOPT_HEADERFUNCTION`) and `CURLINFO_CONTENT_TYPE`, built
152
+ directly on `httpp::client::request`
153
+ - [x] CLI — `server`, `download`, `curl`, `install`/`uninstall`, `path`
154
+ (`httpp --cmake-dir` / `httpp path --include-dir`, etc.)
155
+ - [x] Python bindings for `Client`, `Server`, `DownloadFile`, `Request`
151
156
  - [ ] Route handlers from Python (directory serving works today; custom
152
157
  routes are C++-only for now)
153
158
 
@@ -0,0 +1,114 @@
1
+ #pragma once
2
+
3
+ #include "httpp/export.hpp"
4
+
5
+ #include <algorithm>
6
+ #include <cctype>
7
+ #include <memory>
8
+ #include <string>
9
+ #include <utility>
10
+ #include <vector>
11
+
12
+ namespace httpp {
13
+
14
+ struct response {
15
+ int status = 0;
16
+ std::string body;
17
+ std::vector<std::pair<std::string, std::string>> headers;
18
+
19
+ bool ok() const { return status >= 200 && status < 300; }
20
+
21
+ // HTTP header names are case-insensitive (RFC 7230); this looks up
22
+ // the first matching header and returns "" if it isn't present.
23
+ std::string header(const std::string& name) const {
24
+ auto ci_equal = [](const std::string& a, const std::string& b) {
25
+ return a.size() == b.size() &&
26
+ std::equal(a.begin(), a.end(), b.begin(), [](unsigned char x, unsigned char y) {
27
+ return std::tolower(x) == std::tolower(y);
28
+ });
29
+ };
30
+ for (const auto& [key, value] : headers) {
31
+ if (ci_equal(key, name)) return value;
32
+ }
33
+ return "";
34
+ }
35
+ };
36
+
37
+ // Public API exposes no third-party types (no httplib.h here at all).
38
+ // The real implementation (backed by vendored cpp-httplib + mbedtls for
39
+ // HTTPS) lives in src/core/client.cpp and is hidden behind this pointer, so
40
+ // neither httplib.h nor mbedtls ever leak into consumers of this header.
41
+ class client {
42
+ public:
43
+ // use_ssl selects httplib's SSLClient (mbedtls-backed) vs. its plain
44
+ // Client internally; both http:// and https:// URLs work through
45
+ // fetch()/client::request without the caller ever thinking about this.
46
+ explicit HTTPP_API client(const std::string& host, int port, bool use_ssl = false);
47
+ HTTPP_API ~client();
48
+
49
+ HTTPP_API client(client&&) noexcept;
50
+ HTTPP_API client& operator=(client&&) noexcept;
51
+ client(const client&) = delete;
52
+ client& operator=(const client&) = delete;
53
+
54
+ HTTPP_API response get(const std::string& path);
55
+ HTTPP_API response get(const std::string& path, const std::vector<std::pair<std::string, std::string>>& headers);
56
+
57
+ // Parse `full_url` (via httpp::url) and GET it in one call — handles
58
+ // http:// and https:// alike. No manual URL parsing needed by callers
59
+ // (e.g. the CLI's `download` command).
60
+ static HTTPP_API response fetch(const std::string& full_url);
61
+
62
+ // A small, curl-flavored fluent request builder for the less common
63
+ // cases (custom method, headers, a body) that get()/fetch() don't
64
+ // cover — the common cases only (-X/-H/-d equivalents), not a full
65
+ // HTTP-client-options kitchen sink. Also what httpp/curl_compat.h's
66
+ // `curl_easy_*` C API is built on (see src/core/curl_compat.cpp) — one
67
+ // implementation of "run an HTTP request" in httpp, not two.
68
+ //
69
+ // Nested under `client` (not a free `httpp::request`) because
70
+ // `httpp::request` is already the incoming-request struct passed to
71
+ // server route handlers (see httpp/server.hpp) — naming this
72
+ // `client::request` avoids that collision and reads naturally next to
73
+ // the class it's built on: httpp::client::request(url)....run()
74
+ class request {
75
+ public:
76
+ explicit HTTPP_API request(std::string url);
77
+ HTTPP_API ~request();
78
+
79
+ HTTPP_API request(request&&) noexcept;
80
+ HTTPP_API request& operator=(request&&) noexcept;
81
+ request(const request&) = delete;
82
+ request& operator=(const request&) = delete;
83
+
84
+ // -X METHOD (GET/POST/PUT/PATCH/DELETE). If never called, defaults
85
+ // to GET, unless data() was called, in which case it defaults to
86
+ // POST — matching curl's own behavior.
87
+ HTTPP_API request& method(std::string m);
88
+
89
+ // -H "Name: value"
90
+ HTTPP_API request& header(std::string name, std::string value);
91
+
92
+ // -d "body" (sets Content-Type to
93
+ // application/x-www-form-urlencoded unless content_type() overrides it)
94
+ HTTPP_API request& data(std::string body);
95
+
96
+ HTTPP_API request& content_type(std::string type);
97
+
98
+ // -m/--max-time (seconds), -L/--location
99
+ HTTPP_API request& timeout(long seconds);
100
+ HTTPP_API request& follow_redirects(bool enable = true);
101
+
102
+ HTTPP_API response run() const;
103
+
104
+ private:
105
+ struct impl;
106
+ std::unique_ptr<impl> impl_;
107
+ };
108
+
109
+ private:
110
+ struct impl;
111
+ std::unique_ptr<impl> impl_;
112
+ };
113
+
114
+ } // namespace httpp
@@ -14,35 +14,35 @@ namespace httpp::curl {
14
14
  // plain request API this is built on). Backed by the same vendored
15
15
  // cpp-httplib as the rest of httpp, hidden behind this pointer (see
16
16
  // src/core/curl.cpp) and never exposed in this public header.
17
- class HTTPP_API request {
17
+ class request {
18
18
  public:
19
- explicit request(std::string url);
20
- ~request();
19
+ explicit HTTPP_API request(std::string url);
20
+ HTTPP_API ~request();
21
21
 
22
- request(request&&) noexcept;
23
- request& operator=(request&&) noexcept;
22
+ HTTPP_API request(request&&) noexcept;
23
+ HTTPP_API request& operator=(request&&) noexcept;
24
24
  request(const request&) = delete;
25
25
  request& operator=(const request&) = delete;
26
26
 
27
27
  // -X METHOD (GET/POST/PUT/PATCH/DELETE). If never called, defaults to
28
28
  // GET, unless data() was called, in which case it defaults to POST —
29
29
  // matching curl's own behavior.
30
- request& method(std::string m);
30
+ HTTPP_API request& method(std::string m);
31
31
 
32
32
  // -H "Name: value"
33
- request& header(std::string name, std::string value);
33
+ HTTPP_API request& header(std::string name, std::string value);
34
34
 
35
35
  // -d "body" (sets Content-Type to application/x-www-form-urlencoded
36
36
  // unless content_type() overrides it)
37
- request& data(std::string body);
37
+ HTTPP_API request& data(std::string body);
38
38
 
39
- request& content_type(std::string type);
39
+ HTTPP_API request& content_type(std::string type);
40
40
 
41
41
  // -m/--max-time (seconds), -L/--location
42
- request& timeout(long seconds);
43
- request& follow_redirects(bool enable = true);
42
+ HTTPP_API request& timeout(long seconds);
43
+ HTTPP_API request& follow_redirects(bool enable = true);
44
44
 
45
- response run() const;
45
+ HTTPP_API response run() const;
46
46
 
47
47
  private:
48
48
  struct impl;
@@ -9,21 +9,22 @@
9
9
  *
10
10
  * This is NOT a full libcurl replacement: only the commonly used easy-API
11
11
  * subset below is implemented, and every curl_easy_setopt() call is
12
- * forwarded to (and reuses the exact same code as) httpp::curl::request
13
- * (see include/httpp/curl.hpp, src/core/curl_compat.cpp) — there is no
12
+ * forwarded to (and reuses the exact same code as) httpp::client::request
13
+ * (see include/httpp/client.hpp, src/core/curl_compat.cpp) — there is no
14
14
  * separate/duplicated HTTP implementation here.
15
15
  *
16
16
  * Covered: CURLOPT_URL, CURLOPT_CUSTOMREQUEST, CURLOPT_HTTPGET,
17
17
  * CURLOPT_POST, CURLOPT_POSTFIELDS(+SIZE), CURLOPT_HTTPHEADER,
18
- * CURLOPT_WRITEFUNCTION/DATA, CURLOPT_USERAGENT, CURLOPT_TIMEOUT,
19
- * CURLOPT_FOLLOWLOCATION, curl_slist_*, curl_easy_getinfo
20
- * (CURLINFO_RESPONSE_CODE), curl_easy_strerror, curl_global_init/cleanup.
18
+ * CURLOPT_WRITEFUNCTION/DATA, CURLOPT_HEADERFUNCTION/DATA,
19
+ * CURLOPT_USERAGENT, CURLOPT_TIMEOUT, CURLOPT_FOLLOWLOCATION, curl_slist_*,
20
+ * curl_easy_getinfo (CURLINFO_RESPONSE_CODE, CURLINFO_CONTENT_TYPE),
21
+ * curl_easy_strerror, curl_global_init/cleanup.
21
22
  *
22
23
  * NOT covered (no such option exists here — curl_easy_setopt() returns
23
24
  * CURLE_UNKNOWN_OPTION for anything not listed above): proxies, cookies,
24
25
  * TLS/certificate options, auth (basic/digest/bearer), multipart forms,
25
- * response header callbacks, multi/share handles, and everything else in
26
- * real libcurl's ~300 CURLOPT_* options.
26
+ * multi/share handles, and everything else in real libcurl's ~300
27
+ * CURLOPT_* options.
27
28
  */
28
29
 
29
30
  #include "httpp/export.hpp"
@@ -58,6 +59,8 @@ typedef enum {
58
59
  CURLOPT_HTTPHEADER,
59
60
  CURLOPT_WRITEFUNCTION,
60
61
  CURLOPT_WRITEDATA,
62
+ CURLOPT_HEADERFUNCTION,
63
+ CURLOPT_HEADERDATA,
61
64
  CURLOPT_USERAGENT,
62
65
  CURLOPT_TIMEOUT,
63
66
  CURLOPT_FOLLOWLOCATION,
@@ -65,10 +68,15 @@ typedef enum {
65
68
  } CURLoption;
66
69
 
67
70
  typedef enum {
68
- CURLINFO_RESPONSE_CODE
71
+ CURLINFO_RESPONSE_CODE,
72
+ CURLINFO_CONTENT_TYPE /* returns const char*, or NULL if absent */
69
73
  } CURLINFO;
70
74
 
71
75
  typedef size_t (*curl_write_callback)(char* ptr, size_t size, size_t nmemb, void* userdata);
76
+ /* Called once per response header line, formatted "Name: value\r\n" —
77
+ * matches real libcurl's curl_write_callback signature exactly, since
78
+ * that's what CURLOPT_HEADERFUNCTION expects there too. */
79
+ typedef curl_write_callback curl_header_callback;
72
80
 
73
81
  struct curl_slist {
74
82
  char* data;
@@ -7,7 +7,7 @@
7
7
 
8
8
  namespace httpp {
9
9
 
10
- struct HTTPP_API download_result {
10
+ struct download_result {
11
11
  bool ok = false;
12
12
  int status = 0;
13
13
  std::string error;
@@ -27,16 +27,16 @@ HTTPP_API download_result download(const std::string& url,
27
27
  //
28
28
  // auto fut = httpp::download_file(url).output(path).run_async();
29
29
  // download_result res = fut.get();
30
- class HTTPP_API download_file {
30
+ class download_file {
31
31
  public:
32
- explicit download_file(std::string url);
32
+ explicit HTTPP_API download_file(std::string url);
33
33
 
34
- download_file& output(std::string dest_path);
35
- download_file& enable_progress(bool enable = true);
36
- download_file& disable_progress();
34
+ HTTPP_API download_file& output(std::string dest_path);
35
+ HTTPP_API download_file& enable_progress(bool enable = true);
36
+ HTTPP_API download_file& disable_progress();
37
37
 
38
- download_result run() const;
39
- std::future<download_result> run_async() const;
38
+ HTTPP_API download_result run() const;
39
+ HTTPP_API std::future<download_result> run_async() const;
40
40
 
41
41
  private:
42
42
  std::string url_;
@@ -0,0 +1,26 @@
1
+ #pragma once
2
+
3
+ // Explicit export macro: with CXX_VISIBILITY_PRESET=hidden, nothing is
4
+ // exported from libhttpp.so by default (this is what keeps the vendored
5
+ // httplib symbols compiled into the .so out of the dynamic symbol table).
6
+ // Public httpp classes/functions are marked HTTPP_API to opt back in.
7
+ //
8
+ // Convention: HTTPP_API goes on individual out-of-line member functions
9
+ // (constructors, destructors, methods implemented in src/core/*.cpp), never
10
+ // on the class/struct itself. Marking a whole class dllexport on MSVC
11
+ // requires every member — including private ones — to have "dll-interface"
12
+ // (MSVC warning C4251), which fires even for private std::string/std::vector
13
+ // members and even for the std::unique_ptr<impl> of the pimpl pattern
14
+ // itself. Exporting only the specific symbols that are actually implemented
15
+ // in the DLL avoids this entirely: purely inline types (simple data structs
16
+ // like httpp::response, httpp::request, httpp::download_result) need no
17
+ // HTTPP_API at all, since nothing about them is compiled into the DLL.
18
+ #if defined(_WIN32)
19
+ # if defined(HTTPP_BUILDING_DLL)
20
+ # define HTTPP_API __declspec(dllexport)
21
+ # else
22
+ # define HTTPP_API __declspec(dllimport)
23
+ # endif
24
+ #else
25
+ # define HTTPP_API __attribute__((visibility("default")))
26
+ #endif
@@ -13,23 +13,23 @@ namespace httpp::progress {
13
13
  // Backed by the vendored `indicators` library (src/third_party/indicators),
14
14
  // but that dependency is hidden behind this pointer (see
15
15
  // src/core/progressbar.cpp) and never appears in this public header.
16
- class HTTPP_API bar {
16
+ class bar {
17
17
  public:
18
- explicit bar(std::size_t total, std::string description = "");
19
- ~bar();
18
+ explicit HTTPP_API bar(std::size_t total, std::string description = "");
19
+ HTTPP_API ~bar();
20
20
 
21
- bar(bar&&) noexcept;
22
- bar& operator=(bar&&) noexcept;
21
+ HTTPP_API bar(bar&&) noexcept;
22
+ HTTPP_API bar& operator=(bar&&) noexcept;
23
23
  bar(const bar&) = delete;
24
24
  bar& operator=(const bar&) = delete;
25
25
 
26
- void update(std::size_t n = 1); // advance by n
27
- void set_progress(std::size_t current); // set an absolute position
28
- void finish(); // jump to total and stop
26
+ HTTPP_API void update(std::size_t n = 1); // advance by n
27
+ HTTPP_API void set_progress(std::size_t current); // set an absolute position
28
+ HTTPP_API void finish(); // jump to total and stop
29
29
 
30
- std::size_t total() const;
31
- std::size_t current() const;
32
- bool is_finished() const;
30
+ HTTPP_API std::size_t total() const;
31
+ HTTPP_API std::size_t current() const;
32
+ HTTPP_API bool is_finished() const;
33
33
 
34
34
  private:
35
35
  struct impl;
@@ -40,7 +40,11 @@ private:
40
40
  // it by one on every step of the loop, e.g.:
41
41
  //
42
42
  // for (auto i : httpp::progressbar::range(100, "working")) { ... }
43
- class HTTPP_API range {
43
+ //
44
+ // Entirely defined inline here (calls only bar's already-exported members),
45
+ // so — unlike bar itself — this class needs no HTTPP_API at all: nothing
46
+ // about it is compiled into the DLL for a consumer to link against.
47
+ class range {
44
48
  public:
45
49
  explicit range(std::size_t total, std::string description = "")
46
50
  : total_(total), bar_(total, std::move(description)) {}