4 * Copyright 1999 Corel Corporation
13 #include <sys/types.h>
14 #ifdef HAVE_SYS_SOCKET_H
15 # include <sys/socket.h>
23 #include "debugtools.h"
30 DEFAULT_DEBUG_CHANNEL(wininet);
32 #define MAX_IDLE_WORKER 1000*60*1
33 #define MAX_WORKER_THREADS 10
34 #define RESPONSE_TIMEOUT 30
36 #define GET_HWININET_FROM_LPWININETFINDNEXT(lpwh) \
37 (LPWININETAPPINFOA)(((LPWININETFTPSESSIONA)(lpwh->hdr.lpwhparent))->hdr.lpwhparent)
42 CHAR response[MAX_REPLY_LEN];
43 } WITHREADERROR, *LPWITHREADERROR;
45 INTERNET_SCHEME GetInternetScheme(LPCSTR lpszScheme, INT nMaxCmp);
46 BOOL WINAPI INTERNET_FindNextFileA(HINTERNET hFind, LPVOID lpvFindData);
47 VOID INTERNET_ExecuteWork();
49 DWORD g_dwTlsErrIndex = TLS_OUT_OF_INDEXES;
51 DWORD dwNumIdleThreads;
52 HANDLE hEventArray[2];
53 #define hQuitEvent hEventArray[0]
54 #define hWorkEvent hEventArray[1]
55 CRITICAL_SECTION csQueue;
56 LPWORKREQUEST lpHeadWorkQueue;
57 LPWORKREQUEST lpWorkQueueTail;
59 /***********************************************************************
60 * WININET_LibMain [Internal] Initializes the internal 'WININET.DLL'.
63 * hinstDLL [I] handle to the DLL's instance
65 * lpvReserved [I] reserved, must be NULL
73 WININET_LibMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
75 TRACE("%x,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
78 case DLL_PROCESS_ATTACH:
80 g_dwTlsErrIndex = TlsAlloc();
82 if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
85 hQuitEvent = CreateEventA(0, TRUE, FALSE, NULL);
86 hWorkEvent = CreateEventA(0, FALSE, FALSE, NULL);
87 InitializeCriticalSection(&csQueue);
92 case DLL_THREAD_ATTACH:
94 LPWITHREADERROR lpwite = HeapAlloc(GetProcessHeap(), 0, sizeof(WITHREADERROR));
98 TlsSetValue(g_dwTlsErrIndex, (LPVOID)lpwite);
102 case DLL_THREAD_DETACH:
103 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
105 LPVOID lpwite = TlsGetValue(g_dwTlsErrIndex);
107 HeapFree(GetProcessHeap(), 0, lpwite);
111 case DLL_PROCESS_DETACH:
113 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
115 HeapFree(GetProcessHeap(), 0, TlsGetValue(g_dwTlsErrIndex));
116 TlsFree(g_dwTlsErrIndex);
119 SetEvent(hQuitEvent);
121 CloseHandle(hQuitEvent);
122 CloseHandle(hWorkEvent);
123 DeleteCriticalSection(&csQueue);
131 /***********************************************************************
132 * InternetOpenA (WININET.113)
134 * Per-application initialization of wininet
137 * HINTERNET on success
141 INTERNETAPI HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent,
142 DWORD dwAccessType, LPCSTR lpszProxy,
143 LPCSTR lpszProxyBypass, DWORD dwFlags)
145 LPWININETAPPINFOA lpwai = NULL;
149 /* Clear any error information */
150 INTERNET_SetLastError(0);
152 lpwai = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETAPPINFOA));
154 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
157 memset(lpwai, 0, sizeof(WININETAPPINFOA));
158 lpwai->hdr.htype = WH_HINIT;
159 lpwai->hdr.lpwhparent = NULL;
160 lpwai->hdr.dwFlags = dwFlags;
161 if (NULL != lpszAgent)
162 lpwai->lpszAgent = HEAP_strdupA(GetProcessHeap(),0,lpszAgent);
163 if (NULL != lpszProxy)
164 lpwai->lpszProxy = HEAP_strdupA(GetProcessHeap(),0,lpszProxy);
165 if (NULL != lpszProxyBypass)
166 lpwai->lpszProxyBypass = HEAP_strdupA(GetProcessHeap(),0,lpszProxyBypass);
167 lpwai->dwAccessType = dwAccessType;
170 return (HINTERNET)lpwai;
174 /***********************************************************************
175 * InternetGetLastResponseInfoA (WININET.108)
177 * Return last wininet error description on the calling thread
180 * TRUE on success of writting to buffer
184 BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
185 LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
187 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
191 *lpdwError = lpwite->dwError;
194 strncpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
195 *lpdwBufferLength = strlen(lpszBuffer);
198 *lpdwBufferLength = 0;
204 /***********************************************************************
205 * InternetGetConnectedState (WININET.103)
207 * Return connected state
211 * if lpdwStatus is not null, return the status (off line,
212 * modem, lan...) in it.
213 * FALSE if not connected
215 BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
222 /***********************************************************************
223 * InternetConnectA (WININET.93)
225 * Open a ftp, gopher or http session
228 * HINTERNET a session handle on success
232 INTERNETAPI HINTERNET WINAPI InternetConnectA(HINTERNET hInternet,
233 LPCSTR lpszServerName, INTERNET_PORT nServerPort,
234 LPCSTR lpszUserName, LPCSTR lpszPassword,
235 DWORD dwService, DWORD dwFlags, DWORD dwContext)
237 HINTERNET rc = (HINTERNET) NULL;
241 /* Clear any error information */
242 INTERNET_SetLastError(0);
246 case INTERNET_SERVICE_FTP:
247 rc = FTP_Connect(hInternet, lpszServerName, nServerPort,
248 lpszUserName, lpszPassword, dwFlags, dwContext);
251 case INTERNET_SERVICE_HTTP:
252 rc = HTTP_Connect(hInternet, lpszServerName, nServerPort,
253 lpszUserName, lpszPassword, dwFlags, dwContext);
256 case INTERNET_SERVICE_GOPHER:
264 /***********************************************************************
265 * InternetFindNextFileA (WININET.102)
267 * Continues a file search from a previous call to FindFirstFile
274 BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
276 LPWININETAPPINFOA hIC = NULL;
277 LPWININETFINDNEXTA lpwh = (LPWININETFINDNEXTA) hFind;
281 if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
283 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
287 hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
288 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
290 WORKREQUEST workRequest;
292 workRequest.asyncall = INTERNETFINDNEXTA;
293 workRequest.HFTPSESSION = (DWORD)hFind;
294 workRequest.LPFINDFILEDATA = (DWORD)lpvFindData;
296 return INTERNET_AsyncCall(&workRequest);
300 return INTERNET_FindNextFileA(hFind, lpvFindData);
304 /***********************************************************************
305 * INTERNET_FindNextFileA (Internal)
307 * Continues a file search from a previous call to FindFirstFile
314 BOOL WINAPI INTERNET_FindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
316 BOOL bSuccess = TRUE;
317 LPWININETAPPINFOA hIC = NULL;
318 LPWIN32_FIND_DATAA lpFindFileData;
319 LPWININETFINDNEXTA lpwh = (LPWININETFINDNEXTA) hFind;
323 if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
325 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
329 /* Clear any error information */
330 INTERNET_SetLastError(0);
332 if (lpwh->hdr.lpwhparent->htype != WH_HFTPSESSION)
334 FIXME("Only FTP find next supported\n");
335 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
339 TRACE("index(%d) size(%ld)\n", lpwh->index, lpwh->size);
341 lpFindFileData = (LPWIN32_FIND_DATAA) lpvFindData;
342 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
344 if (lpwh->index >= lpwh->size)
346 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
351 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
354 TRACE("\nName: %s\nSize: %ld\n", lpFindFileData->cFileName, lpFindFileData->nFileSizeLow);
358 hIC = GET_HWININET_FROM_LPWININETFINDNEXT(lpwh);
359 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
361 INTERNET_ASYNC_RESULT iar;
363 iar.dwResult = (DWORD)bSuccess;
364 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
366 hIC->lpfnStatusCB(hFind, lpwh->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
367 &iar, sizeof(INTERNET_ASYNC_RESULT));
374 /***********************************************************************
375 * INTERNET_CloseHandle (internal)
377 * Close internet handle
383 VOID INTERNET_CloseHandle(LPWININETAPPINFOA lpwai)
385 if (lpwai->lpszAgent)
386 HeapFree(GetProcessHeap(), 0, lpwai->lpszAgent);
388 if (lpwai->lpszProxy)
389 HeapFree(GetProcessHeap(), 0, lpwai->lpszProxy);
391 if (lpwai->lpszProxyBypass)
392 HeapFree(GetProcessHeap(), 0, lpwai->lpszProxyBypass);
394 HeapFree(GetProcessHeap(), 0, lpwai);
398 /***********************************************************************
399 * InternetCloseHandle (WININET.89)
401 * Generic close handle function
408 BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
411 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hInternet;
417 /* Clear any error information */
418 INTERNET_SetLastError(0);
423 INTERNET_CloseHandle((LPWININETAPPINFOA) lpwh);
426 case WH_HHTTPSESSION:
427 HTTP_CloseHTTPSessionHandle((LPWININETHTTPSESSIONA) lpwh);
431 HTTP_CloseHTTPRequestHandle((LPWININETHTTPREQA) lpwh);
435 retval = FTP_CloseSessionHandle((LPWININETFTPSESSIONA) lpwh);
439 retval = FTP_CloseFindNextHandle((LPWININETFINDNEXTA) lpwh);
450 /***********************************************************************
451 * SetUrlComponentValue (Internal)
453 * Helper function for InternetCrackUrlA
460 BOOL SetUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentLen, LPCSTR lpszStart, INT len)
462 TRACE("%s (%d)\n", lpszStart, len);
464 if (*dwComponentLen != 0)
466 if (*lppszComponent == NULL)
468 *lppszComponent = (LPSTR)lpszStart;
469 *dwComponentLen = len;
473 INT ncpylen = min((*dwComponentLen)-1, len);
474 strncpy(*lppszComponent, lpszStart, ncpylen);
475 (*lppszComponent)[ncpylen] = '\0';
476 *dwComponentLen = ncpylen;
484 /***********************************************************************
485 * InternetCrackUrlA (WININET.95)
487 * Break up URL into its components
489 * TODO: Hadnle dwFlags
496 BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
497 LPURL_COMPONENTSA lpUrlComponents)
501 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
504 LPSTR lpszParam = NULL;
505 BOOL bIsAbsolute = FALSE;
506 LPSTR lpszap = (char*)lpszUrl;
511 /* Determine if the URI is absolute. */
512 while (*lpszap != '\0')
514 if (isalnum(*lpszap))
519 if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
526 lpszcp = (LPSTR)lpszUrl; /* Relative url */
533 lpszParam = strpbrk(lpszap, ";?");
534 if (lpszParam != NULL)
536 if (!SetUrlComponentValue(&lpUrlComponents->lpszExtraInfo,
537 &lpUrlComponents->dwExtraInfoLength, lpszParam+1, strlen(lpszParam+1)))
543 if (bIsAbsolute) /* Parse <protocol>:[//<net_loc>] */
547 /* Get scheme first. */
548 lpUrlComponents->nScheme = GetInternetScheme(lpszUrl, lpszcp - lpszUrl);
549 if (!SetUrlComponentValue(&lpUrlComponents->lpszScheme,
550 &lpUrlComponents->dwSchemeLength, lpszUrl, lpszcp - lpszUrl))
553 /* Eat ':' in protocol. */
556 /* Skip over slashes. */
568 lpszNetLoc = strpbrk(lpszcp, "/");
572 lpszNetLoc = min(lpszNetLoc, lpszParam);
574 lpszNetLoc = lpszParam;
576 else if (!lpszNetLoc)
577 lpszNetLoc = lpszcp + strlen(lpszcp);
585 /* [<user>[<:password>]@]<host>[:<port>] */
586 /* First find the user and password if they exist */
588 lpszHost = strchr(lpszcp, '@');
589 if (lpszHost == NULL || lpszHost > lpszNetLoc)
591 /* username and password not specified. */
592 SetUrlComponentValue(&lpUrlComponents->lpszUserName,
593 &lpUrlComponents->dwUserNameLength, NULL, 0);
594 SetUrlComponentValue(&lpUrlComponents->lpszPassword,
595 &lpUrlComponents->dwPasswordLength, NULL, 0);
597 else /* Parse out username and password */
599 LPSTR lpszUser = lpszcp;
600 LPSTR lpszPasswd = lpszHost;
602 while (lpszcp < lpszHost)
610 SetUrlComponentValue(&lpUrlComponents->lpszUserName,
611 &lpUrlComponents->dwUserNameLength, lpszUser, lpszPasswd - lpszUser);
613 SetUrlComponentValue(&lpUrlComponents->lpszPassword,
614 &lpUrlComponents->dwPasswordLength,
615 lpszPasswd == lpszHost ? NULL : ++lpszPasswd,
616 lpszHost - lpszPasswd);
618 lpszcp++; /* Advance to beginning of host */
621 /* Parse <host><:port> */
624 lpszPort = lpszNetLoc;
626 while (lpszcp < lpszNetLoc)
634 SetUrlComponentValue(&lpUrlComponents->lpszHostName,
635 &lpUrlComponents->dwHostNameLength, lpszHost, lpszPort - lpszHost);
637 if (lpszPort != lpszNetLoc)
638 lpUrlComponents->nPort = atoi(++lpszPort);
642 /* Here lpszcp points to:
644 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
645 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
647 if (lpszcp != 0 && *lpszcp != '\0' && (!lpszParam || lpszcp < lpszParam))
651 /* Only truncate the parameter list if it's already been saved
652 * in lpUrlComponents->lpszExtraInfo.
654 if (lpszParam && lpUrlComponents->dwExtraInfoLength)
655 len = lpszParam - lpszcp;
658 /* Leave the parameter list in lpszUrlPath. Strip off any trailing
659 * newlines if necessary.
661 LPSTR lpsznewline = strchr (lpszcp, '\n');
662 if (lpsznewline != NULL)
663 len = lpsznewline - lpszcp;
665 len = strlen(lpszcp);
668 if (!SetUrlComponentValue(&lpUrlComponents->lpszUrlPath,
669 &lpUrlComponents->dwUrlPathLength, lpszcp, len))
674 lpUrlComponents->dwUrlPathLength = 0;
677 TRACE("%s: host(%s) path(%s) extra(%s)\n", lpszUrl, lpUrlComponents->lpszHostName,
678 lpUrlComponents->lpszUrlPath, lpUrlComponents->lpszExtraInfo);
684 /***********************************************************************
685 * InternetAttemptConnect (WININET.81)
687 * Attempt to make a connection to the internet
690 * ERROR_SUCCESS on success
691 * Error value on failure
694 INTERNETAPI DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
697 return ERROR_SUCCESS;
701 /***********************************************************************
702 * InternetCanonicalizeUrlA (WININET.85)
704 * Escape unsafe characters and spaces
711 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
712 LPDWORD lpdwBufferLength, DWORD dwFlags)
714 BOOL bSuccess = FALSE;
720 strncpy(lpszBuffer, lpszUrl, *lpdwBufferLength);
721 *lpdwBufferLength = strlen(lpszBuffer);
729 /***********************************************************************
730 * InternetSetStatusCallback (WININET.133)
732 * Sets up a callback function which is called as progress is made
733 * during an operation.
736 * Previous callback or NULL on success
737 * INTERNET_INVALID_STATUS_CALLBACK on failure
740 INTERNETAPI INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallback(
741 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
743 INTERNET_STATUS_CALLBACK retVal;
744 LPWININETAPPINFOA lpwai = (LPWININETAPPINFOA)hInternet;
746 TRACE("0x%08lx\n", (ULONG)hInternet);
747 if (lpwai->hdr.htype != WH_HINIT)
748 return INTERNET_INVALID_STATUS_CALLBACK;
750 retVal = lpwai->lpfnStatusCB;
751 lpwai->lpfnStatusCB = lpfnIntCB;
757 /***********************************************************************
758 * InternetWriteFile (WININET.138)
760 * Write data to an open internet file
767 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer ,
768 DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
771 int nSocket = INVALID_SOCKET;
772 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hFile;
781 nSocket = ((LPWININETHTTPREQA)hFile)->nSocketFD;
785 nSocket = ((LPWININETFILE)hFile)->nDataSocket;
792 if (INVALID_SOCKET != nSocket)
794 *lpdwNumOfBytesWritten = INTERNET_WriteDataToStream(nSocket, lpBuffer, dwNumOfBytesToWrite);
795 if (*lpdwNumOfBytesWritten < 0)
796 *lpdwNumOfBytesWritten = 0;
805 /***********************************************************************
806 * InternetReadFile (WININET.121)
808 * Read data from an open internet file
815 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
816 DWORD dwNumOfBytesToRead, LPDWORD dwNumOfBytesRead)
819 int nSocket = INVALID_SOCKET;
820 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hFile;
829 nSocket = ((LPWININETHTTPREQA)hFile)->nSocketFD;
833 nSocket = ((LPWININETFILE)hFile)->nDataSocket;
840 if (INVALID_SOCKET != nSocket)
842 *dwNumOfBytesRead = INTERNET_ReadDataFromStream(nSocket, lpBuffer, dwNumOfBytesToRead);
843 if (*dwNumOfBytesRead < 0)
844 *dwNumOfBytesRead = 0;
853 /***********************************************************************
854 * InternetQueryOptionA
856 * Queries an options on the specified handle
863 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
864 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
866 LPWININETHANDLEHEADER lpwhh;
867 BOOL bSuccess = FALSE;
869 TRACE("0x%08lx\n", dwOption);
871 if (NULL == hInternet)
873 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
877 lpwhh = (LPWININETHANDLEHEADER) hInternet;
881 case INTERNET_OPTION_HANDLE_TYPE:
883 ULONG type = lpwhh->htype;
884 TRACE("INTERNET_OPTION_HANDLE_TYPE: %ld\n", type);
886 if (*lpdwBufferLength < sizeof(ULONG))
887 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
890 memcpy(lpBuffer, &type, sizeof(ULONG));
891 *lpdwBufferLength = sizeof(ULONG);
907 /***********************************************************************
908 * GetInternetScheme (internal)
914 * INTERNET_SCHEME_UNKNOWN on failure
917 INTERNET_SCHEME GetInternetScheme(LPCSTR lpszScheme, INT nMaxCmp)
920 return INTERNET_SCHEME_UNKNOWN;
922 if (!strncasecmp("ftp", lpszScheme, nMaxCmp))
923 return INTERNET_SCHEME_FTP;
924 else if (!strncasecmp("gopher", lpszScheme, nMaxCmp))
925 return INTERNET_SCHEME_GOPHER;
926 else if (!strncasecmp("http", lpszScheme, nMaxCmp))
927 return INTERNET_SCHEME_HTTP;
928 else if (!strncasecmp("https", lpszScheme, nMaxCmp))
929 return INTERNET_SCHEME_HTTPS;
930 else if (!strncasecmp("file", lpszScheme, nMaxCmp))
931 return INTERNET_SCHEME_FILE;
932 else if (!strncasecmp("news", lpszScheme, nMaxCmp))
933 return INTERNET_SCHEME_NEWS;
934 else if (!strncasecmp("mailto", lpszScheme, nMaxCmp))
935 return INTERNET_SCHEME_MAILTO;
937 return INTERNET_SCHEME_UNKNOWN;
940 /***********************************************************************
941 * InternetCheckConnectionA
943 * Pings a requested host to check internet connection
947 * TRUE on success and FALSE on failure. if a failures then
948 * ERROR_NOT_CONNECTED is places into GetLastError
951 BOOL WINAPI InternetCheckConnectionA( LPCSTR lpszUrl, DWORD dwFlags, DWORD dwReserved )
954 * this is a kludge which runs the resident ping program and reads the output.
956 * Anyone have a better idea?
965 * Crack or set the Address
970 * According to the doc we are supost to use the ip for the next
971 * server in the WnInet internal server database. I have
972 * no idea what that is or how to get it.
974 * So someone needs to implement this.
976 FIXME("Unimplemented with URL of NULL");
981 URL_COMPONENTSA componets;
983 ZeroMemory(&componets,sizeof(URL_COMPONENTSA));
984 componets.lpszHostName = (LPSTR)&host;
985 componets.dwHostNameLength = 1024;
987 if (!InternetCrackUrlA(lpszUrl,0,0,&componets))
990 TRACE("host name : %s\n",componets.lpszHostName);
994 * Build our ping command
996 strcpy(command,"ping -w 1 ");
997 strcat(command,host);
998 strcat(command," >/dev/null 2>/dev/null");
1000 TRACE("Ping command is : %s\n",command);
1002 status = system(command);
1004 TRACE("Ping returned a code of %i \n",status);
1006 /* Ping return code of 0 indicates success */
1013 SetLastError(ERROR_NOT_CONNECTED);
1020 /***********************************************************************
1021 * INTERNET_WriteDataToStream (internal)
1023 * Send data to server
1027 * number of characters sent on success
1030 int INTERNET_WriteDataToStream(int nDataSocket, LPCVOID Buffer, DWORD BytesToWrite)
1032 if (INVALID_SOCKET == nDataSocket)
1033 return SOCKET_ERROR;
1035 return send(nDataSocket, Buffer, BytesToWrite, 0);
1039 /***********************************************************************
1040 * INTERNET_ReadDataFromStream (internal)
1042 * Read data from http server
1046 * number of characters sent on success
1049 int INTERNET_ReadDataFromStream(int nDataSocket, LPVOID Buffer, DWORD BytesToRead)
1051 if (INVALID_SOCKET == nDataSocket)
1052 return SOCKET_ERROR;
1054 return recv(nDataSocket, Buffer, BytesToRead, 0);
1058 /***********************************************************************
1059 * INTERNET_SetLastError (internal)
1061 * Set last thread specific error
1066 void INTERNET_SetLastError(DWORD dwError)
1068 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
1070 SetLastError(dwError);
1071 lpwite->dwError = dwError;
1075 /***********************************************************************
1076 * INTERNET_GetLastError (internal)
1078 * Get last thread specific error
1083 DWORD INTERNET_GetLastError()
1085 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
1086 return lpwite->dwError;
1090 /***********************************************************************
1091 * INTERNET_WorkerThreadFunc (internal)
1093 * Worker thread execution function
1098 DWORD INTERNET_WorkerThreadFunc(LPVOID *lpvParam)
1104 dwWaitRes = WaitForMultipleObjects(2, hEventArray, FALSE, MAX_IDLE_WORKER);
1106 if (dwWaitRes == WAIT_OBJECT_0 + 1)
1107 INTERNET_ExecuteWork();
1111 InterlockedIncrement(&dwNumIdleThreads);
1114 InterlockedDecrement(&dwNumIdleThreads);
1115 InterlockedDecrement(&dwNumThreads);
1116 TRACE("Worker thread exiting\n");
1121 /***********************************************************************
1122 * INTERNET_InsertWorkRequest (internal)
1124 * Insert work request into queue
1129 BOOL INTERNET_InsertWorkRequest(LPWORKREQUEST lpWorkRequest)
1131 BOOL bSuccess = FALSE;
1132 LPWORKREQUEST lpNewRequest;
1136 lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
1139 memcpy(lpNewRequest, lpWorkRequest, sizeof(WORKREQUEST));
1140 lpNewRequest->prev = NULL;
1142 EnterCriticalSection(&csQueue);
1144 lpNewRequest->next = lpWorkQueueTail;
1145 if (lpWorkQueueTail)
1146 lpWorkQueueTail->prev = lpNewRequest;
1147 lpWorkQueueTail = lpNewRequest;
1148 if (!lpHeadWorkQueue)
1149 lpHeadWorkQueue = lpWorkQueueTail;
1151 LeaveCriticalSection(&csQueue);
1160 /***********************************************************************
1161 * INTERNET_GetWorkRequest (internal)
1163 * Retrieves work request from queue
1168 BOOL INTERNET_GetWorkRequest(LPWORKREQUEST lpWorkRequest)
1170 BOOL bSuccess = FALSE;
1171 LPWORKREQUEST lpRequest = NULL;
1175 EnterCriticalSection(&csQueue);
1177 if (lpHeadWorkQueue)
1179 lpRequest = lpHeadWorkQueue;
1180 lpHeadWorkQueue = lpHeadWorkQueue->prev;
1181 if (lpRequest == lpWorkQueueTail)
1182 lpWorkQueueTail = lpHeadWorkQueue;
1185 LeaveCriticalSection(&csQueue);
1189 memcpy(lpWorkRequest, lpRequest, sizeof(WORKREQUEST));
1190 HeapFree(GetProcessHeap(), 0, lpRequest);
1198 /***********************************************************************
1199 * INTERNET_AsyncCall (internal)
1201 * Retrieves work request from queue
1206 BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
1210 BOOL bSuccess = FALSE;
1214 if (InterlockedDecrement(&dwNumIdleThreads) < 0)
1216 InterlockedIncrement(&dwNumIdleThreads);
1218 if (InterlockedIncrement(&dwNumThreads) > MAX_WORKER_THREADS ||
1219 !(hThread = CreateThread(NULL, 0,
1220 (LPTHREAD_START_ROUTINE)INTERNET_WorkerThreadFunc, NULL, 0, &dwTID)))
1222 InterlockedDecrement(&dwNumThreads);
1223 INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
1227 TRACE("Created new thread\n");
1231 INTERNET_InsertWorkRequest(lpWorkRequest);
1232 SetEvent(hWorkEvent);
1240 /***********************************************************************
1241 * INTERNET_ExecuteWork (internal)
1246 VOID INTERNET_ExecuteWork()
1248 WORKREQUEST workRequest;
1252 if (INTERNET_GetWorkRequest(&workRequest))
1254 switch (workRequest.asyncall)
1257 FTP_FtpPutFileA((HINTERNET)workRequest.HFTPSESSION, (LPCSTR)workRequest.LPSZLOCALFILE,
1258 (LPCSTR)workRequest.LPSZNEWREMOTEFILE, workRequest.DWFLAGS, workRequest.DWCONTEXT);
1259 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZLOCALFILE);
1260 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZNEWREMOTEFILE);
1263 case FTPSETCURRENTDIRECTORYA:
1264 FTP_FtpSetCurrentDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1265 (LPCSTR)workRequest.LPSZDIRECTORY);
1266 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1269 case FTPCREATEDIRECTORYA:
1270 FTP_FtpCreateDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1271 (LPCSTR)workRequest.LPSZDIRECTORY);
1272 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1275 case FTPFINDFIRSTFILEA:
1276 FTP_FtpFindFirstFileA((HINTERNET)workRequest.HFTPSESSION,
1277 (LPCSTR)workRequest.LPSZSEARCHFILE,
1278 (LPWIN32_FIND_DATAA)workRequest.LPFINDFILEDATA, workRequest.DWFLAGS,
1279 workRequest.DWCONTEXT);
1280 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZSEARCHFILE);
1283 case FTPGETCURRENTDIRECTORYA:
1284 FTP_FtpGetCurrentDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1285 (LPSTR)workRequest.LPSZDIRECTORY, (LPDWORD)workRequest.LPDWDIRECTORY);
1289 FTP_FtpOpenFileA((HINTERNET)workRequest.HFTPSESSION,
1290 (LPCSTR)workRequest.LPSZFILENAME,
1291 workRequest.FDWACCESS,
1292 workRequest.DWFLAGS,
1293 workRequest.DWCONTEXT);
1294 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZFILENAME);
1298 FTP_FtpGetFileA((HINTERNET)workRequest.HFTPSESSION,
1299 (LPCSTR)workRequest.LPSZREMOTEFILE,
1300 (LPCSTR)workRequest.LPSZNEWFILE,
1301 (BOOL)workRequest.FFAILIFEXISTS,
1302 workRequest.DWLOCALFLAGSATTRIBUTE,
1303 workRequest.DWFLAGS,
1304 workRequest.DWCONTEXT);
1305 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZREMOTEFILE);
1306 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZNEWFILE);
1309 case FTPDELETEFILEA:
1310 FTP_FtpDeleteFileA((HINTERNET)workRequest.HFTPSESSION,
1311 (LPCSTR)workRequest.LPSZFILENAME);
1312 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZFILENAME);
1315 case FTPREMOVEDIRECTORYA:
1316 FTP_FtpRemoveDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1317 (LPCSTR)workRequest.LPSZDIRECTORY);
1318 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1321 case FTPRENAMEFILEA:
1322 FTP_FtpRenameFileA((HINTERNET)workRequest.HFTPSESSION,
1323 (LPCSTR)workRequest.LPSZSRCFILE,
1324 (LPCSTR)workRequest.LPSZDESTFILE);
1325 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZSRCFILE);
1326 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDESTFILE);
1329 case INTERNETFINDNEXTA:
1330 INTERNET_FindNextFileA((HINTERNET)workRequest.HFTPSESSION,
1331 (LPWIN32_FIND_DATAA)workRequest.LPFINDFILEDATA);
1334 case HTTPSENDREQUESTA:
1335 HTTP_HttpSendRequestA((HINTERNET)workRequest.HFTPSESSION,
1336 (LPCSTR)workRequest.LPSZHEADER,
1337 workRequest.DWHEADERLENGTH,
1338 (LPVOID)workRequest.LPOPTIONAL,
1339 workRequest.DWOPTIONALLENGTH);
1340 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZHEADER);
1343 case HTTPOPENREQUESTA:
1344 HTTP_HttpOpenRequestA((HINTERNET)workRequest.HFTPSESSION,
1345 (LPCSTR)workRequest.LPSZVERB,
1346 (LPCSTR)workRequest.LPSZOBJECTNAME,
1347 (LPCSTR)workRequest.LPSZVERSION,
1348 (LPCSTR)workRequest.LPSZREFERRER,
1349 (LPCSTR*)workRequest.LPSZACCEPTTYPES,
1350 workRequest.DWFLAGS,
1351 workRequest.DWCONTEXT);
1352 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZVERB);
1353 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZOBJECTNAME);
1354 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZVERSION);
1355 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZREFERRER);
1363 /***********************************************************************
1364 * INTERNET_GetResponseBuffer
1369 LPSTR INTERNET_GetResponseBuffer()
1371 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
1372 return lpwite->response;
1376 /***********************************************************************
1377 * INTERNET_GetNextLine (internal)
1379 * Parse next line in directory string listing
1382 * Pointer to begining of next line
1387 LPSTR INTERNET_GetNextLine(INT nSocket, LPSTR lpszBuffer, LPDWORD dwBuffer)
1391 BOOL bSuccess = FALSE;
1397 FD_SET(nSocket, &infd);
1398 tv.tv_sec=RESPONSE_TIMEOUT;
1401 while (nRecv < *dwBuffer)
1403 if (select(nSocket+1,&infd,NULL,NULL,&tv) > 0)
1405 if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
1407 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1411 if (lpszBuffer[nRecv] == '\n')
1416 if (lpszBuffer[nRecv] != '\r')
1421 INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
1429 lpszBuffer[nRecv] = '\0';
1430 *dwBuffer = nRecv - 1;
1431 TRACE(":%d %s\n", nRecv, lpszBuffer);