- Wine was passing the wrong hwnd as the owner when processing owner
[wine.git] / dlls / wininet / internet.c
blob16e5dbef0a5a6cd38e269a51e58d21b43bbb66c3
1 /*
2 * Wininet
4 * Copyright 1999 Corel Corporation
6 * Ulrich Czekalla
8 */
10 #include "config.h"
12 #include <string.h>
13 #include <sys/types.h>
14 #ifdef HAVE_SYS_SOCKET_H
15 # include <sys/socket.h>
16 #endif
17 #include <stdlib.h>
19 #include "windows.h"
20 #include "wininet.h"
21 #include "debugtools.h"
22 #include "winerror.h"
23 #include "winsock.h"
25 #include "internet.h"
27 DEFAULT_DEBUG_CHANNEL(wininet);
29 #define MAX_IDLE_WORKER 1000*60*1
30 #define MAX_WORKER_THREADS 10
32 #define GET_HWININET_FROM_LPWININETFINDNEXT(lpwh) \
33 (LPWININETAPPINFOA)(((LPWININETFTPSESSIONA)(lpwh->hdr.lpwhparent))->hdr.lpwhparent)
35 typedef struct
37 DWORD dwError;
38 CHAR response[MAX_REPLY_LEN];
39 } WITHREADERROR, *LPWITHREADERROR;
41 INTERNET_SCHEME GetInternetScheme(LPSTR lpszScheme);
42 BOOL WINAPI INTERNET_FindNextFileA(HINTERNET hFind, LPVOID lpvFindData);
43 VOID INTERNET_ExecuteWork();
45 DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
46 DWORD dwNumThreads;
47 DWORD dwNumIdleThreads;
48 HANDLE hEventArray[2];
49 #define hQuitEvent hEventArray[0]
50 #define hWorkEvent hEventArray[1]
51 CRITICAL_SECTION csQueue;
52 LPWORKREQUEST lpHeadWorkQueue;
53 LPWORKREQUEST lpWorkQueueTail;
55 /***********************************************************************
56 * WININET_LibMain [Internal] Initializes the internal 'WININET.DLL'.
58 * PARAMS
59 * hinstDLL [I] handle to the 'dlls' instance
60 * fdwReason [I]
61 * lpvReserved [I] reserverd, must be NULL
63 * RETURNS
64 * Success: TRUE
65 * Failure: FALSE
68 BOOL WINAPI
69 WININET_LibMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
71 TRACE("%x,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
73 switch (fdwReason) {
74 case DLL_PROCESS_ATTACH:
76 g_dwTlsErrIndex = TlsAlloc();
78 if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
79 return FALSE;
81 hQuitEvent = CreateEventA(0, TRUE, FALSE, NULL);
82 hWorkEvent = CreateEventA(0, FALSE, FALSE, NULL);
83 InitializeCriticalSection(&csQueue);
85 dwNumThreads = 0;
86 dwNumIdleThreads = 0;
88 case DLL_THREAD_ATTACH:
90 LPWITHREADERROR lpwite = HeapAlloc(GetProcessHeap(), 0, sizeof(WITHREADERROR));
91 if (NULL == lpwite)
92 return FALSE;
94 TlsSetValue(g_dwTlsErrIndex, (LPVOID)lpwite);
96 break;
98 case DLL_THREAD_DETACH:
99 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
100 HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
101 break;
103 case DLL_PROCESS_DETACH:
105 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
107 HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
108 TlsFree(g_dwTlsErrIndex);
111 SetEvent(hQuitEvent);
113 CloseHandle(hQuitEvent);
114 CloseHandle(hWorkEvent);
116 DeleteCriticalSection(&csQueue);
117 break;
120 return TRUE;
124 /***********************************************************************
125 * InternetOpenA (WININET.113)
127 * Per-application initialization of wininet
129 * RETURNS
130 * HINTERNET on success
131 * NULL on failure
134 INTERNETAPI HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent,
135 DWORD dwAccessType, LPCSTR lpszProxy,
136 LPCSTR lpszProxyBypass, DWORD dwFlags)
138 LPWININETAPPINFOA lpwai = NULL;
140 TRACE("\n");
142 /* Clear any error information */
143 INTERNET_SetLastError(0);
145 lpwai = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETAPPINFOA));
146 if (NULL == lpwai)
147 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
148 else
150 memset(lpwai, 0, sizeof(WININETAPPINFOA));
151 lpwai->hdr.htype = WH_HINIT;
152 lpwai->hdr.lpwhparent = NULL;
153 lpwai->hdr.dwFlags = dwFlags;
154 if (NULL != lpszAgent)
155 lpwai->lpszAgent = strdup(lpszAgent);
156 if (NULL != lpszProxy)
157 lpwai->lpszProxy = strdup(lpszProxy);
158 if (NULL != lpszProxyBypass)
159 lpwai->lpszProxyBypass = strdup(lpszProxyBypass);
160 lpwai->dwAccessType = dwAccessType;
163 return (HINTERNET)lpwai;
167 /***********************************************************************
168 * InternetGetLastResponseInfoA (WININET.108)
170 * Return last wininet error description on the calling thread
172 * RETURNS
173 * TRUE on success of writting to buffer
174 * FALSE on failure
177 BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
178 LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
180 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
182 TRACE("\n");
184 *lpdwError = lpwite->dwError;
185 if (lpwite->dwError)
187 strncpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
188 *lpdwBufferLength = strlen(lpszBuffer);
190 else
191 *lpdwBufferLength = 0;
193 return TRUE;
197 /***********************************************************************
198 * InternetGetConnectedState (WININET.103)
200 * Return connected state
202 * RETURNS
203 * TRUE if connected
204 * if lpdwStatus is not null, return the status (off line,
205 * modem, lan...) in it.
206 * FALSE if not connected
208 BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
210 FIXME("Stub\n");
211 return FALSE;
215 /***********************************************************************
216 * InternetConnectA (WININET.93)
218 * Open a ftp, gopher or http session
220 * RETURNS
221 * HINTERNET a session handle on success
222 * NULL on failure
225 INTERNETAPI HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
226 LPCSTR lpszServerName, INTERNET_PORT nServerPort,
227 LPCSTR lpszUserName, LPCSTR lpszPassword,
228 DWORD dwService, DWORD dwFlags, DWORD dwContext)
230 HINTERNET rc = (HINTERNET) NULL;
232 TRACE("\n");
234 /* Clear any error information */
235 INTERNET_SetLastError(0);
237 switch (dwService)
239 case INTERNET_SERVICE_FTP:
240 rc = FTP_Connect(hInternet, lpszServerName, nServerPort,
241 lpszUserName, lpszPassword, dwFlags, dwContext);
242 break;
244 case INTERNET_SERVICE_HTTP:
245 break;
247 case INTERNET_SERVICE_GOPHER:
248 default:
249 break;
252 return rc;
255 /***********************************************************************
256 * InternetFindNextFileA (WININET.102)
258 * Continues a file search from a previous call to FindFirstFile
260 * RETURNS
261 * TRUE on success
262 * FALSE on failure
265 BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
267 LPWININETAPPINFOA hIC = NULL;
268 LPWININETFINDNEXTA lpwh = (LPWININETFINDNEXTA) hFind;
270 TRACE("\n");
272 if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
274 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
275 return FALSE;
278 hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
279 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
281 WORKREQUEST workRequest;
283 workRequest.asyncall = INTERNETFINDNEXTA;
284 workRequest.HFTPSESSION = (DWORD)hFind;
285 workRequest.LPFINDFILEDATA = (DWORD)lpvFindData;
287 return INTERNET_AsyncCall(&workRequest);
289 else
291 return INTERNET_FindNextFileA(hFind, lpvFindData);
295 /***********************************************************************
296 * INTERNET_FindNextFileA (Internal)
298 * Continues a file search from a previous call to FindFirstFile
300 * RETURNS
301 * TRUE on success
302 * FALSE on failure
305 BOOL WINAPI INTERNET_FindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
307 BOOL bSuccess = TRUE;
308 LPWININETAPPINFOA hIC = NULL;
309 LPWIN32_FIND_DATAA lpFindFileData;
310 LPWININETFINDNEXTA lpwh = (LPWININETFINDNEXTA) hFind;
312 TRACE("\n");
314 if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
316 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
317 return FALSE;
320 /* Clear any error information */
321 INTERNET_SetLastError(0);
323 if (lpwh->hdr.lpwhparent->htype != WH_HFTPSESSION)
325 FIXME("Only FTP find next supported\n");
326 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
327 return FALSE;
330 TRACE("index(%d) size(%ld)\n", lpwh->index, lpwh->size);
332 lpFindFileData = (LPWIN32_FIND_DATAA) lpvFindData;
333 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
335 if (lpwh->index >= lpwh->size)
337 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
338 bSuccess = FALSE;
339 goto lend;
342 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
343 lpwh->index++;
345 TRACE("\nName: %s\nSize: %ld\n", lpFindFileData->cFileName, lpFindFileData->nFileSizeLow);
347 lend:
349 hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
350 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
352 INTERNET_ASYNC_RESULT iar;
354 iar.dwResult = (DWORD)bSuccess;
355 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
357 hIC->lpfnStatusCB(hFind, lpwh->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
358 &iar, sizeof(INTERNET_ASYNC_RESULT));
361 return bSuccess;
365 /***********************************************************************
366 * InternetCloseHandle (WININET.89)
368 * Continues a file search from a previous call to FindFirstFile
370 * RETURNS
371 * TRUE on success
372 * FALSE on failure
375 BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
377 BOOL retval = FALSE;
378 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hInternet;
380 TRACE("\n");
381 if (NULL == lpwh)
382 return FALSE;
384 /* Clear any error information */
385 INTERNET_SetLastError(0);
387 switch (lpwh->htype)
389 case WH_HINIT:
390 case WH_HHTTPSESSION:
391 case WH_HHTTPREQ:
392 break;
393 case WH_HFTPSESSION:
394 retval = FTP_CloseSessionHandle((LPWININETFTPSESSIONA) lpwh);
395 break;
397 case WH_HFINDNEXT:
398 retval = FTP_CloseFindNextHandle((LPWININETFINDNEXTA) lpwh);
399 break;
401 default:
402 break;
405 return retval;
409 /***********************************************************************
410 * InternetCrackUrlA (WININET.95)
412 * Break up URL into its components
414 * RETURNS
415 * TRUE on success
416 * FALSE on failure
419 BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
420 LPURL_COMPONENTSA lpUrlComponents)
423 * RFC 1808
424 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
427 char* szScheme = NULL;
428 char* szUser = NULL;
429 char* szPass = NULL;
430 char* szHost = NULL;
431 char* szUrlPath = NULL;
432 char* szParam = NULL;
433 char* szNetLoc = NULL;
434 int nPort = 80;
435 int nSchemeLen = 0;
436 int nUserLen = 0;
437 int nPassLen = 0;
438 int nHostLen = 0;
439 int nUrlLen = 0;
441 /* Find out if the URI is absolute... */
442 BOOL bIsAbsolute = FALSE;
443 char cAlphanum;
444 char* ap = (char*)lpszUrl;
445 char* cp = NULL;
447 TRACE("\n");
448 while( (cAlphanum = *ap) != '\0' )
450 if( ((cAlphanum >= 'a') && (cAlphanum <= 'z')) ||
451 ((cAlphanum >= 'A') && (cAlphanum <= 'Z')) ||
452 ((cAlphanum >= '0') && (cAlphanum <= '9')) )
454 ap++;
455 continue;
457 if( (cAlphanum == ':') && (ap - lpszUrl >= 2) )
459 bIsAbsolute = TRUE;
460 cp = ap;
461 break;
463 break;
466 /* Absolute URI...
467 FIXME!!!! This should work on relative urls too!*/
468 if( bIsAbsolute )
470 /* Get scheme first... */
471 nSchemeLen = cp - lpszUrl;
472 szScheme = strdup( lpszUrl );
473 szScheme[ nSchemeLen ] = '\0';
475 /* Eat ':' in protocol... */
476 cp++;
478 /* Parse <params>... */
479 szParam = strpbrk( lpszUrl, ";" );
480 if( szParam != NULL )
482 char* sParam;
483 /* Eat ';' in Params... */
484 szParam++;
485 sParam = strdup( szParam );
486 *szParam = '\0';
489 /* Skip over slashes...*/
490 if( *cp == '/' )
492 cp++;
493 if( *cp == '/' )
495 cp++;
496 if( *cp == '/' )
497 cp++;
501 /* Parse the <net-loc>...*/
502 if( GetInternetScheme( szScheme ) == INTERNET_SCHEME_FILE )
504 szUrlPath = strdup( cp );
505 nUrlLen = strlen( szUrlPath );
506 if( nUrlLen >= 2 && szUrlPath[ 1 ] == '|' )
507 szUrlPath[ 1 ] = ':';
509 else
511 size_t nNetLocLen;
512 szUrlPath = strpbrk(cp, "/");
513 if( szUrlPath != NULL )
514 nUrlLen = strlen( szUrlPath );
516 /* Find the end of our net-loc... */
517 nNetLocLen = strcspn( cp, "/" );
518 szNetLoc = strdup( cp );
519 szNetLoc[ nNetLocLen ] = '\0';
520 if( szNetLoc != NULL )
522 char* lpszPort;
523 int nPortLen;
524 /* [<user>[<:password>]@]<host>[:<port>] */
525 /* First find the user and password if they exist...*/
527 szHost = strchr( szNetLoc, '@' );
528 if( szHost == NULL )
530 /* username and password not specified... */
531 szHost = szNetLoc;
532 nHostLen = nNetLocLen;
534 else
536 int nUserPassLen = nNetLocLen - nHostLen - 1;
537 char* szUserPass = strdup( szNetLoc );
538 /* Get username and/or password... */
539 /* Eat '@' in domain... */
540 ++szHost;
541 nHostLen = strlen( szHost );
543 szUserPass[ nUserPassLen ] = '\0';
544 if( szUserPass != NULL )
546 szPass = strpbrk( szUserPass, ":" );
547 if( szPass != NULL )
549 /* Eat ':' in UserPass... */
550 ++szPass;
551 nPassLen = strlen( szPass );
552 nUserLen = nUserPassLen - nPassLen - 1;
553 szUser = strdup( szUserPass );
554 szUser[ nUserLen ] = '\0';
556 else
558 /* password not specified... */
559 szUser = strdup( szUserPass );
560 nUserLen = strlen( szUser );
565 /* <host><:port>...*/
566 /* Then get the port if it exists... */
567 lpszPort = strpbrk( szHost, ":" );
568 nPortLen = 0;
569 if( lpszPort != NULL )
571 char* szPort = lpszPort + 1;
572 if( szPort != NULL )
574 nPortLen = strlen( szPort );
575 nPort = atoi( szPort );
577 *lpszPort = '\0';
578 nHostLen = strlen(szHost);
583 /* Relative URI... */
584 else
585 return FALSE;
587 return TRUE;
591 /***********************************************************************
592 * InternetAttemptConnect (WININET.81)
594 * Attempt to make a connection to the internet
596 * RETURNS
597 * ERROR_SUCCESS on success
598 * Error value on failure
601 INTERNETAPI DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
603 FIXME("Stub\n");
604 return ERROR_SUCCESS;
608 /***********************************************************************
609 * InternetCanonicalizeUrlA (WININET.85)
611 * Escape unsafe characters and spaces
613 * RETURNS
614 * TRUE on success
615 * FALSE on failure
618 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
619 LPDWORD lpdwBufferLength, DWORD dwFlags)
621 BOOL bSuccess = FALSE;
623 FIXME("Stub!\n");
625 if (lpszUrl)
627 strncpy(lpszBuffer, lpszUrl, *lpdwBufferLength);
628 *lpdwBufferLength = strlen(lpszBuffer);
629 bSuccess = TRUE;
632 return bSuccess;
636 /***********************************************************************
637 * InternetSetStatusCallback (WININET.133)
639 * Sets up a callback function which is called as progress is made
640 * during an operation.
642 * RETURNS
643 * Previous callback or NULL on success
644 * INTERNET_INVALID_STATUS_CALLBACK on failure
647 INTERNETAPI INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallback(
648 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
650 INTERNET_STATUS_CALLBACK retVal;
651 LPWININETAPPINFOA lpwai = (LPWININETAPPINFOA)hInternet;
653 TRACE("0x%08lx\n", (ULONG)hInternet);
654 if (lpwai->hdr.htype != WH_HINIT)
655 return INTERNET_INVALID_STATUS_CALLBACK;
657 retVal = lpwai->lpfnStatusCB;
658 lpwai->lpfnStatusCB = lpfnIntCB;
660 return retVal;
664 /***********************************************************************
665 * InternetWriteFile (WININET.138)
667 * Write data to an open internet file
669 * RETURNS
670 * TRUE on success
671 * FALSE on failure
674 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer ,
675 DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
677 BOOL retval = FALSE;
678 int nSocket = INVALID_SOCKET;
679 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hFile;
681 TRACE("\n");
682 if (NULL == lpwh)
683 return FALSE;
685 switch (lpwh->htype)
687 case WH_HHTTPREQ:
688 nSocket = ((LPWININETHTTPREQA)hFile)->nSocketFD;
689 break;
691 case WH_HFILE:
692 nSocket = ((LPWININETFILE)hFile)->nDataSocket;
693 break;
695 default:
696 break;
699 if (INVALID_SOCKET != nSocket)
701 *lpdwNumOfBytesWritten = INTERNET_WriteDataToStream(nSocket, lpBuffer, dwNumOfBytesToWrite);
702 if (*lpdwNumOfBytesWritten < 0)
703 *lpdwNumOfBytesWritten = 0;
704 else
705 retval = TRUE;
708 return retval;
712 /***********************************************************************
713 * InternetReadFile (WININET.121)
715 * Read data from an open internet file
717 * RETURNS
718 * TRUE on success
719 * FALSE on failure
722 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
723 DWORD dwNumOfBytesToRead, LPDWORD dwNumOfBytesRead)
725 BOOL retval = FALSE;
726 int nSocket = INVALID_SOCKET;
727 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hFile;
729 TRACE("\n");
730 if (NULL == lpwh)
731 return FALSE;
733 switch (lpwh->htype)
735 case WH_HHTTPREQ:
736 nSocket = ((LPWININETHTTPREQA)hFile)->nSocketFD;
737 break;
739 case WH_HFILE:
740 nSocket = ((LPWININETFILE)hFile)->nDataSocket;
741 break;
743 default:
744 break;
747 if (INVALID_SOCKET != nSocket)
749 *dwNumOfBytesRead = INTERNET_ReadDataFromStream(nSocket, lpBuffer, dwNumOfBytesToRead);
750 if (*dwNumOfBytesRead < 0)
751 *dwNumOfBytesRead = 0;
752 else
753 retval = TRUE;
756 return retval;
760 /***********************************************************************
761 * GetInternetScheme (internal)
763 * Get scheme of url
765 * RETURNS
766 * scheme on success
767 * INTERNET_SCHEME_UNKNOWN on failure
770 INTERNET_SCHEME GetInternetScheme(LPSTR lpszScheme)
772 if(lpszScheme==NULL)
773 return INTERNET_SCHEME_UNKNOWN;
775 if( (strcmp("ftp", lpszScheme) == 0) ||
776 (strcmp("FTP", lpszScheme) == 0) )
777 return INTERNET_SCHEME_FTP;
778 else if( (strcmp("gopher", lpszScheme) == 0) ||
779 (strcmp("GOPHER", lpszScheme) == 0) )
780 return INTERNET_SCHEME_GOPHER;
781 else if( (strcmp("http", lpszScheme) == 0) ||
782 (strcmp("HTTP", lpszScheme) == 0) )
783 return INTERNET_SCHEME_HTTP;
784 else if( (strcmp("https", lpszScheme) == 0) ||
785 (strcmp("HTTPS", lpszScheme) == 0) )
786 return INTERNET_SCHEME_HTTPS;
787 else if( (strcmp("file", lpszScheme) == 0) ||
788 (strcmp("FILE", lpszScheme) == 0) )
789 return INTERNET_SCHEME_FILE;
790 else if( (strcmp("news", lpszScheme) == 0) ||
791 (strcmp("NEWS", lpszScheme) == 0) )
792 return INTERNET_SCHEME_NEWS;
793 else if( (strcmp("mailto", lpszScheme) == 0) ||
794 (strcmp("MAILTO", lpszScheme) == 0) )
795 return INTERNET_SCHEME_MAILTO;
796 else
797 return INTERNET_SCHEME_UNKNOWN;
801 /***********************************************************************
802 * INTERNET_WriteDataToStream (internal)
804 * Send data to server
806 * RETURNS
808 * number of characters sent on success
809 * -1 on error
811 int INTERNET_WriteDataToStream(int nDataSocket, LPCVOID Buffer, DWORD BytesToWrite)
813 if (INVALID_SOCKET == nDataSocket)
814 return SOCKET_ERROR;
816 return send(nDataSocket, Buffer, BytesToWrite, 0);
820 /***********************************************************************
821 * INTERNET_ReadDataFromStream (internal)
823 * Read data from http server
825 * RETURNS
827 * number of characters sent on success
828 * -1 on error
830 int INTERNET_ReadDataFromStream(int nDataSocket, LPVOID Buffer, DWORD BytesToRead)
832 if (INVALID_SOCKET == nDataSocket)
833 return SOCKET_ERROR;
835 return recv(nDataSocket, Buffer, BytesToRead, 0);
839 /***********************************************************************
840 * INTERNET_SetLastError (internal)
842 * Set last thread specific error
844 * RETURNS
847 void INTERNET_SetLastError(DWORD dwError)
849 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
851 SetLastError(dwError);
852 lpwite->dwError = dwError;
856 /***********************************************************************
857 * INTERNET_GetLastError (internal)
859 * Get last thread specific error
861 * RETURNS
864 DWORD INTERNET_GetLastError()
866 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
867 return lpwite->dwError;
871 /***********************************************************************
872 * INTERNET_WorkerThreadFunc (internal)
874 * Worker thread execution function
876 * RETURNS
879 DWORD INTERNET_WorkerThreadFunc(LPVOID *lpvParam)
881 DWORD dwWaitRes;
883 while (1)
885 dwWaitRes = WaitForMultipleObjects(2, hEventArray, FALSE, MAX_IDLE_WORKER);
887 if (dwWaitRes == WAIT_OBJECT_0 + 1)
888 INTERNET_ExecuteWork();
889 else
890 break;
892 InterlockedIncrement(&dwNumIdleThreads);
895 InterlockedDecrement(&dwNumIdleThreads);
896 InterlockedDecrement(&dwNumThreads);
897 TRACE("Worker thread exiting\n");
898 return TRUE;
902 /***********************************************************************
903 * INTERNET_InsertWorkRequest (internal)
905 * Insert work request into queue
907 * RETURNS
910 BOOL INTERNET_InsertWorkRequest(LPWORKREQUEST lpWorkRequest)
912 BOOL bSuccess = FALSE;
913 LPWORKREQUEST lpNewRequest;
915 TRACE("\n");
917 lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
918 if (lpNewRequest)
920 memcpy(lpNewRequest, lpWorkRequest, sizeof(WORKREQUEST));
921 lpNewRequest->prev = NULL;
923 EnterCriticalSection(&csQueue);
925 lpNewRequest->next = lpWorkQueueTail;
926 if (lpWorkQueueTail)
927 lpWorkQueueTail->prev = lpNewRequest;
928 lpWorkQueueTail = lpNewRequest;
929 if (!lpHeadWorkQueue)
930 lpHeadWorkQueue = lpWorkQueueTail;
932 LeaveCriticalSection(&csQueue);
934 bSuccess = TRUE;
937 return bSuccess;
941 /***********************************************************************
942 * INTERNET_GetWorkRequest (internal)
944 * Retrieves work request from queue
946 * RETURNS
949 BOOL INTERNET_GetWorkRequest(LPWORKREQUEST lpWorkRequest)
951 BOOL bSuccess = FALSE;
952 LPWORKREQUEST lpRequest = NULL;
954 TRACE("\n");
956 EnterCriticalSection(&csQueue);
958 if (lpHeadWorkQueue)
960 lpRequest = lpHeadWorkQueue;
961 lpHeadWorkQueue = lpHeadWorkQueue->prev;
962 if (lpRequest == lpWorkQueueTail)
963 lpWorkQueueTail = lpHeadWorkQueue;
966 LeaveCriticalSection(&csQueue);
968 if (lpRequest)
970 memcpy(lpWorkRequest, lpRequest, sizeof(WORKREQUEST));
971 HeapFree(GetProcessHeap(), 0, lpRequest);
972 bSuccess = TRUE;
975 return bSuccess;
979 /***********************************************************************
980 * INTERNET_AsyncCall (internal)
982 * Retrieves work request from queue
984 * RETURNS
987 BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
989 HANDLE hThread;
990 DWORD dwTID;
991 BOOL bSuccess = FALSE;
993 TRACE("\n");
995 if (InterlockedDecrement(&dwNumIdleThreads) < 0)
997 InterlockedIncrement(&dwNumIdleThreads);
999 if (InterlockedIncrement(&dwNumThreads) > MAX_WORKER_THREADS ||
1000 !(hThread = CreateThread(NULL, 0,
1001 (LPTHREAD_START_ROUTINE)INTERNET_WorkerThreadFunc, NULL, 0, &dwTID)))
1003 InterlockedDecrement(&dwNumThreads);
1004 INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
1005 goto lerror;
1008 TRACE("Created new thread\n");
1011 bSuccess = TRUE;
1012 INTERNET_InsertWorkRequest(lpWorkRequest);
1013 SetEvent(hWorkEvent);
1015 lerror:
1017 return bSuccess;
1021 /***********************************************************************
1022 * INTERNET_ExecuteWork (internal)
1024 * RETURNS
1027 VOID INTERNET_ExecuteWork()
1029 WORKREQUEST workRequest;
1031 TRACE("\n");
1033 if (INTERNET_GetWorkRequest(&workRequest))
1035 switch (workRequest.asyncall)
1037 case FTPPUTFILEA:
1038 FTP_FtpPutFileA((HINTERNET)workRequest.HFTPSESSION, (LPCSTR)workRequest.LPSZLOCALFILE,
1039 (LPCSTR)workRequest.LPSZNEWREMOTEFILE, workRequest.DWFLAGS, workRequest.DWCONTEXT);
1040 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZLOCALFILE);
1041 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZNEWREMOTEFILE);
1042 break;
1044 case FTPSETCURRENTDIRECTORYA:
1045 FTP_FtpSetCurrentDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1046 (LPCSTR)workRequest.LPSZDIRECTORY);
1047 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1048 break;
1050 case FTPCREATEDIRECTORYA:
1051 FTP_FtpCreateDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1052 (LPCSTR)workRequest.LPSZDIRECTORY);
1053 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1054 break;
1056 case FTPFINDFIRSTFILEA:
1057 FTP_FtpFindFirstFileA((HINTERNET)workRequest.HFTPSESSION,
1058 (LPCSTR)workRequest.LPSZSEARCHFILE,
1059 (LPWIN32_FIND_DATAA)workRequest.LPFINDFILEDATA, workRequest.DWFLAGS,
1060 workRequest.DWCONTEXT);
1061 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZSEARCHFILE);
1062 break;
1064 case FTPGETCURRENTDIRECTORYA:
1065 FTP_FtpGetCurrentDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1066 (LPSTR)workRequest.LPSZDIRECTORY, (LPDWORD)workRequest.LPDWDIRECTORY);
1067 break;
1069 case FTPOPENFILEA:
1070 FTP_FtpOpenFileA((HINTERNET)workRequest.HFTPSESSION,
1071 (LPCSTR)workRequest.LPSZFILENAME,
1072 workRequest.FDWACCESS,
1073 workRequest.DWFLAGS,
1074 workRequest.DWCONTEXT);
1075 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZFILENAME);
1076 break;
1078 case FTPGETFILEA:
1079 FTP_FtpGetFileA((HINTERNET)workRequest.HFTPSESSION,
1080 (LPCSTR)workRequest.LPSZREMOTEFILE,
1081 (LPCSTR)workRequest.LPSZNEWFILE,
1082 (BOOL)workRequest.FFAILIFEXISTS,
1083 workRequest.DWLOCALFLAGSATTRIBUTE,
1084 workRequest.DWFLAGS,
1085 workRequest.DWCONTEXT);
1086 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZREMOTEFILE);
1087 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZNEWFILE);
1088 break;
1090 case FTPDELETEFILEA:
1091 FTP_FtpDeleteFileA((HINTERNET)workRequest.HFTPSESSION,
1092 (LPCSTR)workRequest.LPSZFILENAME);
1093 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZFILENAME);
1094 break;
1096 case FTPREMOVEDIRECTORYA:
1097 FTP_FtpRemoveDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1098 (LPCSTR)workRequest.LPSZDIRECTORY);
1099 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1100 break;
1102 case FTPRENAMEFILEA:
1103 FTP_FtpRenameFileA((HINTERNET)workRequest.HFTPSESSION,
1104 (LPCSTR)workRequest.LPSZSRCFILE,
1105 (LPCSTR)workRequest.LPSZDESTFILE);
1106 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZSRCFILE);
1107 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDESTFILE);
1108 break;
1110 case INTERNETFINDNEXTA:
1111 INTERNET_FindNextFileA((HINTERNET)workRequest.HFTPSESSION,
1112 (LPWIN32_FIND_DATAA)workRequest.LPFINDFILEDATA);
1113 break;
1119 /***********************************************************************
1120 * INTERNET_GetResponseBuffer
1122 * RETURNS
1125 LPSTR INTERNET_GetResponseBuffer()
1127 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
1128 return lpwite->response;