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.
- {httpp-0.4.0 → httpp-0.5.0}/.github/workflows/cmake.yml +2 -2
- {httpp-0.4.0 → httpp-0.5.0}/.github/workflows/orchestrator.yml +1 -0
- {httpp-0.4.0 → httpp-0.5.0}/.github/workflows/wheels.yml +1 -1
- httpp-0.5.0/CMakeLists.txt +173 -0
- {httpp-0.4.0 → httpp-0.5.0}/PKG-INFO +17 -12
- {httpp-0.4.0 → httpp-0.5.0}/README.md +16 -11
- httpp-0.5.0/include/httpp/client.hpp +114 -0
- {httpp-0.4.0 → httpp-0.5.0}/include/httpp/curl.hpp +12 -12
- {httpp-0.4.0 → httpp-0.5.0}/include/httpp/curl_compat.h +16 -8
- {httpp-0.4.0 → httpp-0.5.0}/include/httpp/download.hpp +8 -8
- httpp-0.5.0/include/httpp/export.hpp +26 -0
- {httpp-0.4.0 → httpp-0.5.0}/include/httpp/progress.hpp +16 -12
- {httpp-0.4.0 → httpp-0.5.0}/include/httpp/server.hpp +12 -12
- {httpp-0.4.0 → httpp-0.5.0}/include/httpp/url.hpp +2 -2
- {httpp-0.4.0 → httpp-0.5.0}/include/httpp.h +1 -2
- {httpp-0.4.0 → httpp-0.5.0}/pyproject.toml +5 -1
- {httpp-0.4.0 → httpp-0.5.0}/requirements-dev.txt +2 -0
- {httpp-0.4.0 → httpp-0.5.0}/src/bindings/python/CMakeLists.txt +9 -4
- {httpp-0.4.0 → httpp-0.5.0}/src/bindings/python/httpp/__init__.py +10 -3
- {httpp-0.4.0 → httpp-0.5.0}/src/bindings/python/httpp/__main__.py +46 -3
- {httpp-0.4.0 → httpp-0.5.0}/src/bindings/python/httpp_cy.pyx +36 -9
- httpp-0.5.0/src/core/client.cpp +172 -0
- {httpp-0.4.0 → httpp-0.5.0}/src/core/curl_compat.cpp +26 -4
- {httpp-0.4.0 → httpp-0.5.0}/src/core/download.cpp +4 -4
- httpp-0.5.0/src/core/internal/httplib_common.hpp +36 -0
- {httpp-0.4.0 → httpp-0.5.0}/tests/cmake/consumer_project/main.cpp +5 -5
- httpp-0.5.0/tests/cpp/test_client_request.cpp +111 -0
- httpp-0.4.0/CMakeLists.txt +0 -107
- httpp-0.4.0/include/httpp/client.hpp +0 -44
- httpp-0.4.0/include/httpp/export.hpp +0 -15
- httpp-0.4.0/src/core/client.cpp +0 -57
- {httpp-0.4.0 → httpp-0.5.0}/.github/workflows/release_template.md +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/.gitignore +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/.gitmodules +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/LICENSE.txt +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/cmake/DynamicVersion.cmake +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/cmake/FindCython.cmake +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/cmake/Optimize.cmake +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/cmake/Startup.cmake +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/cmake/UseCython.cmake +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/cmake/httppConfig.cmake.in +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/docs/index.rst +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/examples/find_httpp_via_python/CMakeLists.txt +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/examples/find_httpp_via_python/main.cpp +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/src/core/curl.cpp +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/src/core/progress.cpp +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/src/core/server.cpp +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/src/core/url.cpp +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/src/third_party/README.md +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/src/third_party/cpp-httplib/httplib.h +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/src/third_party/indicators/indicators.hpp +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/tests/CMakeLists.txt +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/tests/cmake/CMakeLists.txt +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/tests/cmake/consumer_project/CMakeLists.txt +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/tests/cmake/run_consumer_test.cmake +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/tests/cpp/CMakeLists.txt +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/tests/cpp/test_client.cpp +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/tests/cpp/test_curl.cpp +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/tests/cpp/test_curl_compat.cpp +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/tests/cpp/test_download.cpp +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/tests/cpp/test_progress.cpp +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/tests/cpp/test_server.cpp +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/tests/cpp/test_url.cpp +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/tests/python/CMakeLists.txt +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/tests/python/test_httpp_basic.py +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/tests/utest/utest.h +0 -0
- {httpp-0.4.0 → httpp-0.5.0}/tests/utest/utest_main.cxx +0 -0
- {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:
|
|
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:
|
|
56
|
+
submodules: recursive
|
|
57
57
|
|
|
58
58
|
- name: Setup cmake
|
|
59
59
|
uses: jwlawson/actions-setup-cmake@v2
|
|
@@ -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.
|
|
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,
|
|
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 =
|
|
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::
|
|
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
|
|
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::
|
|
168
|
-
|
|
169
|
-
|
|
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,
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
- [
|
|
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,
|
|
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 =
|
|
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::
|
|
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
|
|
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::
|
|
143
|
-
|
|
144
|
-
|
|
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,
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
- [
|
|
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
|
|
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::
|
|
13
|
-
* (see include/httpp/
|
|
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,
|
|
19
|
-
* CURLOPT_FOLLOWLOCATION, curl_slist_*,
|
|
20
|
-
* (CURLINFO_RESPONSE_CODE
|
|
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
|
-
*
|
|
26
|
-
*
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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)) {}
|