diff --git a/common/estring.cpp b/common/estring.cpp index 6822f891..54166380 100644 --- a/common/estring.cpp +++ b/common/estring.cpp @@ -55,30 +55,39 @@ size_t estring_view::find_last_not_of(const charset& set) const bool estring_view::to_uint64_check(uint64_t* v) const { - v ? (*v = 0) : 0; - for (unsigned char c : *this) { - if (c > '9' || c < '0') - return false; - v ? (*v = *v * 10 + (c - '0')) : 0; + if (this->empty()) return false; + uint64_t val = (*this)[0] - '0'; + if (val > 9) return false; + for (unsigned char c : this->substr(1)) { + c -= '0'; + if (c > 9) break; + val = val * 10 + c; } + if (v) *v = val; return true; } -uint64_t estring_view::hex_to_uint64() const -{ - uint64_t ret = 0; - for (unsigned char c : *this) { - if (c >= '0' && c <= '9') { - ret = ret * 16 + (c - '0'); - } else if (c >= 'A' && c <= 'F') { - ret = ret * 16 + (c - 'A' + 10); - } else if (c >= 'a' && c <= 'f') { - ret = ret * 16 + (c - 'a' + 10); - } else { - return ret; - } +inline char hex_char_to_digit(char c) { + unsigned char cc = c - '0'; + if (cc < 10) return cc; + const unsigned char mask = 'a' - 'A'; + static_assert(mask == 32, "..."); // single digit + c |= mask; // unified to 'a'..'f' + cc = c - 'a'; + return (cc < 6) ? (cc + 10) : -1; +} + +bool estring_view::hex_to_uint64_check(uint64_t* v) const { + if (this->empty()) return false; + uint64_t val = hex_char_to_digit((*this)[0]); + if (val == -1ul) return false; + for (unsigned char c : this->substr(1)) { + auto d = hex_char_to_digit(c); + if (d == -1) break; + val = val * 16 + d; } - return ret; + if (v) *v = val; + return true; } estring& estring::append(uint64_t x) diff --git a/common/estring.h b/common/estring.h index 9e57214f..cdd90af7 100644 --- a/common/estring.h +++ b/common/estring.h @@ -18,6 +18,7 @@ limitations under the License. #include #include #include +#include #include #include #include @@ -289,11 +290,41 @@ class estring_view : public std::string_view uint64_t to_uint64(uint64_t default_val = 0) const { uint64_t val; - to_uint64_check(&val); - return val; + return to_uint64_check(&val) ? val : default_val; + } + bool to_int64_check(int64_t* v = nullptr) const + { + if (this->empty()) return false; + if (this->front() != '-') return to_uint64_check((uint64_t*)v); + bool ret = this->substr(1).to_uint64_check((uint64_t*)v); + if (ret) *v = -*v; + return ret; + } + int64_t to_int64(int64_t default_val = 0) const + { + int64_t val; + return to_int64_check(&val) ? val : default_val; + } + bool to_double_check(double* v = nullptr) + { + char buf[32]; + auto len = std::max(this->size(), sizeof(buf) - 1 ); + memcpy(buf, data(), len); + buf[len] = '0'; + return sscanf(buf, "%lf", v) == 1; + } + double to_double(double default_val = NAN) + { + double val; + return to_double_check(&val) ? val : default_val; + } + // not including 0x/0X prefix + bool hex_to_uint64_check(uint64_t* v = nullptr) const; + uint64_t hex_to_uint64(uint64_t default_val = 0) const + { + uint64_t val; + return hex_to_uint64_check(&val) ? val : default_val; } - // do not support 0x/0X prefix - uint64_t hex_to_uint64() const; }; inline bool operator == (const std::string_view& sv, const std::string& s) @@ -312,8 +343,8 @@ class rstring_view // relative string_view, that stores values relative protected: static_assert(std::is_integral::value, "..."); static_assert(std::is_integral::value, "..."); - OffsetType _offset; - LengthType _length; + OffsetType _offset = 0; + LengthType _length = 0; estring_view to_abs(const char* s) const { diff --git a/common/test/test.cpp b/common/test/test.cpp index 7c87049b..e9b2b27e 100644 --- a/common/test/test.cpp +++ b/common/test/test.cpp @@ -867,6 +867,15 @@ TEST(estring, test) estring as = " \tasdf \t\r\n"; auto trimmed = as.trim(); EXPECT_EQ(trimmed, "asdf"); + + EXPECT_EQ(estring_view("234423").to_uint64(), 234423); + EXPECT_EQ(estring_view("-234423").to_int64(), -234423); + EXPECT_EQ(estring_view("asfdsf").to_uint64(32), 32); + EXPECT_EQ(estring_view("-3.14").to_double(), -3.14); + EXPECT_EQ(estring_view("1e10").to_double(), 1e10); + + EXPECT_EQ(estring_view("1").hex_to_uint64(), 0x1); + EXPECT_EQ(estring_view("1a2b3d4e5f").hex_to_uint64(), 0x1a2b3d4e5f); } TEST(generator, example) diff --git a/net/http/message.cpp b/net/http/message.cpp index ab8e3179..481c059f 100644 --- a/net/http/message.cpp +++ b/net/http/message.cpp @@ -331,7 +331,7 @@ int Request::redirect(Verb v, estring_view location, bool enable_proxy) { } StoredURL u(location); auto new_request_line_size = verbstr[v].size() + sizeof(" HTTP/1.1\r\n") + - enable_proxy ? full_url_size(u) : u.target().size(); + (enable_proxy ? full_url_size(u) : u.target().size()); auto delta = new_request_line_size - m_buf_size; LOG_DEBUG(VALUE(delta)); @@ -368,7 +368,7 @@ int Response::parse_status_line(Parser &p) { p.skip_chars(' '); auto code = p.extract_integer(); if (code <= 0 || code >= 1000) - LOG_ERROR_RETURN(0, -1, "invalid status code"); + LOG_ERROR_RETURN(0, -1, "invalid status code ", code); m_status_code = (uint16_t)code; p.skip_chars(' '); m_status_message = p.extract_until_char('\r'); diff --git a/net/http/test/client_function_test.cpp b/net/http/test/client_function_test.cpp index 7af2d2df..062f34c0 100644 --- a/net/http/test/client_function_test.cpp +++ b/net/http/test/client_function_test.cpp @@ -413,9 +413,9 @@ TEST(http_client, debug) { server->setsockopt(SOL_SOCKET, SO_REUSEPORT, 1); server->set_handler({nullptr, &chunked_handler_debug}); auto ret = server->bind(ep.port, ep.addr); - if (ret < 0) LOG_ERROR(VALUE(errno)); + if (ret < 0) LOG_ERROR(ERRNO()); ret |= server->listen(100); - if (ret < 0) LOG_ERROR(VALUE(errno)); + if (ret < 0) LOG_ERROR(ERRNO()); EXPECT_EQ(0, ret); LOG_INFO("Ready to accept"); server->start_loop(); @@ -438,13 +438,13 @@ TEST(http_client, debug) { memset((void*)buf.data(), '0', std_data_size); ret = op_test->resp.read((void*)buf.data(), std_data_size); EXPECT_EQ(std_data_size, ret); - EXPECT_EQ(true, buf == std_data); + EXPECT_TRUE(buf == std_data); for (int i = 0; i < buf.size(); i++) { if (buf[i] != std_data[i]) { - std::cout << i << std::endl; + LOG_ERROR("first occurrence of difference at: ", i); + break; } } - std::cout << "new" << std::endl; } int sleep_handler(void*, ISocketStream* sock) { photon::thread_sleep(3); diff --git a/net/utils.cpp b/net/utils.cpp index e1de9661..82985ffb 100644 --- a/net/utils.cpp +++ b/net/utils.cpp @@ -101,22 +101,25 @@ int _gethostbyname(const char* name, Delegate append_op) { return idx; } -inline __attribute__((always_inline)) void base64_translate_3to4(const char *in, char *out) { - struct xlator { - unsigned char _; - unsigned char a : 6; - unsigned char b : 6; - unsigned char c : 6; - unsigned char d : 6; - } __attribute__((packed)); - static_assert(sizeof(xlator) == 4, "..."); +struct xlator { + unsigned char _; + unsigned char a : 6; + unsigned char b : 6; + unsigned char c : 6; + unsigned char d : 6; +} __attribute__((packed)); +static_assert(sizeof(xlator) == 4, "..."); + +inline __attribute__((always_inline)) +void base64_translate_3to4(const char *in, char *out) { static const unsigned char tbl[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; auto v = htonl(*(uint32_t *)in); - auto x = *(xlator *)(&v); - *(uint32_t *)out = ((tbl[x.a] << 24) + (tbl[x.b] << 16) + - (tbl[x.c] << 8) + (tbl[x.d] << 0)); + auto x = (xlator*) &v; + *(uint32_t *)out = ((tbl[x->a] << 24) + (tbl[x->b] << 16) + + (tbl[x->c] << 8) + (tbl[x->d] << 0)); } + void Base64Encode(std::string_view in, std::string &out) { auto main = in.size() / 3; auto remain = in.size() % 3; @@ -137,7 +140,6 @@ void Base64Encode(std::string_view in, std::string &out) { base64_translate_3to4(_in + 9, _out + 12); } - for (; _in < end; _in += 3, _out += 4) { base64_translate_3to4(_in, _out); } @@ -191,16 +193,8 @@ static unsigned char get_index_of(char val, bool &ok) { } #undef EI +inline bool base64_translate_4to3(const char *in, char *out) { - struct xlator { - unsigned char _; - unsigned char a : 6; - unsigned char b : 6; - unsigned char c : 6; - unsigned char d : 6; - } __attribute__((packed)); - static_assert(sizeof(xlator) == 4, "..."); - xlator v; bool f1, f2, f3, f4; v.a = get_index_of(*(in+3), f1); @@ -208,10 +202,10 @@ bool base64_translate_4to3(const char *in, char *out) { v.c = get_index_of(*(in+1), f3); v.d = get_index_of(*(in), f4); - *(uint32_t *)out = ntohl(*(uint32_t *)&v); return (f1 && f2 && f3 && f4); } + bool Base64Decode(std::string_view in, std::string &out) { #define GSIZE 4 //Size of each group auto in_size = in.size();