| 167 | } |
| 168 | |
| 169 | bool http_post_json(const ParsedUrl &url, const std::string &body, int timeout_ms, std::string &response, |
| 170 | DWORD &status_code, const wchar_t *user_agent) { |
| 171 | status_code = 0; |
| 172 | response.clear(); |
| 173 | |
| 174 | WinHttpHandle session{ |
| 175 | WinHttpOpen(user_agent, WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0)}; |
| 176 | if (!session) |
| 177 | return false; |
| 178 | |
| 179 | bool ok = false; |
| 180 | WinHttpHandle connect; |
| 181 | WinHttpHandle request; |
| 182 | |
| 183 | do { |
| 184 | connect.reset(WinHttpConnect(session.get(), url.host.c_str(), url.port, 0)); |
| 185 | if (!connect) |
| 186 | break; |
| 187 | |
| 188 | request.reset(WinHttpOpenRequest(connect.get(), L"POST", url.path.c_str(), nullptr, WINHTTP_NO_REFERER, |
| 189 | WINHTTP_DEFAULT_ACCEPT_TYPES, url.secure ? WINHTTP_FLAG_SECURE : 0)); |
| 190 | if (!request) |
| 191 | break; |
| 192 | |
| 193 | WinHttpSetTimeouts(request.get(), timeout_ms, timeout_ms, timeout_ms, timeout_ms); |
| 194 | |
| 195 | static const wchar_t *kHeaders = L"Content-Type: application/json\r\n"; |
| 196 | if (!WinHttpSendRequest(request.get(), kHeaders, static_cast<DWORD>(-1L), (LPVOID)body.data(), |
| 197 | static_cast<DWORD>(body.size()), static_cast<DWORD>(body.size()), 0)) { |
| 198 | break; |
| 199 | } |
| 200 | |
| 201 | if (!WinHttpReceiveResponse(request.get(), nullptr)) |
| 202 | break; |
| 203 | |
| 204 | DWORD size = sizeof(status_code); |
| 205 | WinHttpQueryHeaders(request.get(), WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, |
| 206 | WINHTTP_HEADER_NAME_BY_INDEX, &status_code, &size, WINHTTP_NO_HEADER_INDEX); |
| 207 | |
| 208 | while (true) { |
| 209 | DWORD avail = 0; |
| 210 | if (!WinHttpQueryDataAvailable(request.get(), &avail)) { |
| 211 | break; |
| 212 | } |
| 213 | if (avail == 0) { |
| 214 | ok = true; |
| 215 | break; |
| 216 | } |
| 217 | |
| 218 | std::string chunk; |
| 219 | chunk.resize(avail); |
| 220 | DWORD read = 0; |
| 221 | if (!WinHttpReadData(request.get(), &chunk[0], avail, &read)) { |
| 222 | break; |
| 223 | } |
| 224 | chunk.resize(read); |
| 225 | response.append(chunk); |
| 226 | } |