-
Notifications
You must be signed in to change notification settings - Fork 72
/
Copy pathdefault_http_client.cpp
136 lines (125 loc) · 4.71 KB
/
default_http_client.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#include "stdafx.h"
#ifdef USE_CPPRESTSDK
#include "default_http_client.h"
#include <thread>
#pragma warning (push)
#pragma warning (disable : 5204 4355 4625 4626 4868)
#include <cpprest/http_client.h>
#pragma warning (pop)
namespace signalr
{
default_http_client::default_http_client(const signalr_client_config& config) noexcept
: m_config(config)
{ }
void default_http_client::send(const std::string& url, http_request& request,
std::function<void(const http_response&, std::exception_ptr)> callback, cancellation_token token)
{
web::http::method method;
if (request.method == http_method::GET)
{
method = U("GET");
}
else if (request.method == http_method::POST)
{
method = U("POST");
}
else
{
callback(http_response(), std::make_exception_ptr(std::runtime_error("unknown http method")));
return;
}
web::http::http_request http_request;
http_request.set_method(method);
http_request.set_body(request.content);
if (request.headers.size() > 0)
{
web::http::http_headers headers;
for (auto& header : request.headers)
{
headers.add(utility::conversions::to_string_t(header.first), utility::conversions::to_string_t(header.second));
}
http_request.headers() = headers;
}
#pragma warning (push)
#pragma warning (disable : 4625 4626 5026 5027)
struct cancel_wait_context
{
bool complete = false;
std::condition_variable cv;
std::mutex mtx;
};
#pragma warning (pop)
std::shared_ptr<cancel_wait_context> context;
pplx::cancellation_token_source cts;
auto milliseconds = std::chrono::milliseconds(request.timeout);
if (milliseconds.count() != 0)
{
context = std::make_shared<cancel_wait_context>();
pplx::create_task([context, milliseconds, cts]()
{
auto timeout_point = std::chrono::steady_clock::now() + milliseconds;
std::unique_lock<std::mutex> lck(context->mtx);
while (!context->complete)
{
if (context->cv.wait_until(lck, timeout_point) == std::cv_status::timeout)
{
cts.cancel();
break;
}
}
});
}
token.register_callback([cts]()
{
cts.cancel();
});
try
{
web::http::client::http_client client(utility::conversions::to_string_t(url), m_config.get_http_client_config());
client.request(http_request, cts.get_token())
.then([context, callback](pplx::task<web::http::http_response> response_task)
{
try
{
auto http_response = response_task.get();
auto status_code = http_response.status_code();
http_response.extract_utf8string()
.then([callback, status_code](std::string response_body)
{
signalr::http_response response;
response.content = response_body;
response.status_code = status_code;
callback(std::move(response), nullptr);
});
}
catch (...)
{
callback(http_response(), std::current_exception());
}
if (context != nullptr)
{
std::unique_lock<std::mutex> lck(context->mtx);
context->complete = true;
context->cv.notify_all();
}
});
}
// Url validation could throw from the client ctor
catch (...)
{
// unblock timeout task if it was created
if (context != nullptr)
{
std::unique_lock<std::mutex> lck(context->mtx);
context->complete = true;
context->cv.notify_all();
}
callback({}, std::current_exception());
return;
}
}
}
#endif