Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1199 lines
38 KiB

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
dav.cxx
Abstract:
This file contains the implementations of
HttpCheckDavCompliance
HttpCheckDavCollection
HttpCheckCachedDavStatus
The following functions are exported by this module:
HttpCheckDavComplianceA
HttpCheckDavCollectionA
HttpCheckCachedDavStatusA
HttpCheckDavComplianceW
HttpCheckDavCollectionW
HttpCheckCachedDavStatusW
Author:
Mead Himelstein (Meadh) 01-Jun-1998
Revision History:
--*/
#include <wininetp.h>
#include "httpp.h"
#undef DAVCACHING //IE5 bug 15696, removing unused code but may add back in later
INTERNETAPI_(BOOL) HttpCheckDavComplianceA(
IN LPCSTR lpszUrl,
IN LPCSTR lpszComplianceToken,
IN OUT LPBOOL lpfFound,
IN HWND hWnd,
IN LPVOID lpvReserved
)
/*++
Routine Description:
Determines if the resource identified by lpszUrl is DAV compliant (level determined by lpszComplianceToken).
Returns TRUE in lpfFound if detected. Furthermore, if the token is "1" we also cache todays date
and whether or not we found the server to be DAV level 1 compliant in the visited links cache.
Arguments:
lpszUrl - URL to the resource to check for DAV compliance, i.e. "http://webdav/davfood/"
lpszComplianceToken - DAV compliance class identifier (i.e. "1") BUGBUG MUST NOT CONTAIN INTERNAL WHITE SPACE "foo bar" = bad, " foo " = ok
lpfFound - address of a BOOL to receive TRUE if DAV compliance is found or FALSE otherwise.
hWnd - Handle to window for displaying authentication dialog if needed. May be NULL indicating
no UI is to be displayed and authentication failures should be quietly handled.
lpvReserved - Reserved, must be NULL
Return Value:
TRUE - Success, check lpfFound for results.
FALSE - failure, GetLastError returns the error code
--*/
{
BOOL fRet = TRUE;
DEBUG_ENTER((DBG_API,
Bool,
"HttpCheckDavComplianceA",
"%sq, %sq, %#x, %#x, %#x",
lpszUrl,
lpszComplianceToken,
lpfFound,
hWnd,
lpvReserved
));
DWORD dwStatusCode, dwHeaderLength, dwIndex = 0;
DWORD dwError = ERROR_SUCCESS, dwStatusLength = sizeof(DWORD);
HINTERNET hSession = NULL, hConnection = NULL, hHTTPReq = NULL;
LPSTR lpszDavHeader = NULL, lpszRead = NULL, lpszWrite = NULL, lpszVisitedUrl=NULL;
LPCACHE_ENTRY_INFO lpCEI = NULL;
FILETIME ftNow;
WORD wDate, wTime;
URL_COMPONENTS ucUrl;
#define CEI_BUFFER_SIZE 512
#define IsWhite(c) ((DWORD) (c) > 32 ? FALSE : TRUE)
// Debug param checking
INET_ASSERT(lpszUrl && lpszComplianceToken && lpfFound && !lpvReserved);
DEBUG_ENTER_API((DBG_API,
Bool,
"HttpCheckDavComplianceA",
"%s %s %x %x %x",
(lpszUrl)?lpszUrl :"NULL Url",
(lpszComplianceToken)?lpszComplianceToken :"NULL ComplianceToken",
hWnd,
lpfFound, lpvReserved
));
// non-debug param checking
if (!lpszUrl || !lpszComplianceToken || !lpfFound || lpvReserved)
{
dwError = ERROR_INVALID_PARAMETER;
fRet = FALSE;
goto cleanup;
}
*lpfFound = FALSE;
// Build the URL_COMPONENTS struct
memset(&ucUrl, 0, sizeof(ucUrl));
ucUrl.dwStructSize = sizeof(ucUrl);
// non-zero length enables retrieval during CrackUrl
ucUrl.dwSchemeLength = 1;
ucUrl.dwHostNameLength = 1;
ucUrl.dwUrlPathLength = 1;
if (!InternetCrackUrl(lpszUrl, 0, 0, &ucUrl))
{
dwError = GetLastError();
fRet = FALSE;
goto cleanup;
}
DEBUG_PRINT_API(API,
INFO,
("URL Cracked. Host = %q Path = %q\n ",
ucUrl.lpszHostName, ucUrl.lpszUrlPath
));
// Ensures the global vszCurrentUser is set
GetWininetUserName();
INET_ASSERT(vszCurrentUser);
// Perform an OPTIONS call on the server and check for a DAV header
hSession = InternetOpen(NULL,
INTERNET_OPEN_TYPE_PRECONFIG,
NULL,
NULL,
NULL);
if(!hSession)
{
dwError = GetLastError();
fRet = FALSE;
goto cleanup;
}
hConnection = InternetConnect(hSession,
ucUrl.lpszHostName,
INTERNET_DEFAULT_HTTP_PORT,
(LPCSTR) vszCurrentUser,
NULL,
INTERNET_SERVICE_HTTP,
NULL,
NULL);
if(!hConnection)
{
dwError = GetLastError();
fRet = FALSE;
goto cleanup;
}
hHTTPReq = HttpOpenRequest(hConnection,
"OPTIONS",
ucUrl.lpszUrlPath,
"HTTP/1.0",
NULL,
NULL,
INTERNET_FLAG_PRAGMA_NOCACHE,NULL);
if(!hHTTPReq)
{
dwError = GetLastError();
fRet = FALSE;
goto cleanup;
}
if (!HttpSendRequest(hHTTPReq,NULL, 0L, NULL, NULL))
{
dwError = GetLastError();
fRet = FALSE;
goto cleanup;
}
// Authentication handling
if (HttpQueryInfo(hHTTPReq,
HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER,
&dwStatusCode,
&dwStatusLength,
&dwIndex))
{
// fRet = TRUE at this point
// If request was denied or proxy auth required and callee has said
// we can display UI, we put up the InternetErrorDlg and ask for
// credentials. Otherwise, if dwStatus != success we cache that
// this resource is not DAV compliant
if ((hWnd) && ((dwStatusCode == HTTP_STATUS_DENIED) || (dwStatusCode == HTTP_STATUS_PROXY_AUTH_REQ)))
{
DWORD dwRetval;
DWORD dwAuthTries = 0;
BOOL fDone;
fDone = FALSE;
while ((!fDone) && (dwAuthTries < 3))
{
dwRetval = InternetErrorDlg(hWnd,
hHTTPReq,
ERROR_INTERNET_INCORRECT_PASSWORD,
0L,
NULL);
if (dwRetval == ERROR_INTERNET_FORCE_RETRY) // User pressed ok on credentials dialog
{ // Resend request, new credentials are cached and will be replayed by HSR()
if (!HttpSendRequest(hHTTPReq,NULL, 0L, NULL, NULL))
{
dwError = GetLastError();
fRet = FALSE;
goto cleanup;
}
dwStatusCode = 0;
if (!HttpQueryInfo(hHTTPReq,
HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER,
&dwStatusCode,
&dwStatusLength,
&dwIndex))
{
dwError = GetLastError();
fRet = FALSE;
goto cleanup;
}
if ((dwStatusCode != HTTP_STATUS_DENIED) && (dwStatusCode != HTTP_STATUS_PROXY_AUTH_REQ))
{
fDone = TRUE;
}
}
else // User pressed cancel from dialog (note ERROR_SUCCESS == ERROR_CANCELLED from IED())
{
fDone = TRUE;
}
dwAuthTries++;
}
}
if ((dwStatusCode == HTTP_STATUS_DENIED) || (dwStatusCode == HTTP_STATUS_PROXY_AUTH_REQ))
{ // Don't want to cache this (user might have forgotten password or we may not
// be able to show credential UI)
goto cleanup;
}
else if (dwStatusCode != HTTP_STATUS_OK)
{ // Either initial request failed for non-auth issue, cache as not compliant
goto update_cache; //note update_cache NOT cleanup, want to cache this as non compliant
}
}
else
{
dwError = GetLastError();
fRet = FALSE;
goto cleanup;
}
// If we received a DAV header, snag it and check for compliance level
dwHeaderLength = INTERNET_MAX_URL_LENGTH;
lpszDavHeader = (LPSTR)ALLOCATE_MEMORY(LMEM_FIXED, dwHeaderLength);
if (!lpszDavHeader)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
goto cleanup;
}
lstrcpy(lpszDavHeader,"DAV");
if (!HttpQueryInfo(hHTTPReq,
HTTP_QUERY_CUSTOM,
lpszDavHeader,
&dwHeaderLength,
&dwIndex))
{
dwError = GetLastError();
fRet = FALSE;
goto update_cache; //note update_cache NOT cleanup, want to cache this as non compliant
}
INET_ASSERT(fRet); // sb TRUE if it made it this far
// Walk the DAV header looking for the token by itself, indicating DAV compliance
// Note: DAV header is comma delimited, but otherwise we can make no assumptions on formatting.
// BUGBUG Currently will not work for tokens with internal white space i.e. "foo bar" = bad, " foobar " = good
lpszRead = lpszDavHeader;
lpszWrite = lpszDavHeader;
INET_ASSERT(!*lpfFound);
INET_ASSERT(fRet);
while(*lpszRead && !*lpfFound)
{
if (IsWhite(*lpszRead))
{
while ((*(++lpszRead))&&(IsWhite(*lpszRead)));
}
if (*lpszRead)
{
if(*lpszRead == ',')
{
*(lpszRead++) = '\0';
if (*lpfFound = (lstrcmp(lpszDavHeader, lpszComplianceToken) == 0) ? TRUE:FALSE)
{
goto update_cache;
}
lpszWrite = lpszRead;
lpszDavHeader = lpszRead;
}
else *(lpszWrite++) = *(lpszRead++);
}
}
*lpszWrite = *lpszRead; // copy the terminator
INET_ASSERT(!*lpfFound);
*lpfFound = (lstrcmp(lpszDavHeader, lpszComplianceToken) == 0) ? TRUE:FALSE; //Final compare on last fragment
update_cache :
#ifdef DAVCACHING // Commenting out as per bug 15696
if (lstrcmp("1", lpszComplianceToken) == 0)
// Cache if this is a known DAV level 1 server or atleast the last time we tried
{
// Update visited links cache
// We store the cached info as:
// CacheEntryInfo.dwExemptDelta(HiWord) = Date DAV discovery was last run
// CacheEntryInfo.dwExemptDelta(LoWord) & DAV_LEVEL1_STATUS = Is DAV server (*lpfFound)
// CacheEntryInfo.dwExemptDelta(LoWord) & DAV_COLLECTION_STATUS = Is DAV collection (set in HttpCheckDavCollection)
// Assemble the URL to the visited links container "VISITED: username@URL"
DWORD cbNeededBuf = lstrlen("Visited: ") + lstrlen(vszCurrentUser) + lstrlen(lpszUrl) + 32;
lpszVisitedUrl = (LPSTR) ALLOCATE_MEMORY(LMEM_FIXED, cbNeededBuf);
if (!lpszVisitedUrl)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
goto cleanup;
}
lstrcpy(lpszVisitedUrl, "Visited: "); // For compatibility with urlhist.c visited URLs
lstrcat(lpszVisitedUrl, vszCurrentUser);
lstrcat(lpszVisitedUrl, "@");
lstrcat(lpszVisitedUrl, lpszUrl);
lpCEI = (LPCACHE_ENTRY_INFO) ALLOCATE_MEMORY(LMEM_FIXED, CEI_BUFFER_SIZE);
if (!lpCEI)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
goto cleanup;
}
GetSystemTimeAsFileTime(&ftNow);
if (!FileTimeToDosDateTime(&ftNow,
&wDate,
&wTime
))
{
INET_ASSERT(FALSE); // Should "never" hit this
goto cleanup;
}
// Stuff our 16-bit Date into the upper 16-bits of dwExemptDelta
lpCEI->dwExemptDelta = (DWORD)wDate <<16;
// Set the DAV_LEVEL1_STATUS_BIT if the resource was found compliant above
if (*lpfFound)
{
lpCEI->dwExemptDelta |= (DWORD) DAV_LEVEL1_STATUS;
}
if (!SetUrlCacheEntryInfo (lpszVisitedUrl,
lpCEI,
CACHE_ENTRY_EXEMPT_DELTA_FC
))
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
// No existing cache entry, so create one and try again
{
FILETIME ftNone;
if (CommitUrlCacheEntry (lpszVisitedUrl,
NULL,
ftNone,
ftNone,
0,
NULL,
0,
NULL,
0
))
{
// Entry is now created, so try one more time
SetUrlCacheEntryInfo (lpszVisitedUrl,
lpCEI,
CACHE_ENTRY_EXEMPT_DELTA_FC
);
}
}
}
}
#endif //DAVCACHING
cleanup:
// Free memory
if (lpCEI) FREE_MEMORY (lpCEI);
if (lpszVisitedUrl) FREE_MEMORY (lpszVisitedUrl);
if (lpszDavHeader != NULL) FREE_MEMORY(lpszDavHeader);
// Close the handles
if (hHTTPReq) InternetCloseHandle(hHTTPReq);
if (hConnection) InternetCloseHandle(hConnection);
SetLastError(dwError);
DEBUG_LEAVE_API(fRet);
return fRet;
}
INTERNETAPI_(BOOL) HttpCheckDavCollectionA(
IN LPCSTR lpszUrl,
IN OUT LPBOOL lpfFound,
IN HWND hWnd,
IN LPVOID lpvReserved
)
/*++
Routine Description:
Checks the resource at lpszUrl to see if it is a DAV collection. Typically, callee has
already called HttpCheckDavCompliance or HttpCheckCachedDavStatus to determine
the resource supports DAV level 1, although it is not necessary to do so. Note this method
will blindly attempt either way.
Arguments:
lpszUrl - URL of the resource to check
lpfFound - address of a BOOL to receive TRUE if DAV compliance is found or FALSE otherwise.
hWnd - Handle to window for displaying authentication dialog if needed. May be NULL indicating
no UI is to be displayed and authentication failures should be quietly handled.
lpvReserved - Reserved, must be NULL
Return Value:
TRUE - Success, check lpfFound for results.
FALSE - failure, GetLastError returns the error code
--*/
{
#define CEI_BUFFER_SIZE 512
#define READ_BUFFER_SIZE 4096
#define READ_BUFFER_AVAILABLE (READ_BUFFER_SIZE - sizeof(LPSTR))
BOOL fRet = TRUE, fDone=FALSE;
DEBUG_ENTER((DBG_API,
Bool,
"HttpCheckDavCollectionA",
"%sq, %#x, %#x, %#x",
lpszUrl,
lpfFound,
hWnd,
lpvReserved
));
DWORD dwRead=0, dwBuffers =1;
DWORD dwStatusCode, dwIndex = 0;
DWORD dwError = ERROR_SUCCESS, dwStatusLength = sizeof(DWORD);
HINTERNET hSession = NULL, hConnection = NULL, hHTTPReq = NULL;
LPSTR lpszVisitedUrl=NULL, lpszXmlResponse=NULL, lpszBufferHead=NULL;
LPCACHE_ENTRY_INFO lpCEI = NULL;
FILETIME ftNow;
WORD wDate, wTime;
URL_COMPONENTS ucUrl;
char lpszHeaders[] = "Depth:0\r\n";
// Debug param checking
INET_ASSERT(lpszUrl && lpfFound && !lpvReserved);
DEBUG_ENTER_API((DBG_API,
Bool,
"HttpCheckDavCollectionA",
"%s %x %x",
(lpszUrl)?lpszUrl :"NULL Url",
lpfFound, lpvReserved
));
// non-debug param checking
if (!lpszUrl || !lpfFound || lpvReserved)
{
dwError = ERROR_INVALID_PARAMETER;
fRet = FALSE;
goto cleanup;
}
*lpfFound = FALSE;
// Build the URL_COMPONENTS struct
memset(&ucUrl, 0, sizeof(ucUrl));
ucUrl.dwStructSize = sizeof(ucUrl);
// non-zero length enables retrieval during CrackUrl
ucUrl.dwSchemeLength = 1;
ucUrl.dwHostNameLength = 1;
ucUrl.dwUrlPathLength = 1;
if (!InternetCrackUrl(lpszUrl, 0, 0, &ucUrl))
{
dwError = GetLastError();
fRet = FALSE;
goto cleanup;
}
INET_ASSERT(ucUrl.lpszHostName && ucUrl.lpszUrlPath);
DEBUG_PRINT_API(API,
INFO,
("URL Cracked. Host = %q Path = %q\n ",
ucUrl.lpszHostName, ucUrl.lpszUrlPath
));
// Ensures the global vszCurrentUser is set
GetWininetUserName();
INET_ASSERT(vszCurrentUser);
// Build the XML request body for a PROPFIND
//<?xml version='1.0' ?>
//<?xml:namespace ns='DAV:' prefix='D' ?>
//<D:propfind>
// <D:prop>
// <D:resourcetype/>
// </D:prop>
//</D:propfind>
#define REQUEST_RESOURCE_TYPE "\
<?xml version='1.0' ?>\r\n \
<?xml:namespace ns='DAV:' prefix='D' ?>\r\n \
<D:propfind>\r\n \
<D:prop>\r\n \
<D:resourcetype/>\r\n \
</D:prop>\r\n \
</D:propfind>\r\n"
DWORD cbReqSize;
cbReqSize = lstrlen(REQUEST_RESOURCE_TYPE);
LPCSTR lpszXmlRequest;
lpszXmlRequest = (LPSTR)ALLOCATE_MEMORY(LMEM_FIXED, cbReqSize);
// Perform a PROPFIND call, looking for resourcetype = DAV:collection
hSession = InternetOpen(NULL,
INTERNET_OPEN_TYPE_PRECONFIG,
NULL,
NULL,
NULL);
if(!hSession)
{
dwError = GetLastError();
fRet = FALSE;
goto cleanup;
}
hConnection = InternetConnect(hSession,
ucUrl.lpszHostName,
INTERNET_DEFAULT_HTTP_PORT,
(LPCSTR) vszCurrentUser,
NULL,
INTERNET_SERVICE_HTTP,
NULL,
NULL);
if(!hConnection)
{
dwError = GetLastError();
fRet = FALSE;
goto cleanup;
}
hHTTPReq = HttpOpenRequest(hConnection,
"PROPFIND",
ucUrl.lpszUrlPath,
"HTTP/1.0",
NULL,
NULL,
INTERNET_FLAG_PRAGMA_NOCACHE,NULL);
if(!hHTTPReq)
{
dwError = GetLastError();
fRet = FALSE;
goto cleanup;
}
if (!HttpAddRequestHeaders(hHTTPReq, lpszHeaders, -1L, HTTP_ADDREQ_FLAG_ADD))
{
dwError = GetLastError();
fRet = FALSE;
goto cleanup;
}
if (!HttpSendRequest(hHTTPReq,NULL, 0L, (LPVOID)lpszXmlRequest, cbReqSize))
{
dwError = GetLastError();
fRet = FALSE;
goto cleanup;
}
if (HttpQueryInfo(hHTTPReq,
HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER,
&dwStatusCode,
&dwStatusLength,
&dwIndex))
{
// fRet = TRUE at this point
// If request was denied or proxy auth required and callee has said
// we can display UI, we put up the InternetErrorDlg and ask for
// credentials. Otherwise, if dwStatus != success we cache that
// this resource is not DAV compliant
if ((hWnd) && ((dwStatusCode == HTTP_STATUS_DENIED) || (dwStatusCode == HTTP_STATUS_PROXY_AUTH_REQ)))
{
DWORD dwRetval;
BOOL fDone;
fDone = FALSE;
while (!fDone)
{
dwRetval = InternetErrorDlg(hWnd,
hHTTPReq,
ERROR_INTERNET_INCORRECT_PASSWORD,
0L,
NULL);
if (dwRetval == ERROR_INTERNET_FORCE_RETRY) // User pressed ok on credentials dialog
{ // Resend request, new credentials are cached and will be replayed by HSR()
if (!HttpSendRequest(hHTTPReq,NULL, 0L, NULL, NULL))
{
dwError = GetLastError();
fRet = FALSE;
goto cleanup;
}
dwStatusCode = 0;
if (!HttpQueryInfo(hHTTPReq,
HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER,
&dwStatusCode,
&dwStatusLength,
&dwIndex))
{
dwError = GetLastError();
fRet = FALSE;
goto cleanup;
}
if ((dwStatusCode != HTTP_STATUS_DENIED) && (dwStatusCode != HTTP_STATUS_PROXY_AUTH_REQ))
{
fDone = TRUE;
}
}
else // User pressed cancel from dialog (note ERROR_SUCCESS == ERROR_CANCELLED from IED())
{
fDone = TRUE;
}
}
}
if ((dwStatusCode == HTTP_STATUS_DENIED) || (dwStatusCode == HTTP_STATUS_PROXY_AUTH_REQ))
{ // Don't want to cache this (user might have forgotten password or we may not
// be able to show credential UI)
goto cleanup;
}
else if (dwStatusCode != HTTP_STATUS_OK)
{ // Either initial request failed for non-auth issue, cache as not compliant
goto update_cache; //note update_cache NOT cleanup, want to cache this as non compliant
}
}
else
{
dwError = GetLastError();
fRet = FALSE;
goto cleanup;
}
// Note, what we are doing here is allocating a single page of memory and reserving
// the first sizeof(LPSTR) bytes to point to the next buffer fragment if required,
// and so on until the last buffer fragment has NULL at the dwPtrOffset
lpszBufferHead = (LPSTR)ALLOCATE_MEMORY(LMEM_FIXED, READ_BUFFER_SIZE);
if (!lpszBufferHead)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
goto cleanup;
}
memset(lpszBufferHead, 0, READ_BUFFER_SIZE);
LPSTR lpNext;
lpNext=lpszBufferHead+sizeof(LPSTR); // Jump over the next buffer ptr space when writing data
while(!fDone)
{
if (!InternetReadFile(hHTTPReq,
lpNext,
READ_BUFFER_AVAILABLE,
&dwRead))
{
dwError = GetLastError();
fRet = FALSE;
goto cleanup;
}
else
{
if (dwRead < READ_BUFFER_AVAILABLE)
{
fDone = TRUE;
}
else
{
dwBuffers++;
*((LPSTR*)lpNext+READ_BUFFER_AVAILABLE) = (LPSTR)ALLOCATE_MEMORY(LMEM_FIXED, READ_BUFFER_SIZE);
lpNext = *((LPSTR*)lpNext+READ_BUFFER_AVAILABLE);
if (!lpNext)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
goto cleanup;
}
memset(lpNext, 0, READ_BUFFER_SIZE);
}
}
}
// Done reading response, time to parse it
update_cache :
#ifdef DAVCACHING // commenting out as per bug 15696
if (TRUE)
// Cache if this is a known DAV level 1 server or atleast the last time we tried
{
// Update visited links cache
// We store the cached info as:
// CacheEntryInfo.dwExemptDelta(HiWord) = Date DAV discovery was last run
// CacheEntryInfo.dwExemptDelta(LoWord) & DAV_LEVEL1_STATUS = Is DAV server (*lpfFound)
// CacheEntryInfo.dwExemptDelta(LoWord) & DAV_COLLECTION_STATUS = Is DAV collection (set in HttpCheckDavCollection)
// Assemble the URL to the visited links container "VISITED: username@URL"
DWORD cbNeededBuf = lstrlen("Visited: ") + lstrlen(vszCurrentUser) + lstrlen(lpszUrl) + 32;
lpszVisitedUrl = (LPSTR) ALLOCATE_MEMORY(LMEM_FIXED, cbNeededBuf);
if (!lpszVisitedUrl)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
goto cleanup;
}
lstrcpy(lpszVisitedUrl, "Visited: "); // For compatibility with urlhist.c visited URLs
lstrcat(lpszVisitedUrl, vszCurrentUser);
lstrcat(lpszVisitedUrl, "@");
lstrcat(lpszVisitedUrl, lpszUrl);
lpCEI = (LPCACHE_ENTRY_INFO) ALLOCATE_MEMORY(LMEM_FIXED, CEI_BUFFER_SIZE);
if (!lpCEI)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
goto cleanup;
}
GetSystemTimeAsFileTime(&ftNow);
if (!FileTimeToDosDateTime(&ftNow,
&wDate,
&wTime
))
{
INET_ASSERT(FALSE); // Should "never" hit this
goto cleanup;
}
// Stuff our 16-bit Date into the upper 16-bits of dwExemptDelta
lpCEI->dwExemptDelta = (DWORD)wDate <<16;
// Set the DAV_LEVEL1_STATUS_BIT if the resource was found compliant above
if (*lpfFound)
{
lpCEI->dwExemptDelta |= (DWORD) DAV_LEVEL1_STATUS;
}
if (!SetUrlCacheEntryInfo (lpszVisitedUrl,
lpCEI,
CACHE_ENTRY_EXEMPT_DELTA_FC
))
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
// No existing cache entry, so create one and try again
{
FILETIME ftNone;
if (CommitUrlCacheEntry (lpszVisitedUrl,
NULL,
ftNone,
ftNone,
0,
NULL,
0,
NULL,
0
))
{
// Entry is now created, so try one more time
SetUrlCacheEntryInfo (lpszVisitedUrl,
lpCEI,
CACHE_ENTRY_EXEMPT_DELTA_FC
);
}
}
}
}
#endif //DAVCACHING
cleanup:
// Free memory
// Walk buffer chain
if (lpszBufferHead)
{
lpNext = (LPSTR)*(lpszBufferHead+READ_BUFFER_AVAILABLE);
FREE_MEMORY(lpszBufferHead);
while (lpNext)
{
lpszBufferHead = lpNext;
lpNext = (LPSTR)*(lpszBufferHead+READ_BUFFER_AVAILABLE);
FREE_MEMORY(lpszBufferHead);
}
}
if (lpszXmlRequest) FREE_MEMORY(lpszXmlRequest);
if (lpCEI) FREE_MEMORY (lpCEI);
if (lpszVisitedUrl) FREE_MEMORY (lpszVisitedUrl);
// Close the handles
if (hHTTPReq) InternetCloseHandle(hHTTPReq);
if (hConnection) InternetCloseHandle(hConnection);
SetLastError(dwError);
DEBUG_LEAVE_API(fRet);
return fRet;
}
#ifdef DAVCACHING // commenting out as per bug 15696
INTERNETAPI_(BOOL) HttpCheckCachedDavStatusA(
IN LPCSTR lpszUrl,
IN OUT LPDWORD lpdwStatus
)
/*++
Routine Description:
Checks if there is cached DAV information for this site or if detection is required, After a successfull call,
*lpdwStatus will contain a bitfield as described in arguments below.
Checks HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\DaysBetweenDavDetection for time in days
to pass between performing detection. If this key is missing, a default of 10 is used.
Arguments:
lpszUrl - Url of the resource to check
lpdwStatus - address of a DWORD (which must contain zero initially!!) that on return may contain a
combination of the following staus bits:
DAV_LEVEL1_STATUS - If this bit is set, the site is known to support DAV level 1
DAV_COLLECTION_STATUS - If this bit is set, the resource is a collection.
DAV_DETECTION_REQUIRED - Either no information is available or information is stale and detection should be performed.
Return Value:
TRUE - Success, check lpdwStatus for results.
FALSE - failure, GetLastError returns the error code
--*/
{
BOOL fRet = TRUE;
DEBUG_ENTER((DBG_API,
Bool,
"HttpCheckCachedDavStatusA",
"%sq, %#x",
lpszUrl,
lpdwStatus
));
DWORD dwError;
LPCACHE_ENTRY_INFO lpCEI = NULL;
FILETIME ftNow, ftNext, ftWork;
WORD wDate;
LPSTR lpszVisitedUrl=NULL;
DWORD cbCEI = 512, dwDays = 0;
#define DEFAULT_DAV_DAYS 10
#define FILE_SEC_TICKS (10000000)
// SECS PER DAY
#define DAY_SECS (24*60*60)
// Debug param checking
INET_ASSERT(lpszUrl && lpdwStatus && (*lpdwStatus==0));
DEBUG_ENTER_API((DBG_API,
Bool,
"HttpCheckCachedDavStatusA",
"%s %x %x",
(lpszUrl)?lpszUrl :"NULL Url",
lpdwStatus,
*lpdwStatus
));
// non-debug param checking
if (!lpszUrl || !lpdwStatus || (*lpdwStatus != 0))
{
dwError = ERROR_INVALID_PARAMETER;
fRet = FALSE;
goto cleanup;
}
// Ensures the global vszCurrentUser is set
GetWininetUserName();
INET_ASSERT(vszCurrentUser);
// Check visited links cache
// We store the cached info as:
// CacheEntryInfo.dwExemptDelta(HiWord) = Date DAV discovery was last run
// CacheEntryInfo.dwExemptDelta(LoWord) & DAV_LEVEL1_STATUS = Is DAV server (*lpfFound)
// CacheEntryInfo.dwExemptDelta(LoWord) & DAV_COLLECTION_STATUS = Is DAV collection (set in HttpCheckDavCollection)
// Assemble the URL to the visited links container "VISITED: username@URL"
DWORD cbNeededBuf = lstrlen("Visited: ") + lstrlen(vszCurrentUser) + lstrlen(lpszUrl) + 32;
lpszVisitedUrl = (LPSTR) ALLOCATE_MEMORY(LMEM_FIXED, cbNeededBuf);
if (!lpszVisitedUrl)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
goto cleanup;
}
lstrcpy(lpszVisitedUrl, "Visited: "); // For compatibility with urlhist.c visited URLs
lstrcat(lpszVisitedUrl, vszCurrentUser);
lstrcat(lpszVisitedUrl, "@");
lstrcat(lpszVisitedUrl, lpszUrl);
lpCEI = (LPCACHE_ENTRY_INFO) ALLOCATE_MEMORY(LMEM_FIXED, cbCEI);
if (!lpCEI)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
goto cleanup;
}
if (!GetUrlCacheEntryInfo (lpszVisitedUrl,
lpCEI,
&cbCEI
))
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
// No existing cache entry, so return DAV_DETECTION_REQUIRED
{
*lpdwStatus = DAV_DETECTION_REQUIRED;
goto cleanup;
}
else
{
dwError = GetLastError();
fRet = FALSE;
goto cleanup;
}
}
// Get registry setting for # of days between detection or use default if not found
if ((dwError = InternetReadRegistryDword("DaysBetweenDavDetection", &dwDays)) != ERROR_SUCCESS)
{
dwDays = DEFAULT_DAV_DAYS;
}
// Get the last date we checked this URL
wDate = HIWORD(lpCEI->dwExemptDelta);
DosDateTimeToFileTime(wDate, WORD(0), &ftWork);
_int64 i64Base;
i64Base = (((_int64)ftWork.dwHighDateTime) << 32) | ftWork.dwLowDateTime;
i64Base /= FILE_SEC_TICKS;
i64Base /= DAY_SECS;
i64Base += dwDays;
i64Base *= FILE_SEC_TICKS;
i64Base *= DAY_SECS;
ftNext.dwHighDateTime = (DWORD) ((i64Base >> 32) & 0xFFFFFFFF);
ftNext.dwLowDateTime = (DWORD) (i64Base & 0xFFFFFFFF);
GetSystemTimeAsFileTime(&ftNow);
if (CompareFileTime(ftNow, ftNext) >= 0) // If Now >= Next detect date
{
*lpdwStatus = DAV_DETECTION_REQUIRED;
}
*lpdwStatus |= LOWORD(lpCEI->dwExemptDelta);
dwError = ERROR_SUCCESS;
cleanup:
// Free memory
if (lpCEI) FREE_MEMORY (lpCEI);
if (lpszVisitedUrl) FREE_MEMORY (lpszVisitedUrl);
SetLastError(dwError);
DEBUG_LEAVE_API(fRet);
return fRet;
}
#endif //DAVCACHING
INTERNETAPI_(BOOL) HttpCheckDavComplianceW(
IN LPCWSTR lpszUrlW,
IN LPCWSTR lpszComplianceTokenW,
IN OUT LPBOOL lpfFound,
IN HWND hWnd,
IN LPVOID lpvReserved
)
/*++
Routine Description:
Determines the level of DAV compliance of the server. Currently just checks for level 1
compliance and returns TRUE in lpfFound if detected.
Arguments:
lpszServer - name of server to check
lpszPath - path to resource on the server to check
lpszComplianceToken - DAV compliance class identifier (i.e. "1") BUGBUG MUST NOT CONTAIN INTERNAL WHITE SPACE "foo bar" = bad, " foo " = ok
lpfFound - address of a BOOL to receive TRUE if DAV compliance is found or FALSE otherwise.
hWnd - Handle to window for displaying authentication dialog if needed. May be NULL indicating
no UI is to be displayed and authentication failures should be quietly handled.
lpvReserved - Reserved, must be NULL
Return Value:
TRUE - Success, check lpfFound for results.
FALSE - failure, GetLastError returns the error code
--*/
{
DEBUG_ENTER((DBG_API,
Bool,
"HttpCheckDavComplianceW",
"%wq, %wq, %#x, %#x, %#x",
lpszUrlW,
lpszComplianceTokenW,
lpfFound,
hWnd,
lpvReserved
));
MEMORYPACKET mpUrlA, mpComplianceTokenA;
BOOL fRet = TRUE;
DWORD dwError = ERROR_SUCCESS;
// Debug param checking
INET_ASSERT(lpszUrlW && lpszComplianceTokenW && lpfFound && !lpvReserved);
// non-debug param checking
if (!lpszUrlW || !lpszComplianceTokenW || !lpfFound || lpvReserved)
{
dwError = ERROR_INVALID_PARAMETER;
fRet = FALSE;
goto cleanup;
}
ALLOC_MB(lpszUrlW, 0, mpUrlA);
if (!mpUrlA.psStr)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
fRet = FALSE;
goto cleanup;
}
UNICODE_TO_ANSI(lpszUrlW, mpUrlA);
// MAKE_ANSI(lpszComplianceTokenW, 0, mpComplianceTokenA);
ALLOC_MB(lpszComplianceTokenW, 0, mpComplianceTokenA);
if (!mpComplianceTokenA.psStr)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
fRet = FALSE;
goto cleanup;
}
UNICODE_TO_ANSI(lpszComplianceTokenW, mpComplianceTokenA);
fRet = HttpCheckDavComplianceA(mpUrlA.psStr, mpComplianceTokenA.psStr, lpfFound, hWnd, lpvReserved);
cleanup:
DEBUG_LEAVE_API(fRet);
return(fRet);
}
#ifdef DAVCACHING //commenting out as per bug 15696
INTERNETAPI_(BOOL) HttpCheckCachedDavStatusW(
IN LPCWSTR lpszUrlW,
IN OUT LPDWORD lpdwStatus
)
/*++
Routine Description:
Checks if there is cached DAV information for this site or if detection is required,
Arguments:
lpszUrl - Url of the resource to check
lpdwStatus - address of a DWORD (which must contain zero initially!!) that on return may contain a
combination of the following staus bits:
DAV_LEVEL1_STATUS - If this bit is set, the site is known to support DAV level 1
DAV_COLLECTION_STATUS - If this bit is set, the resource is a collection.
DAV_DETECTION_REQUIRED - Either no information is available or information is stale and detection should be performed.
Return Value:
TRUE - Success, check lpdwStatus for results.
FALSE - failure, GetLastError returns the error code
--*/
{
DEBUG_ENTER((DBG_API,
Bool,
"HttpCheckCachedDavStatusW",
"%wq, %#x",
lpszUrlW,
lpdwStatus
));
MEMORYPACKET mpUrlA;
BOOL fRet = TRUE;
DWORD dwError = ERROR_SUCCESS;
// Debug param checking
INET_ASSERT(lpszUrlW && lpdwStatus && (*lpdwStatus==0));
// non-debug param checking
if (!lpszUrlW || !lpdwStatus || (*lpdwStatus!=0))
{
dwError = ERROR_INVALID_PARAMETER;
fRet = FALSE;
goto cleanup;
}
ALLOC_MB(lpszUrlW, 0, mpUrlA);
if (!mpUrlA.psStr)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
fRet = FALSE;
goto cleanup;
}
UNICODE_TO_ANSI(lpszUrlW, mpUrlA);
fRet = HttpCheckCachedDavStatusA(mpUrlA.psStr, lpdwStatus);
cleanup:
DEBUG_LEAVE_API(fRet);
return(fRet);
}
#endif //DAVCACHING