httpp 0.1.0__tar.gz → 0.4.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 (65) hide show
  1. httpp-0.4.0/PKG-INFO +181 -0
  2. httpp-0.4.0/README.md +156 -0
  3. httpp-0.4.0/include/httpp/curl.hpp +52 -0
  4. httpp-0.4.0/include/httpp/curl_compat.h +94 -0
  5. {httpp-0.1.0 → httpp-0.4.0}/include/httpp.h +4 -2
  6. {httpp-0.1.0 → httpp-0.4.0}/pyproject.toml +12 -2
  7. {httpp-0.1.0 → httpp-0.4.0}/src/bindings/python/httpp/__init__.py +2 -2
  8. {httpp-0.1.0 → httpp-0.4.0}/src/bindings/python/httpp/__main__.py +35 -0
  9. {httpp-0.1.0 → httpp-0.4.0}/src/bindings/python/httpp_cy.pyx +48 -0
  10. httpp-0.4.0/src/core/curl.cpp +115 -0
  11. httpp-0.4.0/src/core/curl_compat.cpp +224 -0
  12. httpp-0.4.0/tests/cmake/consumer_project/main.cpp +134 -0
  13. {httpp-0.1.0 → httpp-0.4.0}/tests/cmake/run_consumer_test.cmake +2 -2
  14. httpp-0.4.0/tests/cpp/test_curl.cpp +111 -0
  15. httpp-0.4.0/tests/cpp/test_curl_compat.cpp +116 -0
  16. {httpp-0.1.0 → httpp-0.4.0}/version.py +1 -3
  17. httpp-0.1.0/PKG-INFO +0 -89
  18. httpp-0.1.0/README.md +0 -64
  19. httpp-0.1.0/tests/cmake/consumer_project/main.cpp +0 -8
  20. {httpp-0.1.0 → httpp-0.4.0}/.github/workflows/cmake.yml +0 -0
  21. {httpp-0.1.0 → httpp-0.4.0}/.github/workflows/orchestrator.yml +0 -0
  22. {httpp-0.1.0 → httpp-0.4.0}/.github/workflows/release_template.md +0 -0
  23. {httpp-0.1.0 → httpp-0.4.0}/.github/workflows/wheels.yml +0 -0
  24. {httpp-0.1.0 → httpp-0.4.0}/.gitignore +0 -0
  25. {httpp-0.1.0 → httpp-0.4.0}/.gitmodules +0 -0
  26. {httpp-0.1.0 → httpp-0.4.0}/CMakeLists.txt +0 -0
  27. {httpp-0.1.0 → httpp-0.4.0}/LICENSE.txt +0 -0
  28. {httpp-0.1.0 → httpp-0.4.0}/cmake/DynamicVersion.cmake +0 -0
  29. {httpp-0.1.0 → httpp-0.4.0}/cmake/FindCython.cmake +0 -0
  30. {httpp-0.1.0 → httpp-0.4.0}/cmake/Optimize.cmake +0 -0
  31. {httpp-0.1.0 → httpp-0.4.0}/cmake/Startup.cmake +0 -0
  32. {httpp-0.1.0 → httpp-0.4.0}/cmake/UseCython.cmake +0 -0
  33. {httpp-0.1.0 → httpp-0.4.0}/cmake/httppConfig.cmake.in +0 -0
  34. {httpp-0.1.0 → httpp-0.4.0}/docs/index.rst +0 -0
  35. {httpp-0.1.0 → httpp-0.4.0}/examples/find_httpp_via_python/CMakeLists.txt +0 -0
  36. {httpp-0.1.0 → httpp-0.4.0}/examples/find_httpp_via_python/main.cpp +0 -0
  37. {httpp-0.1.0 → httpp-0.4.0}/include/httpp/client.hpp +0 -0
  38. {httpp-0.1.0 → httpp-0.4.0}/include/httpp/download.hpp +0 -0
  39. {httpp-0.1.0 → httpp-0.4.0}/include/httpp/export.hpp +0 -0
  40. {httpp-0.1.0 → httpp-0.4.0}/include/httpp/progress.hpp +0 -0
  41. {httpp-0.1.0 → httpp-0.4.0}/include/httpp/server.hpp +0 -0
  42. {httpp-0.1.0 → httpp-0.4.0}/include/httpp/url.hpp +0 -0
  43. {httpp-0.1.0 → httpp-0.4.0}/requirements-dev.txt +0 -0
  44. {httpp-0.1.0 → httpp-0.4.0}/src/bindings/python/CMakeLists.txt +0 -0
  45. {httpp-0.1.0 → httpp-0.4.0}/src/core/client.cpp +0 -0
  46. {httpp-0.1.0 → httpp-0.4.0}/src/core/download.cpp +0 -0
  47. {httpp-0.1.0 → httpp-0.4.0}/src/core/progress.cpp +0 -0
  48. {httpp-0.1.0 → httpp-0.4.0}/src/core/server.cpp +0 -0
  49. {httpp-0.1.0 → httpp-0.4.0}/src/core/url.cpp +0 -0
  50. {httpp-0.1.0 → httpp-0.4.0}/src/third_party/README.md +0 -0
  51. {httpp-0.1.0 → httpp-0.4.0}/src/third_party/cpp-httplib/httplib.h +0 -0
  52. {httpp-0.1.0 → httpp-0.4.0}/src/third_party/indicators/indicators.hpp +0 -0
  53. {httpp-0.1.0 → httpp-0.4.0}/tests/CMakeLists.txt +0 -0
  54. {httpp-0.1.0 → httpp-0.4.0}/tests/cmake/CMakeLists.txt +0 -0
  55. {httpp-0.1.0 → httpp-0.4.0}/tests/cmake/consumer_project/CMakeLists.txt +0 -0
  56. {httpp-0.1.0 → httpp-0.4.0}/tests/cpp/CMakeLists.txt +0 -0
  57. {httpp-0.1.0 → httpp-0.4.0}/tests/cpp/test_client.cpp +0 -0
  58. {httpp-0.1.0 → httpp-0.4.0}/tests/cpp/test_download.cpp +0 -0
  59. {httpp-0.1.0 → httpp-0.4.0}/tests/cpp/test_progress.cpp +0 -0
  60. {httpp-0.1.0 → httpp-0.4.0}/tests/cpp/test_server.cpp +0 -0
  61. {httpp-0.1.0 → httpp-0.4.0}/tests/cpp/test_url.cpp +0 -0
  62. {httpp-0.1.0 → httpp-0.4.0}/tests/python/CMakeLists.txt +0 -0
  63. {httpp-0.1.0 → httpp-0.4.0}/tests/python/test_httpp_basic.py +0 -0
  64. {httpp-0.1.0 → httpp-0.4.0}/tests/utest/utest.h +0 -0
  65. {httpp-0.1.0 → httpp-0.4.0}/tests/utest/utest_main.cxx +0 -0
httpp-0.4.0/PKG-INFO ADDED
@@ -0,0 +1,181 @@
1
+ Metadata-Version: 2.2
2
+ Name: httpp
3
+ Version: 0.4.0
4
+ Summary: A Cython project with scikit-build
5
+ Author-Email: Mohammad Raziei <mohammadraziei1375@gmail.com>
6
+ License: MIT
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.8
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Project-URL: Homepage, https://github.com/MohammadRaziei/httpp
17
+ Project-URL: Bug Tracker, https://github.com/MohammadRaziei/httpp/issues
18
+ Project-URL: Document, https://MohammadRaziei.github.io/httpp
19
+ Requires-Python: >=3.8
20
+ Provides-Extra: test
21
+ Requires-Dist: pytest>=7.0; extra == "test"
22
+ Requires-Dist: pytest-xdist>=3.0; extra == "test"
23
+ Requires-Dist: pytest-cov>=4.0; extra == "test"
24
+ Description-Content-Type: text/markdown
25
+
26
+ # httpp
27
+
28
+ <div align="center">
29
+
30
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE.txt)
31
+ [![CMake 3.21+](https://img.shields.io/badge/CMake-3.21+-blue.svg)](https://cmake.org/)
32
+ [![C++17](https://img.shields.io/badge/C++-17-blue.svg)](https://en.cppreference.com/w/cpp/17)
33
+ [![Python 3.8+](https://img.shields.io/badge/Python-3.8+-blue.svg)](https://www.python.org/)
34
+
35
+ </div>
36
+
37
+ A lightweight HTTP **client + server** library for C++ and Python.
38
+ `pip install httpp` and you get: a Python package, a CLI, a compiled C++
39
+ library with headers and a CMake config — no system dependencies at all
40
+ (no `apt`/`choco`/`brew`, nothing outside what `pip` already gives you).
41
+
42
+ ## Why
43
+
44
+ - **Client and server in one library** — most lightweight HTTP libraries
45
+ only do one side.
46
+ - **Zero system dependencies** — every third-party piece is vendored and
47
+ built from source.
48
+ - **One `pip install`, three ways in** — Python API, a CLI, and a real C++
49
+ library (headers + `find_package(httpp)`) all come from the same wheel.
50
+ - **A migration path for existing `libcurl` code** — `httpp/curl_compat.h`
51
+ gives you `curl_easy_*` so you can often switch with just a header swap.
52
+
53
+ ## Install
54
+
55
+ ```bash
56
+ pip install httpp
57
+ ```
58
+
59
+ ## Quick start
60
+
61
+ ### Python
62
+
63
+ ```python
64
+ from httpp import Client, Server, DownloadFile, CurlRequest
65
+
66
+ # client
67
+ res = Client.fetch("http://example.com/")
68
+ print(res.status, res.body)
69
+
70
+ # server — like `python -m http.server`, but embeddable in your own app
71
+ srv = Server()
72
+ srv.serve_directory("/", "./public")
73
+ srv.listen("0.0.0.0", 8000)
74
+
75
+ # download a file, with a tqdm-like progress bar
76
+ DownloadFile("http://example.com/big.zip").output("big.zip").run()
77
+
78
+ # a small curl-flavored request builder
79
+ res = CurlRequest("http://example.com/api").method("POST").data("a=1").run()
80
+ ```
81
+
82
+ ### CLI
83
+
84
+ ```bash
85
+ httpp server . # serve the current directory
86
+ httpp download http://example.com/ # print body to stdout
87
+ httpp download http://example.com/f.zip -o f.zip # save to a file, with a progress bar
88
+ httpp curl -X POST -H "X-Token: abc" -d "a=1" http://example.com/api
89
+ httpp install --user # put headers/lib/cmake config on your system
90
+ ```
91
+
92
+ ### C++
93
+
94
+ ```cpp
95
+ #include <httpp.h>
96
+
97
+ auto res = httpp::client::fetch("http://example.com/");
98
+
99
+ httpp::server srv;
100
+ srv.get("/hello", [](const httpp::request&, httpp::response& res) {
101
+ res.status = 200;
102
+ res.body = "world";
103
+ });
104
+ srv.listen("0.0.0.0", 8000);
105
+
106
+ httpp::download_file("http://example.com/f.zip").output("f.zip").run();
107
+
108
+ auto res2 = httpp::curl::request("http://example.com/api")
109
+ .method("POST")
110
+ .header("X-Token", "abc")
111
+ .data("a=1")
112
+ .run();
113
+ ```
114
+
115
+ ### Migrating from libcurl
116
+
117
+ ```c
118
+ #include <httpp/curl_compat.h> /* was: #include <curl/curl.h> */
119
+
120
+ CURL *curl = curl_easy_init();
121
+ curl_easy_setopt(curl, CURLOPT_URL, "http://example.com/");
122
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
123
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &out);
124
+ CURLcode rc = curl_easy_perform(curl);
125
+ curl_easy_cleanup(curl);
126
+ ```
127
+
128
+ Covers the common `curl_easy_*` subset (URL, method, headers, POST data,
129
+ write callback, timeout, follow-redirect, response code) — not a full
130
+ libcurl replacement. See the comment at the top of `curl_compat.h` for the
131
+ exact list.
132
+
133
+ ### Using it from CMake, from a plain `pip install`
134
+
135
+ No system-wide install needed — point CMake at the package Python already
136
+ installed:
137
+
138
+ ```cmake
139
+ execute_process(
140
+ COMMAND python3 -c "import httpp; print(httpp.get_cmake_dir())"
141
+ OUTPUT_VARIABLE httpp_DIR
142
+ OUTPUT_STRIP_TRAILING_WHITESPACE
143
+ )
144
+ find_package(httpp CONFIG REQUIRED)
145
+ target_link_libraries(app PRIVATE httpp::httpp_core)
146
+ ```
147
+
148
+ Or, after `httpp install [--user]`, plain `find_package(httpp)` works with
149
+ no Python involved at all — see [`tests/cmake/consumer_project`](tests/cmake/consumer_project)
150
+ for a full working example.
151
+
152
+ ## Build from source
153
+
154
+ ```bash
155
+ git clone --recurse-submodules https://github.com/MohammadRaziei/httpp.git
156
+ cd httpp
157
+ pip install -r requirements-dev.txt
158
+ cmake -B build -DHTTPP_BUILD_TESTS=ON -DHTTPP_BUILD_PYTHON=ON
159
+ cmake --build build -j4
160
+ ctest --test-dir build --output-on-failure # C++, Python, and CMake-integration tests
161
+ ```
162
+
163
+ ## Status
164
+
165
+ - [x] `httpp::client` — GET requests; `.fetch(url)` parses a full URL in one call
166
+ - [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()`)
170
+ - [x] `httpp::progress` — `bar` (tqdm-like) and `range` (trange-like)
171
+ - [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
176
+ - [ ] Route handlers from Python (directory serving works today; custom
177
+ routes are C++-only for now)
178
+
179
+ ## License
180
+
181
+ MIT
httpp-0.4.0/README.md ADDED
@@ -0,0 +1,156 @@
1
+ # httpp
2
+
3
+ <div align="center">
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE.txt)
6
+ [![CMake 3.21+](https://img.shields.io/badge/CMake-3.21+-blue.svg)](https://cmake.org/)
7
+ [![C++17](https://img.shields.io/badge/C++-17-blue.svg)](https://en.cppreference.com/w/cpp/17)
8
+ [![Python 3.8+](https://img.shields.io/badge/Python-3.8+-blue.svg)](https://www.python.org/)
9
+
10
+ </div>
11
+
12
+ A lightweight HTTP **client + server** library for C++ and Python.
13
+ `pip install httpp` and you get: a Python package, a CLI, a compiled C++
14
+ library with headers and a CMake config — no system dependencies at all
15
+ (no `apt`/`choco`/`brew`, nothing outside what `pip` already gives you).
16
+
17
+ ## Why
18
+
19
+ - **Client and server in one library** — most lightweight HTTP libraries
20
+ only do one side.
21
+ - **Zero system dependencies** — every third-party piece is vendored and
22
+ built from source.
23
+ - **One `pip install`, three ways in** — Python API, a CLI, and a real C++
24
+ library (headers + `find_package(httpp)`) all come from the same wheel.
25
+ - **A migration path for existing `libcurl` code** — `httpp/curl_compat.h`
26
+ gives you `curl_easy_*` so you can often switch with just a header swap.
27
+
28
+ ## Install
29
+
30
+ ```bash
31
+ pip install httpp
32
+ ```
33
+
34
+ ## Quick start
35
+
36
+ ### Python
37
+
38
+ ```python
39
+ from httpp import Client, Server, DownloadFile, CurlRequest
40
+
41
+ # client
42
+ res = Client.fetch("http://example.com/")
43
+ print(res.status, res.body)
44
+
45
+ # server — like `python -m http.server`, but embeddable in your own app
46
+ srv = Server()
47
+ srv.serve_directory("/", "./public")
48
+ srv.listen("0.0.0.0", 8000)
49
+
50
+ # download a file, with a tqdm-like progress bar
51
+ DownloadFile("http://example.com/big.zip").output("big.zip").run()
52
+
53
+ # a small curl-flavored request builder
54
+ res = CurlRequest("http://example.com/api").method("POST").data("a=1").run()
55
+ ```
56
+
57
+ ### CLI
58
+
59
+ ```bash
60
+ httpp server . # serve the current directory
61
+ httpp download http://example.com/ # print body to stdout
62
+ httpp download http://example.com/f.zip -o f.zip # save to a file, with a progress bar
63
+ httpp curl -X POST -H "X-Token: abc" -d "a=1" http://example.com/api
64
+ httpp install --user # put headers/lib/cmake config on your system
65
+ ```
66
+
67
+ ### C++
68
+
69
+ ```cpp
70
+ #include <httpp.h>
71
+
72
+ auto res = httpp::client::fetch("http://example.com/");
73
+
74
+ httpp::server srv;
75
+ srv.get("/hello", [](const httpp::request&, httpp::response& res) {
76
+ res.status = 200;
77
+ res.body = "world";
78
+ });
79
+ srv.listen("0.0.0.0", 8000);
80
+
81
+ httpp::download_file("http://example.com/f.zip").output("f.zip").run();
82
+
83
+ auto res2 = httpp::curl::request("http://example.com/api")
84
+ .method("POST")
85
+ .header("X-Token", "abc")
86
+ .data("a=1")
87
+ .run();
88
+ ```
89
+
90
+ ### Migrating from libcurl
91
+
92
+ ```c
93
+ #include <httpp/curl_compat.h> /* was: #include <curl/curl.h> */
94
+
95
+ CURL *curl = curl_easy_init();
96
+ curl_easy_setopt(curl, CURLOPT_URL, "http://example.com/");
97
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
98
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &out);
99
+ CURLcode rc = curl_easy_perform(curl);
100
+ curl_easy_cleanup(curl);
101
+ ```
102
+
103
+ Covers the common `curl_easy_*` subset (URL, method, headers, POST data,
104
+ write callback, timeout, follow-redirect, response code) — not a full
105
+ libcurl replacement. See the comment at the top of `curl_compat.h` for the
106
+ exact list.
107
+
108
+ ### Using it from CMake, from a plain `pip install`
109
+
110
+ No system-wide install needed — point CMake at the package Python already
111
+ installed:
112
+
113
+ ```cmake
114
+ execute_process(
115
+ COMMAND python3 -c "import httpp; print(httpp.get_cmake_dir())"
116
+ OUTPUT_VARIABLE httpp_DIR
117
+ OUTPUT_STRIP_TRAILING_WHITESPACE
118
+ )
119
+ find_package(httpp CONFIG REQUIRED)
120
+ target_link_libraries(app PRIVATE httpp::httpp_core)
121
+ ```
122
+
123
+ Or, after `httpp install [--user]`, plain `find_package(httpp)` works with
124
+ no Python involved at all — see [`tests/cmake/consumer_project`](tests/cmake/consumer_project)
125
+ for a full working example.
126
+
127
+ ## Build from source
128
+
129
+ ```bash
130
+ git clone --recurse-submodules https://github.com/MohammadRaziei/httpp.git
131
+ cd httpp
132
+ pip install -r requirements-dev.txt
133
+ cmake -B build -DHTTPP_BUILD_TESTS=ON -DHTTPP_BUILD_PYTHON=ON
134
+ cmake --build build -j4
135
+ ctest --test-dir build --output-on-failure # C++, Python, and CMake-integration tests
136
+ ```
137
+
138
+ ## Status
139
+
140
+ - [x] `httpp::client` — GET requests; `.fetch(url)` parses a full URL in one call
141
+ - [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()`)
145
+ - [x] `httpp::progress` — `bar` (tqdm-like) and `range` (trange-like)
146
+ - [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
151
+ - [ ] Route handlers from Python (directory serving works today; custom
152
+ routes are C++-only for now)
153
+
154
+ ## License
155
+
156
+ MIT
@@ -0,0 +1,52 @@
1
+ #pragma once
2
+
3
+ #include "httpp/export.hpp"
4
+ #include "httpp/client.hpp" // reuses httpp::response
5
+
6
+ #include <memory>
7
+ #include <string>
8
+
9
+ namespace httpp::curl {
10
+
11
+ // A small, curl-flavored fluent request builder — the common cases only
12
+ // (-X method, -H headers, -d data), NOT a libcurl API/ABI compatible shim
13
+ // (that's a much bigger, different project; see httpp::client for the
14
+ // plain request API this is built on). Backed by the same vendored
15
+ // cpp-httplib as the rest of httpp, hidden behind this pointer (see
16
+ // src/core/curl.cpp) and never exposed in this public header.
17
+ class HTTPP_API request {
18
+ public:
19
+ explicit request(std::string url);
20
+ ~request();
21
+
22
+ request(request&&) noexcept;
23
+ request& operator=(request&&) noexcept;
24
+ request(const request&) = delete;
25
+ request& operator=(const request&) = delete;
26
+
27
+ // -X METHOD (GET/POST/PUT/PATCH/DELETE). If never called, defaults to
28
+ // GET, unless data() was called, in which case it defaults to POST —
29
+ // matching curl's own behavior.
30
+ request& method(std::string m);
31
+
32
+ // -H "Name: value"
33
+ request& header(std::string name, std::string value);
34
+
35
+ // -d "body" (sets Content-Type to application/x-www-form-urlencoded
36
+ // unless content_type() overrides it)
37
+ request& data(std::string body);
38
+
39
+ request& content_type(std::string type);
40
+
41
+ // -m/--max-time (seconds), -L/--location
42
+ request& timeout(long seconds);
43
+ request& follow_redirects(bool enable = true);
44
+
45
+ response run() const;
46
+
47
+ private:
48
+ struct impl;
49
+ std::unique_ptr<impl> impl_;
50
+ };
51
+
52
+ } // namespace httpp::curl
@@ -0,0 +1,94 @@
1
+ #pragma once
2
+
3
+ /*
4
+ * A small, drop-in-ish subset of libcurl's `curl_easy_*` C API — meant to
5
+ * let existing code migrate to httpp with (ideally) just a header swap:
6
+ *
7
+ * -#include <curl/curl.h>
8
+ * +#include <httpp/curl_compat.h>
9
+ *
10
+ * This is NOT a full libcurl replacement: only the commonly used easy-API
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
14
+ * separate/duplicated HTTP implementation here.
15
+ *
16
+ * Covered: CURLOPT_URL, CURLOPT_CUSTOMREQUEST, CURLOPT_HTTPGET,
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.
21
+ *
22
+ * NOT covered (no such option exists here — curl_easy_setopt() returns
23
+ * CURLE_UNKNOWN_OPTION for anything not listed above): proxies, cookies,
24
+ * 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.
27
+ */
28
+
29
+ #include "httpp/export.hpp"
30
+
31
+ #include <stddef.h>
32
+
33
+ #ifdef __cplusplus
34
+ extern "C" {
35
+ #endif
36
+
37
+ typedef struct CURL CURL;
38
+
39
+ typedef enum {
40
+ CURLE_OK = 0,
41
+ CURLE_UNSUPPORTED_PROTOCOL,
42
+ CURLE_COULDNT_CONNECT,
43
+ CURLE_HTTP_RETURNED_ERROR,
44
+ CURLE_WRITE_ERROR,
45
+ CURLE_OUT_OF_MEMORY,
46
+ CURLE_OPERATION_TIMEDOUT,
47
+ CURLE_BAD_FUNCTION_ARGUMENT,
48
+ CURLE_UNKNOWN_OPTION
49
+ } CURLcode;
50
+
51
+ typedef enum {
52
+ CURLOPT_URL,
53
+ CURLOPT_CUSTOMREQUEST,
54
+ CURLOPT_HTTPGET,
55
+ CURLOPT_POST,
56
+ CURLOPT_POSTFIELDS,
57
+ CURLOPT_POSTFIELDSIZE,
58
+ CURLOPT_HTTPHEADER,
59
+ CURLOPT_WRITEFUNCTION,
60
+ CURLOPT_WRITEDATA,
61
+ CURLOPT_USERAGENT,
62
+ CURLOPT_TIMEOUT,
63
+ CURLOPT_FOLLOWLOCATION,
64
+ CURLOPT_VERBOSE /* accepted, has no effect */
65
+ } CURLoption;
66
+
67
+ typedef enum {
68
+ CURLINFO_RESPONSE_CODE
69
+ } CURLINFO;
70
+
71
+ typedef size_t (*curl_write_callback)(char* ptr, size_t size, size_t nmemb, void* userdata);
72
+
73
+ struct curl_slist {
74
+ char* data;
75
+ struct curl_slist* next;
76
+ };
77
+
78
+ HTTPP_API CURL* curl_easy_init(void);
79
+ HTTPP_API void curl_easy_cleanup(CURL* curl);
80
+ HTTPP_API CURLcode curl_easy_setopt(CURL* curl, CURLoption option, ...);
81
+ HTTPP_API CURLcode curl_easy_perform(CURL* curl);
82
+ HTTPP_API CURLcode curl_easy_getinfo(CURL* curl, CURLINFO info, ...);
83
+ HTTPP_API const char* curl_easy_strerror(CURLcode code);
84
+
85
+ HTTPP_API struct curl_slist* curl_slist_append(struct curl_slist* list, const char* value);
86
+ HTTPP_API void curl_slist_free_all(struct curl_slist* list);
87
+
88
+ #define CURL_GLOBAL_DEFAULT 0L
89
+ HTTPP_API CURLcode curl_global_init(long flags);
90
+ HTTPP_API void curl_global_cleanup(void);
91
+
92
+ #ifdef __cplusplus
93
+ }
94
+ #endif
@@ -38,8 +38,8 @@
38
38
  *============================================================================*/
39
39
 
40
40
  #define HTTPP_VERSION_MAJOR 0
41
- #define HTTPP_VERSION_MINOR 1
42
- #define HTTPP_VERSION_PATCH 1
41
+ #define HTTPP_VERSION_MINOR 4
42
+ #define HTTPP_VERSION_PATCH 0
43
43
 
44
44
  /*==============================================================================
45
45
  * MARK: - Public API
@@ -51,5 +51,7 @@
51
51
  #include "httpp/server.hpp"
52
52
  #include "httpp/progress.hpp"
53
53
  #include "httpp/download.hpp"
54
+ #include "httpp/curl.hpp"
55
+ #include "httpp/curl_compat.h"
54
56
 
55
57
  #endif /* HTTPP_H */
@@ -8,7 +8,7 @@ build-backend = "scikit_build_core.build"
8
8
 
9
9
  [project]
10
10
  name = "httpp"
11
- version = "0.1.0"
11
+ dynamic = ["version"]
12
12
  description = "A Cython project with scikit-build"
13
13
  authors = [
14
14
  {name = "Mohammad Raziei", email = "mohammadraziei1375@gmail.com"},
@@ -59,6 +59,16 @@ sdist.include = [
59
59
  "src/third_party/liburlparser/**/*",
60
60
  ]
61
61
 
62
+ [tool.scikit-build.metadata.version]
63
+ provider = "scikit_build_core.metadata.regex"
64
+ input = "include/httpp.h"
65
+ regex = '''(?sx)
66
+ \#define \s+ HTTPP_VERSION_MAJOR \s+ (?P<major>\d+) .*?
67
+ \#define \s+ HTTPP_VERSION_MINOR \s+ (?P<minor>\d+) .*?
68
+ \#define \s+ HTTPP_VERSION_PATCH \s+ (?P<patch>\d+) .*?
69
+ '''
70
+ result = "{major}.{minor}.{patch}"
71
+
62
72
 
63
73
  [tool.cibuildwheel]
64
74
  skip = "*i686*"
@@ -85,4 +95,4 @@ target-version = ['py311']
85
95
 
86
96
  [tool.isort]
87
97
  profile = "black"
88
- multi_line_output = 3
98
+ multi_line_output = 3
@@ -17,7 +17,7 @@ if _sys.platform == "win32" and hasattr(_os, "add_dll_directory"):
17
17
  _os.add_dll_directory(_lib_dir)
18
18
 
19
19
  # Import the compiled Cython module
20
- from .httpp_cy import Client, Server, download, DownloadFile, DownloadResult
20
+ from .httpp_cy import Client, Server, download, DownloadFile, DownloadResult, CurlRequest
21
21
 
22
22
 
23
23
  def get_include_dir():
@@ -38,6 +38,6 @@ def get_cmake_dir():
38
38
 
39
39
 
40
40
  __all__ = [
41
- "Client", "Server", "download", "DownloadFile", "DownloadResult",
41
+ "Client", "Server", "download", "DownloadFile", "DownloadResult", "CurlRequest",
42
42
  "get_include_dir", "get_lib_dir", "get_cmake_dir",
43
43
  ]
@@ -98,6 +98,33 @@ def _cmd_uninstall(args):
98
98
  return 0
99
99
 
100
100
 
101
+ def _cmd_curl(args):
102
+ from httpp import CurlRequest
103
+
104
+ req = CurlRequest(args.url)
105
+ if args.request:
106
+ req.method(args.request)
107
+ for h in args.header or []:
108
+ if ":" not in h:
109
+ print(f"error: malformed header (expected 'Name: value'): {h!r}", file=sys.stderr)
110
+ return 1
111
+ name, value = h.split(":", 1)
112
+ req.header(name.strip(), value.strip())
113
+ if args.data is not None:
114
+ req.data(args.data)
115
+
116
+ res = req.run()
117
+ if args.output:
118
+ with open(args.output, "w", encoding="utf-8") as f:
119
+ f.write(res.body)
120
+ else:
121
+ print(res.body)
122
+ if not res.ok:
123
+ print(f"error: request failed with status {res.status}", file=sys.stderr)
124
+ return 1
125
+ return 0
126
+
127
+
101
128
  def build_parser():
102
129
  parser = argparse.ArgumentParser(
103
130
  prog="httpp", description="httpp: a lightweight HTTP client + server toolkit."
@@ -116,6 +143,14 @@ def build_parser():
116
143
  p_download.add_argument("-q", "--quiet", action="store_true", help="With -o, suppress the progress bar.")
117
144
  p_download.set_defaults(func=_cmd_download)
118
145
 
146
+ p_curl = sub.add_parser("curl", help="Make a request (limited curl-like subset: -X/-H/-d).")
147
+ p_curl.add_argument("url")
148
+ p_curl.add_argument("-X", "--request", default=None, help="HTTP method (default: GET, or POST if -d is given).")
149
+ p_curl.add_argument("-H", "--header", action="append", default=None, help="Extra header 'Name: value' (repeatable).")
150
+ p_curl.add_argument("-d", "--data", default=None, help="Request body.")
151
+ p_curl.add_argument("-o", "--output", default=None, help="Write the response body to this file instead of stdout.")
152
+ p_curl.set_defaults(func=_cmd_curl)
153
+
119
154
  sdk_parent = argparse.ArgumentParser(add_help=False)
120
155
  sdk_parent.add_argument("--prefix", default=None, help="Install location (parent of httpp/). Default: /usr/local.")
121
156
  sdk_parent.add_argument("--user", action="store_true", help="Use ~/.local instead of /usr/local.")
@@ -50,6 +50,16 @@ cdef extern from "httpp/download.hpp" namespace "httpp":
50
50
  download_result run() except + nogil
51
51
 
52
52
 
53
+ cdef extern from "httpp/curl.hpp" namespace "httpp::curl":
54
+ cdef cppclass cpp_curl_request "httpp::curl::request":
55
+ cpp_curl_request(string url) except +
56
+ cpp_curl_request& method(string m) except +
57
+ cpp_curl_request& header(string name, string value) except +
58
+ cpp_curl_request& data(string body) except +
59
+ cpp_curl_request& content_type(string type) except +
60
+ response run() except + nogil
61
+
62
+
53
63
  cdef class Response:
54
64
  """A response to an HTTP request made via Client.get()."""
55
65
  cdef int _status
@@ -191,3 +201,41 @@ def download(str url, str dest_path, cbool show_progress=True):
191
201
  bar unless show_progress=False. Shorthand for
192
202
  DownloadFile(url).output(dest_path).run()."""
193
203
  return DownloadFile(url).output(dest_path).enable_progress(show_progress).run()
204
+
205
+ cdef class CurlRequest:
206
+ """A small, curl-flavored fluent request builder — the common cases
207
+ only (-X method, -H headers, -d data). NOT a libcurl-compatible shim;
208
+ see Client for the plain request API this is built on.
209
+
210
+ CurlRequest(url).method("PUT").header("X-Token", "abc").data("body").run()
211
+ """
212
+ cdef cpp_curl_request* _req
213
+
214
+ def __init__(self, str url):
215
+ self._req = new cpp_curl_request(url.encode("utf-8"))
216
+
217
+ def __dealloc__(self):
218
+ if self._req is not NULL:
219
+ del self._req
220
+
221
+ def method(self, str m):
222
+ self._req.method(m.encode("utf-8"))
223
+ return self
224
+
225
+ def header(self, str name, str value):
226
+ self._req.header(name.encode("utf-8"), value.encode("utf-8"))
227
+ return self
228
+
229
+ def data(self, str body):
230
+ self._req.data(body.encode("utf-8"))
231
+ return self
232
+
233
+ def content_type(self, str type_):
234
+ self._req.content_type(type_.encode("utf-8"))
235
+ return self
236
+
237
+ def run(self):
238
+ cdef response res
239
+ with nogil:
240
+ res = self._req.run()
241
+ return Response(res.status, res.body)