1 /*=============================================================================
2 xmlrpc_wininet_transport
3 ===============================================================================
4 WinInet-based client transport for Xmlrpc-c. Copyright information at
5 the bottom of this file.
7 Changelog (changes by Steven A. Bone - sbone@pobox.com unless otherwise noted):
8 05.01.01 - Significant refactoring of the transport layer due to internal
9 changes of the xmlrpc-c transports. Modeled after the CURL
10 based transport changes by Bryan Henderson.
11 05.02.03 - Fixed Authorization header - thanks yamer.
12 05.03.20 - Supports xmlrpc_xportparms, xmlrpc_wininet_xportparms added
13 *potential breaking change* - now by default we fail on invalid
14 SSL certs, use the xmlrpc_wininet_xportparms option to enable old
17 =============================================================================*/
24 #include "xmlrpc_config.h"
27 #include "mallocvar.h"
29 #include "casprintf.h"
31 #include "xmlrpc-c/base.h"
32 #include "xmlrpc-c/base_int.h"
33 #include "xmlrpc-c/client.h"
34 #include "xmlrpc-c/client_int.h"
41 #if defined (WIN32) && defined(_DEBUG)
43 # define new DEBUG_NEW
44 # define malloc(size) _malloc_dbg( size, _NORMAL_BLOCK, __FILE__, __LINE__)
46 static char THIS_FILE[] = __FILE__;
47 #endif /*WIN32 && _DEBUG*/
50 static HINTERNET hSyncInternetSession = NULL;
52 /* Declare WinInet status callback. */
53 void CALLBACK statusCallback (HINTERNET hInternet,
54 unsigned long dwContext,
55 unsigned long dwInternetStatus,
56 void * lpvStatusInformation,
57 unsigned long dwStatusInformationLength);
60 struct xmlrpc_client_transport {
61 pthread_mutex_t listLock;
62 struct list_head rpcList;
63 /* List of all RPCs that exist for this transport. An RPC exists
64 from the time the user requests it until the time the user
65 acknowledges it is done.
67 int allowInvalidSSLCerts;
68 /* Flag to specify if we ignore invalid SSL Certificates. If this
69 is set to zero, calling a XMLRPC server with an invalid SSL
70 certificate will fail. This is the default behavior of the other
71 transports, but invalid certificates were allowed in pre 1.2
72 wininet xmlrpc-c transports.
77 unsigned long http_status;
78 HINTERNET hHttpRequest;
86 xmlrpc_mem_block *pResponseData;
90 struct list_head link; /* link in transport's list of RPCs */
91 winInetTransaction * winInetTransactionP;
92 /* The object which does the HTTP transaction, with no knowledge
93 of XML-RPC or Xmlrpc-c.
95 xmlrpc_mem_block * responseXmlP;
96 xmlrpc_bool threadExists;
98 xmlrpc_transport_asynch_complete complete;
99 /* Routine to call to complete the RPC after it is complete HTTP-wise.
102 struct xmlrpc_call_info * callInfoP;
103 /* User's identifier for this RPC */
104 struct xmlrpc_client_transport * clientTransportP;
108 createWinInetHeaderList( xmlrpc_env * const envP,
109 const xmlrpc_server_info * const serverP,
110 char ** const headerListP) {
112 char *szHeaderList = NULL;
113 char *szContentType = "Content-Type: text/xml\r\n";
115 /* Send an authorization header if we need one. */
116 if (serverP->_http_basic_auth) {
117 /* Make the header with content type and authorization */
118 /* NOTE: A newline is required between each added header */
119 szHeaderList = malloc(strlen(szContentType) + 17 + strlen(serverP->_http_basic_auth) + 1 );
121 if (szHeaderList == NULL)
122 xmlrpc_env_set_fault_formatted(
123 envP, XMLRPC_INTERNAL_ERROR,
124 "Couldn't allocate memory for authorization header");
126 memcpy(szHeaderList,szContentType, strlen(szContentType));
127 memcpy(szHeaderList + strlen(szContentType),"\r\nAuthorization: ", 17);
128 memcpy(szHeaderList + strlen(szContentType) + 17, serverP->_http_basic_auth,
129 strlen(serverP->_http_basic_auth) + 1);
134 /* Just the content type header is needed */
135 szHeaderList = malloc(strlen(szContentType) + 1);
137 if (szHeaderList == NULL)
138 xmlrpc_env_set_fault_formatted(
139 envP, XMLRPC_INTERNAL_ERROR, "Couldn't allocate memory for standard header");
141 memcpy(szHeaderList,szContentType, strlen(szContentType)+1);
144 *headerListP = szHeaderList;
148 createWinInetTransaction(xmlrpc_env * const envP,
149 const xmlrpc_server_info * const serverP,
150 xmlrpc_mem_block * const callXmlP,
151 xmlrpc_mem_block * const responseXmlP,
152 winInetTransaction ** const winInetTransactionPP) {
154 winInetTransaction * winInetTransactionP;
156 MALLOCVAR(winInetTransactionP);
157 if (winInetTransactionP == NULL)
158 xmlrpc_env_set_fault_formatted(
159 envP, XMLRPC_INTERNAL_ERROR,
160 "No memory to create WinInet transaction.");
162 char szExtraInfo[255];
166 /* Init to defaults */
167 winInetTransactionP->http_status = 0;
168 winInetTransactionP->hHttpRequest = NULL;
169 winInetTransactionP->hURL = NULL;
170 winInetTransactionP->headerList=NULL;
171 winInetTransactionP->pSendData=NULL;
172 winInetTransactionP->pResponseData=responseXmlP;
174 /* Parse the URL and store results into the winInetTransaction struct */
175 memset (&uc, 0, sizeof (uc));
176 uc.dwStructSize = sizeof (uc);
177 uc.lpszScheme = szScheme;
178 uc.dwSchemeLength = 100;
179 uc.lpszHostName = winInetTransactionP->szHostName;
180 uc.dwHostNameLength = 255;
181 uc.lpszUrlPath = winInetTransactionP->szUrlPath;
182 uc.dwUrlPathLength = 255;
183 uc.lpszExtraInfo = szExtraInfo;
184 uc.dwExtraInfoLength = 255;
185 if (InternetCrackUrl (serverP->_server_url, strlen (serverP->_server_url), ICU_ESCAPE, &uc) == FALSE)
187 xmlrpc_env_set_fault_formatted( envP, XMLRPC_INTERNAL_ERROR,
188 "Unable to parse the server URL.");
192 winInetTransactionP->nPort = (uc.nPort) ? uc.nPort : INTERNET_DEFAULT_HTTP_PORT;
193 if (_strnicmp (uc.lpszScheme, "https", 5) == 0)
194 winInetTransactionP->bUseSSL=TRUE;
196 winInetTransactionP->bUseSSL=FALSE;
197 createWinInetHeaderList(envP, serverP, &winInetTransactionP->headerList);
199 XMLRPC_MEMBLOCK_APPEND(char, envP, callXmlP, "\0", 1);
200 if (!envP->fault_occurred) {
201 winInetTransactionP->pSendData = XMLRPC_MEMBLOCK_CONTENTS(char, callXmlP);
206 if (envP->fault_occurred)
207 free(winInetTransactionP);
209 *winInetTransactionPP = winInetTransactionP;
215 destroyWinInetTransaction(winInetTransaction * const winInetTransactionP) {
217 XMLRPC_ASSERT_PTR_OK(winInetTransactionP);
219 if (winInetTransactionP->hHttpRequest)
220 InternetCloseHandle (winInetTransactionP->hHttpRequest);
222 if (winInetTransactionP->hURL)
223 InternetCloseHandle (winInetTransactionP->hURL);
225 if (winInetTransactionP->headerList)
226 free(winInetTransactionP->headerList);
228 free(winInetTransactionP);
231 static void get_wininet_response ( xmlrpc_env * const envP,
232 winInetTransaction * const winInetTransactionP)
234 INTERNET_BUFFERS inetBuffer;
236 PVOID pMsgMem = NULL;
237 unsigned long dwFlags;
238 unsigned long dwErr = 0;
239 unsigned long nExpected = 0;
240 unsigned long dwLen = sizeof (unsigned long);
244 inetBuffer.dwStructSize = sizeof (INTERNET_BUFFERS);
245 inetBuffer.Next = NULL;
246 inetBuffer.lpcszHeader = NULL;
247 inetBuffer.dwHeadersTotal = inetBuffer.dwHeadersLength = 0;
248 inetBuffer.dwOffsetHigh = inetBuffer.dwOffsetLow = 0;
249 inetBuffer.dwBufferLength = 0;
251 bOK = HttpQueryInfo (winInetTransactionP->hHttpRequest,
252 HTTP_QUERY_CONTENT_LENGTH|HTTP_QUERY_FLAG_NUMBER,
253 &inetBuffer.dwBufferTotal, &dwLen, NULL);
256 dwErr = GetLastError ();
257 FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
258 FORMAT_MESSAGE_FROM_SYSTEM,
261 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
265 pMsg = (pMsgMem) ? (LPTSTR)(pMsgMem) : "Sync HttpQueryInfo failed.";
266 XMLRPC_FAIL (envP, XMLRPC_NETWORK_ERROR, pMsg);
269 if (inetBuffer.dwBufferTotal == 0)
270 XMLRPC_FAIL (envP, XMLRPC_NETWORK_ERROR, "WinInet returned no data");
272 body = inetBuffer.lpvBuffer = calloc (inetBuffer.dwBufferTotal, sizeof (TCHAR));
274 inetBuffer.dwBufferLength = nExpected = inetBuffer.dwBufferTotal;
275 InternetQueryDataAvailable (winInetTransactionP->hHttpRequest, &inetBuffer.dwBufferLength, 0, 0);
277 /* Read Response from InternetFile */
280 if (inetBuffer.dwBufferLength != 0)
281 bOK = InternetReadFileEx (winInetTransactionP->hHttpRequest, &inetBuffer, dwFlags, 1);
284 dwErr = GetLastError ();
288 if (dwErr == WSAEWOULDBLOCK || dwErr == ERROR_IO_PENDING)
290 /* Non-block socket operation wait 10 msecs */
292 /* Reset dwErr to zero for next pass */
297 FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
298 FORMAT_MESSAGE_FROM_SYSTEM,
301 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
304 pMsg = (pMsgMem) ? (LPTSTR)(pMsgMem) : "ASync InternetReadFileEx failed.";
305 XMLRPC_FAIL (envP, XMLRPC_NETWORK_ERROR, pMsg);
309 if (inetBuffer.dwBufferLength)
311 TCHAR * bufptr = inetBuffer.lpvBuffer;
312 bufptr += inetBuffer.dwBufferLength;
313 inetBuffer.lpvBuffer = bufptr;
314 nExpected -= inetBuffer.dwBufferLength;
315 /* Adjust inetBuffer.dwBufferLength when it is greater than the */
316 /* expected end of file */
317 if (inetBuffer.dwBufferLength > nExpected)
318 inetBuffer.dwBufferLength = nExpected;
322 inetBuffer.dwBufferLength = nExpected;
324 } while (nExpected != 0);
327 /* Add to the response buffer. */
328 xmlrpc_mem_block_append(envP, winInetTransactionP->pResponseData, body, inetBuffer.dwBufferTotal);
329 XMLRPC_FAIL_IF_FAULT (envP);
332 /* Since the XMLRPC_FAIL calls goto cleanup, we must handle */
333 /* the free'ing of the memory here. */
336 LocalFree( pMsgMem );
345 performWinInetTransaction(xmlrpc_env * const envP,
346 winInetTransaction * const winInetTransactionP,
347 struct xmlrpc_client_transport * const clientTransportP) {
349 LPVOID pMsgMem = NULL;
351 unsigned long lastErr;
352 unsigned long reqFlags = INTERNET_FLAG_NO_UI;
353 char * acceptTypes[] = {"text/xml", NULL};
354 unsigned long queryLen = sizeof (unsigned long);
356 winInetTransactionP->hURL = InternetConnect (hSyncInternetSession,
357 winInetTransactionP->szHostName, winInetTransactionP->nPort,
358 NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
360 /* Start our request running. */
361 if (winInetTransactionP->bUseSSL == TRUE)
362 reqFlags |= INTERNET_FLAG_SECURE |INTERNET_FLAG_IGNORE_CERT_CN_INVALID;
364 winInetTransactionP->hHttpRequest = HttpOpenRequest (winInetTransactionP->hURL, "POST",
365 winInetTransactionP->szUrlPath, "HTTP/1.1", NULL, (const char **)&acceptTypes,
368 XMLRPC_FAIL_IF_NULL(winInetTransactionP->hHttpRequest,envP, XMLRPC_INTERNAL_ERROR,
369 "Unable to open the requested URL.");
371 if ( HttpAddRequestHeaders (winInetTransactionP->hHttpRequest, winInetTransactionP->headerList,
372 strlen (winInetTransactionP->headerList), HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE ) ==FALSE)
374 XMLRPC_FAIL (envP, XMLRPC_INTERNAL_ERROR, "Could not set Content-Type.");
378 /* Provide the user with transport status information */
379 InternetSetStatusCallback (winInetTransactionP->hHttpRequest, statusCallback);
383 /* Send the requested XML remote procedure command */
384 if (HttpSendRequest (winInetTransactionP->hHttpRequest, NULL, 0,
385 winInetTransactionP->pSendData,
386 strlen(winInetTransactionP->pSendData))==FALSE)
388 lastErr = GetLastError ();
390 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
391 FORMAT_MESSAGE_ALLOCATE_BUFFER |
392 FORMAT_MESSAGE_IGNORE_INSERTS,
395 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
404 case ERROR_INTERNET_CANNOT_CONNECT:
405 pMsg = "Sync HttpSendRequest failed: Connection refused.";
407 case ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED:
408 pMsg = "Sync HttpSendRequest failed: Client authorization certificate needed.";
411 /* The following conditions are recommendations that microsoft */
412 /* provides in their knowledge base. */
414 /* HOWTO: Handle Invalid Certificate Authority Error with WinInet (Q182888) */
415 case ERROR_INTERNET_INVALID_CA:
416 if (clientTransportP->allowInvalidSSLCerts){
417 OutputDebugString ("Sync HttpSendRequest failed: "
418 "The function is unfamiliar with the certificate "
419 "authority that generated the server's certificate. ");
420 reqFlags = SECURITY_FLAG_IGNORE_UNKNOWN_CA;
422 InternetSetOption (winInetTransactionP->hHttpRequest, INTERNET_OPTION_SECURITY_FLAGS,
423 &reqFlags, sizeof (reqFlags));
428 pMsg = "Invalid or unknown/untrusted SSL Certificate Authority.";
432 /* HOWTO: Make SSL Requests Using WinInet (Q168151) */
433 case ERROR_INTERNET_SEC_CERT_CN_INVALID:
434 if (clientTransportP->allowInvalidSSLCerts){
435 OutputDebugString ("Sync HttpSendRequest failed: "
436 "The SSL certificate common name (host name field) is incorrect\r\n "
437 "for example, if you entered www.server.com and the common name "
438 "on the certificate says www.different.com. ");
440 reqFlags = INTERNET_FLAG_IGNORE_CERT_CN_INVALID;
442 InternetSetOption (winInetTransactionP->hHttpRequest, INTERNET_OPTION_SECURITY_FLAGS,
443 &reqFlags, sizeof (reqFlags));
448 pMsg = "The SSL certificate common name (host name field) is incorrect.";
452 case ERROR_INTERNET_SEC_CERT_DATE_INVALID:
453 if (clientTransportP->allowInvalidSSLCerts){
454 OutputDebugString ("Sync HttpSendRequest failed: "
455 "The SSL certificate date that was received from the server is "
456 "bad. The certificate is expired. ");
458 reqFlags = INTERNET_FLAG_IGNORE_CERT_DATE_INVALID;
460 InternetSetOption (winInetTransactionP->hHttpRequest, INTERNET_OPTION_SECURITY_FLAGS,
461 &reqFlags, sizeof (reqFlags));
466 pMsg = "The SSL certificate date that was received from the server is invalid.";
471 pMsg = (LPTSTR)pMsgMem = LocalAlloc (LPTR, MAX_PATH);
472 sprintf (pMsg, "Sync HttpSendRequest failed: GetLastError (%d)", lastErr);
479 pMsg = (LPTSTR)(pMsgMem);
482 XMLRPC_FAIL (envP, XMLRPC_NETWORK_ERROR, pMsg);
486 if( HttpQueryInfo (winInetTransactionP->hHttpRequest,
487 HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,
488 &winInetTransactionP->http_status, &queryLen, NULL) == FALSE)
490 lastErr = GetLastError ();
491 FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
492 FORMAT_MESSAGE_FROM_SYSTEM,
495 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
499 pMsg = (pMsgMem) ? (LPTSTR)(pMsgMem) : "Sync HttpQueryInfo failed.";
500 XMLRPC_FAIL (envP, XMLRPC_NETWORK_ERROR, pMsg);
504 /* Make sure we got a "200 OK" message from the remote server. */
505 if(winInetTransactionP->http_status!=200)
507 unsigned long msgLen = 1024;
510 HttpQueryInfo (winInetTransactionP->hHttpRequest, HTTP_QUERY_STATUS_TEXT, errMsg, &msgLen, NULL);
512 /* Set our fault. We break this into multiple lines because it */
513 /* will generally contain line breaks to begin with. */
514 xmlrpc_env_set_fault_formatted (envP, XMLRPC_NETWORK_ERROR,
515 "HTTP error #%d occurred\n %s", winInetTransactionP->http_status, errMsg);
519 /* Read the response. */
520 get_wininet_response (envP, winInetTransactionP);
521 XMLRPC_FAIL_IF_FAULT (envP);
524 /* Since the XMLRPC_FAIL calls goto cleanup, we must handle */
525 /* the free'ing of the memory here. */
528 LocalFree( pMsgMem );
533 static unsigned __stdcall
534 doAsyncRpc(void * arg) {
535 rpc * const rpcP = arg;
537 xmlrpc_env_init(&env);
538 performWinInetTransaction(&env, rpcP->winInetTransactionP, rpcP->clientTransportP );
539 rpcP->complete(rpcP->callInfoP, rpcP->responseXmlP, env);
540 xmlrpc_env_clean(&env);
546 createRpcThread(xmlrpc_env * const envP,
548 pthread_t * const threadP) {
552 rc = pthread_create(threadP, NULL, doAsyncRpc, rpcP);
557 xmlrpc_env_set_fault_formatted(
558 envP, XMLRPC_INTERNAL_ERROR,
559 "pthread_create() failed: System Resources exceeded.");
562 xmlrpc_env_set_fault_formatted(
563 envP, XMLRPC_INTERNAL_ERROR,
564 "pthread_create() failed: Param Error for attr.");
567 xmlrpc_env_set_fault_formatted(
568 envP, XMLRPC_INTERNAL_ERROR,
569 "pthread_create() failed: No memory for new thread.");
572 xmlrpc_env_set_fault_formatted(
573 envP, XMLRPC_INTERNAL_ERROR,
574 "pthread_create() failed: Unrecognized error code %d.", rc);
580 rpcCreate(xmlrpc_env * const envP,
581 struct xmlrpc_client_transport * const clientTransportP,
582 const xmlrpc_server_info * const serverP,
583 xmlrpc_mem_block * const callXmlP,
584 xmlrpc_mem_block * const responseXmlP,
585 xmlrpc_transport_asynch_complete complete,
586 struct xmlrpc_call_info * const callInfoP,
587 rpc ** const rpcPP) {
593 xmlrpc_env_set_fault_formatted(
594 envP, XMLRPC_INTERNAL_ERROR,
595 "Couldn't allocate memory for rpc object");
597 rpcP->callInfoP = callInfoP;
598 rpcP->complete = complete;
599 rpcP->responseXmlP = responseXmlP;
600 rpcP->threadExists = FALSE;
602 createWinInetTransaction(envP, serverP,
603 callXmlP, responseXmlP,
604 &rpcP->winInetTransactionP);
605 if (!envP->fault_occurred) {
607 createRpcThread(envP, rpcP, &rpcP->thread);
608 if (!envP->fault_occurred)
609 rpcP->threadExists = TRUE;
611 if (!envP->fault_occurred) {
612 list_init_header(&rpcP->link, rpcP);
613 pthread_mutex_lock(&clientTransportP->listLock);
614 list_add_head(&clientTransportP->rpcList, &rpcP->link);
615 pthread_mutex_unlock(&clientTransportP->listLock);
617 if (envP->fault_occurred)
618 destroyWinInetTransaction(rpcP->winInetTransactionP);
620 if (envP->fault_occurred)
627 rpcDestroy(rpc * const rpcP) {
629 XMLRPC_ASSERT_PTR_OK(rpcP);
630 XMLRPC_ASSERT(!rpcP->threadExists);
632 destroyWinInetTransaction(rpcP->winInetTransactionP);
634 list_remove(&rpcP->link);
640 finishRpc(struct list_head * const headerP,
641 void * const context ATTR_UNUSED) {
643 rpc * const rpcP = headerP->itemP;
645 if (rpcP->threadExists) {
649 result = pthread_join(rpcP->thread, &status);
651 rpcP->threadExists = FALSE;
654 XMLRPC_MEMBLOCK_FREE(char, rpcP->responseXmlP);
662 /* Used for debugging purposes to track the status of
664 void CALLBACK statusCallback (HINTERNET hInternet,
665 unsigned long dwContext,
666 unsigned long dwInternetStatus,
667 void * lpvStatusInformation,
668 unsigned long dwStatusInformationLength)
670 switch (dwInternetStatus)
672 case INTERNET_STATUS_RESOLVING_NAME:
673 OutputDebugString("INTERNET_STATUS_RESOLVING_NAME\r\n");
676 case INTERNET_STATUS_NAME_RESOLVED:
677 OutputDebugString("INTERNET_STATUS_NAME_RESOLVED\r\n");
680 case INTERNET_STATUS_HANDLE_CREATED:
681 OutputDebugString("INTERNET_STATUS_HANDLE_CREATED\r\n");
684 case INTERNET_STATUS_CONNECTING_TO_SERVER:
685 OutputDebugString("INTERNET_STATUS_CONNECTING_TO_SERVER\r\n");
688 case INTERNET_STATUS_REQUEST_SENT:
689 OutputDebugString("INTERNET_STATUS_REQUEST_SENT\r\n");
692 case INTERNET_STATUS_SENDING_REQUEST:
693 OutputDebugString("INTERNET_STATUS_SENDING_REQUEST\r\n");
696 case INTERNET_STATUS_CONNECTED_TO_SERVER:
697 OutputDebugString("INTERNET_STATUS_CONNECTED_TO_SERVER\r\n");
700 case INTERNET_STATUS_RECEIVING_RESPONSE:
701 OutputDebugString("INTERNET_STATUS_RECEIVING_RESPONSE\r\n");
704 case INTERNET_STATUS_RESPONSE_RECEIVED:
705 OutputDebugString("INTERNET_STATUS_RESPONSE_RECEIVED\r\n");
708 case INTERNET_STATUS_CLOSING_CONNECTION:
709 OutputDebugString("INTERNET_STATUS_CLOSING_CONNECTION\r\n");
712 case INTERNET_STATUS_CONNECTION_CLOSED:
713 OutputDebugString("INTERNET_STATUS_CONNECTION_CLOSED\r\n");
716 case INTERNET_STATUS_HANDLE_CLOSING:
717 OutputDebugString("INTERNET_STATUS_HANDLE_CLOSING\r\n");
720 case INTERNET_STATUS_CTL_RESPONSE_RECEIVED:
721 OutputDebugString("INTERNET_STATUS_CTL_RESPONSE_RECEIVED\r\n");
724 case INTERNET_STATUS_REDIRECT:
725 OutputDebugString("INTERNET_STATUS_REDIRECT\r\n");
728 case INTERNET_STATUS_REQUEST_COMPLETE:
729 /* This indicates the data is ready. */
730 OutputDebugString("INTERNET_STATUS_REQUEST_COMPLETE\r\n");
734 OutputDebugString("statusCallback, default case!\r\n");
740 create(xmlrpc_env * const envP,
741 int const flags ATTR_UNUSED,
742 const char * const appname ATTR_UNUSED,
743 const char * const appversion ATTR_UNUSED,
744 const struct xmlrpc_xportparms * const transportparmsP,
745 size_t const parm_size,
746 struct xmlrpc_client_transport ** const handlePP) {
747 /*----------------------------------------------------------------------------
748 This does the 'create' operation for a WinInet client transport.
749 -----------------------------------------------------------------------------*/
750 struct xmlrpc_client_transport * transportP;
752 struct xmlrpc_wininet_xportparms * const wininetXportParmsP =
753 (struct xmlrpc_wininet_xportparms *) transportparmsP;
755 MALLOCVAR(transportP);
756 if (transportP == NULL)
757 xmlrpc_env_set_fault_formatted(
758 envP, XMLRPC_INTERNAL_ERROR,
759 "Unable to allocate transport descriptor.");
761 pthread_mutex_init(&transportP->listLock, NULL);
763 list_make_empty(&transportP->rpcList);
765 if (hSyncInternetSession == NULL)
766 hSyncInternetSession = InternetOpen ("xmlrpc-c wininet transport",
767 INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
769 if (!wininetXportParmsP || parm_size < XMLRPC_WXPSIZE(allowInvalidSSLCerts))
770 transportP->allowInvalidSSLCerts = 0;
772 transportP->allowInvalidSSLCerts = wininetXportParmsP->allowInvalidSSLCerts;
774 *handlePP = transportP;
780 destroy(struct xmlrpc_client_transport * const clientTransportP) {
781 /*----------------------------------------------------------------------------
782 This does the 'destroy' operation for a WinInet client transport.
783 -----------------------------------------------------------------------------*/
784 XMLRPC_ASSERT(clientTransportP != NULL);
786 XMLRPC_ASSERT(list_is_empty(&clientTransportP->rpcList));
788 if (hSyncInternetSession)
789 InternetCloseHandle(hSyncInternetSession);
790 hSyncInternetSession = NULL;
792 pthread_mutex_destroy(&clientTransportP->listLock);
794 free(clientTransportP);
799 sendRequest(xmlrpc_env * const envP,
800 struct xmlrpc_client_transport * const clientTransportP,
801 const xmlrpc_server_info * const serverP,
802 xmlrpc_mem_block * const callXmlP,
803 xmlrpc_transport_asynch_complete complete,
804 struct xmlrpc_call_info * const callInfoP) {
805 /*----------------------------------------------------------------------------
806 Initiate an XML-RPC rpc asynchronously. Don't wait for it to go to
809 Unless we return failure, we arrange to have complete() called when
812 This does the 'send_request' operation for a WinInet client transport.
813 -----------------------------------------------------------------------------*/
815 xmlrpc_mem_block * responseXmlP;
817 responseXmlP = XMLRPC_MEMBLOCK_NEW(char, envP, 0);
818 if (!envP->fault_occurred) {
819 rpcCreate(envP, clientTransportP, serverP, callXmlP, responseXmlP,
823 if (envP->fault_occurred)
824 XMLRPC_MEMBLOCK_FREE(char, responseXmlP);
826 /* The user's eventual finish_asynch call will destroy this RPC
832 finishAsynch(struct xmlrpc_client_transport * const clientTransportP,
833 xmlrpc_timeoutType const timeoutType ATTR_UNUSED,
834 xmlrpc_timeout const timeout ATTR_UNUSED) {
835 /*----------------------------------------------------------------------------
836 Wait for the threads of all outstanding RPCs to exit and destroy those
839 This does the 'finish_asynch' operation for a WinInet client transport.
840 -----------------------------------------------------------------------------*/
841 /* We ignore any timeout request. Some day, we should figure out how
842 to set an alarm and interrupt running threads.
845 pthread_mutex_lock(&clientTransportP->listLock);
847 list_foreach(&clientTransportP->rpcList, finishRpc, NULL);
849 pthread_mutex_unlock(&clientTransportP->listLock);
854 call(xmlrpc_env * const envP,
855 struct xmlrpc_client_transport * const clientTransportP,
856 const xmlrpc_server_info * const serverP,
857 xmlrpc_mem_block * const callXmlP,
858 xmlrpc_mem_block ** const responsePP) {
861 xmlrpc_mem_block * responseXmlP;
864 XMLRPC_ASSERT_ENV_OK(envP);
865 XMLRPC_ASSERT_PTR_OK(serverP);
866 XMLRPC_ASSERT_PTR_OK(callXmlP);
867 XMLRPC_ASSERT_PTR_OK(responsePP);
869 responseXmlP = XMLRPC_MEMBLOCK_NEW(char, envP, 0);
870 if (!envP->fault_occurred) {
871 rpcCreate(envP, clientTransportP, serverP, callXmlP, responseXmlP,
873 if (!envP->fault_occurred) {
874 performWinInetTransaction(envP, rpcP->winInetTransactionP, clientTransportP);
876 *responsePP = responseXmlP;
880 if (envP->fault_occurred)
881 XMLRPC_MEMBLOCK_FREE(char, responseXmlP);
886 struct xmlrpc_client_transport_ops xmlrpc_wininet_transport_ops = {
896 /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
898 ** Redistribution and use in source and binary forms, with or without
899 ** modification, are permitted provided that the following conditions
901 ** 1. Redistributions of source code must retain the above copyright
902 ** notice, this list of conditions and the following disclaimer.
903 ** 2. Redistributions in binary form must reproduce the above copyright
904 ** notice, this list of conditions and the following disclaimer in the
905 ** documentation and/or other materials provided with the distribution.
906 ** 3. The name of the author may not be used to endorse or promote products
907 ** derived from this software without specific prior written permission.
909 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
910 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
911 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
912 ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
913 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
914 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
915 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
916 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
917 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
918 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF