2 See the header file for details. This file is distributed under the MIT licence.
5 #include "gsoapWinInet.h"
7 /* ensure that the wininet library is linked */
8 #pragma comment( lib, "wininet.lib" )
9 /* disable deprecation warnings */
10 #pragma warning(disable : 4996)
12 #define UNUSED_ARG(x) (x)
13 #define INVALID_BUFFER_LENGTH ((DWORD)-1)
16 static const char wininet_id
[] = "wininet-2.0";
18 /* plugin private data */
21 HINTERNET hInternet
; /* internet session handle */
22 HINTERNET hConnection
; /* current connection handle */
23 BOOL bDisconnect
; /* connection is disconnected */
24 BOOL bKeepAlive
; /* keep connection alive */
25 DWORD dwRequestFlags
; /* extra request flags from user */
26 char * pBuffer
; /* send buffer */
27 size_t uiBufferLenMax
; /* total length of the message */
28 size_t uiBufferLen
; /* length of data in buffer */
29 BOOL bIsChunkSize
; /* expecting a chunk size buffer */
30 wininet_rse_callback pRseCallback
; /* wininet_resolve_send_error callback. Allows clients to resolve ssl errors programatically */
31 wininet_progress_callback pProgressCallback
; /* callback to report a progress */
32 LPVOID pProgressCallbackContext
; /* context for pProgressCallback */
33 char * pRespHeaders
; /* buffer for response headers */
34 size_t uiRespHeadersLen
; /* length of data in response headers buffer */
35 size_t uiRespHeadersReaded
;/* length of data readed from response headers buffer */
36 char * pszErrorMessage
; /* wininet/system error message */
40 #define Trace(pszFunc, pBuffer, uiBufferLen) \
41 DBGLOG(TEST, SOAP_MESSAGE(fdebug, "wininet %p: %s 0x%p %d\n", soap, pszFunc, pBuffer, uiBufferLen));
43 void Trace(const char* pszFunc
, const void* pBuffer
, DWORD uiBufferLen
)
46 static bool newOne = true;
47 FILE* f = fopen("C:\\log.log", newOne ? "wt" : "at");
51 fprintf(f, "\n============================================\n%s:\n", pszFunc);
53 fwrite(pBuffer, uiBufferLen, 1, f);
60 /* forward declarations */
64 struct wininet_data
* a_pData
,
65 DWORD a_dwRequestFlags
);
69 struct soap_plugin
* a_pDst
,
70 struct soap_plugin
* a_pSrc
);
74 struct soap_plugin
* a_pPluginData
);
78 const char * a_pszEndpoint
,
79 const char * a_pszHost
,
84 const char * a_pszKey
,
85 const char * a_pszValue
);
89 const char * a_pBuffer
,
90 size_t a_uiBufferLen
);
95 size_t a_uiBufferLen
);
103 DWORD dwInternetStatus
,
104 LPVOID lpvStatusInformation
,
105 DWORD dwStatusInformationLength
);
107 wininet_have_connection(
109 struct wininet_data
* a_pData
);
112 struct soap
* soap
);
116 struct wininet_data
* a_pData
,
117 const char * a_pszTimeout
,
121 wininet_resolve_send_error(
122 HINTERNET a_hHttpRequest
,
123 DWORD a_dwErrorCode
);
125 wininet_error_message(
126 struct soap
* a_pData
,
127 DWORD a_dwErrorMsgId
);
129 wininet_free_error_message(
130 struct wininet_data
* a_pData
);
132 /* plugin registration */
136 struct soap_plugin
* a_pPluginData
,
137 void * a_dwRequestFlags
)
140 return SOAP_FATAL_ERROR
;
142 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
143 "wininet %p: plugin registration\n", soap
));
145 a_pPluginData
->id
= wininet_id
;
146 a_pPluginData
->fcopy
= wininet_copy
;
147 a_pPluginData
->fdelete
= wininet_delete
;
148 a_pPluginData
->data
= (void*) malloc( sizeof(struct wininet_data
) );
149 if ( !a_pPluginData
->data
)
153 if ( !wininet_init( soap
,
154 (struct wininet_data
*) a_pPluginData
->data
,
155 (DWORD
) (size_t) a_dwRequestFlags
) )
157 free( a_pPluginData
->data
);
162 if ( (soap
->omode
& SOAP_IO
) == SOAP_IO_STORE
)
164 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
165 "wininet %p: use of SOAP_IO_STORE is not recommended\n", soap
));
172 /* initialize private data */
176 struct wininet_data
* a_pData
,
177 DWORD a_dwRequestFlags
)
180 return SOAP_FATAL_ERROR
;
182 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
183 "wininet %p: init private data\n", soap
));
185 memset( a_pData
, 0, sizeof(struct wininet_data
) );
186 a_pData
->dwRequestFlags
= a_dwRequestFlags
;
188 Trace("InternetOpenA", 0, 0);
190 /* start our internet session */
191 a_pData
->hInternet
= InternetOpenA(
192 "gSOAP", INTERNET_OPEN_TYPE_PRECONFIG
, NULL
, NULL
, 0 );
193 if ( !a_pData
->hInternet
)
195 soap
->error
= SOAP_EOF
;
196 soap
->errnum
= GetLastError();
197 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
198 "wininet %p: init, error %d (%s) in InternetOpen\n",
199 soap
, soap
->errnum
, wininet_error_message(soap
,soap
->errnum
) ));
200 wininet_free_error_message( a_pData
);
204 /* set the timeouts, if any of these fail the error isn't fatal */
205 wininet_set_timeout( soap
, a_pData
, "connect",
206 INTERNET_OPTION_CONNECT_TIMEOUT
, soap
->connect_timeout
);
207 wininet_set_timeout( soap
, a_pData
, "receive",
208 INTERNET_OPTION_RECEIVE_TIMEOUT
, soap
->recv_timeout
);
209 wininet_set_timeout( soap
, a_pData
, "send",
210 INTERNET_OPTION_SEND_TIMEOUT
, soap
->send_timeout
);
212 /* set up the callback function so we get notifications */
213 InternetSetStatusCallback( a_pData
->hInternet
, wininet_callback
);
215 /* set all of our callbacks */
216 soap
->fopen
= wininet_connect
;
217 soap
->fposthdr
= wininet_post_header
;
218 soap
->fsend
= wininet_fsend
;
219 soap
->frecv
= wininet_frecv
;
220 soap
->fclose
= wininet_disconnect
;
221 soap
->fpoll
= wininet_fpoll
;
227 wininet_set_rse_callback(
229 wininet_rse_callback a_pRsecallback
)
231 struct wininet_data
* pData
= (struct wininet_data
*) soap_lookup_plugin( soap
, wininet_id
);
233 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
234 "wininet %p: resolve_send_error callback = '%p'\n", soap
, a_pRsecallback
));
236 pData
->pRseCallback
= a_pRsecallback
;
240 wininet_set_progress_callback(
242 wininet_progress_callback a_pProgressCallback
,
245 struct wininet_data
* pData
= (struct wininet_data
*) soap_lookup_plugin( soap
, wininet_id
);
247 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
248 "wininet %p: progress callback = '%p', context = '%p'\n", soap
, a_pProgressCallback
, a_pContext
));
250 pData
->pProgressCallback
= a_pProgressCallback
;
251 pData
->pProgressCallbackContext
= a_pContext
;
254 /* copy the private data structure */
258 struct soap_plugin
* a_pDst
,
259 struct soap_plugin
* a_pSrc
)
262 UNUSED_ARG( a_pDst
);
263 UNUSED_ARG( a_pSrc
);
265 _ASSERTE( !"wininet doesn't support copy" );
266 return SOAP_FATAL_ERROR
;
269 /* deallocate of our private structure */
273 struct soap_plugin
* a_pPluginData
)
275 struct wininet_data
* pData
=
276 (struct wininet_data
*) a_pPluginData
->data
;
280 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
281 "wininet %p: delete private data\n", soap
));
283 /* force a disconnect of any existing connection */
284 pData
->bDisconnect
= TRUE
;
285 wininet_have_connection( soap
, pData
);
287 /* close down the internet */
288 if ( pData
->hInternet
)
290 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
291 "wininet %p: closing internet handle\n", soap
));
292 InternetCloseHandle( pData
->hInternet
);
293 pData
->hInternet
= NULL
;
297 wininet_free_error_message( pData
);
298 free( a_pPluginData
->data
);
301 /* gsoap documentation:
302 Called from a client proxy to open a connection to a Web Service located
303 at endpoint. Input parameters host and port are micro-parsed from endpoint.
304 Should return a valid file descriptor, or SOAP_INVALID_SOCKET and
305 soap->error set to an error code. Built-in gSOAP function: tcp_connect
310 const char * a_pszEndpoint
,
311 const char * a_pszHost
,
314 URL_COMPONENTSA urlComponents
;
315 char szUrlPath
[MAX_PATH
] = {0};
316 char szHost
[MAX_PATH
] = {0};
318 HINTERNET hConnection
= NULL
;
319 HINTERNET hHttpRequest
= NULL
;
320 const char * pszVerb
;
322 struct wininet_data
* pData
=
323 (struct wininet_data
*) soap_lookup_plugin( soap
, wininet_id
);
325 soap
->error
= SOAP_OK
;
327 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
328 "wininet %p: connect, endpoint = '%s'\n", soap
, a_pszEndpoint
));
330 /* we should be initialized but not connected */
331 _ASSERTE( pData
->hInternet
);
332 if ( !pData
->hInternet
)
333 return SOAP_FATAL_ERROR
;
334 _ASSERTE( !pData
->bKeepAlive
&& !pData
->hConnection
|| pData
->bKeepAlive
&& pData
->hConnection
);
335 if ( !(!pData
->bKeepAlive
&& !pData
->hConnection
|| pData
->bKeepAlive
&& pData
->hConnection
) )
336 return SOAP_FATAL_ERROR
;
337 _ASSERTE( soap
->socket
== SOAP_INVALID_SOCKET
);
338 if ( soap
->socket
!= SOAP_INVALID_SOCKET
)
339 return SOAP_FATAL_ERROR
;
341 /* parse out the url path */
342 memset( &urlComponents
, 0, sizeof(urlComponents
) );
343 urlComponents
.dwStructSize
= sizeof(urlComponents
);
344 urlComponents
.lpszHostName
= szHost
;
345 urlComponents
.dwHostNameLength
= MAX_PATH
;
346 urlComponents
.lpszUrlPath
= szUrlPath
;
347 urlComponents
.dwUrlPathLength
= MAX_PATH
;
348 if ( !InternetCrackUrlA( a_pszEndpoint
, 0, 0, &urlComponents
) )
350 soap
->error
= SOAP_TCP_ERROR
;
351 soap
->errnum
= GetLastError();
352 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
353 "wininet %p: connect, error %d (%s) in InternetCrackUrl\n",
354 soap
, soap
->errnum
, wininet_error_message(soap
,soap
->errnum
) ));
355 return SOAP_INVALID_SOCKET
;
358 nPort
= urlComponents
.nPort
;
360 if ( !pData
->hConnection
)
362 Trace("InternetConnectA", szHost
, (DWORD
)strlen(szHost
));
364 /* connect to the target url, if we haven't connected yet
365 or if it was dropped */
366 hConnection
= InternetConnectA( pData
->hInternet
,
367 szHost
, nPort
, "", "", INTERNET_SERVICE_HTTP
,
368 0, (DWORD_PTR
) soap
);
371 soap
->error
= SOAP_TCP_ERROR
;
372 soap
->errnum
= GetLastError();
373 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
374 "wininet %p: connect, error %d (%s) in InternetConnect\n",
375 soap
, soap
->errnum
, wininet_error_message(soap
,soap
->errnum
) ));
376 return SOAP_INVALID_SOCKET
;
381 hConnection
= pData
->hConnection
;
382 pData
->hConnection
= NULL
;
386 Note that although we specify HTTP/1.1 for the connection here, the
387 actual connection may be HTTP/1.0 depending on the settings in the
388 control panel. See the "Internet Options", "HTTP 1.1 settings".
390 dwFlags
= pData
->dwRequestFlags
| INTERNET_FLAG_NO_CACHE_WRITE
;
391 if ( soap
->omode
& SOAP_IO_KEEPALIVE
)
393 dwFlags
|= INTERNET_FLAG_KEEP_CONNECTION
;
394 pData
->bKeepAlive
= TRUE
;
396 if ( urlComponents
.nScheme
== INTERNET_SCHEME_HTTPS
)
398 dwFlags
|= INTERNET_FLAG_SECURE
;
401 /* proxy requires full endpoint URL */
402 if ( soap
->proxy_host
)
404 strncpy(szUrlPath
, a_pszEndpoint
, MAX_PATH
);
407 /* status determines the HTTP verb */
408 switch ( soap
->status
)
421 _snprintf(szUrlPath
, MAX_PATH
, "%s:%d", a_pszHost
, a_nPort
);
427 Trace("HttpOpenRequestA", szUrlPath
, (DWORD
)strlen(szUrlPath
));
429 hHttpRequest
= HttpOpenRequestA(
430 hConnection
, pszVerb
, szUrlPath
, "HTTP/1.1", NULL
, NULL
,
431 dwFlags
, (DWORD_PTR
) soap
);
434 InternetCloseHandle( hConnection
);
435 pData
->bKeepAlive
= FALSE
;
436 soap
->error
= SOAP_HTTP_ERROR
;
437 soap
->errnum
= GetLastError();
438 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
439 "wininet %p: connect, error %d (%s) in HttpOpenRequest\n",
440 soap
, soap
->errnum
, wininet_error_message(soap
,soap
->errnum
) ));
441 wininet_free_error_message(pData
);
442 return SOAP_INVALID_SOCKET
;
445 /* save the connection handle in our data structure */
446 pData
->hConnection
= hConnection
;
448 /* return the http request handle as our file descriptor. */
449 _ASSERTE( sizeof(soap
->socket
) >= sizeof(HINTERNET
) );
450 return (SOAP_SOCKET
) hHttpRequest
;
453 /* gsoap documentation:
454 Called by http_post and http_response (through the callbacks). Emits HTTP
455 key: val header entries. Should return SOAP_OK, or a gSOAP error code.
456 Built-in gSOAP function: http_post_header.
461 const char * a_pszKey
,
462 const char * a_pszValue
)
464 HINTERNET hHttpRequest
= (HINTERNET
) soap
->socket
;
467 BOOL bResult
= FALSE
;
468 struct wininet_data
* pData
=
469 (struct wininet_data
*) soap_lookup_plugin( soap
, wininet_id
);
471 soap
->error
= SOAP_OK
;
473 /* ensure that our connection hasn't been disconnected */
474 if ( !wininet_have_connection( soap
, pData
) )
479 /* if this is the initial POST header then we initialize our send buffer */
480 if ( a_pszKey
&& !a_pszValue
)
482 _ASSERTE( !pData
->pBuffer
);
483 pData
->uiBufferLenMax
= INVALID_BUFFER_LENGTH
;
484 pData
->uiBufferLen
= 0;
486 /* if we are using chunk output then we start with a chunk size */
487 pData
->bIsChunkSize
= ( (soap
->omode
& SOAP_IO
) == SOAP_IO_CHUNK
);
489 else if ( a_pszValue
)
491 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
492 "wininet %p: post_header, adding '%s: %s'\n",
493 soap
, a_pszKey
, a_pszValue
));
495 /* determine the maximum length of this message so that we can
496 correctly determine when we have completed the send */
497 if ( !strcmp( a_pszKey
, "Content-Length" ) )
499 _ASSERTE( pData
->uiBufferLenMax
== INVALID_BUFFER_LENGTH
);
500 pData
->uiBufferLenMax
= strtoul( a_pszValue
, NULL
, 10 );
504 szHeader
, 4096, "%s: %s\r\n", a_pszKey
, a_pszValue
);
510 Trace("HttpAddRequestHeadersA", szHeader
, nLen
);
512 bResult
= HttpAddRequestHeadersA( hHttpRequest
, szHeader
, nLen
,
513 HTTP_ADDREQ_FLAG_ADD_IF_NEW
);
516 we don't return an error if this fails because it isn't
517 (or shouldn't be) critical.
521 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
522 "wininet %p: post_header, error %d (%s) in HttpAddRequestHeaders\n",
523 soap
, GetLastError(), wininet_error_message(soap
,GetLastError()) ));
530 /* gsoap documentation:
531 Called for all send operations to emit contents of s of length n.
532 Should return SOAP_OK, or a gSOAP error code. Built-in gSOAP
536 I do a heap of buffering here because we need the entire message available
537 in a single buffer in order to iterate through the sending loop. I had
538 hoped that the SOAP_IO_STORE flag would have worked to do the same, however
539 this still breaks the messages up into blocks. Although there were a number
540 of ways this could've been implemented, this works and supports all of the
541 possible SOAP_IO flags, even though the entire message is still buffered
542 the same as if SOAP_IO_STORE was used.
547 const char * a_pBuffer
,
548 size_t a_uiBufferLen
)
550 HINTERNET hHttpRequest
= (HINTERNET
) soap
->socket
;
554 DWORD dwStatusCodeLen
;
555 int nResult
= SOAP_OK
;
556 struct wininet_data
* pData
=
557 (struct wininet_data
*) soap_lookup_plugin( soap
, wininet_id
);
559 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
560 "wininet %p: fsend, data len = %lu bytes\n", soap
, a_uiBufferLen
));
562 /* allow the request to be sent with a NULL buffer */
563 if (a_uiBufferLen
== 0)
565 pData
->uiBufferLenMax
= 0;
568 /* ensure that our connection hasn't been disconnected */
569 if ( !wininet_have_connection( soap
, pData
) )
574 /* initialize on our first time through. pData->pBuffer will always be
575 non-null if this is not the first call. */
576 if ( !pData
->pBuffer
)
579 If we are using chunked sending, then we don't know how big the
580 buffer will need to be. So we start with a 0 length buffer and
581 grow it later to ensure that it is always large enough.
583 uiBufferLenMax = length of the allocated memory
584 uiBufferLen = length of the data in the buffer
586 if ( (soap
->mode
& SOAP_IO
) == SOAP_IO_CHUNK
)
588 /* we make the initial allocation large enough for this chunksize
589 buffer, plus the next chunk of actual data, and a few extra
590 bytes for the final "0" chunksize block. */
591 size_t uiChunkSize
= strtoul( a_pBuffer
, NULL
, 16 );
592 pData
->uiBufferLenMax
= uiChunkSize
+ a_uiBufferLen
+ 16;
594 else if ( a_uiBufferLen
== pData
->uiBufferLenMax
)
597 If the currently supplied buffer from gsoap holds the entire
598 message then we just use their buffer and avoid any memory
599 allocation. This will only be true when (1) we are not using
600 chunked send (so uiBufferLenMax has been previously set to
601 the Content-Length header length), and (2) gsoap is sending
602 the entire message at one time.
604 pData
->pBuffer
= (char *) a_pBuffer
;
605 pData
->uiBufferLen
= a_uiBufferLen
;
608 _ASSERTE( pData
->uiBufferLenMax
!= INVALID_BUFFER_LENGTH
);
612 If we can't use the gsoap buffer, then we need to allocate our own
613 buffer for the entire message. This is because authentication may
614 require the entire message to be sent multiple times. Since this send
615 is only a part of the message, we need to buffer until we have the
618 if ( pData
->pBuffer
!= a_pBuffer
)
621 We already have a buffer pointer, this means that it isn't the
622 first time we have been called. We have allocated a buffer and
623 are current filling it.
625 If we don't have enough room in the our buffer to add this new
626 data, then we need to reallocate. This case will only occur with
629 size_t uiNewBufferLen
= pData
->uiBufferLen
+ a_uiBufferLen
;
630 if ( !pData
->pBuffer
|| uiNewBufferLen
> pData
->uiBufferLenMax
)
632 while ( uiNewBufferLen
> pData
->uiBufferLenMax
)
634 pData
->uiBufferLenMax
= pData
->uiBufferLenMax
* 2;
636 char *pReallocatedBuffer
= (char *) realloc( pData
->pBuffer
, pData
->uiBufferLenMax
);
637 if ( !pReallocatedBuffer
)
641 pData
->pBuffer
= pReallocatedBuffer
;
643 memcpy( pData
->pBuffer
+ pData
->uiBufferLen
,
644 a_pBuffer
, a_uiBufferLen
);
645 pData
->uiBufferLen
= uiNewBufferLen
;
647 /* if we are doing chunked transfers, and this is a chunk size block,
648 and it is "0", then this is the last block in the transfer and we
649 can set the maximum size now to continue to the actual send. */
650 if ( (soap
->mode
& SOAP_IO
) == SOAP_IO_CHUNK
651 && pData
->bIsChunkSize
652 && a_pBuffer
[2] == '0' && !isalnum((unsigned char)a_pBuffer
[3]) )
654 pData
->uiBufferLenMax
= pData
->uiBufferLen
;
658 /* if we haven't got the entire length of the message yet, then
659 we return to gsoap and let it continue */
660 if ( pData
->uiBufferLen
< pData
->uiBufferLenMax
)
662 /* toggle our chunk size marker if we are chunking */
663 pData
->bIsChunkSize
=
664 ((soap
->mode
& SOAP_IO
) == SOAP_IO_CHUNK
)
665 && !pData
->bIsChunkSize
;
668 _ASSERTE( pData
->uiBufferLen
== pData
->uiBufferLenMax
);
670 /* we've now got the entire message, now we can enter our sending loop */
676 soap
->error
= SOAP_OK
;
678 /* to report a progress when sending a big buffer we need to send it by small
679 chunks since INTERNET_STATUS_REQUEST_SENT callback is sent for entire buffer */
680 const DWORD dwChunkSize
= 64 * 1024;
681 if ( pData
->pProgressCallback
&& (DWORD
)pData
->uiBufferLen
> dwChunkSize
)
683 INTERNET_BUFFERSA buffer
;
684 memset(&buffer
, 0, sizeof(buffer
));
685 buffer
.dwStructSize
= sizeof(buffer
);
686 buffer
.lpvBuffer
= pData
->pBuffer
;
687 buffer
.dwBufferLength
= min((DWORD
)pData
->uiBufferLen
, dwChunkSize
);
688 buffer
.dwBufferTotal
= (DWORD
)pData
->uiBufferLen
;
689 Trace("HttpSendRequestExA", pData
->pBuffer
, buffer
.dwBufferLength
);
690 bResult
= HttpSendRequestExA( hHttpRequest
, &buffer
, NULL
, 0, 0 );
691 while ( bResult
&& buffer
.dwBufferLength
< buffer
.dwBufferTotal
)
693 DWORD bytesWritten
= min(buffer
.dwBufferTotal
- buffer
.dwBufferLength
, dwChunkSize
);
694 Trace("InternetWriteFile", pData
->pBuffer
+ buffer
.dwBufferLength
, bytesWritten
);
695 bResult
= InternetWriteFile( hHttpRequest
, pData
->pBuffer
+ buffer
.dwBufferLength
, bytesWritten
, &bytesWritten
);
696 buffer
.dwBufferLength
+= bytesWritten
;
700 bResult
= HttpEndRequestA( hHttpRequest
, NULL
, 0, 0 );
705 Trace("HttpSendRequestA", pData
->pBuffer
, (DWORD
)pData
->uiBufferLen
);
707 bResult
= HttpSendRequestA(
708 hHttpRequest
, NULL
, 0, pData
->pBuffer
, (DWORD
)pData
->uiBufferLen
);
712 soap
->error
= SOAP_EOF
;
713 soap
->errnum
= GetLastError();
714 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
715 "wininet %p: fsend, error %d (%s) in HttpSendRequest\n",
716 soap
, soap
->errnum
, wininet_error_message(soap
,soap
->errnum
) ));
718 /* see if we can handle this error, see the MSDN documentation
719 for InternetErrorDlg for details */
720 switch ( soap
->errnum
)
722 case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR
:
723 case ERROR_INTERNET_HTTPS_TO_HTTP_ON_REDIR
:
724 case ERROR_INTERNET_INCORRECT_PASSWORD
:
725 case ERROR_INTERNET_INVALID_CA
:
726 case ERROR_INTERNET_POST_IS_NON_SECURE
:
727 case ERROR_INTERNET_SEC_CERT_CN_INVALID
:
728 case ERROR_INTERNET_SEC_CERT_DATE_INVALID
:
729 case ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED
:
731 wininet_rseReturn errorResolved
= rseDisplayDlg
;
732 if (pData
->pRseCallback
)
734 errorResolved
= pData
->pRseCallback(hHttpRequest
, soap
->errnum
);
736 if (errorResolved
== rseDisplayDlg
)
738 errorResolved
= (wininet_rseReturn
)
739 wininet_resolve_send_error( hHttpRequest
, soap
->errnum
);
740 if ( errorResolved
== rseTrue
)
742 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
743 "wininet %p: fsend, error %d has been resolved\n",
744 soap
, soap
->errnum
));
748 we would have been disconnected by the error. Since we
749 are going to try again, we will automatically be
750 reconnected. Therefore we want to disregard any
751 previous disconnection messages.
753 pData
->bDisconnect
= FALSE
;
761 /* if the error wasn't handled then we exit */
762 switch ( soap
->errnum
)
764 case ERROR_INTERNET_NAME_NOT_RESOLVED
:
765 case ERROR_INTERNET_CANNOT_CONNECT
:
766 nResult
= SOAP_TCP_ERROR
;
769 nResult
= SOAP_HTTP_ERROR
;
772 soap_set_sender_error(soap
, "HttpSendRequest failed", wininet_error_message(soap
,soap
->errnum
), nResult
);
776 /* get the status code from the response to determine if we need
778 dwStatusCodeLen
= sizeof(dwStatusCode
);
779 Trace("HttpQueryInfo - wininet_fsend", 0, 0);
780 bResult
= HttpQueryInfo(
781 hHttpRequest
, HTTP_QUERY_STATUS_CODE
| HTTP_QUERY_FLAG_NUMBER
,
782 &dwStatusCode
, &dwStatusCodeLen
, NULL
);
784 char buf
[1024];dwStatusCodeLen
= sizeof(buf
);
785 bResult
= HttpQueryInfo(
786 hHttpRequest
, HTTP_QUERY_STATUS_TEXT
,
787 buf
, &dwStatusCodeLen
, NULL
);
791 soap
->error
= SOAP_EOF
;
792 soap
->errnum
= GetLastError();
793 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
794 "wininet %p: fsend, error %d (%s) in HttpQueryInfo\n",
795 soap
, soap
->errnum
, wininet_error_message(soap
,soap
->errnum
) ));
796 nResult
= SOAP_HTTP_ERROR
;
800 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
801 "wininet %p: fsend, HTTP status code = %lu\n",
802 soap
, dwStatusCode
));
805 if we need authentication, then request the user for the
806 appropriate data. Their reply is saved into the request so
807 that we can use it later.
809 switch ( dwStatusCode
)
811 case HTTP_STATUS_DENIED
:
812 case HTTP_STATUS_PROXY_AUTH_REQ
:
814 wininet_rseReturn errorResolved
= rseDisplayDlg
;
815 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
816 "wininet %p: fsend, user authenication required\n",
818 if (pData
->pRseCallback
)
820 errorResolved
= pData
->pRseCallback(hHttpRequest
, dwStatusCode
);
822 if (errorResolved
== rseDisplayDlg
)
824 errorResolved
= (wininet_rseReturn
)
825 wininet_resolve_send_error( hHttpRequest
, ERROR_INTERNET_INCORRECT_PASSWORD
);
827 if ( errorResolved
== rseTrue
)
829 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
830 "wininet %p: fsend, authentication has been provided\n",
834 we may have been disconnected by the error. Since we
835 are going to try again, we will automatically be
836 reconnected. Therefore we want to disregard any previous
837 disconnection messages.
839 pData
->bDisconnect
= FALSE
;
848 /* if we have an allocated buffer then we can deallocate it now */
849 if ( pData
->pBuffer
!= a_pBuffer
)
851 free( pData
->pBuffer
);
855 pData
->uiBufferLen
= 0;
856 pData
->uiBufferLenMax
= INVALID_BUFFER_LENGTH
;
858 pData
->pRespHeaders
= 0;
863 /* gsoap documentation:
864 Called for all receive operations to fill buffer s of maximum length n.
865 Should return the number of bytes read or 0 in case of an error, e.g. EOF.
866 Built-in gSOAP function: frecv
872 size_t a_uiBufferLen
)
874 HINTERNET hHttpRequest
= (HINTERNET
) soap
->socket
;
875 DWORD dwBytesRead
= 0;
876 size_t uiTotalBytesRead
= 0;
879 struct wininet_data
* pData
=
880 (struct wininet_data
*) soap_lookup_plugin( soap
, wininet_id
);
882 if (!pData
->pRespHeaders
)
887 // This call will fail on the first pass, because no buffer is allocated.
888 if (!HttpQueryInfo(hHttpRequest
, HTTP_QUERY_RAW_HEADERS_CRLF
,
889 (LPVOID
)pData
->pRespHeaders
, &size
, NULL
))
891 // Check for an insufficient buffer.
892 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
894 // Allocate the necessary buffer.
895 pData
->pRespHeaders
= (char*) malloc(size
);
902 pData
->pRespHeaders
= (char*) malloc(0);
903 pData
->uiRespHeadersLen
= 0;
904 pData
->uiRespHeadersReaded
= 0;
905 Trace("HttpQueryInfo - no headers", 0, 0);
910 pData
->uiRespHeadersLen
= size
;
911 pData
->uiRespHeadersReaded
= 0;
912 Trace("HttpQueryInfo - reading headers", pData
->pRespHeaders
, static_cast<DWORD
>(pData
->uiRespHeadersLen
));
916 if (pData
->pRespHeaders
&& pData
->uiRespHeadersReaded
< pData
->uiRespHeadersLen
)
918 size_t notReceivedPart
= pData
->uiRespHeadersLen
- pData
->uiRespHeadersReaded
;
919 size_t recvSize
= min(a_uiBufferLen
, notReceivedPart
);
921 memcpy(a_pBuffer
, pData
->pRespHeaders
+ pData
->uiRespHeadersReaded
, recvSize
);
922 pData
->uiRespHeadersReaded
+= recvSize
;
923 if (a_uiBufferLen
== recvSize
)
924 return a_uiBufferLen
;
925 uiTotalBytesRead
= recvSize
;
928 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
929 "wininet %p: frecv, available buffer len = %lu\n",
930 soap
, a_uiBufferLen
));
933 NOTE: we do not check here that our connection hasn't been
934 disconnected because in HTTP/1.0 connections, it will always have been
935 disconnected by now. This is because the response is checked by the
936 wininet_fsend function to ensure that we didn't need any special
937 authentication. At that time the connection would have been
938 disconnected. This is okay however as we can still read the response
939 from the request handle.
944 /* read from the connection up to our maximum amount of data */
945 _ASSERTE( a_uiBufferLen
<= ULONG_MAX
);
946 bResult
= InternetReadFile(
948 &a_pBuffer
[uiTotalBytesRead
],
949 static_cast<DWORD
>(a_uiBufferLen
- uiTotalBytesRead
),
951 Trace("InternetReadFile", &a_pBuffer
[uiTotalBytesRead
], dwBytesRead
);
954 uiTotalBytesRead
+= dwBytesRead
;
955 if ( dwBytesRead
== 0 )
957 if (pData
->pRespHeaders
)
959 free(pData
->pRespHeaders
);
960 pData
->pRespHeaders
= 0;
962 pData
->bDisconnect
= TRUE
;
967 soap
->errnum
= GetLastError();
968 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
969 "wininet %p: frecv, error %d (%s) in InternetReadFile\n",
970 soap
, soap
->errnum
, wininet_error_message(soap
,soap
->errnum
) ));
971 soap_set_sender_error(soap
, "InternetReadFile failed", wininet_error_message(soap
,soap
->errnum
), SOAP_HTTP_ERROR
);
974 while ( bResult
&& dwBytesRead
&& uiTotalBytesRead
< a_uiBufferLen
);
976 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
977 "wininet %p: recv, received %lu bytes\n", soap
, uiTotalBytesRead
));
979 return uiTotalBytesRead
;
982 /* gsoap documentation:
983 Called by client proxy multiple times, to close a socket connection before
984 a new socket connection is established and at the end of communications
985 when the SOAP_IO_KEEPALIVE flag is not set and soap.keep_alive = 0
986 (indicating that the other party supports keep alive). Should return
987 SOAP_OK, or a gSOAP error code. Built-in gSOAP function: tcp_disconnect
993 struct wininet_data
* pData
=
994 (struct wininet_data
*) soap_lookup_plugin( soap
, wininet_id
);
996 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
, "wininet %p: disconnect\n", soap
));
998 /* force a disconnect by setting the disconnect flag to TRUE */
999 pData
->bDisconnect
= TRUE
;
1000 pData
->bKeepAlive
= FALSE
;
1001 wininet_have_connection( soap
, pData
);
1003 return soap
->error
= SOAP_OK
;
1006 /* this is mostly for debug tracing */
1009 HINTERNET hInternet
,
1010 DWORD_PTR dwContext
,
1011 DWORD dwInternetStatus
,
1012 LPVOID lpvStatusInformation
,
1013 DWORD dwStatusInformationLength
)
1015 struct soap
* soap
= (struct soap
*) dwContext
;
1017 UNUSED_ARG( hInternet
);
1018 UNUSED_ARG( lpvStatusInformation
);
1019 UNUSED_ARG( dwStatusInformationLength
);
1021 switch ( dwInternetStatus
)
1023 case INTERNET_STATUS_RESOLVING_NAME
:
1024 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1025 "wininet %p: INTERNET_STATUS_RESOLVING_NAME\n", soap
));
1027 case INTERNET_STATUS_NAME_RESOLVED
:
1028 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1029 "wininet %p: INTERNET_STATUS_NAME_RESOLVED\n", soap
));
1031 case INTERNET_STATUS_CONNECTING_TO_SERVER
:
1032 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1033 "wininet %p: INTERNET_STATUS_CONNECTING_TO_SERVER\n", soap
));
1035 case INTERNET_STATUS_CONNECTED_TO_SERVER
:
1036 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1037 "wininet %p: INTERNET_STATUS_CONNECTED_TO_SERVER\n", soap
));
1039 case INTERNET_STATUS_SENDING_REQUEST
:
1040 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1041 "wininet %p: INTERNET_STATUS_SENDING_REQUEST\n", soap
));
1043 case INTERNET_STATUS_REQUEST_SENT
:
1045 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1046 "wininet %p: INTERNET_STATUS_REQUEST_SENT, bytes sent = %lu\n",
1047 soap
, *(DWORD
*)lpvStatusInformation
));
1048 struct wininet_data
* pData
=
1049 (struct wininet_data
*) soap_lookup_plugin( soap
, wininet_id
);
1050 if ( pData
->pProgressCallback
)
1052 pData
->pProgressCallback( TRUE
, *(DWORD
*)lpvStatusInformation
, pData
->pProgressCallbackContext
);
1056 case INTERNET_STATUS_RECEIVING_RESPONSE
:
1057 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1058 "wininet %p: INTERNET_STATUS_RECEIVING_RESPONSE\n", soap
));
1060 case INTERNET_STATUS_RESPONSE_RECEIVED
:
1062 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1063 "wininet %p: INTERNET_STATUS_RESPONSE_RECEIVED, bytes received = %lu\n",
1064 soap
, *(DWORD
*)lpvStatusInformation
));
1065 struct wininet_data
* pData
=
1066 (struct wininet_data
*) soap_lookup_plugin( soap
, wininet_id
);
1067 if ( pData
->pProgressCallback
)
1069 pData
->pProgressCallback( FALSE
, *(DWORD
*)lpvStatusInformation
, pData
->pProgressCallbackContext
);
1073 case INTERNET_STATUS_CTL_RESPONSE_RECEIVED
:
1074 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1075 "wininet %p: INTERNET_STATUS_CTL_RESPONSE_RECEIVED\n", soap
));
1077 case INTERNET_STATUS_PREFETCH
:
1078 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1079 "wininet %p: INTERNET_STATUS_PREFETCH\n", soap
));
1081 case INTERNET_STATUS_CLOSING_CONNECTION
:
1082 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1083 "wininet %p: INTERNET_STATUS_CLOSING_CONNECTION\n", soap
));
1085 case INTERNET_STATUS_CONNECTION_CLOSED
:
1086 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1087 "wininet %p: INTERNET_STATUS_CONNECTION_CLOSED\n", soap
));
1089 /* the connection has been closed, so we close the handle here */
1090 struct wininet_data
* pData
=
1091 (struct wininet_data
*) soap_lookup_plugin( soap
, wininet_id
);
1092 if ( pData
->hConnection
)
1095 we only mark this for disconnection otherwise we get
1096 errors when reading the data from the handle. In every
1097 function that we use the connection we will check first to
1098 see if it has been disconnected.
1100 pData
->bDisconnect
= TRUE
;
1104 case INTERNET_STATUS_HANDLE_CREATED
:
1105 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1106 "wininet %p: INTERNET_STATUS_HANDLE_CREATED\n", soap
));
1108 case INTERNET_STATUS_HANDLE_CLOSING
:
1109 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1110 "wininet %p: INTERNET_STATUS_HANDLE_CLOSING\n", soap
));
1112 #ifdef INTERNET_STATUS_DETECTING_PROXY
1113 case INTERNET_STATUS_DETECTING_PROXY
:
1114 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1115 "wininet %p: INTERNET_STATUS_DETECTING_PROXY\n", soap
));
1118 case INTERNET_STATUS_REQUEST_COMPLETE
:
1119 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1120 "wininet %p: INTERNET_STATUS_REQUEST_COMPLETE\n", soap
));
1122 case INTERNET_STATUS_REDIRECT
:
1123 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1124 "wininet %p: INTERNET_STATUS_REDIRECT, new url = %s\n",
1125 soap
, (char*) lpvStatusInformation
));
1127 case INTERNET_STATUS_INTERMEDIATE_RESPONSE
:
1128 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1129 "wininet %p: INTERNET_STATUS_INTERMEDIATE_RESPONSE\n", soap
));
1131 #ifdef INTERNET_STATUS_USER_INPUT_REQUIRED
1132 case INTERNET_STATUS_USER_INPUT_REQUIRED
:
1133 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1134 "wininet %p: INTERNET_STATUS_USER_INPUT_REQUIRED\n", soap
));
1137 case INTERNET_STATUS_STATE_CHANGE
:
1138 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1139 "wininet %p: INTERNET_STATUS_STATE_CHANGE\n", soap
));
1141 #ifdef INTERNET_STATUS_COOKIE_SENT
1142 case INTERNET_STATUS_COOKIE_SENT
:
1143 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1144 "wininet %p: INTERNET_STATUS_COOKIE_SENT\n", soap
));
1147 #ifdef INTERNET_STATUS_COOKIE_RECEIVED
1148 case INTERNET_STATUS_COOKIE_RECEIVED
:
1149 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1150 "wininet %p: INTERNET_STATUS_COOKIE_RECEIVED\n", soap
));
1153 #ifdef INTERNET_STATUS_PRIVACY_IMPACTED
1154 case INTERNET_STATUS_PRIVACY_IMPACTED
:
1155 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1156 "wininet %p: INTERNET_STATUS_PRIVACY_IMPACTED\n", soap
));
1159 #ifdef INTERNET_STATUS_P3P_HEADER
1160 case INTERNET_STATUS_P3P_HEADER
:
1161 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1162 "wininet %p: INTERNET_STATUS_P3P_HEADER\n", soap
));
1165 #ifdef INTERNET_STATUS_P3P_POLICYREF
1166 case INTERNET_STATUS_P3P_POLICYREF
:
1167 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1168 "wininet %p: INTERNET_STATUS_P3P_POLICYREF\n", soap
));
1171 #ifdef INTERNET_STATUS_COOKIE_HISTORY
1172 case INTERNET_STATUS_COOKIE_HISTORY
:
1173 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1174 "wininet %p: INTERNET_STATUS_COOKIE_HISTORY\n", soap
));
1181 check to ensure that our connection hasn't been disconnected
1182 and disconnect remaining handles if necessary.
1185 wininet_have_connection(
1187 struct wininet_data
* a_pData
)
1189 /* close the http request if we don't have a connection */
1190 BOOL bCloseRequest
= a_pData
->bDisconnect
|| !a_pData
->hConnection
;
1191 if ( bCloseRequest
&& soap
->socket
!= SOAP_INVALID_SOCKET
)
1193 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1194 "wininet %p: closing request\n", soap
));
1196 Trace("InternetCloseHandle (closing request)", 0, 0);
1197 InternetCloseHandle( (HINTERNET
) soap
->socket
);
1198 soap
->socket
= SOAP_INVALID_SOCKET
;
1201 if ( a_pData
->bKeepAlive
)
1204 HINTERNET hHttpRequest
= NULL
;
1205 dwFlags
= a_pData
->dwRequestFlags
| INTERNET_FLAG_NO_CACHE_WRITE
;
1206 if ( soap
->omode
& SOAP_IO_KEEPALIVE
)
1208 dwFlags
|= INTERNET_FLAG_KEEP_CONNECTION
;
1209 a_pData
->bKeepAlive
= TRUE
;
1211 /*if ( urlComponents.nScheme == INTERNET_SCHEME_HTTPS )
1213 dwFlags |= INTERNET_FLAG_SECURE;
1216 hHttpRequest
= HttpOpenRequestA(
1217 a_pData
->hConnection
, "POST", "/MyWebService/Service.asmx"/*szUrlPath*/, "HTTP/1.1", NULL
, NULL
,
1218 dwFlags
, (DWORD_PTR
) soap
);
1220 soap
->socket
= (SOAP_SOCKET
) hHttpRequest
;
1222 a_pData
->bKeepAlive
= FALSE
;
1227 /* close the connection if we don't have a request */
1228 if ( soap
->socket
== SOAP_INVALID_SOCKET
&& a_pData
->hConnection
&& !a_pData
->bKeepAlive
)
1230 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1231 "wininet %p: closing connection\n", soap
));
1233 Trace("InternetCloseHandle (closing connection)", 0, 0);
1234 InternetCloseHandle( a_pData
->hConnection
);
1235 a_pData
->hConnection
= NULL
;
1237 a_pData
->bDisconnect
= FALSE
;
1239 /* clean up the send details if we don't have a request */
1240 if ( soap
->socket
== SOAP_INVALID_SOCKET
)
1242 if ( a_pData
->pBuffer
)
1244 free( a_pData
->pBuffer
);
1245 a_pData
->pBuffer
= 0;
1247 a_pData
->uiBufferLen
= 0;
1248 a_pData
->uiBufferLenMax
= INVALID_BUFFER_LENGTH
;
1251 return (soap
->socket
!= SOAP_INVALID_SOCKET
);
1258 struct wininet_data
* pData
=
1259 (struct wininet_data
*) soap_lookup_plugin( soap
, wininet_id
);
1260 return wininet_have_connection(soap
, pData
) ? SOAP_OK
: SOAP_EOF
;
1264 wininet_set_timeout(
1266 struct wininet_data
* a_pData
,
1267 const char * a_pszTimeout
,
1272 UNUSED_ARG( a_pszTimeout
);
1274 if ( a_nTimeout
> 0 )
1276 DWORD dwTimeout
= a_nTimeout
* 1000;
1277 if ( !InternetSetOption( a_pData
->hInternet
,
1278 a_dwOption
, &dwTimeout
, sizeof(DWORD
) ) )
1280 DWORD dwErrorCode
= GetLastError();
1281 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1282 "wininet %p: failed to set %s timeout, error %d (%s)\n",
1283 soap
, a_pszTimeout
, dwErrorCode
,
1284 wininet_error_message(soap
,dwErrorCode
) ));
1293 wininet_flag_set_option(
1294 HINTERNET a_hHttpRequest
,
1299 DWORD dwBufferLength
= sizeof(DWORD
);
1301 BOOL bSuccess
= InternetQueryOption(
1307 dwBuffer
|= a_dwFlag
;
1308 bSuccess
= InternetSetOption(
1316 DWORD dwErrorCode
= GetLastError();
1317 DBGLOG(TEST
, SOAP_MESSAGE(fdebug
,
1318 "wininet %p: failed to set option: %X, error %d (%s)\n",
1319 a_hHttpRequest
, a_dwOption
, dwErrorCode
,
1320 wininet_error_message(soap
,dwErrorCode
) ));
1328 wininet_resolve_send_error(
1329 HINTERNET a_hHttpRequest
,
1330 DWORD a_dwErrorCode
)
1332 DWORD dwResult
= InternetErrorDlg(
1336 FLAGS_ERROR_UI_FILTER_FOR_ERRORS
|
1337 FLAGS_ERROR_UI_FLAGS_GENERATE_DATA
|
1338 FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS
,
1340 BOOL bRetVal
= (a_dwErrorCode
== ERROR_INTERNET_INCORRECT_PASSWORD
) ?
1341 (dwResult
== ERROR_INTERNET_FORCE_RETRY
) :
1342 (dwResult
== ERROR_SUCCESS
);
1343 /* If appropriate for your application, it is possible to ignore
1344 errors in future once they have been handled or ignored once.
1345 For example, to ignore invalid SSL certificate dates on this
1346 connection once the client has indicated to ignore them this
1347 time, uncomment this code.
1352 switch (a_dwErrorCode)
1354 case ERROR_INTERNET_SEC_CERT_CN_INVALID:
1355 wininet_flag_set_option(a_hHttpRequest,
1356 INTERNET_OPTION_SECURITY_FLAGS,
1357 SECURITY_FLAG_IGNORE_CERT_CN_INVALID );
1367 wininet_error_message(
1369 DWORD a_dwErrorMsgId
)
1373 DWORD dwFormatFlags
;
1374 struct wininet_data
* pData
=
1375 (struct wininet_data
*) soap_lookup_plugin( soap
, wininet_id
);
1377 /* free any existing error message */
1378 wininet_free_error_message( pData
);
1381 FORMAT_MESSAGE_ALLOCATE_BUFFER
|
1382 FORMAT_MESSAGE_IGNORE_INSERTS
|
1383 FORMAT_MESSAGE_FROM_SYSTEM
;
1385 /* load wininet.dll for the error messages */
1386 hModule
= LoadLibraryExA( "wininet.dll", NULL
,
1387 LOAD_LIBRARY_AS_DATAFILE
| DONT_RESOLVE_DLL_REFERENCES
);
1390 dwFormatFlags
|= FORMAT_MESSAGE_FROM_HMODULE
;
1393 /* format the messages */
1394 wchar_t* pszErrorMessage
= NULL
;
1395 dwResult
= FormatMessageW(
1399 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
1400 (LPWSTR
) &pszErrorMessage
,
1404 /* remove the CR LF from the error message and convert to proper char set */
1408 pszErrorMessage
[dwResult
] = 0;
1410 wchar_t* pszExtendedErrorMessage
= (wchar_t*)_alloca(dwResult
+ 100);
1411 swprintf(pszExtendedErrorMessage
, L
"WinInet %d, %ls", a_dwErrorMsgId
, pszErrorMessage
);
1413 UINT newCodePage
= CP_UTF8
; // TODO: May be it should use SOAP_C_UTFSTRING or SOAP_C_MBSTRING?
1414 int len
= WideCharToMultiByte(newCodePage
, 0, pszExtendedErrorMessage
, -1, NULL
, 0, NULL
, NULL
);
1417 pData
->pszErrorMessage
= new char[len
];
1418 WideCharToMultiByte(newCodePage
, 0, pszExtendedErrorMessage
, -1, pData
->pszErrorMessage
, len
, NULL
, NULL
);
1422 pData
->pszErrorMessage
= NULL
;
1424 LocalFree( pszErrorMessage
);
1428 pData
->pszErrorMessage
= NULL
;
1431 /* free the library if we loaded it */
1434 FreeLibrary( hModule
);
1437 if ( pData
->pszErrorMessage
)
1439 return pData
->pszErrorMessage
;
1443 const static char szUnknown
[] = "(unknown)";
1449 wininet_free_error_message(
1450 struct wininet_data
* a_pData
)
1452 if ( a_pData
->pszErrorMessage
)
1454 delete[] a_pData
->pszErrorMessage
;
1455 a_pData
->pszErrorMessage
= 0;