Skip to content

Commit 0a6ddca

Browse files
committed
Improved error reporting for winhttp base http_client.
1 parent c7774b7 commit 0a6ddca

File tree

4 files changed

+124
-66
lines changed

4 files changed

+124
-66
lines changed

Release/include/cpprest/http_client_impl.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,20 @@ class request_context
148148
finish();
149149
}
150150

151-
void report_error(unsigned long error_code, const utility::string_t & errorMessage)
151+
void report_error(unsigned long error_code, const std::string &errorMessage)
152152
{
153-
report_exception(http_exception((int)error_code, errorMessage));
153+
report_exception(http_exception(static_cast<int>(error_code), errorMessage));
154154
}
155155

156+
#ifdef _MS_WINDOWS
157+
void report_error(unsigned long error_code, const std::wstring &errorMessage)
158+
{
159+
report_exception(http_exception(static_cast<int>(error_code), errorMessage));
160+
}
161+
#endif
162+
156163
template<typename _ExceptionType>
157-
void report_exception(_ExceptionType e)
164+
void report_exception(const _ExceptionType &e)
158165
{
159166
report_exception(std::make_exception_ptr(e));
160167
}

Release/include/cpprest/http_msg.h

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,14 @@ class http_exception : public std::exception
168168
http_exception(const utility::string_t &whatArg)
169169
: m_msg(utility::conversions::to_utf8string(whatArg)) {}
170170

171+
#ifdef _MS_WINDOWS
172+
/// <summary>
173+
/// Creates an <c>http_exception</c> with just a string message and no error code.
174+
/// </summary>
175+
/// <param name="whatArg">Error message string.</param>
176+
http_exception(std::string whatArg) : m_msg(std::move(whatArg)) {}
177+
#endif
178+
171179
/// <summary>
172180
/// Creates an <c>http_exception</c> with from a error code using the current platform error category.
173181
/// The message of the error code will be used as the what() string message.
@@ -189,6 +197,18 @@ class http_exception : public std::exception
189197
m_msg(utility::conversions::to_utf8string(whatArg))
190198
{}
191199

200+
#ifdef _MS_WINDOWS
201+
/// <summary>
202+
/// Creates an <c>http_exception</c> with from a error code using the current platform error category.
203+
/// </summary>
204+
/// <param name="errorCode">Error code value.</param>
205+
/// <param name="whatArg">Message to use in what() string.</param>
206+
http_exception(int errorCode, std::string whatArg) :
207+
m_errorCode(utility::details::create_error_code(errorCode)),
208+
m_msg(std::move(whatArg))
209+
{}
210+
#endif
211+
192212
/// <summary>
193213
/// Creates an <c>http_exception</c> with from a error code and category. The message of the error code will be used
194214
/// as the <c>what</c> string message.
@@ -200,8 +220,10 @@ class http_exception : public std::exception
200220
m_msg = m_errorCode.message();
201221
}
202222

203-
~http_exception() CPPREST_NOEXCEPT {}
204-
223+
/// <summary>
224+
/// Gets a string identifying the cause of the exception.
225+
/// </summary>
226+
/// <returns>A null terminated character string.</returns>
205227
const char* what() const CPPREST_NOEXCEPT
206228
{
207229
return m_msg.c_str();

Release/src/http/client/http_win7.cpp

Lines changed: 68 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ static utility::string_t parse_reason_phrase(HINTERNET request_handle)
8989
}
9090

9191
/// <summary>
92-
/// Parses a string containing Http headers.
92+
/// Parses a string containing HTTP headers.
9393
/// </summary>
9494
static void parse_winhttp_headers(HINTERNET request_handle, _In_z_ utf16char *headersStr, http_response &response)
9595
{
@@ -103,34 +103,35 @@ static void parse_winhttp_headers(HINTERNET request_handle, _In_z_ utf16char *he
103103
parse_headers_string(headersStr, response.headers());
104104
}
105105

106+
// Helper function to build error messages.
107+
static std::string build_error_msg(unsigned long code, const std::string &location)
108+
{
109+
std::string msg(location);
110+
msg.append(": ");
111+
msg.append(std::to_string(code));
112+
msg.append(": ");
113+
msg.append(utility::details::windows_category().message(code));
114+
return msg;
115+
}
116+
106117
// Helper function to build an error message from a WinHTTP async result.
107-
static std::string build_callback_error_msg(_In_ WINHTTP_ASYNC_RESULT *error_result)
118+
static std::string build_error_msg(_In_ WINHTTP_ASYNC_RESULT *error_result)
108119
{
109-
std::stringstream error_msg;
110120
switch(error_result->dwResult)
111121
{
112122
case API_RECEIVE_RESPONSE:
113-
error_msg << "WinHttpReceiveResponse";
114-
break;
123+
return build_error_msg(error_result->dwError, "WinHttpReceiveResponse");
115124
case API_QUERY_DATA_AVAILABLE:
116-
error_msg << "WinHttpQueryDataAvaliable";
117-
break;
125+
return build_error_msg(error_result->dwError, "WinHttpQueryDataAvaliable");
118126
case API_READ_DATA:
119-
error_msg << "WinHttpReadData";
120-
break;
127+
return build_error_msg(error_result->dwError, "WinHttpReadData");
121128
case API_WRITE_DATA:
122-
error_msg << "WinHttpWriteData";
123-
break;
129+
return build_error_msg(error_result->dwError, "WinHttpWriteData");
124130
case API_SEND_REQUEST:
125-
error_msg << "WinHttpSendRequest";
126-
break;
131+
return build_error_msg(error_result->dwError, "WinHttpSendRequest");
127132
default:
128-
error_msg << "Unknown WinHTTP Function";
129-
break;
133+
return build_error_msg(error_result->dwError, "Unknown WinHTTP Function");
130134
}
131-
error_msg << ": " << error_result->dwError << ": "
132-
<< utility::details::windows_category().message(error_result->dwError);
133-
return error_msg.str();
134135
}
135136

136137
class memory_holder
@@ -416,7 +417,7 @@ class winhttp_client : public _http_client_communicator
416417
}
417418
}
418419

419-
#if 0 // Work in progress. Enable this to support server certrificate revocation check
420+
#if 0 // Work in progress. Enable this to support server certificate revocation check
420421
if( m_secure )
421422
{
422423
DWORD dwEnableSSLRevocOpt = WINHTTP_ENABLE_SSL_REVOCATION;
@@ -502,11 +503,12 @@ class winhttp_client : public _http_client_communicator
502503
WINHTTP_FLAG_ESCAPE_DISABLE | (m_secure ? WINHTTP_FLAG_SECURE : 0));
503504
if(winhttp_context->m_request_handle == nullptr)
504505
{
505-
request->report_error(GetLastError(), _XPLATSTR("Error opening request"));
506+
auto errorCode = GetLastError();
507+
request->report_error(errorCode, build_error_msg(errorCode, "WinHttpOpenRequest"));
506508
return;
507509
}
508510

509-
if( proxy_info_required )
511+
if(proxy_info_required)
510512
{
511513
auto result = WinHttpSetOption(
512514
winhttp_context->m_request_handle,
@@ -515,7 +517,8 @@ class winhttp_client : public _http_client_communicator
515517
sizeof(WINHTTP_PROXY_INFO) );
516518
if(!result)
517519
{
518-
request->report_error(GetLastError(), _XPLATSTR("Error setting http proxy option"));
520+
auto errorCode = GetLastError();
521+
request->report_error(errorCode, build_error_msg(errorCode, "Setting proxy options"));
519522
return;
520523
}
521524
}
@@ -534,7 +537,8 @@ class winhttp_client : public _http_client_communicator
534537
sizeof(data));
535538
if(!result)
536539
{
537-
request->report_error(GetLastError(), _XPLATSTR("Error setting autologon policy to WINHTTP_AUTOLOGON_SECURITY_LEVEL_HIGH."));
540+
auto errorCode = GetLastError();
541+
request->report_error(errorCode, build_error_msg(errorCode, "Setting autologon policy to WINHTTP_AUTOLOGON_SECURITY_LEVEL_HIGH"));
538542
return;
539543
}
540544
}
@@ -554,7 +558,8 @@ class winhttp_client : public _http_client_communicator
554558
sizeof(data));
555559
if(!result)
556560
{
557-
request->report_error(GetLastError(), U("Error setting WinHttp to ignore server certification validation errors."));
561+
auto errorCode = GetLastError();
562+
request->report_error(errorCode, build_error_msg(errorCode, "Setting ignore server certificate verification"));
558563
return;
559564
}
560565
}
@@ -572,7 +577,7 @@ class winhttp_client : public _http_client_communicator
572577
if (content_length == std::numeric_limits<size_t>::max())
573578
{
574579
// The content length is unknown and the application set a stream. This is an
575-
// indication that we will use tranfer encoding chunked.
580+
// indication that we will use transfer encoding chunked.
576581
winhttp_context->m_bodyType = transfer_encoding_chunked;
577582
}
578583
else
@@ -593,7 +598,8 @@ class winhttp_client : public _http_client_communicator
593598
static_cast<DWORD>(flattened_headers.length()),
594599
WINHTTP_ADDREQ_FLAG_ADD))
595600
{
596-
request->report_error(GetLastError(), _XPLATSTR("Error adding request headers"));
601+
auto errorCode = GetLastError();
602+
request->report_error(errorCode, build_error_msg(errorCode, "WinHttpAddRequestHeaders"));
597603
return;
598604
}
599605
}
@@ -647,7 +653,8 @@ class winhttp_client : public _http_client_communicator
647653
0,
648654
(DWORD_PTR)winhttp_context))
649655
{
650-
winhttp_context->report_error(GetLastError(), _XPLATSTR("Error starting to send request"));
656+
auto errorCode = GetLastError();
657+
winhttp_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpSendRequest"));
651658
}
652659

653660
return;
@@ -671,7 +678,8 @@ class winhttp_client : public _http_client_communicator
671678
winhttp_context->m_bodyType == content_length_chunked ? (DWORD)content_length : WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH,
672679
(DWORD_PTR)winhttp_context))
673680
{
674-
winhttp_context->report_error(GetLastError(), _XPLATSTR("Error starting to send chunked request"));
681+
auto errorCode = GetLastError();
682+
winhttp_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpSendRequest chunked"));
675683
}
676684
}
677685

@@ -685,12 +693,13 @@ class winhttp_client : public _http_client_communicator
685693
{
686694
if (!WinHttpQueryDataAvailable(pContext->m_request_handle, nullptr))
687695
{
688-
pContext->report_error(GetLastError(), _XPLATSTR("Error querying for http body data"));
696+
auto errorCode = GetLastError();
697+
pContext->report_error(errorCode, build_error_msg(errorCode, "WinHttpQueryDataAvaliable"));
689698
}
690699
}
691700
else
692701
{
693-
// If bytes read is less than the chunksize this request is done.
702+
// If bytes read is less than the chunk size this request is done.
694703
const size_t chunkSize = pContext->m_http_client->client_config().chunksize();
695704
if (bytesRead < chunkSize && !firstRead)
696705
{
@@ -707,7 +716,8 @@ class winhttp_client : public _http_client_communicator
707716
static_cast<DWORD>(chunkSize),
708717
nullptr))
709718
{
710-
pContext->report_error(GetLastError(), _XPLATSTR("Error receiving http response body chunk"));
719+
auto errorCode = GetLastError();
720+
pContext->report_error(errorCode, build_error_msg(errorCode, "WinHttpReadData"));
711721
}
712722
}
713723
}
@@ -763,7 +773,8 @@ class winhttp_client : public _http_client_communicator
763773
static_cast<DWORD>(length),
764774
nullptr))
765775
{
766-
p_request_context->report_error(GetLastError(), _XPLATSTR("Error writing data"));
776+
auto errorCode = GetLastError();
777+
p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpWriteData"));
767778
}
768779
};
769780

@@ -776,17 +787,21 @@ class winhttp_client : public _http_client_communicator
776787
SafeInt<size64_t> safeCount = p_request_context->m_remaining_to_write;
777788
safeCount = safeCount.Min(p_request_context->m_http_client->client_config().chunksize());
778789

779-
uint8_t* block = nullptr;
790+
uint8_t* block = nullptr;
780791
size_t length = 0;
781-
if ( rbuf.acquire(block, length) )
792+
if (rbuf.acquire(block, length))
782793
{
783-
if ( length == 0 )
794+
if (length == 0)
784795
{
785796
// Unexpected end-of-stream.
786-
if (!(rbuf.exception() == nullptr))
787-
p_request_context->report_exception(rbuf.exception());
788-
else
797+
if (rbuf.exception() == nullptr)
798+
{
789799
p_request_context->report_error(GetLastError(), _XPLATSTR("Error reading outgoing HTTP body from its stream."));
800+
}
801+
else
802+
{
803+
p_request_context->report_exception(rbuf.exception());
804+
}
790805
return;
791806
}
792807

@@ -807,7 +822,8 @@ class winhttp_client : public _http_client_communicator
807822
static_cast<DWORD>(to_write),
808823
nullptr))
809824
{
810-
p_request_context->report_error(GetLastError(), _XPLATSTR("Error writing data"));
825+
auto errorCode = GetLastError();
826+
p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpWriteData"));
811827
}
812828
}
813829
else
@@ -839,13 +855,14 @@ class winhttp_client : public _http_client_communicator
839855
p_request_context->m_bodyType = no_body;
840856
}
841857

842-
if( !WinHttpWriteData(
858+
if(!WinHttpWriteData(
843859
p_request_context->m_request_handle,
844860
p_request_context->m_body_data.get(),
845861
static_cast<DWORD>(read),
846862
nullptr))
847863
{
848-
p_request_context->report_error(GetLastError(), _XPLATSTR("Error writing data"));
864+
auto errorCode = GetLastError();
865+
p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpWriteData"));
849866
}
850867
});
851868
}
@@ -1003,7 +1020,7 @@ class winhttp_client : public _http_client_communicator
10031020
}
10041021
}
10051022

1006-
p_request_context->report_error(errorCode, utility::conversions::to_string_t(build_callback_error_msg(error_result)));
1023+
p_request_context->report_error(errorCode, build_error_msg(error_result));
10071024
break;
10081025
}
10091026
case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE :
@@ -1034,7 +1051,8 @@ class winhttp_client : public _http_client_communicator
10341051
{
10351052
if(!WinHttpReceiveResponse(hRequestHandle, nullptr))
10361053
{
1037-
p_request_context->report_error(GetLastError(), _XPLATSTR("Error receiving response"));
1054+
auto errorCode = GetLastError();
1055+
p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpReceiveResponse"));
10381056
}
10391057
}
10401058
break;
@@ -1075,7 +1093,8 @@ class winhttp_client : public _http_client_communicator
10751093
{
10761094
if(!WinHttpReceiveResponse(hRequestHandle, nullptr))
10771095
{
1078-
p_request_context->report_error(GetLastError(), _XPLATSTR("Error receiving response"));
1096+
auto errorCode = GetLastError();
1097+
p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpReceiveResponse"));
10791098
}
10801099
}
10811100
break;
@@ -1098,7 +1117,8 @@ class winhttp_client : public _http_client_communicator
10981117
&headerBufferLength,
10991118
WINHTTP_NO_HEADER_INDEX))
11001119
{
1101-
p_request_context->report_error(GetLastError(), _XPLATSTR("Error receiving http headers"));
1120+
auto errorCode = GetLastError();
1121+
p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpQueryHeaders"));;
11021122
return;
11031123
}
11041124

@@ -1154,7 +1174,8 @@ class winhttp_client : public _http_client_communicator
11541174
num_bytes,
11551175
nullptr))
11561176
{
1157-
p_request_context->report_error(GetLastError(), _XPLATSTR("Error receiving http body chunk"));
1177+
auto errorCode = GetLastError();
1178+
p_request_context->report_error(errorCode, build_error_msg(errorCode, "WinHttpReadData"));
11581179
}
11591180
}
11601181
else
@@ -1265,4 +1286,4 @@ pplx::task<http_response> http_network_handler::propagate(http_request request)
12651286
return result_task;
12661287
}
12671288

1268-
}}}} // namespaces
1289+
}}}}

0 commit comments

Comments
 (0)