Spelling fixes.
[wine.git] / dlls / wininet / internet.c
blob79b556de16ce6e45b15fa0645c827b0332ca4814
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>
18 #include <ctype.h>
20 #include "windows.h"
21 #include "wininet.h"
22 #include "debugtools.h"
23 #include "winerror.h"
24 #include "winsock.h"
25 #include "tchar.h"
26 #include "heap.h"
28 #include "internet.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)
39 typedef struct
41 DWORD dwError;
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;
50 DWORD dwNumThreads;
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'.
62 * PARAMS
63 * hinstDLL [I] handle to the DLL's instance
64 * fdwReason [I]
65 * lpvReserved [I] reserved, must be NULL
67 * RETURNS
68 * Success: TRUE
69 * Failure: FALSE
72 BOOL WINAPI
73 WININET_LibMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
75 TRACE("%x,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
77 switch (fdwReason) {
78 case DLL_PROCESS_ATTACH:
80 g_dwTlsErrIndex = TlsAlloc();
82 if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
83 return FALSE;
85 hQuitEvent = CreateEventA(0, TRUE, FALSE, NULL);
86 hWorkEvent = CreateEventA(0, FALSE, FALSE, NULL);
87 InitializeCriticalSection(&csQueue);
89 dwNumThreads = 0;
90 dwNumIdleThreads = 0;
92 case DLL_THREAD_ATTACH:
94 LPWITHREADERROR lpwite = HeapAlloc(GetProcessHeap(), 0, sizeof(WITHREADERROR));
95 if (NULL == lpwite)
96 return FALSE;
98 TlsSetValue(g_dwTlsErrIndex, (LPVOID)lpwite);
100 break;
102 case DLL_THREAD_DETACH:
103 if (g_dwTlsErrIndex != TLS_OUT_OF_INDEXES)
105 LPVOID lpwite = TlsGetValue(g_dwTlsErrIndex);
106 if (lpwite)
107 HeapFree(GetProcessHeap(), 0, lpwite);
109 break;
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);
124 break;
127 return TRUE;
131 /***********************************************************************
132 * InternetOpenA (WININET.113)
134 * Per-application initialization of wininet
136 * RETURNS
137 * HINTERNET on success
138 * NULL on failure
141 INTERNETAPI HINTERNET WINAPI InternetOpenA(LPCSTR lpszAgent,
142 DWORD dwAccessType, LPCSTR lpszProxy,
143 LPCSTR lpszProxyBypass, DWORD dwFlags)
145 LPWININETAPPINFOA lpwai = NULL;
147 TRACE("\n");
149 /* Clear any error information */
150 INTERNET_SetLastError(0);
152 lpwai = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETAPPINFOA));
153 if (NULL == lpwai)
154 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
155 else
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
179 * RETURNS
180 * TRUE on success of writting to buffer
181 * FALSE on failure
184 BOOL WINAPI InternetGetLastResponseInfoA(LPDWORD lpdwError,
185 LPSTR lpszBuffer, LPDWORD lpdwBufferLength)
187 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
189 TRACE("\n");
191 *lpdwError = lpwite->dwError;
192 if (lpwite->dwError)
194 strncpy(lpszBuffer, lpwite->response, *lpdwBufferLength);
195 *lpdwBufferLength = strlen(lpszBuffer);
197 else
198 *lpdwBufferLength = 0;
200 return TRUE;
204 /***********************************************************************
205 * InternetGetConnectedState (WININET.103)
207 * Return connected state
209 * RETURNS
210 * TRUE if connected
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)
217 FIXME("Stub\n");
218 return FALSE;
222 /***********************************************************************
223 * InternetConnectA (WININET.93)
225 * Open a ftp, gopher or http session
227 * RETURNS
228 * HINTERNET a session handle on success
229 * NULL on failure
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;
239 TRACE("\n");
241 /* Clear any error information */
242 INTERNET_SetLastError(0);
244 switch (dwService)
246 case INTERNET_SERVICE_FTP:
247 rc = FTP_Connect(hInternet, lpszServerName, nServerPort,
248 lpszUserName, lpszPassword, dwFlags, dwContext);
249 break;
251 case INTERNET_SERVICE_HTTP:
252 rc = HTTP_Connect(hInternet, lpszServerName, nServerPort,
253 lpszUserName, lpszPassword, dwFlags, dwContext);
254 break;
256 case INTERNET_SERVICE_GOPHER:
257 default:
258 break;
261 return rc;
264 /***********************************************************************
265 * InternetFindNextFileA (WININET.102)
267 * Continues a file search from a previous call to FindFirstFile
269 * RETURNS
270 * TRUE on success
271 * FALSE on failure
274 BOOL WINAPI InternetFindNextFileA(HINTERNET hFind, LPVOID lpvFindData)
276 LPWININETAPPINFOA hIC = NULL;
277 LPWININETFINDNEXTA lpwh = (LPWININETFINDNEXTA) hFind;
279 TRACE("\n");
281 if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
283 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
284 return FALSE;
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);
298 else
300 return INTERNET_FindNextFileA(hFind, lpvFindData);
304 /***********************************************************************
305 * INTERNET_FindNextFileA (Internal)
307 * Continues a file search from a previous call to FindFirstFile
309 * RETURNS
310 * TRUE on success
311 * FALSE on failure
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;
321 TRACE("\n");
323 if (NULL == lpwh || lpwh->hdr.htype != WH_HFINDNEXT)
325 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
326 return FALSE;
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);
336 return FALSE;
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);
347 bSuccess = FALSE;
348 goto lend;
351 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
352 lpwh->index++;
354 TRACE("\nName: %s\nSize: %ld\n", lpFindFileData->cFileName, lpFindFileData->nFileSizeLow);
356 lend:
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));
370 return bSuccess;
374 /***********************************************************************
375 * INTERNET_CloseHandle (internal)
377 * Close internet handle
379 * RETURNS
380 * Void
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
403 * RETURNS
404 * TRUE on success
405 * FALSE on failure
408 BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
410 BOOL retval = FALSE;
411 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hInternet;
413 TRACE("\n");
414 if (NULL == lpwh)
415 return FALSE;
417 /* Clear any error information */
418 INTERNET_SetLastError(0);
420 switch (lpwh->htype)
422 case WH_HINIT:
423 INTERNET_CloseHandle((LPWININETAPPINFOA) lpwh);
424 break;
426 case WH_HHTTPSESSION:
427 HTTP_CloseHTTPSessionHandle((LPWININETHTTPSESSIONA) lpwh);
428 break;
430 case WH_HHTTPREQ:
431 HTTP_CloseHTTPRequestHandle((LPWININETHTTPREQA) lpwh);
432 break;
434 case WH_HFTPSESSION:
435 retval = FTP_CloseSessionHandle((LPWININETFTPSESSIONA) lpwh);
436 break;
438 case WH_HFINDNEXT:
439 retval = FTP_CloseFindNextHandle((LPWININETFINDNEXTA) lpwh);
440 break;
442 default:
443 break;
446 return retval;
450 /***********************************************************************
451 * SetUrlComponentValue (Internal)
453 * Helper function for InternetCrackUrlA
455 * RETURNS
456 * TRUE on success
457 * FALSE on failure
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;
471 else
473 INT ncpylen = min((*dwComponentLen)-1, len);
474 strncpy(*lppszComponent, lpszStart, ncpylen);
475 (*lppszComponent)[ncpylen] = '\0';
476 *dwComponentLen = ncpylen;
480 return TRUE;
484 /***********************************************************************
485 * InternetCrackUrlA (WININET.95)
487 * Break up URL into its components
489 * TODO: Hadnle dwFlags
491 * RETURNS
492 * TRUE on success
493 * FALSE on failure
496 BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
497 LPURL_COMPONENTSA lpUrlComponents)
500 * RFC 1808
501 * <protocol>:[//<net_loc>][/path][;<params>][?<query>][#<fragment>]
504 LPSTR lpszParam = NULL;
505 BOOL bIsAbsolute = FALSE;
506 LPSTR lpszap = (char*)lpszUrl;
507 LPSTR lpszcp = NULL;
509 TRACE("\n");
511 /* Determine if the URI is absolute. */
512 while (*lpszap != '\0')
514 if (isalnum(*lpszap))
516 lpszap++;
517 continue;
519 if ((*lpszap == ':') && (lpszap - lpszUrl >= 2))
521 bIsAbsolute = TRUE;
522 lpszcp = lpszap;
524 else
526 lpszcp = (LPSTR)lpszUrl; /* Relative url */
529 break;
532 /* Parse <params> */
533 lpszParam = strpbrk(lpszap, ";?");
534 if (lpszParam != NULL)
536 if (!SetUrlComponentValue(&lpUrlComponents->lpszExtraInfo,
537 &lpUrlComponents->dwExtraInfoLength, lpszParam+1, strlen(lpszParam+1)))
539 return FALSE;
543 if (bIsAbsolute) /* Parse <protocol>:[//<net_loc>] */
545 LPSTR lpszNetLoc;
547 /* Get scheme first. */
548 lpUrlComponents->nScheme = GetInternetScheme(lpszUrl, lpszcp - lpszUrl);
549 if (!SetUrlComponentValue(&lpUrlComponents->lpszScheme,
550 &lpUrlComponents->dwSchemeLength, lpszUrl, lpszcp - lpszUrl))
551 return FALSE;
553 /* Eat ':' in protocol. */
554 lpszcp++;
556 /* Skip over slashes. */
557 if (*lpszcp == '/')
559 lpszcp++;
560 if (*lpszcp == '/')
562 lpszcp++;
563 if (*lpszcp == '/')
564 lpszcp++;
568 lpszNetLoc = strpbrk(lpszcp, "/");
569 if (lpszParam)
571 if (lpszNetLoc)
572 lpszNetLoc = min(lpszNetLoc, lpszParam);
573 else
574 lpszNetLoc = lpszParam;
576 else if (!lpszNetLoc)
577 lpszNetLoc = lpszcp + strlen(lpszcp);
579 /* Parse net-loc */
580 if (lpszNetLoc)
582 LPSTR lpszHost;
583 LPSTR lpszPort;
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)
604 if (*lpszcp == ':')
605 lpszPasswd = lpszcp;
607 lpszcp++;
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> */
623 lpszHost = lpszcp;
624 lpszPort = lpszNetLoc;
626 while (lpszcp < lpszNetLoc)
628 if (*lpszcp == ':')
629 lpszPort = lpszcp;
631 lpszcp++;
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))
649 if (!SetUrlComponentValue(&lpUrlComponents->lpszUrlPath,
650 &lpUrlComponents->dwUrlPathLength, lpszcp,
651 lpszParam ? lpszParam - lpszcp : strlen(lpszcp)))
652 return FALSE;
654 else
656 lpUrlComponents->dwUrlPathLength = 0;
659 TRACE("%s: host(%s) path(%s)\n", lpszUrl, lpUrlComponents->lpszHostName, lpUrlComponents->lpszUrlPath);
661 return TRUE;
665 /***********************************************************************
666 * InternetAttemptConnect (WININET.81)
668 * Attempt to make a connection to the internet
670 * RETURNS
671 * ERROR_SUCCESS on success
672 * Error value on failure
675 INTERNETAPI DWORD WINAPI InternetAttemptConnect(DWORD dwReserved)
677 FIXME("Stub\n");
678 return ERROR_SUCCESS;
682 /***********************************************************************
683 * InternetCanonicalizeUrlA (WININET.85)
685 * Escape unsafe characters and spaces
687 * RETURNS
688 * TRUE on success
689 * FALSE on failure
692 BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
693 LPDWORD lpdwBufferLength, DWORD dwFlags)
695 BOOL bSuccess = FALSE;
697 FIXME("Stub!\n");
699 if (lpszUrl)
701 strncpy(lpszBuffer, lpszUrl, *lpdwBufferLength);
702 *lpdwBufferLength = strlen(lpszBuffer);
703 bSuccess = TRUE;
706 return bSuccess;
710 /***********************************************************************
711 * InternetSetStatusCallback (WININET.133)
713 * Sets up a callback function which is called as progress is made
714 * during an operation.
716 * RETURNS
717 * Previous callback or NULL on success
718 * INTERNET_INVALID_STATUS_CALLBACK on failure
721 INTERNETAPI INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallback(
722 HINTERNET hInternet ,INTERNET_STATUS_CALLBACK lpfnIntCB)
724 INTERNET_STATUS_CALLBACK retVal;
725 LPWININETAPPINFOA lpwai = (LPWININETAPPINFOA)hInternet;
727 TRACE("0x%08lx\n", (ULONG)hInternet);
728 if (lpwai->hdr.htype != WH_HINIT)
729 return INTERNET_INVALID_STATUS_CALLBACK;
731 retVal = lpwai->lpfnStatusCB;
732 lpwai->lpfnStatusCB = lpfnIntCB;
734 return retVal;
738 /***********************************************************************
739 * InternetWriteFile (WININET.138)
741 * Write data to an open internet file
743 * RETURNS
744 * TRUE on success
745 * FALSE on failure
748 BOOL WINAPI InternetWriteFile(HINTERNET hFile, LPCVOID lpBuffer ,
749 DWORD dwNumOfBytesToWrite, LPDWORD lpdwNumOfBytesWritten)
751 BOOL retval = FALSE;
752 int nSocket = INVALID_SOCKET;
753 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hFile;
755 TRACE("\n");
756 if (NULL == lpwh)
757 return FALSE;
759 switch (lpwh->htype)
761 case WH_HHTTPREQ:
762 nSocket = ((LPWININETHTTPREQA)hFile)->nSocketFD;
763 break;
765 case WH_HFILE:
766 nSocket = ((LPWININETFILE)hFile)->nDataSocket;
767 break;
769 default:
770 break;
773 if (INVALID_SOCKET != nSocket)
775 *lpdwNumOfBytesWritten = INTERNET_WriteDataToStream(nSocket, lpBuffer, dwNumOfBytesToWrite);
776 if (*lpdwNumOfBytesWritten < 0)
777 *lpdwNumOfBytesWritten = 0;
778 else
779 retval = TRUE;
782 return retval;
786 /***********************************************************************
787 * InternetReadFile (WININET.121)
789 * Read data from an open internet file
791 * RETURNS
792 * TRUE on success
793 * FALSE on failure
796 BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
797 DWORD dwNumOfBytesToRead, LPDWORD dwNumOfBytesRead)
799 BOOL retval = FALSE;
800 int nSocket = INVALID_SOCKET;
801 LPWININETHANDLEHEADER lpwh = (LPWININETHANDLEHEADER) hFile;
803 TRACE("\n");
804 if (NULL == lpwh)
805 return FALSE;
807 switch (lpwh->htype)
809 case WH_HHTTPREQ:
810 nSocket = ((LPWININETHTTPREQA)hFile)->nSocketFD;
811 break;
813 case WH_HFILE:
814 nSocket = ((LPWININETFILE)hFile)->nDataSocket;
815 break;
817 default:
818 break;
821 if (INVALID_SOCKET != nSocket)
823 *dwNumOfBytesRead = INTERNET_ReadDataFromStream(nSocket, lpBuffer, dwNumOfBytesToRead);
824 if (*dwNumOfBytesRead < 0)
825 *dwNumOfBytesRead = 0;
826 else
827 retval = TRUE;
830 return retval;
834 /***********************************************************************
835 * InternetQueryOptionA
837 * Queries an options on the specified handle
839 * RETURNS
840 * TRUE on success
841 * FALSE on failure
844 BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
845 LPVOID lpBuffer, LPDWORD lpdwBufferLength)
847 LPWININETHANDLEHEADER lpwhh;
848 BOOL bSuccess = FALSE;
850 TRACE("0x%08lx\n", dwOption);
852 if (NULL == hInternet)
854 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
855 return FALSE;
858 lpwhh = (LPWININETHANDLEHEADER) hInternet;
860 switch (dwOption)
862 case INTERNET_OPTION_HANDLE_TYPE:
864 ULONG type = lpwhh->htype;
865 TRACE("INTERNET_OPTION_HANDLE_TYPE: %ld\n", type);
867 if (*lpdwBufferLength < sizeof(ULONG))
868 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
869 else
871 memcpy(lpBuffer, &type, sizeof(ULONG));
872 *lpdwBufferLength = sizeof(ULONG);
873 bSuccess = TRUE;
876 break;
879 default:
880 FIXME("Stub!");
881 break;
884 return bSuccess;
888 /***********************************************************************
889 * GetInternetScheme (internal)
891 * Get scheme of url
893 * RETURNS
894 * scheme on success
895 * INTERNET_SCHEME_UNKNOWN on failure
898 INTERNET_SCHEME GetInternetScheme(LPCSTR lpszScheme, INT nMaxCmp)
900 if(lpszScheme==NULL)
901 return INTERNET_SCHEME_UNKNOWN;
903 if (!_strnicmp("ftp", lpszScheme, nMaxCmp))
904 return INTERNET_SCHEME_FTP;
905 else if (!_strnicmp("gopher", lpszScheme, nMaxCmp))
906 return INTERNET_SCHEME_GOPHER;
907 else if (!_strnicmp("http", lpszScheme, nMaxCmp))
908 return INTERNET_SCHEME_HTTP;
909 else if (!_strnicmp("https", lpszScheme, nMaxCmp))
910 return INTERNET_SCHEME_HTTPS;
911 else if (!_strnicmp("file", lpszScheme, nMaxCmp))
912 return INTERNET_SCHEME_FILE;
913 else if (!_strnicmp("news", lpszScheme, nMaxCmp))
914 return INTERNET_SCHEME_NEWS;
915 else if (!_strnicmp("mailto", lpszScheme, nMaxCmp))
916 return INTERNET_SCHEME_MAILTO;
917 else
918 return INTERNET_SCHEME_UNKNOWN;
922 /***********************************************************************
923 * INTERNET_WriteDataToStream (internal)
925 * Send data to server
927 * RETURNS
929 * number of characters sent on success
930 * -1 on error
932 int INTERNET_WriteDataToStream(int nDataSocket, LPCVOID Buffer, DWORD BytesToWrite)
934 if (INVALID_SOCKET == nDataSocket)
935 return SOCKET_ERROR;
937 return send(nDataSocket, Buffer, BytesToWrite, 0);
941 /***********************************************************************
942 * INTERNET_ReadDataFromStream (internal)
944 * Read data from http server
946 * RETURNS
948 * number of characters sent on success
949 * -1 on error
951 int INTERNET_ReadDataFromStream(int nDataSocket, LPVOID Buffer, DWORD BytesToRead)
953 if (INVALID_SOCKET == nDataSocket)
954 return SOCKET_ERROR;
956 return recv(nDataSocket, Buffer, BytesToRead, 0);
960 /***********************************************************************
961 * INTERNET_SetLastError (internal)
963 * Set last thread specific error
965 * RETURNS
968 void INTERNET_SetLastError(DWORD dwError)
970 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
972 SetLastError(dwError);
973 lpwite->dwError = dwError;
977 /***********************************************************************
978 * INTERNET_GetLastError (internal)
980 * Get last thread specific error
982 * RETURNS
985 DWORD INTERNET_GetLastError()
987 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
988 return lpwite->dwError;
992 /***********************************************************************
993 * INTERNET_WorkerThreadFunc (internal)
995 * Worker thread execution function
997 * RETURNS
1000 DWORD INTERNET_WorkerThreadFunc(LPVOID *lpvParam)
1002 DWORD dwWaitRes;
1004 while (1)
1006 dwWaitRes = WaitForMultipleObjects(2, hEventArray, FALSE, MAX_IDLE_WORKER);
1008 if (dwWaitRes == WAIT_OBJECT_0 + 1)
1009 INTERNET_ExecuteWork();
1010 else
1011 break;
1013 InterlockedIncrement(&dwNumIdleThreads);
1016 InterlockedDecrement(&dwNumIdleThreads);
1017 InterlockedDecrement(&dwNumThreads);
1018 TRACE("Worker thread exiting\n");
1019 return TRUE;
1023 /***********************************************************************
1024 * INTERNET_InsertWorkRequest (internal)
1026 * Insert work request into queue
1028 * RETURNS
1031 BOOL INTERNET_InsertWorkRequest(LPWORKREQUEST lpWorkRequest)
1033 BOOL bSuccess = FALSE;
1034 LPWORKREQUEST lpNewRequest;
1036 TRACE("\n");
1038 lpNewRequest = HeapAlloc(GetProcessHeap(), 0, sizeof(WORKREQUEST));
1039 if (lpNewRequest)
1041 memcpy(lpNewRequest, lpWorkRequest, sizeof(WORKREQUEST));
1042 lpNewRequest->prev = NULL;
1044 EnterCriticalSection(&csQueue);
1046 lpNewRequest->next = lpWorkQueueTail;
1047 if (lpWorkQueueTail)
1048 lpWorkQueueTail->prev = lpNewRequest;
1049 lpWorkQueueTail = lpNewRequest;
1050 if (!lpHeadWorkQueue)
1051 lpHeadWorkQueue = lpWorkQueueTail;
1053 LeaveCriticalSection(&csQueue);
1055 bSuccess = TRUE;
1058 return bSuccess;
1062 /***********************************************************************
1063 * INTERNET_GetWorkRequest (internal)
1065 * Retrieves work request from queue
1067 * RETURNS
1070 BOOL INTERNET_GetWorkRequest(LPWORKREQUEST lpWorkRequest)
1072 BOOL bSuccess = FALSE;
1073 LPWORKREQUEST lpRequest = NULL;
1075 TRACE("\n");
1077 EnterCriticalSection(&csQueue);
1079 if (lpHeadWorkQueue)
1081 lpRequest = lpHeadWorkQueue;
1082 lpHeadWorkQueue = lpHeadWorkQueue->prev;
1083 if (lpRequest == lpWorkQueueTail)
1084 lpWorkQueueTail = lpHeadWorkQueue;
1087 LeaveCriticalSection(&csQueue);
1089 if (lpRequest)
1091 memcpy(lpWorkRequest, lpRequest, sizeof(WORKREQUEST));
1092 HeapFree(GetProcessHeap(), 0, lpRequest);
1093 bSuccess = TRUE;
1096 return bSuccess;
1100 /***********************************************************************
1101 * INTERNET_AsyncCall (internal)
1103 * Retrieves work request from queue
1105 * RETURNS
1108 BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest)
1110 HANDLE hThread;
1111 DWORD dwTID;
1112 BOOL bSuccess = FALSE;
1114 TRACE("\n");
1116 if (InterlockedDecrement(&dwNumIdleThreads) < 0)
1118 InterlockedIncrement(&dwNumIdleThreads);
1120 if (InterlockedIncrement(&dwNumThreads) > MAX_WORKER_THREADS ||
1121 !(hThread = CreateThread(NULL, 0,
1122 (LPTHREAD_START_ROUTINE)INTERNET_WorkerThreadFunc, NULL, 0, &dwTID)))
1124 InterlockedDecrement(&dwNumThreads);
1125 INTERNET_SetLastError(ERROR_INTERNET_ASYNC_THREAD_FAILED);
1126 goto lerror;
1129 TRACE("Created new thread\n");
1132 bSuccess = TRUE;
1133 INTERNET_InsertWorkRequest(lpWorkRequest);
1134 SetEvent(hWorkEvent);
1136 lerror:
1138 return bSuccess;
1142 /***********************************************************************
1143 * INTERNET_ExecuteWork (internal)
1145 * RETURNS
1148 VOID INTERNET_ExecuteWork()
1150 WORKREQUEST workRequest;
1152 TRACE("\n");
1154 if (INTERNET_GetWorkRequest(&workRequest))
1156 switch (workRequest.asyncall)
1158 case FTPPUTFILEA:
1159 FTP_FtpPutFileA((HINTERNET)workRequest.HFTPSESSION, (LPCSTR)workRequest.LPSZLOCALFILE,
1160 (LPCSTR)workRequest.LPSZNEWREMOTEFILE, workRequest.DWFLAGS, workRequest.DWCONTEXT);
1161 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZLOCALFILE);
1162 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZNEWREMOTEFILE);
1163 break;
1165 case FTPSETCURRENTDIRECTORYA:
1166 FTP_FtpSetCurrentDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1167 (LPCSTR)workRequest.LPSZDIRECTORY);
1168 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1169 break;
1171 case FTPCREATEDIRECTORYA:
1172 FTP_FtpCreateDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1173 (LPCSTR)workRequest.LPSZDIRECTORY);
1174 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1175 break;
1177 case FTPFINDFIRSTFILEA:
1178 FTP_FtpFindFirstFileA((HINTERNET)workRequest.HFTPSESSION,
1179 (LPCSTR)workRequest.LPSZSEARCHFILE,
1180 (LPWIN32_FIND_DATAA)workRequest.LPFINDFILEDATA, workRequest.DWFLAGS,
1181 workRequest.DWCONTEXT);
1182 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZSEARCHFILE);
1183 break;
1185 case FTPGETCURRENTDIRECTORYA:
1186 FTP_FtpGetCurrentDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1187 (LPSTR)workRequest.LPSZDIRECTORY, (LPDWORD)workRequest.LPDWDIRECTORY);
1188 break;
1190 case FTPOPENFILEA:
1191 FTP_FtpOpenFileA((HINTERNET)workRequest.HFTPSESSION,
1192 (LPCSTR)workRequest.LPSZFILENAME,
1193 workRequest.FDWACCESS,
1194 workRequest.DWFLAGS,
1195 workRequest.DWCONTEXT);
1196 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZFILENAME);
1197 break;
1199 case FTPGETFILEA:
1200 FTP_FtpGetFileA((HINTERNET)workRequest.HFTPSESSION,
1201 (LPCSTR)workRequest.LPSZREMOTEFILE,
1202 (LPCSTR)workRequest.LPSZNEWFILE,
1203 (BOOL)workRequest.FFAILIFEXISTS,
1204 workRequest.DWLOCALFLAGSATTRIBUTE,
1205 workRequest.DWFLAGS,
1206 workRequest.DWCONTEXT);
1207 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZREMOTEFILE);
1208 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZNEWFILE);
1209 break;
1211 case FTPDELETEFILEA:
1212 FTP_FtpDeleteFileA((HINTERNET)workRequest.HFTPSESSION,
1213 (LPCSTR)workRequest.LPSZFILENAME);
1214 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZFILENAME);
1215 break;
1217 case FTPREMOVEDIRECTORYA:
1218 FTP_FtpRemoveDirectoryA((HINTERNET)workRequest.HFTPSESSION,
1219 (LPCSTR)workRequest.LPSZDIRECTORY);
1220 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDIRECTORY);
1221 break;
1223 case FTPRENAMEFILEA:
1224 FTP_FtpRenameFileA((HINTERNET)workRequest.HFTPSESSION,
1225 (LPCSTR)workRequest.LPSZSRCFILE,
1226 (LPCSTR)workRequest.LPSZDESTFILE);
1227 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZSRCFILE);
1228 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZDESTFILE);
1229 break;
1231 case INTERNETFINDNEXTA:
1232 INTERNET_FindNextFileA((HINTERNET)workRequest.HFTPSESSION,
1233 (LPWIN32_FIND_DATAA)workRequest.LPFINDFILEDATA);
1234 break;
1236 case HTTPSENDREQUESTA:
1237 HTTP_HttpSendRequestA((HINTERNET)workRequest.HFTPSESSION,
1238 (LPCSTR)workRequest.LPSZHEADER,
1239 workRequest.DWHEADERLENGTH,
1240 (LPVOID)workRequest.LPOPTIONAL,
1241 workRequest.DWOPTIONALLENGTH);
1242 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZHEADER);
1243 break;
1245 case HTTPOPENREQUESTA:
1246 HTTP_HttpOpenRequestA((HINTERNET)workRequest.HFTPSESSION,
1247 (LPCSTR)workRequest.LPSZVERB,
1248 (LPCSTR)workRequest.LPSZOBJECTNAME,
1249 (LPCSTR)workRequest.LPSZVERSION,
1250 (LPCSTR)workRequest.LPSZREFERRER,
1251 (LPCSTR*)workRequest.LPSZACCEPTTYPES,
1252 workRequest.DWFLAGS,
1253 workRequest.DWCONTEXT);
1254 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZVERB);
1255 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZOBJECTNAME);
1256 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZVERSION);
1257 HeapFree(GetProcessHeap(), 0, (LPVOID)workRequest.LPSZREFERRER);
1258 break;
1265 /***********************************************************************
1266 * INTERNET_GetResponseBuffer
1268 * RETURNS
1271 LPSTR INTERNET_GetResponseBuffer()
1273 LPWITHREADERROR lpwite = (LPWITHREADERROR)TlsGetValue(g_dwTlsErrIndex);
1274 return lpwite->response;
1278 /***********************************************************************
1279 * INTERNET_GetNextLine (internal)
1281 * Parse next line in directory string listing
1283 * RETURNS
1284 * Pointer to begining of next line
1285 * NULL on failure
1289 LPSTR INTERNET_GetNextLine(INT nSocket, LPSTR lpszBuffer, LPDWORD dwBuffer)
1291 struct timeval tv;
1292 fd_set infd;
1293 BOOL bSuccess = FALSE;
1294 INT nRecv = 0;
1296 TRACE("\n");
1298 FD_ZERO(&infd);
1299 FD_SET(nSocket, &infd);
1300 tv.tv_sec=RESPONSE_TIMEOUT;
1301 tv.tv_usec=0;
1303 while (nRecv < *dwBuffer)
1305 if (select(nSocket+1,&infd,NULL,NULL,&tv) > 0)
1307 if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
1309 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1310 goto lend;
1313 if (lpszBuffer[nRecv] == '\n')
1315 bSuccess = TRUE;
1316 break;
1318 if (lpszBuffer[nRecv] != '\r')
1319 nRecv++;
1321 else
1323 INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
1324 goto lend;
1328 lend:
1329 if (bSuccess)
1331 lpszBuffer[nRecv] = '\0';
1332 *dwBuffer = nRecv - 1;
1333 TRACE(":%d %s\n", nRecv, lpszBuffer);
1334 return lpszBuffer;
1336 else
1338 return NULL;