11 #include "string/string_utils.h"
12 #include "utility/countof.h"
21 assert((i < _headers.size()) &&
"Index out of bounds!");
22 if (i >= _headers.size())
23 return std::make_tuple(std::string_view(), std::string_view());
25 auto item = _headers[i];
27 return std::make_tuple(std::string_view(_cache.data() + std::get<0>(item), std::get<1>(item)), std::string_view(_cache.data() + std::get<2>(item), std::get<3>(item)));
32 assert((i < _cookies.size()) &&
"Index out of bounds!");
33 if (i >= _cookies.size())
34 return std::make_tuple(std::string_view(), std::string_view());
36 auto item = _cookies[i];
38 return std::make_tuple(std::string_view(_cache.data() + std::get<0>(item), std::get<1>(item)), std::string_view(_cache.data() + std::get<2>(item), std::get<3>(item)));
55 _body_length_provided =
false;
71 _method_index = index;
72 _method_size =
method.size();
75 index = _cache.size();
80 _url_size =
url.size();
83 index = _cache.size();
87 _protocol_index = index;
90 _cache.append(
"\r\n");
96 size_t index = _cache.size();
100 size_t key_index = index;
101 size_t key_size = key.size();
104 index = _cache.size();
107 _cache.append(value);
108 size_t value_index = index;
109 size_t value_size = value.size();
111 _cache.append(
"\r\n");
114 _headers.emplace_back(key_index, key_size, value_index, value_size);
120 size_t index = _cache.size();
123 _cache.append(
"Cookie");
124 size_t key_index = index;
128 index = _cache.size();
131 size_t value_index = index;
134 index = _cache.size();
136 size_t name_index = index;
137 size_t name_size = name.size();
139 index = _cache.size();
140 _cache.append(value);
141 size_t cookie_index = index;
142 size_t cookie_size = value.size();
144 size_t value_size = _cache.size() - value_index;
146 _cache.append(
"\r\n");
149 _headers.emplace_back(key_index, key_size, value_index, value_size);
151 _cookies.emplace_back(name_index, name_size, cookie_index, cookie_size);
159 size_t index = _cache.size();
161 size_t name_index = index;
162 size_t name_size = name.size();
164 index = _cache.size();
165 _cache.append(value);
166 size_t cookie_index = index;
167 size_t cookie_size = value.size();
170 _cookies.emplace_back(name_index, name_size, cookie_index, cookie_size);
178 SetHeader(
"Content-Length", FastConvert(
body.size(), buffer, CppCommon::countof(buffer)));
180 _cache.append(
"\r\n");
182 size_t index = _cache.size();
187 _body_size =
body.size();
188 _body_length =
body.size();
189 _body_length_provided =
true;
197 SetHeader(
"Content-Length", FastConvert(length, buffer, CppCommon::countof(buffer)));
199 _cache.append(
"\r\n");
201 size_t index = _cache.size();
206 _body_length = length;
207 _body_length_provided =
true;
231 if (!content_type.empty())
241 if (!content_type.empty())
271 bool HTTPRequest::IsPendingHeader()
const
273 return (!_error && (_body_index == 0));
276 bool HTTPRequest::IsPendingBody()
const
278 return (!_error && (_body_index > 0) && (_body_size > 0));
281 bool HTTPRequest::ReceiveHeader(
const void* buffer,
size_t size)
284 _cache.insert(_cache.end(), (
const char*)buffer, (
const char*)buffer + size);
287 for (
size_t i = _cache_size; i < _cache.size(); ++i)
290 if ((i + 3) >= _cache.size())
294 if ((_cache[i + 0] ==
'\r') && (_cache[i + 1] ==
'\n') && (_cache[i + 2] ==
'\r') && (_cache[i + 3] ==
'\n'))
302 _method_index = index;
304 while (_cache[index] !=
' ')
308 if (index >= _cache.size())
312 if (index >= _cache.size())
318 while (_cache[index] !=
' ')
322 if (index >= _cache.size())
326 if (index >= _cache.size())
330 _protocol_index = index;
332 while (_cache[index] !=
'\r')
336 if (index >= _cache.size())
340 if ((index >= _cache.size()) || (_cache[index] !=
'\n'))
343 if (index >= _cache.size())
347 while ((index < _cache.size()) && (index < i))
350 size_t header_name_index = index;
351 size_t header_name_size = 0;
352 while (_cache[index] !=
':')
358 if (index >= _cache.size())
364 if (index >= _cache.size())
368 while (std::isspace(_cache[index]))
373 if (index >= _cache.size())
378 size_t header_value_index = index;
379 size_t header_value_size = 0;
380 while (_cache[index] !=
'\r')
386 if (index >= _cache.size())
390 if ((index >= _cache.size()) || (_cache[index] !=
'\n'))
393 if (index >= _cache.size())
397 if (header_name_size == 0)
401 _headers.emplace_back(header_name_index, header_name_size, header_value_index, header_value_size);
404 if (CppCommon::StringUtils::CompareNoCase(std::string_view(_cache.data() + header_name_index, header_name_size),
"Content-Length"))
407 for (
size_t j = header_value_index; j < (header_value_index + header_value_size); ++j)
409 if ((_cache[j] <
'0') || (_cache[j] >
'9'))
412 _body_length += _cache[j] -
'0';
413 _body_length_provided =
true;
418 if (CppCommon::StringUtils::CompareNoCase(std::string_view(_cache.data() + header_name_index, header_name_size),
"Cookie"))
422 size_t current = header_value_index;
423 size_t name_index = index;
424 size_t name_size = 0;
425 size_t cookie_index = index;
426 size_t cookie_size = 0;
427 for (
size_t j = header_value_index; j < (header_value_index + header_value_size); ++j)
429 if (_cache[j] ==
' ')
435 name_index = current;
436 name_size = j - current;
440 cookie_index = current;
441 cookie_size = j - current;
447 if (_cache[j] ==
'=')
453 name_index = current;
454 name_size = j - current;
458 cookie_index = current;
459 cookie_size = j - current;
466 if (_cache[j] ==
';')
472 name_index = current;
473 name_size = j - current;
477 cookie_index = current;
478 cookie_size = j - current;
482 if ((name_size > 0) && (cookie_size > 0))
485 _cookies.emplace_back(name_index, name_size, cookie_index, cookie_size);
510 name_index = current;
511 name_size = header_value_index + header_value_size - current;
515 cookie_index = current;
516 cookie_size = header_value_index + header_value_size - current;
520 if ((name_size > 0) && (cookie_size > 0))
523 _cookies.emplace_back(name_index, name_size, cookie_index, cookie_size);
534 _body_size = _cache.size() - i - 4;
537 _cache_size = _cache.size();
544 _cache_size = (_cache.size() >= 3) ? (_cache.size() - 3) : 0;
549 bool HTTPRequest::ReceiveBody(
const void* buffer,
size_t size)
552 _cache.insert(_cache.end(), (
const char*)buffer, (
const char*)buffer + size);
555 _cache_size = _cache.size();
561 if (_body_length_provided)
564 if (_body_size >= _body_length)
566 _body_size = _body_length;
583 size_t index = _body_index + _body_size - 4;
586 if ((_cache[index + 0] ==
'\r') && (_cache[index + 1] ==
'\n') && (_cache[index + 2] ==
'\r') && (_cache[index + 3] ==
'\n'))
588 _body_length = _body_size;
598 std::string_view HTTPRequest::FastConvert(
size_t value,
char* buffer,
size_t size)
603 buffer[--index] =
'0' + (value % 10);
607 return std::string_view(buffer + index, size - index);
612 os <<
"Request method: " << request.
method() << std::endl;
613 os <<
"Request URL: " << request.
url() << std::endl;
614 os <<
"Request protocol: " << request.
protocol() << std::endl;
615 os <<
"Request headers: " << request.
headers() << std::endl;
616 for (
size_t i = 0; i < request.
headers(); ++i)
618 auto header = request.
header(i);
619 os << std::get<0>(header) <<
": " << std::get<1>(header) << std::endl;
621 os <<
"Request body:" << request.
body_length() << std::endl;
622 os << request.
body() << std::endl;
629 swap(_error, request._error);
630 swap(_method_index, request._method_index);
631 swap(_method_size, request._method_size);
632 swap(_url_index, request._url_index);
633 swap(_url_size, request._url_size);
634 swap(_protocol_index, request._protocol_index);
635 swap(_protocol_size, request._protocol_size);
636 swap(_headers, request._headers);
637 swap(_cookies, request._cookies);
638 swap(_body_index, request._body_index);
639 swap(_body_size, request._body_size);
640 swap(_body_length, request._body_length);
641 swap(_body_length_provided, request._body_length_provided);
642 swap(_cache, request._cache);
643 swap(_cache_size, request._cache_size);
size_t body_length() const noexcept
Get the HTTP request body length.
HTTPRequest & SetBody(std::string_view body="")
Set the HTTP request body.
HTTPRequest & MakePutRequest(std::string_view url, std::string_view content, std::string_view content_type="text/plain; charset=UTF-8")
Make PUT request.
void swap(HTTPRequest &request) noexcept
Swap two instances.
HTTPRequest & MakeHeadRequest(std::string_view url)
Make HEAD request.
HTTPRequest & Clear()
Clear the HTTP request cache.
std::tuple< std::string_view, std::string_view > cookie(size_t i) const noexcept
Get the HTTP request cookie by index.
HTTPRequest & MakeDeleteRequest(std::string_view url)
Make DELETE request.
HTTPRequest & MakePostRequest(std::string_view url, std::string_view content, std::string_view content_type="text/plain; charset=UTF-8")
Make POST request.
HTTPRequest & AddCookie(std::string_view name, std::string_view value)
Add the HTTP request cookie.
HTTPRequest & MakeOptionsRequest(std::string_view url)
Make OPTIONS request.
HTTPRequest & SetBodyLength(size_t length)
Set the HTTP request body length.
HTTPRequest & SetBegin(std::string_view method, std::string_view url, std::string_view protocol="HTTP/1.1")
Set the HTTP request begin with a given method, URL and protocol.
HTTPRequest & MakeGetRequest(std::string_view url)
Make GET request.
size_t headers() const noexcept
Get the HTTP request headers count.
HTTPRequest & SetHeader(std::string_view key, std::string_view value)
Set the HTTP request header.
std::string_view method() const noexcept
Get the HTTP request method.
std::tuple< std::string_view, std::string_view > header(size_t i) const noexcept
Get the HTTP request header by index.
HTTPRequest & SetCookie(std::string_view name, std::string_view value)
Set the HTTP request cookie.
HTTPRequest & MakeTraceRequest(std::string_view url)
Make TRACE request.
std::string_view url() const noexcept
Get the HTTP request URL.
std::string_view body() const noexcept
Get the HTTP request body.
std::string_view protocol() const noexcept
Get the HTTP request protocol version.
std::ostream & operator<<(std::ostream &os, const HTTPRequest &request)
C++ Server project definitions.