@@ -1357,6 +1357,26 @@ inline bool is_connection_error() {
1357
1357
#endif
1358
1358
}
1359
1359
1360
+ inline socket_t create_client_socket (
1361
+ const char *host, int port, time_t timeout_sec) {
1362
+ return create_socket (
1363
+ host, port, [=](socket_t sock, struct addrinfo &ai) -> bool {
1364
+ set_nonblocking (sock, true );
1365
+
1366
+ auto ret = ::connect (sock, ai.ai_addr , static_cast <int >(ai.ai_addrlen ));
1367
+ if (ret < 0 ) {
1368
+ if (is_connection_error () ||
1369
+ !wait_until_socket_is_ready (sock, timeout_sec, 0 )) {
1370
+ close_socket (sock);
1371
+ return false ;
1372
+ }
1373
+ }
1374
+
1375
+ set_nonblocking (sock, false );
1376
+ return true ;
1377
+ });
1378
+ }
1379
+
1360
1380
inline std::string get_remote_addr (socket_t sock) {
1361
1381
struct sockaddr_storage addr;
1362
1382
socklen_t len = sizeof (addr);
@@ -1542,7 +1562,11 @@ inline uint64_t get_header_value_uint64(const Headers &headers, const char *key,
1542
1562
}
1543
1563
1544
1564
inline bool read_headers (Stream &strm, Headers &headers) {
1545
- static std::regex re (R"( (.+?):\s*(.+?)\s*\r\n)" );
1565
+ // Horizontal tab and ' ' are considered whitespace and are ignored when on
1566
+ // the left or right side of the header value:
1567
+ // - https://stackoverflow.com/questions/50179659/
1568
+ // - https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html
1569
+ static std::regex re (R"( (.+?):[\t ]*(.+))" );
1546
1570
1547
1571
const auto bufsiz = 2048 ;
1548
1572
char buf[bufsiz];
@@ -1551,9 +1575,23 @@ inline bool read_headers(Stream &strm, Headers &headers) {
1551
1575
1552
1576
for (;;) {
1553
1577
if (!line_reader.getline ()) { return false ; }
1554
- if (!strcmp (line_reader.ptr (), " \r\n " )) { break ; }
1578
+ const char *end = line_reader.ptr () + line_reader.size ();
1579
+ auto erase_last_char = [&](char c) {
1580
+ if (line_reader.ptr () == end || end[-1 ] != c) {
1581
+ return false ;
1582
+ }
1583
+ end--;
1584
+ return true ;
1585
+ };
1586
+ if (!erase_last_char (' \n ' )) { continue ; }
1587
+ if (!erase_last_char (' \r ' )) { continue ; }
1588
+
1589
+ // Blank line indicates end of headers.
1590
+ if (line_reader.ptr () == end) { break ; }
1591
+
1592
+ while (erase_last_char (' ' ) || erase_last_char (' \t ' )) {}
1555
1593
std::cmatch m;
1556
- if (std::regex_match (line_reader.ptr (), m, re)) {
1594
+ if (std::regex_match (line_reader.ptr (), end, m, re)) {
1557
1595
auto key = std::string (m[1 ]);
1558
1596
auto val = std::string (m[2 ]);
1559
1597
headers.emplace (key, val);
@@ -3167,22 +3205,7 @@ inline Client::~Client() {}
3167
3205
inline bool Client::is_valid () const { return true ; }
3168
3206
3169
3207
inline socket_t Client::create_client_socket () const {
3170
- return detail::create_socket (
3171
- host_.c_str (), port_, [=](socket_t sock, struct addrinfo &ai) -> bool {
3172
- detail::set_nonblocking (sock, true );
3173
-
3174
- auto ret = connect (sock, ai.ai_addr , static_cast <int >(ai.ai_addrlen ));
3175
- if (ret < 0 ) {
3176
- if (detail::is_connection_error () ||
3177
- !detail::wait_until_socket_is_ready (sock, timeout_sec_, 0 )) {
3178
- detail::close_socket (sock);
3179
- return false ;
3180
- }
3181
- }
3182
-
3183
- detail::set_nonblocking (sock, false );
3184
- return true ;
3185
- });
3208
+ return detail::create_client_socket (host_.c_str (), port_, timeout_sec_);
3186
3209
}
3187
3210
3188
3211
inline bool Client::read_response_line (Stream &strm, Response &res) {
0 commit comments