@@ -57,11 +57,14 @@ namespace web { namespace http
57
57
}
58
58
59
59
std::unique_ptr<tcp::socket> m_socket;
60
+ std::unique_ptr<boost::asio::ssl::stream<tcp::socket>> p_ssl_stream;
61
+
60
62
uri m_what;
61
63
size_t m_known_size;
62
64
size_t m_current_size;
63
65
bool m_needChunked;
64
66
bool m_timedout;
67
+ bool m_ssl;
65
68
boost::asio::streambuf m_request_buf;
66
69
boost::asio::streambuf m_response_buf;
67
70
std::unique_ptr<boost::asio::deadline_timer> m_timer;
@@ -74,18 +77,23 @@ namespace web { namespace http
74
77
m_timer.reset ();
75
78
}
76
79
77
- if (m_socket)
80
+ if (!m_ssl && m_socket)
78
81
{
79
82
boost::system::error_code ignore;
80
83
m_socket->shutdown (tcp::socket::shutdown_both, ignore);
81
84
m_socket->close ();
82
85
m_socket.reset ();
83
86
}
87
+
88
+ if (m_ssl && p_ssl_stream)
89
+ {
90
+ p_ssl_stream->shutdown ();
91
+ }
84
92
}
85
93
86
94
void cancel (const boost::system::error_code& ec)
87
95
{
88
- if (!ec)
96
+ if (!ec)
89
97
{
90
98
m_timedout = true ;
91
99
auto sock = m_socket.get ();
@@ -113,7 +121,6 @@ namespace web { namespace http
113
121
}
114
122
};
115
123
116
-
117
124
struct client
118
125
{
119
126
client (boost::asio::io_service& io_service, size_t chunk_size)
@@ -124,9 +131,19 @@ namespace web { namespace http
124
131
void send_request (linux_request_context* ctx, int timeout)
125
132
{
126
133
auto what = ctx->m_what ;
127
- ctx->m_socket .reset (new tcp::socket (m_io_service));
128
-
129
134
auto resource = what.resource ().to_string ();
135
+
136
+ ctx->m_ssl = what.scheme () == " https" ;
137
+
138
+ if (ctx->m_ssl )
139
+ {
140
+ boost::asio::ssl::context context (boost::asio::ssl::context::sslv23);
141
+ context.set_verify_mode (boost::asio::ssl::context::verify_none);
142
+ ctx->p_ssl_stream .reset (new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(m_io_service, context));
143
+ }
144
+ else
145
+ ctx->m_socket .reset (new tcp::socket (m_io_service));
146
+
130
147
if (resource == " " ) resource = " /" ;
131
148
132
149
auto method = ctx->m_request .method ();
@@ -139,15 +156,12 @@ namespace web { namespace http
139
156
auto host = what.host ();
140
157
std::ostream request_stream (&ctx->m_request_buf );
141
158
142
- request_stream << method << " "
143
- << resource << " "
144
- << " HTTP/1.1" << CRLF
145
- << " Host: " << host;
146
-
147
- if (what.port () != 0 && what.port () != 80 )
148
- request_stream << " :" << what.port ();
159
+ request_stream << method << " " << resource << " " << " HTTP/1.1" << CRLF << " Host: " << host;
149
160
150
- request_stream << CRLF;
161
+ int port = what.port ();
162
+ if (port == 0 )
163
+ port = (ctx->m_ssl ? 443 : 80 );
164
+ request_stream << " :" << port << CRLF;
151
165
152
166
// Check user specified transfer-encoding
153
167
std::string transferencoding;
@@ -169,7 +183,8 @@ namespace web { namespace http
169
183
else
170
184
{
171
185
has_body = false ;
172
- ctx->m_request .headers ()[header_names::content_length] = U (" 0" );
186
+ if (!ctx->m_ssl )
187
+ ctx->m_request .headers ()[header_names::content_length] = U (" 0" );
173
188
}
174
189
}
175
190
@@ -180,16 +195,24 @@ namespace web { namespace http
180
195
181
196
request_stream << flatten_http_headers (ctx->m_request .headers ());
182
197
183
- request_stream << " Connection: close" << CRLF; // so we can just read to EOF
198
+ if (!ctx->m_ssl )
199
+ request_stream << " Connection: close" << CRLF; // so we can just read to EOF
200
+
184
201
request_stream << CRLF;
185
202
186
- tcp::resolver::query query (host, utility::conversions::print_string (what. port () == 0 ? 80 : what. port () ));
203
+ tcp::resolver::query query (host, utility::conversions::print_string (port));
187
204
188
205
ctx->m_timer .reset (new boost::asio::deadline_timer (m_io_service));
189
206
ctx->m_timer ->expires_from_now (boost::posix_time::milliseconds (timeout));
190
207
ctx->m_timer ->async_wait (boost::bind (&linux_request_context::cancel, ctx, boost::asio::placeholders::error));
191
208
192
- m_resolver.async_resolve (query, boost::bind (&client::handle_resolve, this , boost::asio::placeholders::error, boost::asio::placeholders::iterator, ctx));
209
+ if (ctx->m_ssl )
210
+ {
211
+ boost::asio::ip::tcp::resolver::iterator iter = m_resolver.resolve (query);
212
+ boost::asio::async_connect (ctx->p_ssl_stream ->lowest_layer (), iter, boost::bind (&client::handle_connect, this , boost::asio::placeholders::error, boost::asio::placeholders::iterator, ctx));
213
+ }
214
+ else
215
+ m_resolver.async_resolve (query, boost::bind (&client::handle_resolve, this , boost::asio::placeholders::error, boost::asio::placeholders::iterator, ctx));
193
216
}
194
217
195
218
private:
@@ -223,28 +246,55 @@ namespace web { namespace http
223
246
else
224
247
{
225
248
auto endpoint = *endpoints;
226
- ctx->m_socket ->async_connect (endpoint, boost::bind (&client::handle_connect, this , boost::asio::placeholders::error, ++endpoints, ctx));
249
+ if (ctx->m_ssl )
250
+ {
251
+ boost::asio::ip::tcp::resolver::iterator endpoint_iterator;
252
+ boost::asio::async_connect ((*(ctx->p_ssl_stream )).lowest_layer (), endpoint_iterator, boost::bind (&client::handle_connect, this , boost::asio::placeholders::error, ++endpoints, ctx));
253
+ }
254
+ else
255
+ ctx->m_socket ->async_connect (endpoint, boost::bind (&client::handle_connect, this , boost::asio::placeholders::error, ++endpoints, ctx));
227
256
}
228
257
}
229
258
230
259
void handle_connect (const boost::system::error_code& ec, tcp::resolver::iterator endpoints, linux_request_context* ctx)
231
260
{
232
261
if (!ec)
233
262
{
234
- boost::asio::async_write (*ctx->m_socket , ctx->m_request_buf , boost::bind (&client::handle_write_request, this , boost::asio::placeholders::error, ctx));
263
+ if (ctx->m_ssl )
264
+ ctx->p_ssl_stream ->async_handshake (boost::asio::ssl::stream_base::client, boost::bind (&client::handle_handshake, this , boost::asio::placeholders::error, ctx));
265
+ else
266
+ boost::asio::async_write (*ctx->m_socket , ctx->m_request_buf , boost::bind (&client::handle_write_request, this , boost::asio::placeholders::error, ctx));
235
267
}
236
268
else if (endpoints == tcp::resolver::iterator ())
237
269
{
238
270
ctx->report_error (" Failed to connect to any resolved endpoint" , ec);
239
271
}
240
272
else
241
273
{
274
+ if (ctx->m_ssl )
275
+ {
276
+ ctx->report_error (" SSL Failed to connect to any resolved endpoint" , ec);
277
+ return ;
278
+ }
279
+
242
280
boost::system::error_code ignore;
243
281
ctx->m_socket ->shutdown (tcp::socket::shutdown_both, ignore);
244
282
ctx->m_socket ->close ();
245
283
ctx->m_socket .reset (new tcp::socket (m_io_service));
246
284
auto endpoint = *endpoints;
247
285
ctx->m_socket ->async_connect (endpoint, boost::bind (&client::handle_connect, this , boost::asio::placeholders::error, ++endpoints, ctx));
286
+ }
287
+ }
288
+
289
+ void handle_handshake (const boost::system::error_code& ec, linux_request_context* ctx)
290
+ {
291
+ if (!ec)
292
+ {
293
+ boost::asio::async_write (*ctx->p_ssl_stream , ctx->m_request_buf , boost::bind (&client::handle_write_request, this , boost::asio::placeholders::error, ctx));
294
+ }
295
+ else
296
+ {
297
+ std::cout << " Error code in handle_handshake is " << ec << std::endl;
248
298
}
249
299
}
250
300
@@ -275,8 +325,12 @@ namespace web { namespace http
275
325
ctx->m_request_buf .consume (offset);
276
326
ctx->m_current_size += readSize;
277
327
ctx->m_uploaded += (size64_t )readSize;
278
- boost::asio::async_write (*ctx->m_socket , ctx->m_request_buf ,
279
- boost::bind (readSize != 0 ? &client::handle_write_chunked_body : &client::handle_write_body, this , boost::asio::placeholders::error, ctx));
328
+ if (ctx->m_ssl )
329
+ boost::asio::async_write (*ctx->p_ssl_stream , ctx->m_request_buf ,
330
+ boost::bind (readSize != 0 ? &client::handle_write_chunked_body : &client::handle_write_body, this , boost::asio::placeholders::error, ctx));
331
+ else
332
+ boost::asio::async_write (*ctx->m_socket , ctx->m_request_buf ,
333
+ boost::bind (readSize != 0 ? &client::handle_write_chunked_body : &client::handle_write_body, this , boost::asio::placeholders::error, ctx));
280
334
});
281
335
}
282
336
@@ -308,6 +362,10 @@ namespace web { namespace http
308
362
ctx->m_uploaded += (size64_t )actualSize;
309
363
ctx->m_current_size += actualSize;
310
364
ctx->m_request_buf .commit (actualSize);
365
+ if (ctx->m_ssl )
366
+ boost::asio::async_write (*ctx->p_ssl_stream , ctx->m_request_buf ,
367
+ boost::bind (&client::handle_write_large_body, this , boost::asio::placeholders::error, ctx));
368
+ else
311
369
boost::asio::async_write (*ctx->m_socket , ctx->m_request_buf ,
312
370
boost::bind (&client::handle_write_large_body, this , boost::asio::placeholders::error, ctx));
313
371
});
@@ -339,8 +397,12 @@ namespace web { namespace http
339
397
{
340
398
(*progress)(message_direction::upload, ctx->m_uploaded );
341
399
}
342
-
343
- // Read until the end of entire headers
400
+
401
+ // Read until the end of entire headers
402
+ if (ctx->m_ssl )
403
+ boost::asio::async_read_until (*ctx->p_ssl_stream , ctx->m_response_buf , CRLF+CRLF,
404
+ boost::bind (&client::handle_status_line, this , boost::asio::placeholders::error, ctx));
405
+ else
344
406
boost::asio::async_read_until (*ctx->m_socket , ctx->m_response_buf , CRLF+CRLF,
345
407
boost::bind (&client::handle_status_line, this , boost::asio::placeholders::error, ctx));
346
408
}
@@ -410,6 +472,7 @@ namespace web { namespace http
410
472
411
473
ctx->m_known_size = 0 ;
412
474
ctx->m_response .headers ().match (header_names::content_length, ctx->m_known_size );
475
+
413
476
// note: need to check for 'chunked' here as well, azure storage sends both
414
477
// transfer-encoding:chunked and content-length:0 (although HTTP says not to)
415
478
if (ctx->m_request .method () == U (" HEAD" ) || (!ctx->m_needChunked && ctx->m_known_size == 0 ))
@@ -430,18 +493,34 @@ namespace web { namespace http
430
493
async_read_until_buffersize (std::min (ctx->m_known_size , m_chunksize),
431
494
boost::bind (&client::handle_read_content, this , boost::asio::placeholders::error, ctx), ctx);
432
495
else
433
- boost::asio::async_read_until (*ctx->m_socket , ctx->m_response_buf , CRLF,
434
- boost::bind (&client::handle_chunk_header, this , boost::asio::placeholders::error, ctx));
496
+ {
497
+ if (ctx->m_ssl )
498
+ boost::asio::async_read_until (*ctx->p_ssl_stream , ctx->m_response_buf , CRLF,
499
+ boost::bind (&client::handle_chunk_header, this , boost::asio::placeholders::error, ctx));
500
+ else
501
+ boost::asio::async_read_until (*ctx->m_socket , ctx->m_response_buf , CRLF,
502
+ boost::bind (&client::handle_chunk_header, this , boost::asio::placeholders::error, ctx));
503
+ }
435
504
}
436
505
}
437
506
438
507
template <typename ReadHandler>
439
508
void async_read_until_buffersize (size_t size, ReadHandler handler, linux_request_context* ctx)
440
509
{
441
- if (ctx->m_response_buf .size () >= size)
442
- boost::asio::async_read (*ctx->m_socket , ctx->m_response_buf , boost::asio::transfer_at_least (0 ), handler);
510
+ if (ctx->m_ssl )
511
+ {
512
+ if (ctx->m_response_buf .size () >= size)
513
+ boost::asio::async_read (*ctx->p_ssl_stream , ctx->m_response_buf , boost::asio::transfer_at_least (0 ), handler);
514
+ else
515
+ boost::asio::async_read (*ctx->p_ssl_stream , ctx->m_response_buf , boost::asio::transfer_at_least (size - ctx->m_response_buf .size ()), handler);
516
+ }
443
517
else
444
- boost::asio::async_read (*ctx->m_socket , ctx->m_response_buf , boost::asio::transfer_at_least (size - ctx->m_response_buf .size ()), handler);
518
+ {
519
+ if (ctx->m_response_buf .size () >= size)
520
+ boost::asio::async_read (*ctx->m_socket , ctx->m_response_buf , boost::asio::transfer_at_least (0 ), handler);
521
+ else
522
+ boost::asio::async_read (*ctx->m_socket , ctx->m_response_buf , boost::asio::transfer_at_least (size - ctx->m_response_buf .size ()), handler);
523
+ }
445
524
}
446
525
447
526
void handle_chunk_header (const boost::system::error_code& ec, linux_request_context* ctx)
@@ -452,7 +531,7 @@ namespace web { namespace http
452
531
std::string line;
453
532
std::getline (response_stream, line);
454
533
455
- std::istringstream octetLine (line);
534
+ std::istringstream octetLine (line);
456
535
int octets = 0 ;
457
536
octetLine >> std::hex >> octets;
458
537
@@ -509,8 +588,13 @@ namespace web { namespace http
509
588
return ;
510
589
}
511
590
ctx->m_response_buf .consume (to_read + CRLF.size ()); // consume crlf
512
- boost::asio::async_read_until (*ctx->m_socket , ctx->m_response_buf , CRLF,
513
- boost::bind (&client::handle_chunk_header, this , boost::asio::placeholders::error, ctx));
591
+
592
+ if (ctx->m_ssl )
593
+ boost::asio::async_read_until (*ctx->p_ssl_stream , ctx->m_response_buf , CRLF,
594
+ boost::bind (&client::handle_chunk_header, this , boost::asio::placeholders::error, ctx));
595
+ else
596
+ boost::asio::async_read_until (*ctx->m_socket , ctx->m_response_buf , CRLF,
597
+ boost::bind (&client::handle_chunk_header, this , boost::asio::placeholders::error, ctx));
514
598
});
515
599
}
516
600
}
@@ -575,6 +659,7 @@ namespace web { namespace http
575
659
}
576
660
}
577
661
};
662
+
578
663
class linux_client : public _http_client_communicator
579
664
{
580
665
private:
0 commit comments