I am trying to retrieve cookies using c#, but I get an error 12006 complaining about the URL. I use InternetGetCookieEx
successfully to retrieve cookie data, but I need to retrieve the entire cookie for my current exercise
I'm not sure If I call it incorrectly, or my flags is not correct, but there are only 4 flags, and 2 of them is retrictive. My problem I believe is the pointer of the array of INTERNET_COOKIE2
that needs to returned. I am really stuck here and need some guidance.
This is my code
[DllImport("wininet.dll", SetLastError = true)]
internal static extern bool InternetGetCookieEx2(
string url,
string cookieName,
Int32 dwFlags,
INTERNET_COOKIE[] cookie,
ref Int32 cookieCount);
[SecurityCritical]
public static Cookie[] GetCookieInternal(Uri uri, bool throwIfNoCookie)
{
int cookieCount = 0;
string url = UriToString(uri);
int flag = 0;
DemandWebPermission(uri);
//There is no error here, but cookieCount comes back as 0. If I ommit this code and
//pass in the array directly I get the 12006 error. url is valid. I've checked multiple times
if (CookieHelper.InternetGetCookieEx2(url, null, flag, null, ref cookieCount))
{
if (cookieCount > 0)
{
CookieHelper.INTERNET_COOKIE[] pchCookies = new CookieHelper.INTERNET_COOKIE[cookieCount];
if (CookieHelper.InternetGetCookieEx2(url, null, flag, pchCookies, ref cookieCount))
{
var result = new Cookie[cookieCount];
for (int i = 0; i < cookieCount; i++)
{
result[i] = new Cookie
{
HttpOnly = (pchCookies[i].dwFlags & (int)CookieHelper.InternetFlags.INTERNET_COOKIE_HTTPONLY) > 0,
Domain = pchCookies[i].pwszDomain,
Expired = pchCookies[i].fExpiresSet,
Expires = pchCookies[i].fExpiresSet ? DateTime.FromFileTime(pchCookies[i].ftExpires.dwHighDateTime) : DateTime.MinValue,
Name = pchCookies[i].pwszName,
Path = pchCookies[i].pwszPath,
Secure = (pchCookies[i].dwFlags & (int)CookieHelper.InternetFlags.INTERNET_COOKIE_IS_SECURE) > 0,
Value = pchCookies[i].pwszValue
};
}
return result;
}
}
}
int lastErrorCode = Marshal.GetLastWin32Error();
if (throwIfNoCookie || (lastErrorCode != (int)CookieHelper.ErrorFlags.ERROR_NO_MORE_ITEMS))
{
throw new Win32Exception(lastErrorCode);
}
return null;
}
private static void DemandWebPermission(Uri uri)
{
string uriString = UriToString(uri);
if (uri.IsFile)
{
string localPath = uri.LocalPath;
new FileIOPermission(FileIOPermissionAccess.Read, localPath).Demand();
}
else
{
new WebPermission(NetworkAccess.Connect, uriString).Demand();
}
}
private static string UriToString(Uri uri)
{
if (uri == null)
{
throw new ArgumentNullException("uri");
}
UriComponents components = (uri.IsAbsoluteUri ? UriComponents.AbsoluteUri : UriComponents.SerializationInfoString);
return new StringBuilder(uri.GetComponents(components, UriFormat.SafeUnescaped), 2083).ToString();
}
UPDATE Working Code Here is my code for anyone in the future.
public class CookieHelper
{
[DllImport("wininet.dll", CharSet = CharSet.Unicode)]
internal static extern int InternetGetCookieEx2(
string url,
string cookieName,
int dwFlags,
[Out] out IntPtr cookie,
[Out] out int cookieCount);
[DllImport("wininet.dll")]
internal static extern void InternetFreeCookies(
IntPtr pCookies,
int dwCookieCount);
public enum InternetFlags
{
INTERNET_COOKIE_IS_SECURE = 32,
INTERNET_COOKIE_HTTPONLY = 8192, //Requires IE 8 or higher
INTERNET_COOKIE_THIRD_PARTY = 131072,
INTERNET_FLAG_RESTRICTED_ZONE = 16
}
public struct INTERNET_COOKIE
{
public IntPtr pwszName;
public IntPtr pwszValue;
public IntPtr pwszDomain;
public IntPtr pwszPath;
public int dwFlags;
public System.Runtime.InteropServices.ComTypes.FILETIME ftExpires;
public bool fExpiresSet;
}
}
public class FullWebBrowserCookie
{
/// <summary>
/// Internal Get Cookie
/// </summary>
/// <param name="uri"></param>
/// <param name="throwIfNoCookie"></param>
/// <returns></returns>
[SecurityCritical]
public static Cookie[] GetCookieInternal(Uri uri, bool throwIfNoCookie)
{
string url = UriToString(uri);
int flag = 0; //Change to 4096 if you want to retrieve HTTP Only cookies
DemandWebPermission(uri);
var error = CookieHelper.InternetGetCookieEx2(url, null, flag, out var ptr, out var cookieCount);
if (error != 0)
throw new Win32Exception(error);
if (ptr == IntPtr.Zero)
{
if (throwIfNoCookie)
throw new InvalidOperationException("No cookie");
return Array.Empty<Cookie>();
}
try
{
if (throwIfNoCookie && cookieCount == 0)
throw new InvalidOperationException("No cookie");
var result = new Cookie[cookieCount];
var size = Marshal.SizeOf<CookieHelper.INTERNET_COOKIE>();
for (int i = 0; i < cookieCount; i++)
{
var pchCookie = Marshal.PtrToStructure<CookieHelper.INTERNET_COOKIE>(ptr + i * size);
result[i] = new Cookie
{
HttpOnly = (pchCookie.dwFlags & (int)CookieHelper.InternetFlags.INTERNET_COOKIE_HTTPONLY) > 0,
Domain = Marshal.PtrToStringAuto(pchCookie.pwszDomain),
Expires = pchCookie.fExpiresSet ? DateTime.FromFileTime((((long)pchCookie.ftExpires.dwHighDateTime) << 32) + pchCookie.ftExpires.dwLowDateTime) : DateTime.MinValue,
Expired = pchCookie.fExpiresSet && DateTime.FromFileTime((((long)pchCookie.ftExpires.dwHighDateTime) << 32) + pchCookie.ftExpires.dwLowDateTime) < DateTime.Now,
Name = Marshal.PtrToStringAuto(pchCookie.pwszName),
Path = Marshal.PtrToStringAuto(pchCookie.pwszPath),
Secure = (pchCookie.dwFlags & (int)CookieHelper.InternetFlags.INTERNET_COOKIE_IS_SECURE) > 0,
Value = Marshal.PtrToStringAuto(pchCookie.pwszValue)
};
}
return result;
}
finally
{
CookieHelper.InternetFreeCookies(ptr, cookieCount);
}
}
private static void DemandWebPermission(Uri uri)
{
string uriString = UriToString(uri);
if (uri.IsFile)
{
string localPath = uri.LocalPath;
new FileIOPermission(FileIOPermissionAccess.Read, localPath).Demand();
}
else
{
new WebPermission(NetworkAccess.Connect, uriString).Demand();
}
}
private static string UriToString(Uri uri)
{
if (uri == null)
{
throw new ArgumentNullException("uri");
}
UriComponents components = (uri.IsAbsoluteUri ? UriComponents.AbsoluteUri : UriComponents.SerializationInfoString);
return new StringBuilder(uri.GetComponents(components, UriFormat.SafeUnescaped), 2083).ToString();
}
}
You seems to have mixed up the docs for InternetGetCookieEx2
with the docs for InternetGetCookieEx
.
You have a number of issues:
InternetGetCookieEx2
does not set the last error code, it just returns it.CharSet.Unicode
.InternetGetCookieEx2
is not documented to return partial results, you will get everything in a single call.PtrToStructure
manually.Unicode
to your struct, so that the strings are marshalled correctly.[DllImport("wininet.dll", CharSet = CharSet.Unicode)]
internal static extern int InternetGetCookieEx2(
string? url,
string? cookieName,
int dwFlags,
[Out] out IntPtr cookie,
[Out] out int cookieCount);
[DllImport("wininet.dll")]
internal static extern void InternetFreeCookies(
IntPtr pCookies,
int dwCookieCount);
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct INTERNET_COOKIE2
{
public string pwszName;
public string pwszValue;
public string pwszDomain;
public string pwszPath;
public int dwFlags;
public System.Runtime.InteropServices.ComTypes.FILETIME ftExpires;
public bool fExpiresSet;
}
[SecurityCritical]
public static Cookie[] GetCookieInternal(Uri uri, bool throwIfNoCookie)
{
string url = UriToString(uri);
int flag = 0;
DemandWebPermission(uri);
var error = CookieHelper.InternetGetCookieEx2(url, null, flag, out var ptr, out var cookieCount);
if (error != 0)
throw new Win32Exception(error);
if (ptr == IntPtr.Zero)
{
if (throwIfNoCookie)
throw new InvalidOperationException("No cookie");
return Array.Empty<Cookie>();
}
try
{
if (throwIfNoCookie && cookieCount == 0)
throw new InvalidOperationException("No cookie");
var result = new Cookie[cookieCount];
var size = Marshal.SizeOf<CookieHelper.INTERNET_COOKIE>();
for (int i = 0; i < cookieCount; i++)
{
var pchCookie = Marshal.PtrToStructure<CookieHelper.INTERNET_COOKIE>(ptr + i * size)
result[i] = new Cookie
{
HttpOnly = (pchCookie.dwFlags & (int)CookieHelper.InternetFlags.INTERNET_COOKIE_HTTPONLY) > 0,
Domain = pchCookie.pwszDomain,
Expired = pchCookie.fExpiresSet,
Expires = pchCookie.fExpiresSet ? DateTime.FromFileTime(pchCookie.ftExpires.dwHighDateTime) : DateTime.MinValue,
Name = pchCookie.pwszName,
Path = pchCookie.pwszPath,
Secure = (pchCookie.dwFlags & (int)CookieHelper.InternetFlags.INTERNET_COOKIE_IS_SECURE) > 0,
Value = pchCookie.pwszValue
};
}
return result;
}
finally
{
InternetFreeCookies(ptr, cookieCount);
}
}