├── test ├── CMakeLists.txt └── main.cpp ├── .gitignore ├── .semaphore └── semaphore.yml ├── LICENSE ├── README.md └── influxdb.hpp /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8) 2 | CMAKE_POLICY(VERSION 2.8) 3 | 4 | PROJECT(influxdb_cpp_ut) 5 | 6 | AUX_SOURCE_DIRECTORY(. DIR_SRCS) 7 | 8 | IF(CMAKE_SYSTEM_NAME MATCHES "Linux") 9 | LINK_LIBRARIES(gtest pthread) 10 | SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb") 11 | SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall") 12 | ENDIF() 13 | 14 | SET(CMAKE_BUILD_TYPE "Debug") 15 | 16 | ADD_EXECUTABLE(influxdb_cpp_ut ${DIR_SRCS}) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | CMakeFiles 10 | CMakeCache.txt 11 | *.cmake 12 | Makefile 13 | 14 | # Precompiled Headers 15 | *.gch 16 | *.pch 17 | 18 | # Compiled Dynamic libraries 19 | *.so 20 | *.dylib 21 | *.dll 22 | 23 | # Fortran module files 24 | *.mod 25 | *.smod 26 | 27 | # Compiled Static libraries 28 | *.lai 29 | *.la 30 | *.a 31 | *.lib 32 | 33 | # Executables 34 | *.exe 35 | *.out 36 | *.app 37 | *_ut 38 | 39 | # ctags files 40 | .tags* 41 | -------------------------------------------------------------------------------- /.semaphore/semaphore.yml: -------------------------------------------------------------------------------- 1 | version: v1.0 2 | name: Initial Pipeline 3 | agent: 4 | machine: 5 | type: e1-standard-2 6 | os_image: ubuntu2004 7 | blocks: 8 | - name: 'Block #1' 9 | task: 10 | jobs: 11 | - name: 'Job #1' 12 | commands: 13 | - checkout 14 | - sudo apt-get -qq update 15 | - sudo apt-get install -y valgrind 16 | - 'sudo wget https://github.com/google/googletest/archive/release-1.7.0.tar.gz' 17 | - sudo tar xf release-1.7.0.tar.gz 18 | - cd googletest-release-1.7.0 19 | - sudo cmake -DBUILD_SHARED_LIBS=ON . 20 | - sudo make -j8 21 | - sudo cp -a include/gtest /usr/include 22 | - sudo cp -a libgtest_main.so libgtest.so /usr/lib/ 23 | - which valgrind 24 | - cd .. 25 | - ls -l 26 | - cd test 27 | - cmake . 28 | - make -j8 29 | - valgrind ./influxdb_cpp_ut 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Orca 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | #include "../influxdb.hpp" 2 | #include 3 | using namespace std; 4 | 5 | // Visit https://github.com/orca-zhang/influxdb-c for more test cases 6 | 7 | int main(int argc, char const *argv[]) 8 | { 9 | influxdb_cpp::server_info si("127.0.0.1", 8086, "testx", "test", "test"); 10 | // post_http demo with resp[optional] 11 | string resp; 12 | int ret = influxdb_cpp::builder() 13 | .meas("test") 14 | .tag("k", "v") 15 | .tag("x", "y") 16 | .field("x", 10) 17 | .field("y", 10.3, 2) 18 | .field("b", !!10) 19 | .timestamp(1512722735522840439) 20 | .post_http(si, &resp); 21 | 22 | cout << ret << endl << resp << endl; 23 | 24 | // send_udp demo 25 | ret = influxdb_cpp::builder() 26 | .meas("test") 27 | .tag("k", "v") 28 | .tag("x", "y") 29 | .field("x", 10) 30 | .field("y", 3.14e18, 3) 31 | .field("b", !!10) 32 | .timestamp(1512722735522840439) 33 | .send_udp("127.0.0.1", 8089); 34 | 35 | cout << ret << endl; 36 | 37 | // query from table 38 | influxdb_cpp::server_info si_new("127.0.0.1", 8086, "", "test", "test"); 39 | influxdb_cpp::query(resp, "show databases", si); 40 | cout << resp << endl; 41 | 42 | // create_db 43 | influxdb_cpp::create_db(resp, "x", si_new); 44 | cout << resp << endl; 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # influxdb-cpp 2 | 3 | A header-only C++ query & write client for InfluxDB. 4 | 5 | [![license](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)](https://github.com/orca-zhang/influxdb-cpp/blob/master/LICENSE) [![Build Status](https://orca-zhang.semaphoreci.com/badges/influxdb-cpp/branches/master.svg?style=shields)](https://orca-zhang.semaphoreci.com/projects/influxdb-cpp) [![Build status](https://ci.appveyor.com/api/projects/status/gusrrn0mn67q2yaj?svg=true)](https://ci.appveyor.com/project/orca-zhang/influxdb-cpp) 6 | 7 | - Support versions: 8 | - InfluxDB v0.9 ~ 2.0+ 9 | - Check yourself while using other versions. 10 | 11 | ### Why use influxdb-cpp? 12 | 13 | - **Exactly-small**: 14 | - Less than 300 lines and only 10KB+. 15 | - **Easy-to-use**: 16 | - It's designed to be used without extra studies. 17 | - **Easy-to-assemble**: 18 | - Only a tiny header file needs to be included. 19 | - **No-dependencies**: 20 | - Unless STL and std C libraries. 21 | 22 | ### Examples 23 | 24 | #### Before using 25 | 26 | - The very simple thing you should do before using is only: 27 | 28 | ```cpp 29 | #include "influxdb.hpp" 30 | ``` 31 | 32 | #### Writing example 33 | 34 | - You should refer to the [write syntax](https://docs.influxdata.com/influxdb/v1.4/write_protocols/line_protocol_reference/) while writing series(metrics). 35 | 36 | ``` 37 | measurement[,tag-key=tag-value...] field-key=field-value[,field2-key=field2-value...] [unix-nano-timestamp] 38 | ``` 39 | 40 | 41 | - You can rapidly start writing serires by according to the following example. 42 | 43 | ```cpp 44 | influxdb_cpp::server_info si("127.0.0.1", 8086, "db", "usr", "pwd"); 45 | influxdb_cpp::builder() 46 | .meas("foo") 47 | .tag("k", "v") 48 | .tag("x", "y") 49 | .field("x", 10) 50 | .field("y", 10.3, 2) 51 | .field("z", 10.3456) 52 | .field("b", !!10) 53 | .timestamp(1512722735522840439) 54 | .post_http(si); 55 | ``` 56 | 57 | - **Remarks**: 58 | - 3rd parameter `precision` of `field()` is optional for floating point value, and default precision is `2`. 59 | - `usr` and `pwd` is optional for authorization. 60 | 61 | - The series sent is: 62 | 63 | ``` 64 | foo,k=v,x=y x=10i,y=10.30,z=10.35,b=t 1512722735522840439 65 | ``` 66 | 67 | - You could change `post_http` to `send_udp` for udp request. And only `host` and `port` is required for udp. 68 | 69 | ```cpp 70 | influxdb_cpp::builder() 71 | .meas("foo") 72 | .field("x", 10) 73 | .send_udp("127.0.0.1", 8091); 74 | ``` 75 | 76 | - Bulk/batch/multiple insert also supports: 77 | 78 | ```cpp 79 | influxdb_cpp::builder() 80 | .meas("foo") // series 1 81 | .field("x", 10) 82 | 83 | .meas("bar") // series 2 84 | .field("y", 10.3) 85 | .send_udp("127.0.0.1", 8091); 86 | ``` 87 | 88 | - The series sent are: 89 | 90 | ``` 91 | foo x=10i 92 | bar y=10.30 93 | ``` 94 | 95 | #### Query example 96 | 97 | - And you can query series by according to the following example. 98 | 99 | ```cpp 100 | influxdb_cpp::server_info si("127.0.0.1", 8086, "db", "usr", "pwd"); 101 | 102 | string resp; 103 | influxdb_cpp::query(resp, "select * from t", si); 104 | ``` 105 | 106 | - You can use [xpjson](https://github.com/ez8-co/xpjson) to parse the result refer to [issue #3](https://github.com/orca-zhang/influxdb-cpp/issues/3). 107 | 108 | ### **Remarks for Windows** 109 | 110 | - You should **init socket environment by yourself** under Windows. 111 | - FYR: [MSDN doc for `WSAStartup`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms742213(v=vs.85).aspx) 112 | 113 | ### **Remarks for Special Characters in Password** 114 | 115 | - You should do URL encode first. 116 | 117 | ``` c++ 118 | string encoded_pwd; 119 | influxdb_cpp::url_encode(encoded_pwd, pwd); 120 | ``` 121 | 122 | ### Return code cheat-sheet 123 | 124 | |Functions|Code|Description| 125 | |-|-|-| 126 | |`send_udp` `post_http`|0|success| 127 | |`send_udp` `post_http`|-1|convert host address to network order error| 128 | |`send_udp` `post_http`|-2|create socket error| 129 | |`send_udp` `post_http`|-3|`sendto` / `connect` failed| 130 | |`post_http`|-6|send buffer error| 131 | |`post_http`|-7|expect a character but read no more| 132 | |`post_http`|-8|unexpected characters while parsing chunk length| 133 | |`post_http`|-9|unexpected characters while parsing new line| 134 | |`post_http`|-10|unexpected null character| 135 | |`post_http`|-11|unexpected end| 136 | 137 | ### TODO 138 | 139 | - Add more test cases. 140 | - Supports DSN initializatin for server_info. 141 | - Do not need to connect every time. 142 | 143 | ### Misc 144 | 145 | - Please feel free to use influxdb-cpp. 146 | - Looking forward to your suggestions. 147 | - If your project is using influxdb-cpp, you can show your project or company here by creating a issue or let me know. 148 | -------------------------------------------------------------------------------- /influxdb.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | influxdb-cpp -- 💜 C++ client for InfluxDB. 3 | 4 | Copyright (c) 2010-2018 5 | This library is released under the MIT License. 6 | 7 | Please see LICENSE file or visit https://github.com/orca-zhang/influxdb-cpp for details. 8 | */ 9 | 10 | #ifndef INFLUXDB_CPP_HPP 11 | #define INFLUXDB_CPP_HPP 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #ifdef _WIN32 18 | #define NOMINMAX 19 | #include 20 | #include 21 | #pragma comment(lib, "ws2_32") 22 | typedef struct iovec { void* iov_base; size_t iov_len; } iovec; 23 | inline __int64 writev(int sock, struct iovec* iov, int cnt) { 24 | __int64 r = send(sock, (const char*)iov->iov_base, iov->iov_len, 0); 25 | return (r < 0 || cnt == 1) ? r : r + writev(sock, iov + 1, cnt - 1); 26 | } 27 | #else 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #define closesocket close 35 | #endif 36 | 37 | namespace influxdb_cpp { 38 | struct server_info { 39 | std::string host_; 40 | int port_; 41 | std::string db_; 42 | std::string usr_; 43 | std::string pwd_; 44 | std::string precision_; 45 | std::string token_; 46 | server_info(const std::string& host, int port, const std::string& db = "", const std::string& usr = "", const std::string& pwd = "", const std::string& precision = "ms", const std::string& token = "") 47 | : host_(host), port_(port), db_(db), usr_(usr), pwd_(pwd), precision_(precision), token_(token) {} 48 | }; 49 | namespace detail { 50 | struct meas_caller; 51 | struct tag_caller; 52 | struct field_caller; 53 | struct ts_caller; 54 | struct inner { 55 | static int http_request(const char*, const char*, const std::string&, const std::string&, const server_info&, std::string*, unsigned timeout_sec = 0); 56 | static inline unsigned char to_hex(unsigned char x) { return x > 9 ? x + 55 : x + 48; } 57 | }; 58 | } 59 | static void url_encode(std::string& out, const std::string& src); 60 | 61 | inline int query(std::string& resp, const std::string& query, const server_info& si, unsigned timeout_sec = 0) { 62 | std::string qs("&q="); 63 | url_encode(qs, query); 64 | return detail::inner::http_request("GET", "query", qs, "", si, &resp, timeout_sec); 65 | } 66 | inline int create_db(std::string& resp, const std::string& db_name, const server_info& si, unsigned timeout_sec = 0) { 67 | std::string qs("&q=create+database+"); 68 | url_encode(qs, db_name); 69 | return detail::inner::http_request("POST", "query", qs, "", si, &resp, timeout_sec); 70 | } 71 | 72 | struct builder { 73 | detail::tag_caller& meas(const std::string& m) { 74 | lines_.imbue(std::locale("C")); 75 | lines_.clear(); 76 | return _m(m); 77 | } 78 | protected: 79 | detail::tag_caller& _m(const std::string& m) { 80 | _escape(m, ", "); 81 | return reinterpret_cast(*this); 82 | } 83 | detail::tag_caller& _t(const std::string& k, const std::string& v) { 84 | lines_ << ','; 85 | _escape(k, ",= "); 86 | lines_ << '='; 87 | _escape(v, ",= "); 88 | return reinterpret_cast(*this); 89 | } 90 | detail::field_caller& _f_s(char delim, const std::string& k, const std::string& v) { 91 | lines_ << delim; 92 | _escape(k, ",= "); 93 | lines_ << "=\""; 94 | _escape(v, "\""); 95 | lines_ << '\"'; 96 | return reinterpret_cast(*this); 97 | } 98 | detail::field_caller& _f_i(char delim, const std::string& k, long long v) { 99 | lines_ << delim; 100 | _escape(k, ",= "); 101 | lines_ << '='; 102 | lines_ << v << 'i'; 103 | return reinterpret_cast(*this); 104 | } 105 | detail::field_caller& _f_f(char delim, const std::string& k, double v, int prec) { 106 | lines_ << delim; 107 | _escape(k, ",= "); 108 | lines_.precision(prec); 109 | lines_.setf(std::ios::fixed); 110 | lines_ << '=' << v; 111 | return reinterpret_cast(*this); 112 | } 113 | detail::field_caller& _f_b(char delim, const std::string& k, bool v) { 114 | lines_ << delim; 115 | _escape(k, ",= "); 116 | lines_ << '=' << (v ? 't' : 'f'); 117 | return reinterpret_cast(*this); 118 | } 119 | detail::ts_caller& _ts(long long ts) { 120 | lines_ << ' ' << ts; 121 | return reinterpret_cast(*this); 122 | } 123 | int _post_http(const server_info& si, std::string* resp, unsigned timeout_sec = 0) { 124 | return detail::inner::http_request("POST", "write", "", lines_.str(), si, resp, timeout_sec); 125 | } 126 | int _send_udp(const std::string& host, int port) { 127 | int sock, ret = 0; 128 | struct sockaddr_in addr; 129 | 130 | addr.sin_family = AF_INET; 131 | addr.sin_port = htons(port); 132 | if((addr.sin_addr.s_addr = inet_addr(host.c_str())) == INADDR_NONE) return -1; 133 | 134 | if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) return -2; 135 | 136 | lines_ << '\n'; 137 | if(sendto(sock, &lines_.str()[0], lines_.str().length(), 0, reinterpret_cast(&addr), sizeof(addr)), static_cast(lines_.str().length())) 138 | ret = -3; 139 | 140 | closesocket(sock); 141 | return ret; 142 | } 143 | void _escape(const std::string& src, const char* escape_seq) { 144 | size_t pos = 0, start = 0; 145 | while((pos = src.find_first_of(escape_seq, start)) != std::string::npos) { 146 | lines_.write(src.c_str() + start, pos - start); 147 | lines_ << '\\' << src[pos]; 148 | start = ++pos; 149 | } 150 | lines_.write(src.c_str() + start, src.length() - start); 151 | } 152 | 153 | std::stringstream lines_; 154 | }; 155 | inline void url_encode(std::string& out, const std::string& src) { 156 | size_t pos = 0, start = 0; 157 | while((pos = src.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~", start)) != std::string::npos) { 158 | out.append(src.c_str() + start, pos - start); 159 | if(src[pos] == ' ') 160 | out += "+"; 161 | else { 162 | out += '%'; 163 | out += detail::inner::to_hex(static_cast(src[pos]) >> 4); 164 | out += detail::inner::to_hex(static_cast(src[pos]) & 0xF); 165 | } 166 | start = ++pos; 167 | } 168 | out.append(src.c_str() + start, src.length() - start); 169 | } 170 | 171 | namespace detail { 172 | struct tag_caller : public builder { 173 | detail::tag_caller& tag(const std::string& k, const std::string& v) { return _t(k, v); } 174 | detail::field_caller& field(const std::string& k, const std::string& v) { return _f_s(' ', k, v); } 175 | detail::field_caller& field(const std::string& k, bool v) { return _f_b(' ', k, v); } 176 | detail::field_caller& field(const std::string& k, short v) { return _f_i(' ', k, v); } 177 | detail::field_caller& field(const std::string& k, int v) { return _f_i(' ', k, v); } 178 | detail::field_caller& field(const std::string& k, long v) { return _f_i(' ', k, v); } 179 | detail::field_caller& field(const std::string& k, long long v) { return _f_i(' ', k, v); } 180 | detail::field_caller& field(const std::string& k, double v, int prec = 2) { return _f_f(' ', k, v, prec); } 181 | private: 182 | detail::tag_caller& meas(const std::string& m); 183 | }; 184 | struct ts_caller : public builder { 185 | detail::tag_caller& meas(const std::string& m) { lines_ << '\n'; return _m(m); } 186 | int post_http(const server_info& si, std::string* resp = NULL, 187 | unsigned timeout_sec = 0) { return _post_http(si, resp, timeout_sec); } 188 | int send_udp(const std::string& host, int port) { return _send_udp(host, port); } 189 | }; 190 | struct field_caller : public ts_caller { 191 | detail::field_caller& field(const std::string& k, const std::string& v) { return _f_s(',', k, v); } 192 | detail::field_caller& field(const std::string& k, bool v) { return _f_b(',', k, v); } 193 | detail::field_caller& field(const std::string& k, short v) { return _f_i(',', k, v); } 194 | detail::field_caller& field(const std::string& k, int v) { return _f_i(',', k, v); } 195 | detail::field_caller& field(const std::string& k, long v) { return _f_i(',', k, v); } 196 | detail::field_caller& field(const std::string& k, long long v) { return _f_i(',', k, v); } 197 | detail::field_caller& field(const std::string& k, double v, int prec = 2) { return _f_f(',', k, v, prec); } 198 | detail::ts_caller& timestamp(unsigned long long ts) { return _ts(ts); } 199 | }; 200 | inline int inner::http_request(const char* method, const char* uri, 201 | const std::string& querystring, const std::string& body, const server_info& si, std::string* resp, unsigned timeout_sec) { 202 | std::string header; 203 | struct iovec iv[2]; 204 | struct sockaddr_in addr; 205 | int sock, ret_code = 0, content_length = 0, len = 0; 206 | char ch; 207 | unsigned char chunked = 0; 208 | 209 | addr.sin_family = AF_INET; 210 | addr.sin_port = htons(si.port_); 211 | if((addr.sin_addr.s_addr = inet_addr(si.host_.c_str())) == INADDR_NONE) return -1; 212 | 213 | if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) return -2; 214 | 215 | struct timeval timeout; 216 | timeout.tv_sec = static_cast(timeout_sec); 217 | timeout.tv_usec = 0; 218 | if(setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast (&timeout), sizeof(timeout)) < 0 || 219 | setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast (&timeout), sizeof(timeout)) < 0) return -2; 220 | 221 | if(connect(sock, reinterpret_cast(&addr), sizeof(addr)) < 0) { 222 | closesocket(sock); 223 | return -3; 224 | } 225 | 226 | header.resize(len = 0x100); 227 | 228 | for(;;) { 229 | iv[0].iov_len = snprintf(&header[0], len, 230 | "%s /%s?db=%s%s%s%s%s%s%s%s HTTP/1.1\r\nHost: %s%s%s\r\nContent-Length: %d\r\n\r\n", 231 | method, uri, si.db_.c_str(), !si.token_.empty() ? "" : "&u=", !si.token_.empty() ? "" : si.usr_.c_str(), !si.token_.empty() ? "" : "&p=", !si.token_.empty() ? "" : si.pwd_.c_str(), 232 | strcmp(uri, "write") ? "&epoch=" : "&precision=", si.precision_.c_str(), querystring.c_str(), si.host_.c_str(), si.token_.empty() ? "" : "\r\nAuthorization: Token ", si.token_.c_str(), (int)body.length()); 233 | if(static_cast(iv[0].iov_len) >= len) 234 | header.resize(len *= 2); 235 | else 236 | break; 237 | } 238 | iv[0].iov_base = &header[0]; 239 | iv[1].iov_base = const_cast(&body[0]); 240 | iv[1].iov_len = body.length(); 241 | 242 | if(writev(sock, iv, 2) < static_cast(iv[0].iov_len + iv[1].iov_len)) { 243 | ret_code = -6; 244 | goto END; 245 | } 246 | 247 | iv[0].iov_len = len; 248 | 249 | #define _NO_MORE() (len >= static_cast(iv[0].iov_len) && \ 250 | (iv[0].iov_len = recv(sock, &header[0], header.length(), len = 0)) == static_cast(-1)) 251 | #define _GET_NEXT_CHAR() (ch = _NO_MORE() ? 0 : header[len++]) 252 | #define _LOOP_NEXT(statement) for(;;) { if(!(_GET_NEXT_CHAR())) { ret_code = -7; goto END; } statement } 253 | #define _UNTIL(c) _LOOP_NEXT( if(ch == c) break; ) 254 | #define _GET_NUMBER(n) _LOOP_NEXT( if(ch >= '0' && ch <= '9') n = n * 10 + (ch - '0'); else break; ) 255 | #define _GET_CHUNKED_LEN(n, c) _LOOP_NEXT( if(ch >= '0' && ch <= '9') n = n * 16 + (ch - '0'); \ 256 | else if(ch >= 'A' && ch <= 'F') n = n * 16 + (ch - 'A') + 10; \ 257 | else if(ch >= 'a' && ch <= 'f') n = n * 16 + (ch - 'a') + 10; else {if(ch != c) { ret_code = -8; goto END; } break;} ) 258 | #define _(c) if((_GET_NEXT_CHAR()) != c) break; 259 | #define __(c) if((_GET_NEXT_CHAR()) != c) { ret_code = -9; goto END; } 260 | 261 | if(resp) resp->clear(); 262 | 263 | _UNTIL(' ')_GET_NUMBER(ret_code) 264 | for(;;) { 265 | _UNTIL('\n') 266 | switch(_GET_NEXT_CHAR()) { 267 | case 'C':_('o')_('n')_('t')_('e')_('n')_('t')_('-') 268 | _('L')_('e')_('n')_('g')_('t')_('h')_(':')_(' ') 269 | _GET_NUMBER(content_length) 270 | break; 271 | case 'T':_('r')_('a')_('n')_('s')_('f')_('e')_('r')_('-') 272 | _('E')_('n')_('c')_('o')_('d')_('i')_('n')_('g')_(':') 273 | _(' ')_('c')_('h')_('u')_('n')_('k')_('e')_('d') 274 | chunked = 1; 275 | break; 276 | case '\r':__('\n') 277 | switch(chunked) { 278 | do {__('\r')__('\n') 279 | case 1: 280 | _GET_CHUNKED_LEN(content_length, '\r')__('\n') 281 | if(!content_length) { 282 | __('\r')__('\n') 283 | goto END; 284 | } 285 | case 0: 286 | while(content_length > 0 && !_NO_MORE()) { 287 | content_length -= (iv[1].iov_len = std::min(content_length, static_cast(iv[0].iov_len) - len)); 288 | if(resp) resp->append(&header[len], iv[1].iov_len); 289 | len += iv[1].iov_len; 290 | } 291 | } while(chunked); 292 | } 293 | goto END; 294 | } 295 | if(!ch) { 296 | ret_code = -10; 297 | goto END; 298 | } 299 | } 300 | ret_code = -11; 301 | END: 302 | closesocket(sock); 303 | return ret_code / 100 == 2 ? 0 : ret_code; 304 | #undef _NO_MORE 305 | #undef _GET_NEXT_CHAR 306 | #undef _LOOP_NEXT 307 | #undef _UNTIL 308 | #undef _GET_NUMBER 309 | #undef _GET_CHUNKED_LEN 310 | #undef _ 311 | #undef __ 312 | } 313 | } 314 | } 315 | 316 | #endif // INFLUXDB_CPP_HPP 317 | --------------------------------------------------------------------------------