Skip to content

Commit 7e5db48

Browse files
committed
Fixed yhirose#33
1 parent c76d0e4 commit 7e5db48

File tree

3 files changed

+188
-50
lines changed

3 files changed

+188
-50
lines changed

README.md

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,15 +126,28 @@ auto res = cli.post("/post", params);
126126
httplib::Client client(url, port);
127127

128128
// prints: 0 / 000 bytes => 50% complete
129-
std::shared_ptr<httplib::Response> res =
130-
cli.get("/", [](int64_t len, int64_t total) {
131-
printf("%lld / %lld bytes => %d%% complete\n",
129+
std::shared_ptr<httplib::Response> res =
130+
cli.get("/", [](uint64_t len, uint64_t total) {
131+
printf("%lld / %lld bytes => %d%% complete\n",
132132
len, total,
133133
(int)((len/total)*100));
134134
}
135135
);
136136
```
137137

138+
### Range (HTTP/1.1)
139+
140+
```cpp
141+
httplib::Client cli("httpbin.org", 80, httplib::HttpVersion::v1_1);
142+
143+
// 'Range: bytes=1-10'
144+
httplib::Headers headers = { httplib::make_range_header(1, 10) };
145+
146+
auto res = cli.get("/range/32", headers);
147+
// res->status should be 206.
148+
// res->body should be "bcdefghijk".
149+
```
150+
138151
![progress](https://user-images.githubusercontent.com/236374/33138910-495c4ecc-cf86-11e7-8693-2fc6d09615c4.gif)
139152
140153
This feature was contributed by [underscorediscovery](https://github.com/yhirose/cpp-httplib/pull/23).

httplib.h

Lines changed: 87 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,13 @@ struct ci {
9191
enum class HttpVersion { v1_0 = 0, v1_1 };
9292

9393
typedef std::multimap<std::string, std::string, detail::ci> Headers;
94+
95+
template<typename uint64_t, typename... Args>
96+
std::pair<std::string, std::string> make_range_header(uint64_t value, Args... args);
97+
9498
typedef std::multimap<std::string, std::string> Params;
9599
typedef std::smatch Match;
96-
typedef std::function<void (int64_t current, int64_t total)> Progress;
100+
typedef std::function<void (uint64_t current, uint64_t total)> Progress;
97101

98102
struct MultipartFile {
99103
std::string filename;
@@ -111,11 +115,11 @@ struct Request {
111115
Params params;
112116
MultipartFiles files;
113117
Match matches;
118+
114119
Progress progress;
115120

116121
bool has_header(const char* key) const;
117122
std::string get_header_value(const char* key) const;
118-
void set_header(const char* key, const char* val);
119123

120124
bool has_param(const char* key) const;
121125
std::string get_param_value(const char* key) const;
@@ -211,10 +215,17 @@ class Client {
211215
Client(const char* host, int port, HttpVersion http_version = HttpVersion::v1_0);
212216
virtual ~Client();
213217

214-
std::shared_ptr<Response> get(const char* path, Progress callback = [](int64_t,int64_t){});
218+
std::shared_ptr<Response> get(const char* path, Progress progress = nullptr);
219+
std::shared_ptr<Response> get(const char* path, const Headers& headers, Progress progress = nullptr);
220+
215221
std::shared_ptr<Response> head(const char* path);
222+
std::shared_ptr<Response> head(const char* path, const Headers& headers);
223+
216224
std::shared_ptr<Response> post(const char* path, const std::string& body, const char* content_type);
225+
std::shared_ptr<Response> post(const char* path, const Headers& headers, const std::string& body, const char* content_type);
226+
217227
std::shared_ptr<Response> post(const char* path, const Params& params);
228+
std::shared_ptr<Response> post(const char* path, const Headers& headers, const Params& params);
218229

219230
bool send(const Request& req, Response& res);
220231

@@ -633,7 +644,9 @@ bool read_content_with_length(Stream& strm, T& x, size_t len, Progress progress)
633644
if (r_incr <= 0) {
634645
return false;
635646
}
647+
636648
r += r_incr;
649+
637650
if (progress) {
638651
progress(r, len);
639652
}
@@ -702,7 +715,7 @@ bool read_content_chunked(Stream& strm, T& x)
702715
}
703716

704717
template <typename T>
705-
bool read_content(Stream& strm, T& x, Progress progress = [](int64_t,int64_t){})
718+
bool read_content(Stream& strm, T& x, Progress progress = Progress())
706719
{
707720
auto len = get_header_value_int(x.headers, "Content-Length", 0);
708721

@@ -980,6 +993,38 @@ inline bool parse_multipart_formdata(
980993
return true;
981994
}
982995

996+
inline std::string to_lower(const char* beg, const char* end)
997+
{
998+
std::string out;
999+
auto it = beg;
1000+
while (it != end) {
1001+
out += ::tolower(*it);
1002+
it++;
1003+
}
1004+
return out;
1005+
}
1006+
1007+
inline void make_range_header_core(std::string&) {}
1008+
1009+
template<typename uint64_t>
1010+
inline void make_range_header_core(std::string& field, uint64_t value)
1011+
{
1012+
if (!field.empty()) {
1013+
field += ", ";
1014+
}
1015+
field += std::to_string(value) + "-";
1016+
}
1017+
1018+
template<typename uint64_t, typename... Args>
1019+
inline void make_range_header_core(std::string& field, uint64_t value1, uint64_t value2, Args... args)
1020+
{
1021+
if (!field.empty()) {
1022+
field += ", ";
1023+
}
1024+
field += std::to_string(value1) + "-" + std::to_string(value2);
1025+
make_range_header_core(field, args...);
1026+
}
1027+
9831028
#ifdef _WIN32
9841029
class WSInit {
9851030
public:
@@ -996,19 +1041,18 @@ class WSInit {
9961041
static WSInit wsinit_;
9971042
#endif
9981043

999-
inline std::string to_lower(const char* beg, const char* end)
1044+
} // namespace detail
1045+
1046+
// Header utilities
1047+
template<typename uint64_t, typename... Args>
1048+
inline std::pair<std::string, std::string> make_range_header(uint64_t value, Args... args)
10001049
{
1001-
std::string out;
1002-
auto it = beg;
1003-
while (it != end) {
1004-
out += ::tolower(*it);
1005-
it++;
1006-
}
1007-
return out;
1050+
std::string field;
1051+
detail::make_range_header_core(field, value, args...);
1052+
field.insert(0, "bytes=");
1053+
return std::make_pair("Range", field);
10081054
}
10091055

1010-
} // namespace detail
1011-
10121056
// Request implementation
10131057
inline bool Request::has_header(const char* key) const
10141058
{
@@ -1020,11 +1064,6 @@ inline std::string Request::get_header_value(const char* key) const
10201064
return detail::get_header_value(headers, key, "");
10211065
}
10221066

1023-
inline void Request::set_header(const char* key, const char* val)
1024-
{
1025-
headers.emplace(key, val);
1026-
}
1027-
10281067
inline bool Request::has_param(const char* key) const
10291068
{
10301069
return params.find(key) != params.end();
@@ -1485,22 +1524,34 @@ inline bool Client::read_and_close_socket(socket_t sock, const Request& req, Res
14851524
});
14861525
}
14871526

1488-
inline std::shared_ptr<Response> Client::get(const char* path, Progress callback)
1527+
inline std::shared_ptr<Response> Client::get(const char* path, Progress progress)
1528+
{
1529+
return get(path, Headers(), progress);
1530+
}
1531+
1532+
inline std::shared_ptr<Response> Client::get(const char* path, const Headers& headers, Progress progress)
14891533
{
14901534
Request req;
14911535
req.method = "GET";
14921536
req.path = path;
1493-
req.progress = callback;
1537+
req.headers = headers;
1538+
req.progress = progress;
14941539

14951540
auto res = std::make_shared<Response>();
14961541

14971542
return send(req, *res) ? res : nullptr;
14981543
}
14991544

15001545
inline std::shared_ptr<Response> Client::head(const char* path)
1546+
{
1547+
return head(path, Headers());
1548+
}
1549+
1550+
inline std::shared_ptr<Response> Client::head(const char* path, const Headers& headers)
15011551
{
15021552
Request req;
15031553
req.method = "HEAD";
1554+
req.headers = headers;
15041555
req.path = path;
15051556

15061557
auto res = std::make_shared<Response>();
@@ -1510,21 +1561,32 @@ inline std::shared_ptr<Response> Client::head(const char* path)
15101561

15111562
inline std::shared_ptr<Response> Client::post(
15121563
const char* path, const std::string& body, const char* content_type)
1564+
{
1565+
return post(path, Headers(), body, content_type);
1566+
}
1567+
1568+
inline std::shared_ptr<Response> Client::post(
1569+
const char* path, const Headers& headers, const std::string& body, const char* content_type)
15131570
{
15141571
Request req;
15151572
req.method = "POST";
1573+
req.headers = headers;
15161574
req.path = path;
15171575

1518-
req.set_header("Content-Type", content_type);
1576+
req.headers.emplace("Content-Type", content_type);
15191577
req.body = body;
15201578

15211579
auto res = std::make_shared<Response>();
15221580

15231581
return send(req, *res) ? res : nullptr;
15241582
}
15251583

1526-
inline std::shared_ptr<Response> Client::post(
1527-
const char* path, const Params& params)
1584+
inline std::shared_ptr<Response> Client::post(const char* path, const Params& params)
1585+
{
1586+
return post(path, Headers(), params);
1587+
}
1588+
1589+
inline std::shared_ptr<Response> Client::post(const char* path, const Headers& headers, const Params& params)
15281590
{
15291591
std::string query;
15301592
for (auto it = params.begin(); it != params.end(); ++it) {
@@ -1536,7 +1598,7 @@ inline std::shared_ptr<Response> Client::post(
15361598
query += it->second;
15371599
}
15381600

1539-
return post(path, query, "application/x-www-form-urlencoded");
1601+
return post(path, headers, query, "application/x-www-form-urlencoded");
15401602
}
15411603

15421604
/*

0 commit comments

Comments
 (0)