pass std::string_view to parse

This commit is contained in:
orignal 2024-09-02 17:34:15 -04:00
parent 56b8534e0c
commit a3e0b3710c
2 changed files with 63 additions and 38 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2023, The PurpleI2P Project * Copyright (c) 2013-2024, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -41,11 +41,12 @@ namespace http
return std::find(HTTP_METHODS.begin(), HTTP_METHODS.end(), str) != std::end(HTTP_METHODS); return std::find(HTTP_METHODS.begin(), HTTP_METHODS.end(), str) != std::end(HTTP_METHODS);
} }
void strsplit(const std::string & line, std::vector<std::string> &tokens, char delim, std::size_t limit = 0) { static void strsplit(std::stringstream& ss, std::vector<std::string> &tokens, char delim, std::size_t limit = 0)
{
std::size_t count = 0; std::size_t count = 0;
std::stringstream ss(line);
std::string token; std::string token;
while (1) { while (1)
{
count++; count++;
if (limit > 0 && count >= limit) if (limit > 0 && count >= limit)
delim = '\n'; /* reset delimiter */ delim = '\n'; /* reset delimiter */
@ -55,7 +56,19 @@ namespace http
} }
} }
static std::pair<std::string, std::string> parse_header_line(const std::string& line) static void strsplit(const std::string & line, std::vector<std::string> &tokens, char delim, std::size_t limit = 0)
{
std::stringstream ss(line);
strsplit (ss, tokens, delim, limit);
}
static void strsplit(std::string_view line, std::vector<std::string> &tokens, char delim, std::size_t limit = 0)
{
std::stringstream ss(std::move(std::string(line)));
strsplit (ss, tokens, delim, limit);
}
static std::pair<std::string, std::string> parse_header_line(std::string_view line)
{ {
std::size_t pos = 0; std::size_t pos = 0;
std::size_t len = 1; /*: */ std::size_t len = 1; /*: */
@ -69,7 +82,8 @@ namespace http
if (len == 1) if (len == 1)
return std::make_pair("", ""); // no following space, but something else return std::make_pair("", ""); // no following space, but something else
} }
return std::make_pair(line.substr(0, pos), line.substr(pos + len)); return std::make_pair(std::move (std::string (line.substr(0, pos))),
std::move (std::string (line.substr(pos + len))));
} }
void gen_rfc7231_date(std::string & out) { void gen_rfc7231_date(std::string & out) {
@ -83,15 +97,17 @@ namespace http
out = buf; out = buf;
} }
bool URL::parse(const char *str, std::size_t len) { bool URL::parse(const char *str, std::size_t len)
std::string url(str, len ? len : strlen(str)); {
return parse(url); return parse({str, len ? len : strlen(str)});
} }
bool URL::parse(const std::string& url) { bool URL::parse(std::string_view url)
{
std::size_t pos_p = 0; /* < current parse position */ std::size_t pos_p = 0; /* < current parse position */
std::size_t pos_c = 0; /* < work position */ std::size_t pos_c = 0; /* < work position */
if(url.at(0) != '/' || pos_p > 0) { if(url.at(0) != '/' || pos_p > 0)
{
std::size_t pos_s = 0; std::size_t pos_s = 0;
/* schema */ /* schema */
@ -141,7 +157,7 @@ namespace http
/* port[/path] */ /* port[/path] */
pos_p = pos_c + 1; pos_p = pos_c + 1;
pos_c = url.find('/', pos_p); pos_c = url.find('/', pos_p);
std::string port_str = (pos_c == std::string::npos) std::string_view port_str = (pos_c == std::string::npos)
? url.substr(pos_p, std::string::npos) ? url.substr(pos_p, std::string::npos)
: url.substr(pos_p, pos_c - pos_p); : url.substr(pos_p, pos_c - pos_p);
/* stoi throws exception on failure, we don't need it */ /* stoi throws exception on failure, we don't need it */
@ -272,12 +288,13 @@ namespace http
headers.erase(name); headers.erase(name);
} }
int HTTPReq::parse(const char *buf, size_t len) { int HTTPReq::parse(const char *buf, size_t len)
std::string str(buf, len); {
return parse(str); return parse({buf, len});
} }
int HTTPReq::parse(const std::string& str) { int HTTPReq::parse(std::string_view str)
{
enum { REQ_LINE, HEADER_LINE } expect = REQ_LINE; enum { REQ_LINE, HEADER_LINE } expect = REQ_LINE;
std::size_t eoh = str.find(HTTP_EOH); /* request head size */ std::size_t eoh = str.find(HTTP_EOH); /* request head size */
std::size_t eol = 0, pos = 0; std::size_t eol = 0, pos = 0;
@ -286,9 +303,11 @@ namespace http
if (eoh == std::string::npos) if (eoh == std::string::npos)
return 0; /* str not contains complete request */ return 0; /* str not contains complete request */
while ((eol = str.find(CRLF, pos)) != std::string::npos) { while ((eol = str.find(CRLF, pos)) != std::string::npos)
if (expect == REQ_LINE) { {
std::string line = str.substr(pos, eol - pos); if (expect == REQ_LINE)
{
std::string_view line = str.substr(pos, eol - pos);
std::vector<std::string> tokens; std::vector<std::string> tokens;
strsplit(line, tokens, ' '); strsplit(line, tokens, ' ');
if (tokens.size() != 3) if (tokens.size() != 3)
@ -307,7 +326,7 @@ namespace http
} }
else else
{ {
std::string line = str.substr(pos, eol - pos); std::string_view line = str.substr(pos, eol - pos);
auto p = parse_header_line(line); auto p = parse_header_line(line);
if (p.first.length () > 0) if (p.first.length () > 0)
headers.push_back (p); headers.push_back (p);
@ -413,12 +432,13 @@ namespace http
return length; return length;
} }
int HTTPRes::parse(const char *buf, size_t len) { int HTTPRes::parse(const char *buf, size_t len)
std::string str(buf, len); {
return parse(str); return parse({buf,len});
} }
int HTTPRes::parse(const std::string& str) { int HTTPRes::parse(std::string_view str)
{
enum { RES_LINE, HEADER_LINE } expect = RES_LINE; enum { RES_LINE, HEADER_LINE } expect = RES_LINE;
std::size_t eoh = str.find(HTTP_EOH); /* request head size */ std::size_t eoh = str.find(HTTP_EOH); /* request head size */
std::size_t eol = 0, pos = 0; std::size_t eol = 0, pos = 0;
@ -426,9 +446,11 @@ namespace http
if (eoh == std::string::npos) if (eoh == std::string::npos)
return 0; /* str not contains complete request */ return 0; /* str not contains complete request */
while ((eol = str.find(CRLF, pos)) != std::string::npos) { while ((eol = str.find(CRLF, pos)) != std::string::npos)
if (expect == RES_LINE) { {
std::string line = str.substr(pos, eol - pos); if (expect == RES_LINE)
{
std::string_view line = str.substr(pos, eol - pos);
std::vector<std::string> tokens; std::vector<std::string> tokens;
strsplit(line, tokens, ' ', 3); strsplit(line, tokens, ' ', 3);
if (tokens.size() != 3) if (tokens.size() != 3)
@ -442,8 +464,10 @@ namespace http
version = tokens[0]; version = tokens[0];
status = tokens[2]; status = tokens[2];
expect = HEADER_LINE; expect = HEADER_LINE;
} else { }
std::string line = str.substr(pos, eol - pos); else
{
std::string_view line = str.substr(pos, eol - pos);
auto p = parse_header_line(line); auto p = parse_header_line(line);
if (p.first.length () > 0) if (p.first.length () > 0)
headers.insert (p); headers.insert (p);
@ -508,14 +532,14 @@ namespace http
return ptr; return ptr;
} }
std::string UrlDecode(const std::string& data, bool allow_null) std::string UrlDecode(std::string_view data, bool allow_null)
{ {
std::string decoded(data); std::string decoded(data);
size_t pos = 0; size_t pos = 0;
while ((pos = decoded.find('%', pos)) != std::string::npos) while ((pos = decoded.find('%', pos)) != std::string::npos)
{ {
char c = strtol(decoded.substr(pos + 1, 2).c_str(), NULL, 16); char c = std::stol(decoded.substr(pos + 1, 2), nullptr, 16);
if (c == '\0' && !allow_null) if (!c && !allow_null)
{ {
pos += 3; pos += 3;
continue; continue;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2023, The PurpleI2P Project * Copyright (c) 2013-2024, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -14,6 +14,7 @@
#include <list> #include <list>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <string_view>
#include <vector> #include <vector>
namespace i2p namespace i2p
@ -45,7 +46,7 @@ namespace http
* @return true on success, false on invalid url * @return true on success, false on invalid url
*/ */
bool parse (const char *str, std::size_t len = 0); bool parse (const char *str, std::size_t len = 0);
bool parse (const std::string& url); bool parse (std::string_view url);
/** /**
* @brief Parse query part of url to key/value map * @brief Parse query part of url to key/value map
@ -92,7 +93,7 @@ namespace http
* @note Positive return value is a size of header * @note Positive return value is a size of header
*/ */
int parse(const char *buf, size_t len); int parse(const char *buf, size_t len);
int parse(const std::string& buf); int parse(std::string_view buf);
/** @brief Serialize HTTP request to string */ /** @brief Serialize HTTP request to string */
std::string to_string(); std::string to_string();
@ -128,7 +129,7 @@ namespace http
* @note Positive return value is a size of header * @note Positive return value is a size of header
*/ */
int parse(const char *buf, size_t len); int parse(const char *buf, size_t len);
int parse(const std::string& buf); int parse(const std::string_view buf);
/** /**
* @brief Serialize HTTP response to string * @brief Serialize HTTP response to string
@ -161,7 +162,7 @@ namespace http
* @param null If set to true - decode also %00 sequence, otherwise - skip * @param null If set to true - decode also %00 sequence, otherwise - skip
* @return Decoded string * @return Decoded string
*/ */
std::string UrlDecode(const std::string& data, bool null = false); std::string UrlDecode(std::string_view data, bool null = false);
/** /**
* @brief Merge HTTP response content with Transfer-Encoding: chunked * @brief Merge HTTP response content with Transfer-Encoding: chunked