4 * Copyright 1999 Corel Corporation
13 #include <sys/types.h>
14 #ifdef HAVE_SYS_SOCKET_H
15 # include <sys/socket.h>
24 #include "debugtools.h"
31 DEFAULT_DEBUG_CHANNEL(wininet);
33 #define MAX_IDLE_WORKER 1000*60*1
34 #define MAX_WORKER_THREADS 10
35 #define RESPONSE_TIMEOUT 30
37 #define GET_HWININET_FROM_LPWININETFINDNEXT(lpwh) \
38 (LPWININETAPPINFOA)(((LPWININETFTPSESSIONA)(lpwh->hdr.lpwhparent))->hdr.lpwhparent)
43 CHAR response[MAX_REPLY_LEN];
44 } WITHREADERROR, *LPWITHREADERROR;
46 INTERNET_SCHEME GetInternetScheme(LPCSTR lpszScheme, INT nMaxCmp);
47 BOOL WINAPI INTERNET_FindNextFileA(HINTERNET hFind, LPVOID lpvFindData);
48 VOID INTERNET_ExecuteWork();
50 DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
52 DWORD dwNumIdleThreads;
53 HANDLE hEventArray[2];
54 #define hQuitEvent hEventArray[0]
55 #define hWorkEvent hEventArray[1]
56 CRITICAL_SECTION csQueue;
57 LPWORKREQUEST lpHeadWorkQueue;
58 LPWORKREQUEST lpWorkQueueTail;
60 /***********************************************************************
61 * WININET_LibMain [Internal] Initializes the internal 'WININET.DLL'.
64 * hinstDLL [I] handle to the DLL's instance
66 * lpvReserved [I] reserved, must be NULL
74 WININET_LibMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
76 TRACE("%x,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
79 case DLL_PROCESS_ATTACH:
81 g_dwTlsErrIndex = TlsAlloc();
83 if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
86 hQuitEvent = CreateEventA(0, TRUE, FALSE, NULL);
87 hWorkEvent = CreateEventA(0, FALSE, FALSE, NULL);
88 InitializeCriticalSection(&csQueue);
93 case DLL_THREAD_ATTACH:
95 LPWITHREADERROR lpwite = HeapAlloc(GetProcessHeap(), 0, sizeof(WITHREADERROR));
99 TlsSetValue(g_dwTlsErrIndex, (LPVOID)lpwite);
103 case DLL_THREAD_DETACH:
104 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
106 LPVOID lpwite = TlsGetValue(g_dwTlsErrIndex);
108 HeapFree(GetProcessHeap(), 0, lpwite);
112 case DLL_PROCESS_DETACH:
114 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
116 HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
117 TlsFree(g_dwTlsErrIndex);
120 SetEvent(hQuitEvent);
122 CloseHandle(hQuitEvent);
123 CloseHandle(hWorkEvent);
124 DeleteCriticalSection(&csQueue);
132 /***********************************************************************
133 * InternetOpenA (WININET.113)
135 * Per-application initialization of wininet
138 * HINTERNET on success
142 INTERNETAPI HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent,
143 DWORD dwAccessType, LPCSTR lpszProxy,
144 LPCSTR lpszProxyBypass, DWORD dwFlags)
146 LPWININETAPPINFOA lpwai = NULL;
150 /* Clear any error information */
151 INTERNET_SetLastError(0);
153 lpwai = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETAPPINFOA));
155 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
158 memset(lpwai, 0, sizeof(WININETAPPINFOA));
159 lpwai->hdr.htype = WH_HINIT;
160 lpwai->hdr.lpwhparent = NULL;
161 lpwai->hdr.dwFlags = dwFlags;
162 if (NULL != lpszAgent)
163 lpwai->lpszAgent = HEAP_strdupA(GetProcessHeap(),0,lpszAgent);
164 if (NULL != lpszProxy)
165 lpwai->lpszProxy = HEAP_strdupA(GetProcessHeap(),0,lpszProxy);
166 if (NULL != lpszProxyBypass)
167 lpwai->lpszProxyBypass = HEAP_strdupA(GetProcessHeap(),0,lpszProxyBypass);
168 lpwai->dwAccessType = dwAccessType;
171 return (HINTERNET)lpwai;
175 /***********************************************************************
176 * InternetGetLastResponseInfoA (WININET.108)
178 * Return last wininet error description on the calling thread
181 * TRUE on success of writting to buffer
185 BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
186 LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
188 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
192 *lpdwError = lpwite->dwError;
195 strncpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
196 *lpdwBufferLength = strlen(lpszBuffer);
199 *lpdwBufferLength = 0;
205 /***********************************************************************
206 * InternetGetConnectedState (WININET.103)
208 * Return connected state
212 * if lpdwStatus is not null, return the status (off line,
213 * modem, lan...) in it.
214 * FALSE if not connected
216 BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
223 /***********************************************************************
224 * InternetConnectA (WININET.93)
226 * Open a ftp, gopher or http session
229 * HINTERNET a session handle on success
233 INTERNETAPI HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
234 LPCSTR lpszServerName, INTERNET_PORT nServerPort,
235 LPCSTR lpszUserName, LPCSTR lpszPassword,
236 DWORD dwService, DWORD dwFlags, DWORD dwContext)
238 HINTERNET rc = (HINTERNET) NULL;
242 /* Clear any error information */
243 INTERNET_SetLastError(0);
247 case INTERNET_SERVICE_FTP:
248 rc = FTP_Connect(hInternet, lpszServerName, nServerPort,
249 lpszUserName, lpszPassword, dwFlags, dwContext);
252 case INTERNET_SERVICE_HTTP:
253 rc = HTTP_Connect(hInternet, lpszServerName, nServerPort,
254 lpszUserName, lpszPassword, dwFlags, dwContext);
257 case INTERNET_SERVICE_GOPHER:
265 /***********************************************************************
266 * InternetFindNextFileA (WININET.102)
268 * Continues a file search from a previous call to FindFirstFile
275 BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
277 LPWININETAPPINFOA hIC = NULL;
278 LPWININETFINDNEXTA lpwh = (LPWININETFINDNEXTA) hFind;
282 if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
284 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
288 hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
289 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
291 WORKREQUEST workRequest;
293 workRequest.asyncall = INTERNETFINDNEXTA;
294 workRequest.HFTPSESSION = (DWORD)hFind;
295 workRequest.LPFINDFILEDATA = (DWORD)lpvFindData;
297 return INTERNET_AsyncCall(&workRequest);
301 return INTERNET_FindNextFileA(hFind, lpvFindData);
305 /***********************************************************************
306 * INTERNET_FindNextFileA (Internal)
308 * Continues a file search from a previous call to FindFirstFile
315 BOOL WINAPI INTERNET_FindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
317 BOOL bSuccess = TRUE;
318 LPWININETAPPINFOA hIC = NULL;
319 LPWIN32_FIND_DATAA lpFindFileData;
320 LPWININETFINDNEXTA lpwh = (LPWININETFINDNEXTA) hFind;
324 if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
326 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
330 /* Clear any error information */
331 INTERNET_SetLastError(0);
333 if (lpwh->hdr.lpwhparent->htype != WH_HFTPSESSION)
335 FIXME("Only FTP find next supported\n");
336 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
340 TRACE("index(%d) size(%ld)\n", lpwh->index, lpwh->size);
342 lpFindFileData = (LPWIN32_FIND_DATAA) lpvFindData;
343 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
345 if (lpwh->index >= lpwh->size)
347 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
352 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
355 TRACE("\nName: %s\nSize: %ld\n", lpFindFileData->cFileName, lpFindFileData->nFileSizeLow);
359 hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
360 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
362 INTERNET_ASYNC_RESULT iar;
364 iar.dwResult = (DWORD)bSuccess;
365 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
367 hIC->lpfnStatusCB(hFind, lpwh->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
368 &iar, sizeof(INTERNET_ASYNC_RESULT));
375 /***********************************************************************
376 * INTERNET_CloseHandle (internal)
378 * Close internet handle
384 VOID INTERNET_CloseHandle(LPWININETAPPINFOA lpwai)
386 if (lpwai->lpszAgent)
387 HeapFree(GetProcessHeap(), 0, lpwai->lpszAgent);
389 if (lpwai->lpszProxy)
390 HeapFree(GetProcessHeap(), 0, lpwai->lpszProxy);
392 if (lpwai->lpszProxyBypass)
393 HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyBypass);
395 HeapFree(GetProcessHeap(), 0, lpwai);
399 /***********************************************************************
400 * InternetCloseHandle (WININET.89)
402 * Generic close handle function
409 BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
412 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hInternet;
418 /* Clear any error information */
419 INTERNET_SetLastError(0);
424 INTERNET_CloseHandle((LPWININETAPPINFOA) lpwh);
427 case WH_HHTTPSESSION:
428 HTTP_CloseHTTPSessionHandle((LPWININETHTTPSESSIONA) lpwh);
432 HTTP_CloseHTTPRequestHandle((LPWININETHTTPREQA) lpwh);
436 retval = FTP_CloseSessionHandle((LPWININETFTPSESSIONA) lpwh);
440 retval = FTP_CloseFindNextHandle((LPWININETFINDNEXTA) lpwh);
451 /***********************************************************************
452 * SetUrlComponentValue (Internal)
454 * Helper function for InternetCrackUrlA
461 BOOL SetUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentLen, LPCSTR lpszStart, INT len)
463 TRACE("%s (%d)\n", lpszStart, len);
465 if (*dwComponentLen != 0)
467 if (*lppszComponent == NULL)
469 *lppszComponent = (LPSTR)lpszStart;
470 *dwComponentLen = len;
474 INT ncpylen = min((*dwComponentLen)-1, len);
475 strncpy(*lppszComponent, lpszStart, ncpylen);
476 (*lppszComponent)[ncpylen] = '\0';
477 *dwComponentLen = ncpylen;
485 /***********************************************************************
486 * InternetCrackUrlA (WININET.95)
488 * Break up URL into its components
490 * TODO: Hadnle dwFlags
497 BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
498 LPURL_COMPONENTSA lpUrlComponents)
502 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
505 LPSTR lpszParam = NULL;
506 BOOL bIsAbsolute = FALSE;
507 LPSTR lpszap = (char*)lpszUrl;
512 /* Determine if the URI is absolute. */
513 while (*lpszap != '\0')
515 if (isalnum(*lpszap))
520 if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
527 lpszcp = (LPSTR)lpszUrl; /* Relative url */
534 lpszParam = strpbrk(lpszap, ";?");
535 if (lpszParam != NULL)
537 if (!SetUrlComponentValue(&lpUrlComponents->lpszExtraInfo,
538 &lpUrlComponents->dwExtraInfoLength, lpszParam+1, strlen(lpszParam+1)))
544 if (bIsAbsolute) /* Parse <protocol>:[//<net_loc>] */
548 /* Get scheme first. */
549 lpUrlComponents->nScheme = GetInternetScheme(lpszUrl, lpszcp - lpszUrl);
550 if (!SetUrlComponentValue(&lpUrlComponents->lpszScheme,
551 &lpUrlComponents->dwSchemeLength, lpszUrl, lpszcp - lpszUrl))
554 /* Eat ':' in protocol. */
557 /* Skip over slashes. */
569 lpszNetLoc = strpbrk(lpszcp, "/");
573 lpszNetLoc = min(lpszNetLoc, lpszParam);
575 lpszNetLoc = lpszParam;
577 else if (!lpszNetLoc)
578 lpszNetLoc = lpszcp + strlen(lpszcp);
586 /* [<user>[<:password>]@]<host>[:<port>] */
587 /* First find the user and password if they exist */
589 lpszHost = strchr(lpszcp, '@');
590 if (lpszHost == NULL || lpszHost > lpszNetLoc)
592 /* username and password not specified. */
593 SetUrlComponentValue(&lpUrlComponents->lpszUserName,
594 &lpUrlComponents->dwUserNameLength, NULL, 0);
595 SetUrlComponentValue(&lpUrlComponents->lpszPassword,
596 &lpUrlComponents->dwPasswordLength, NULL, 0);
598 else /* Parse out username and password */
600 LPSTR lpszUser = lpszcp;
601 LPSTR lpszPasswd = lpszHost;
603 while (lpszcp < lpszHost)
611 SetUrlComponentValue(&lpUrlComponents->lpszUserName,
612 &lpUrlComponents->dwUserNameLength, lpszUser, lpszPasswd - lpszUser);
614 SetUrlComponentValue(&lpUrlComponents->lpszPassword,
615 &lpUrlComponents->dwPasswordLength,
616 lpszPasswd == lpszHost ? NULL : ++lpszPasswd,
617 lpszHost - lpszPasswd);
619 lpszcp++; /* Advance to beginning of host */
622 /* Parse <host><:port> */
625 lpszPort = lpszNetLoc;
627 while (lpszcp < lpszNetLoc)
635 SetUrlComponentValue(&lpUrlComponents->lpszHostName,
636 &lpUrlComponents->dwHostNameLength, lpszHost, lpszPort - lpszHost);
638 if (lpszPort != lpszNetLoc)
639 lpUrlComponents->nPort = atoi(++lpszPort);
643 /* Here lpszcp points to:
645 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
646 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
648 if (lpszcp != 0 && *lpszcp != '\0' && (!lpszParam || lpszcp < lpszParam))
652 /* Only truncate the parameter list if it's already been saved
653 * in lpUrlComponents->lpszExtraInfo.
655 if (lpszParam && lpUrlComponents->dwExtraInfoLength)
656 len = lpszParam - lpszcp;
659 /* Leave the parameter list in lpszUrlPath. Strip off any trailing
660 * newlines if necessary.
662 LPSTR lpsznewline = strchr (lpszcp, '\n');
663 if (lpsznewline != NULL)
664 len = lpsznewline - lpszcp;
666 len = strlen(lpszcp);
669 if (!SetUrlComponentValue(&lpUrlComponents->lpszUrlPath,
670 &lpUrlComponents->dwUrlPathLength, lpszcp, len))
675 lpUrlComponents->dwUrlPathLength = 0;
678 TRACE("%s: host(%s) path(%s) extra(%s)\n", lpszUrl, lpUrlComponents->lpszHostName,
679 lpUrlComponents->lpszUrlPath, lpUrlComponents->lpszExtraInfo);
685 /***********************************************************************
686 * InternetAttemptConnect (WININET.81)
688 * Attempt to make a connection to the internet
691 * ERROR_SUCCESS on success
692 * Error value on failure
695 INTERNETAPI DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
698 return ERROR_SUCCESS;
702 /***********************************************************************
703 * InternetCanonicalizeUrlA (WININET.85)
705 * Escape unsafe characters and spaces
712 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
713 LPDWORD lpdwBufferLength, DWORD dwFlags)
715 BOOL bSuccess = FALSE;
721 strncpy(lpszBuffer, lpszUrl, *lpdwBufferLength);
722 *lpdwBufferLength = strlen(lpszBuffer);
730 /***********************************************************************
731 * InternetSetStatusCallback (WININET.133)
733 * Sets up a callback function which is called as progress is made
734 * during an operation.
737 * Previous callback or NULL on success
738 * INTERNET_INVALID_STATUS_CALLBACK on failure
741 INTERNETAPI INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallback(
742 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
744 INTERNET_STATUS_CALLBACK retVal;
745 LPWININETAPPINFOA lpwai = (LPWININETAPPINFOA)hInternet;
747 TRACE("0x%08lx\n", (ULONG)hInternet);
748 if (lpwai->hdr.htype != WH_HINIT)
749 return INTERNET_INVALID_STATUS_CALLBACK;
751 retVal = lpwai->lpfnStatusCB;
752 lpwai->lpfnStatusCB = lpfnIntCB;
758 /***********************************************************************
759 * InternetWriteFile (WININET.138)
761 * Write data to an open internet file
768 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer ,
769 DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
772 int nSocket = INVALID_SOCKET;
773 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hFile;
782 nSocket = ((LPWININETHTTPREQA)hFile)->nSocketFD;
786 nSocket = ((LPWININETFILE)hFile)->nDataSocket;
793 if (INVALID_SOCKET != nSocket)
795 *lpdwNumOfBytesWritten = INTERNET_WriteDataToStream(nSocket, lpBuffer, dwNumOfBytesToWrite);
796 if (*lpdwNumOfBytesWritten < 0)
797 *lpdwNumOfBytesWritten = 0;
806 /***********************************************************************
807 * InternetReadFile (WININET.121)
809 * Read data from an open internet file
816 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
817 DWORD dwNumOfBytesToRead, LPDWORD dwNumOfBytesRead)
820 int nSocket = INVALID_SOCKET;
821 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hFile;
830 nSocket = ((LPWININETHTTPREQA)hFile)->nSocketFD;
834 nSocket = ((LPWININETFILE)hFile)->nDataSocket;
841 if (INVALID_SOCKET != nSocket)
843 *dwNumOfBytesRead = INTERNET_ReadDataFromStream(nSocket, lpBuffer, dwNumOfBytesToRead);
844 if (*dwNumOfBytesRead < 0)
845 *dwNumOfBytesRead = 0;
854 /***********************************************************************
855 * InternetQueryOptionA
857 * Queries an options on the specified handle
864 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
865 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
867 LPWININETHANDLEHEADER lpwhh;
868 BOOL bSuccess = FALSE;
870 TRACE("0x%08lx\n", dwOption);
872 if (NULL == hInternet)
874 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
878 lpwhh = (LPWININETHANDLEHEADER) hInternet;
882 case INTERNET_OPTION_HANDLE_TYPE:
884 ULONG type = lpwhh->htype;
885 TRACE("INTERNET_OPTION_HANDLE_TYPE: %ld\n", type);
887 if (*lpdwBufferLength < sizeof(ULONG))
888 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
891 memcpy(lpBuffer, &type, sizeof(ULONG));
892 *lpdwBufferLength = sizeof(ULONG);
908 /***********************************************************************
909 * GetInternetScheme (internal)
915 * INTERNET_SCHEME_UNKNOWN on failure
918 INTERNET_SCHEME GetInternetScheme(LPCSTR lpszScheme, INT nMaxCmp)
921 return INTERNET_SCHEME_UNKNOWN;
923 if (!strncasecmp("ftp", lpszScheme, nMaxCmp))
924 return INTERNET_SCHEME_FTP;
925 else if (!strncasecmp("gopher", lpszScheme, nMaxCmp))
926 return INTERNET_SCHEME_GOPHER;
927 else if (!strncasecmp("http", lpszScheme, nMaxCmp))
928 return INTERNET_SCHEME_HTTP;
929 else if (!strncasecmp("https", lpszScheme, nMaxCmp))
930 return INTERNET_SCHEME_HTTPS;
931 else if (!strncasecmp("file", lpszScheme, nMaxCmp))
932 return INTERNET_SCHEME_FILE;
933 else if (!strncasecmp("news", lpszScheme, nMaxCmp))
934 return INTERNET_SCHEME_NEWS;
935 else if (!strncasecmp("mailto", lpszScheme, nMaxCmp))
936 return INTERNET_SCHEME_MAILTO;
938 return INTERNET_SCHEME_UNKNOWN;
941 /***********************************************************************
942 * InternetCheckConnectionA
944 * Pings a requested host to check internet connection
948 * TRUE on success and FALSE on failure. if a failures then
949 * ERROR_NOT_CONNECTED is places into GetLastError
952 BOOL WINAPI InternetCheckConnectionA( LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
955 * this is a kludge which runs the resident ping program and reads the output.
957 * Anyone have a better idea?
966 * Crack or set the Address
971 * According to the doc we are supost to use the ip for the next
972 * server in the WnInet internal server database. I have
973 * no idea what that is or how to get it.
975 * So someone needs to implement this.
977 FIXME("Unimplemented with URL of NULL");
982 URL_COMPONENTSA componets;
984 ZeroMemory(&componets,sizeof(URL_COMPONENTSA));
985 componets.lpszHostName = (LPSTR)&host;
986 componets.dwHostNameLength = 1024;
988 if (!InternetCrackUrlA(lpszUrl,0,0,&componets))
991 TRACE("host name : %s\n",componets.lpszHostName);
995 * Build our ping command
997 strcpy(command,"ping -w 1 ");
998 strcat(command,host);
999 strcat(command," >/dev/null 2>/dev/null");
1001 TRACE("Ping command is : %s\n",command);
1003 status = system(command);
1005 TRACE("Ping returned a code of %i \n",status);
1007 /* Ping return code of 0 indicates success */
1014 SetLastError(ERROR_NOT_CONNECTED);
1021 /***********************************************************************
1022 * INTERNET_WriteDataToStream (internal)
1024 * Send data to server
1028 * number of characters sent on success
1031 int INTERNET_WriteDataToStream(int nDataSocket, LPCVOID Buffer, DWORD BytesToWrite)
1033 if (INVALID_SOCKET == nDataSocket)
1034 return SOCKET_ERROR;
1036 return send(nDataSocket, Buffer, BytesToWrite, 0);
1040 /***********************************************************************
1041 * INTERNET_ReadDataFromStream (internal)
1043 * Read data from http server
1047 * number of characters sent on success
1050 int INTERNET_ReadDataFromStream(int nDataSocket, LPVOID Buffer, DWORD BytesToRead)
1052 if (INVALID_SOCKET == nDataSocket)
1053 return SOCKET_ERROR;
1055 return recv(nDataSocket, Buffer, BytesToRead, 0);
1059 /***********************************************************************
1060 * INTERNET_SetLastError (internal)
1062 * Set last thread specific error
1067 void INTERNET_SetLastError(DWORD dwError)
1069 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
1071 SetLastError(dwError);
1072 lpwite->dwError = dwError;
1076 /***********************************************************************
1077 * INTERNET_GetLastError (internal)
1079 * Get last thread specific error
1084 DWORD INTERNET_GetLastError()
1086 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
1087 return lpwite->dwError;
1091 /***********************************************************************
1092 * INTERNET_WorkerThreadFunc (internal)
1094 * Worker thread execution function
1099 DWORD INTERNET_WorkerThreadFunc(LPVOID *lpvParam)
1105 dwWaitRes = WaitForMultipleObjects(2, hEventArray, FALSE, MAX_IDLE_WORKER);
1107 if (dwWaitRes == WAIT_OBJECT_0 + 1)
1108 INTERNET_ExecuteWork();
1112 InterlockedIncrement(&dwNumIdleThreads);
1115 InterlockedDecrement(&dwNumIdleThreads);
1116 InterlockedDecrement(&dwNumThreads);
1117 TRACE("Worker thread exiting\n");
1122 /***********************************************************************
1123 * INTERNET_InsertWorkRequest (internal)
1125 * Insert work request into queue
1130 BOOL INTERNET_InsertWorkRequest(LPWORKREQUEST lpWorkRequest)
1132 BOOL bSuccess = FALSE;
1133 LPWORKREQUEST lpNewRequest;
1137 lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
1140 memcpy(lpNewRequest, lpWorkRequest, sizeof(WORKREQUEST));
1141 lpNewRequest->prev = NULL;
1143 EnterCriticalSection(&csQueue);
1145 lpNewRequest->next = lpWorkQueueTail;
1146 if (lpWorkQueueTail)
1147 lpWorkQueueTail->prev = lpNewRequest;
1148 lpWorkQueueTail = lpNewRequest;
1149 if (!lpHeadWorkQueue)
1150 lpHeadWorkQueue = lpWorkQueueTail;
1152 LeaveCriticalSection(&csQueue);
1161 /***********************************************************************
1162 * INTERNET_GetWorkRequest (internal)
1164 * Retrieves work request from queue
1169 BOOL INTERNET_GetWorkRequest(LPWORKREQUEST lpWorkRequest)
1171 BOOL bSuccess = FALSE;
1172 LPWORKREQUEST lpRequest = NULL;
1176 EnterCriticalSection(&csQueue);
1178 if (lpHeadWorkQueue)
1180 lpRequest = lpHeadWorkQueue;
1181 lpHeadWorkQueue = lpHeadWorkQueue->prev;
1182 if (lpRequest == lpWorkQueueTail)
1183 lpWorkQueueTail = lpHeadWorkQueue;
1186 LeaveCriticalSection(&csQueue);
1190 memcpy(lpWorkRequest, lpRequest, sizeof(WORKREQUEST));
1191 HeapFree(GetProcessHeap(), 0, lpRequest);
1199 /***********************************************************************
1200 * INTERNET_AsyncCall (internal)
1202 * Retrieves work request from queue
1207 BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
1211 BOOL bSuccess = FALSE;
1215 if (InterlockedDecrement(&dwNumIdleThreads) < 0)
1217 InterlockedIncrement(&dwNumIdleThreads);
1219 if (InterlockedIncrement(&dwNumThreads) > MAX_WORKER_THREADS ||
1220 !(hThread = CreateThread(NULL, 0,
1221 (LPTHREAD_START_ROUTINE)INTERNET_WorkerThreadFunc, NULL, 0, &dwTID)))
1223 InterlockedDecrement(&dwNumThreads);
1224 INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
1228 TRACE("Created new thread\n");
1232 INTERNET_InsertWorkRequest(lpWorkRequest);
1233 SetEvent(hWorkEvent);
1241 /***********************************************************************
1242 * INTERNET_ExecuteWork (internal)
1247 VOID INTERNET_ExecuteWork()
1249 WORKREQUEST workRequest;
1253 if (INTERNET_GetWorkRequest(&workRequest))
1255 switch (workRequest.asyncall)
1258 FTP_FtpPutFileA((HINTERNET)workRequest.HFTPSESSION, (LPCSTR)workRequest.LPSZLOCALFILE,
1259 (LPCSTR)workRequest.LPSZNEWREMOTEFILE, workRequest.DWFLAGS, workRequest.DWCONTEXT);
1260 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZLOCALFILE);
1261 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZNEWREMOTEFILE);
1264 case FTPSETCURRENTDIRECTORYA:
1265 FTP_FtpSetCurrentDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1266 (LPCSTR)workRequest.LPSZDIRECTORY);
1267 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1270 case FTPCREATEDIRECTORYA:
1271 FTP_FtpCreateDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1272 (LPCSTR)workRequest.LPSZDIRECTORY);
1273 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1276 case FTPFINDFIRSTFILEA:
1277 FTP_FtpFindFirstFileA((HINTERNET)workRequest.HFTPSESSION,
1278 (LPCSTR)workRequest.LPSZSEARCHFILE,
1279 (LPWIN32_FIND_DATAA)workRequest.LPFINDFILEDATA, workRequest.DWFLAGS,
1280 workRequest.DWCONTEXT);
1281 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZSEARCHFILE);
1284 case FTPGETCURRENTDIRECTORYA:
1285 FTP_FtpGetCurrentDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1286 (LPSTR)workRequest.LPSZDIRECTORY, (LPDWORD)workRequest.LPDWDIRECTORY);
1290 FTP_FtpOpenFileA((HINTERNET)workRequest.HFTPSESSION,
1291 (LPCSTR)workRequest.LPSZFILENAME,
1292 workRequest.FDWACCESS,
1293 workRequest.DWFLAGS,
1294 workRequest.DWCONTEXT);
1295 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZFILENAME);
1299 FTP_FtpGetFileA((HINTERNET)workRequest.HFTPSESSION,
1300 (LPCSTR)workRequest.LPSZREMOTEFILE,
1301 (LPCSTR)workRequest.LPSZNEWFILE,
1302 (BOOL)workRequest.FFAILIFEXISTS,
1303 workRequest.DWLOCALFLAGSATTRIBUTE,
1304 workRequest.DWFLAGS,
1305 workRequest.DWCONTEXT);
1306 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZREMOTEFILE);
1307 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZNEWFILE);
1310 case FTPDELETEFILEA:
1311 FTP_FtpDeleteFileA((HINTERNET)workRequest.HFTPSESSION,
1312 (LPCSTR)workRequest.LPSZFILENAME);
1313 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZFILENAME);
1316 case FTPREMOVEDIRECTORYA:
1317 FTP_FtpRemoveDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1318 (LPCSTR)workRequest.LPSZDIRECTORY);
1319 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1322 case FTPRENAMEFILEA:
1323 FTP_FtpRenameFileA((HINTERNET)workRequest.HFTPSESSION,
1324 (LPCSTR)workRequest.LPSZSRCFILE,
1325 (LPCSTR)workRequest.LPSZDESTFILE);
1326 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZSRCFILE);
1327 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDESTFILE);
1330 case INTERNETFINDNEXTA:
1331 INTERNET_FindNextFileA((HINTERNET)workRequest.HFTPSESSION,
1332 (LPWIN32_FIND_DATAA)workRequest.LPFINDFILEDATA);
1335 case HTTPSENDREQUESTA:
1336 HTTP_HttpSendRequestA((HINTERNET)workRequest.HFTPSESSION,
1337 (LPCSTR)workRequest.LPSZHEADER,
1338 workRequest.DWHEADERLENGTH,
1339 (LPVOID)workRequest.LPOPTIONAL,
1340 workRequest.DWOPTIONALLENGTH);
1341 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZHEADER);
1344 case HTTPOPENREQUESTA:
1345 HTTP_HttpOpenRequestA((HINTERNET)workRequest.HFTPSESSION,
1346 (LPCSTR)workRequest.LPSZVERB,
1347 (LPCSTR)workRequest.LPSZOBJECTNAME,
1348 (LPCSTR)workRequest.LPSZVERSION,
1349 (LPCSTR)workRequest.LPSZREFERRER,
1350 (LPCSTR*)workRequest.LPSZACCEPTTYPES,
1351 workRequest.DWFLAGS,
1352 workRequest.DWCONTEXT);
1353 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZVERB);
1354 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZOBJECTNAME);
1355 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZVERSION);
1356 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZREFERRER);
1364 /***********************************************************************
1365 * INTERNET_GetResponseBuffer
1370 LPSTR INTERNET_GetResponseBuffer()
1372 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
1373 return lpwite->response;
1377 /***********************************************************************
1378 * INTERNET_GetNextLine (internal)
1380 * Parse next line in directory string listing
1383 * Pointer to begining of next line
1388 LPSTR INTERNET_GetNextLine(INT nSocket, LPSTR lpszBuffer, LPDWORD dwBuffer)
1392 BOOL bSuccess = FALSE;
1398 FD_SET(nSocket, &infd);
1399 tv.tv_sec=RESPONSE_TIMEOUT;
1402 while (nRecv < *dwBuffer)
1404 if (select(nSocket+1,&infd,NULL,NULL,&tv) > 0)
1406 if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
1408 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1412 if (lpszBuffer[nRecv] == '\n')
1417 if (lpszBuffer[nRecv] != '\r')
1422 INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
1430 lpszBuffer[nRecv] = '\0';
1431 *dwBuffer = nRecv - 1;
1432 TRACE(":%d %s\n", nRecv, lpszBuffer);