CookieHandler.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / MS / Internal / AppModel / CookieHandler.cs / 1305600 / CookieHandler.cs

                            //+------------------------------------------------------------------------ 
//
//  Copyright (c) Microsoft Corporation.  All rights reserved.
//
//  Description: 
//      A helper class for access to HTTP cookies and attaching cookies to HttpWebRequests and storing
//      cookies from HttpWebResponses. 
// 
//      In standalone WPF applications, the WinInet cookie store is used. PresentationHost intercepts calls
//      to the WinInet cookie functions and delegates them to the browser. See host\DLL\CookieShim.hxx. 
//
//  History:
//     2007/04/11   [....]     Created
// 
//-----------------------------------------------------------------------
 
using System; 
using System.Net;
using System.Security; 
using System.Diagnostics;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Diagnostics.CodeAnalysis; 

using System.Windows; 
using System.Windows.Interop; 
using MS.Win32;
using MS.Internal.PresentationCore; 

namespace MS.Internal.AppModel
{
 
static class CookieHandler
{ 
    internal static void HandleWebRequest(WebRequest request) 
    {
        HttpWebRequest httpRequest = request as HttpWebRequest; 
        if (httpRequest != null)
        {
            try
            { 
                string cookies = GetCookie(httpRequest.RequestUri, false/*throwIfNoCookie*/);
                if(!string.IsNullOrEmpty(cookies)) 
                { 
                    if (httpRequest.CookieContainer == null)
                    { 
                        httpRequest.CookieContainer = new CookieContainer();
                    }
                    // CookieContainer.SetCookies() expects multiple cookie definitions to be separated by
                    // comma, but GetCookie() returns them separated by ';', so we change that. 
                    // Comma is generally not valid within a cookie (except in the 'expires' date setting, but
                    // we don't get that from GetCookie()). 
                    // ClickOnce does the same in System.Deployment.Application.SystemNetDownloader.DownloadSingleFile(). 
                    httpRequest.CookieContainer.SetCookies(httpRequest.RequestUri, cookies.Replace(';', ','));
                } 
            }
            catch (Exception ex) // Attaching cookies shouldn't fail a web request.
            {
                if (CriticalExceptions.IsCriticalException(ex)) 
                    throw;
            } 
        } 
    }
 
    /// 
    /// Extracts cookies from a (Http)WebResponse and stores them.
    /// 
    ///  
    /// Critical: Calls SetCookieUnsafe().
    ///     An authentic WebResponse is expected, not altered by untrusted code. P3P headers fabricated by the 
    ///     application cannot be trusted. And the application should have been able to make the web request in 
    ///     the first place. Otherwise there is danger of overwriting someone else's cookies.
    ///  
    [SecurityCritical]
    internal static void HandleWebResponse(WebResponse response)
    {
        HttpWebResponse httpResponse = response as HttpWebResponse; 
        if (httpResponse != null)
        { 
            // Not relying on httpResponse.Cookies, because the original cookie header is needed, with all 
            // attributes. (A CookieCollection can be stuffed in a CookieContainer, but CookieContainer.
            // GetCookieHeader() returns only name=value pairs.) 
            WebHeaderCollection headers = httpResponse.Headers;
            // Further complication: headers["Set-cookie"] returns all cookies comma-separated. Splitting them
            // is not trivial, because expiration dates have commas.
            // Plan B fails too: headers.GetValues("Set-Cookie") returns the cookies broken: It does some 
            // "normalization" and munging and apparently confuses the commas in cookie expiration dates for
            // cookie separators... 
            // The working solution is to find the index of the header and get all individual raw values 
            // associated with it. (WebHeaderCollection's internal storage is a string->ArrayList(of string) map.)
            for (int i = headers.Count-1; i >= 0; i--) 
            {
                if (string.Compare(headers.Keys[i], "Set-Cookie", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    string p3pHeader = httpResponse.Headers["P3P"]; 
                    foreach (string cookie in headers.GetValues(i))
                    { 
                        try 
                        {
                            SetCookieUnsafe(httpResponse.ResponseUri, cookie, p3pHeader); 
                        }
                        catch (Exception ex) // A malformed cookie shouldn't fail the whole web request.
                        {
                            if (CriticalExceptions.IsCriticalException(ex)) 
                                throw;
                        } 
                    } 

                    break; 
                }
            }
        }
    } 

    ///  
    /// Critical: Calls the native InternetGetCookieEx(). There is potential for information disclosure. 
    /// Safe: A WebPermission demand is made for the given URI.
    ///  
    [SecurityCritical, SecurityTreatAsSafe]
    [FriendAccessAllowed] // called by PF.Application.GetCookie()
    [SuppressMessage("Microsoft.Interoperability", "CA1404:CallGetLastErrorImmediatelyAfterPInvoke",
        Justification="It's okay now. Be careful on change.")] 
    internal static string GetCookie(Uri uri, bool throwIfNoCookie)
    { 
        // Always demand in order to prevent any cross-domain information leak. 
        SecurityHelper.DemandWebPermission(uri);
 
        UInt32 size = 0;
        string uriString = BindUriHelper.UriToString(uri);
        if (UnsafeNativeMethods.InternetGetCookieEx(uriString, null, null, ref size, 0, IntPtr.Zero))
        { 
            Debug.Assert(size > 0);
            size++; 
            System.Text.StringBuilder sb = new System.Text.StringBuilder((int)size); 
            // PresentationHost intercepts InternetGetCookieEx(). It will set the INTERNET_COOKIE_THIRD_PARTY
            // flag if necessary. 
            if (UnsafeNativeMethods.InternetGetCookieEx(uriString, null, sb, ref size, 0, IntPtr.Zero))
            {
                return sb.ToString();
            } 
        }
        if (!throwIfNoCookie && Marshal.GetLastWin32Error() == NativeMethods.ERROR_NO_MORE_ITEMS) 
            return null; 
        throw new Win32Exception(/*uses last error code*/);
    } 

    /// 
    /// Critical: Calls SetCookieUnsafe().
    /// Safe: A WebPermission is demanded for the cookie URI, and no P3P header is passed. 
    /// 
    [SecurityCritical, SecurityTreatAsSafe] 
    [FriendAccessAllowed] // called by PF.Application.SetCookie() 
    internal static bool SetCookie(Uri uri, string cookieData)
    { 
        SecurityHelper.DemandWebPermission(uri);

        return SetCookieUnsafe(uri, cookieData, null);
    } 

    ///  
    /// Critical: Sets cookies via the native InternetSetCookieEx(); doesn't demand WebPermission for the given 
    ///     URI. This creates danger of overwriting someone else's cookies.
    ///     The P3P header has to be from an authentic web response in order to be trusted at all. 
    /// 
    [SecurityCritical]
    private static bool SetCookieUnsafe(Uri uri, string cookieData, string p3pHeader)
    { 
        string uriString = BindUriHelper.UriToString(uri);
        // PresentationHost intercepts InternetSetCookieEx(). It will set the INTERNET_COOKIE_THIRD_PARTY 
        // flag if necessary. (This doesn't look very elegant but is much simpler than having to make the 
        // 3rd party decision here as well or calling into the native code (from PresentationCore).)
        uint res = UnsafeNativeMethods.InternetSetCookieEx( 
            uriString, null, cookieData, UnsafeNativeMethods.INTERNET_COOKIE_EVALUATE_P3P, p3pHeader);
        if(res == 0)
            throw new Win32Exception(/*uses last error code*/);
        return res != UnsafeNativeMethods.COOKIE_STATE_REJECT; 
    }
 
}; 

} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//+------------------------------------------------------------------------ 
//
//  Copyright (c) Microsoft Corporation.  All rights reserved.
//
//  Description: 
//      A helper class for access to HTTP cookies and attaching cookies to HttpWebRequests and storing
//      cookies from HttpWebResponses. 
// 
//      In standalone WPF applications, the WinInet cookie store is used. PresentationHost intercepts calls
//      to the WinInet cookie functions and delegates them to the browser. See host\DLL\CookieShim.hxx. 
//
//  History:
//     2007/04/11   [....]     Created
// 
//-----------------------------------------------------------------------
 
using System; 
using System.Net;
using System.Security; 
using System.Diagnostics;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Diagnostics.CodeAnalysis; 

using System.Windows; 
using System.Windows.Interop; 
using MS.Win32;
using MS.Internal.PresentationCore; 

namespace MS.Internal.AppModel
{
 
static class CookieHandler
{ 
    internal static void HandleWebRequest(WebRequest request) 
    {
        HttpWebRequest httpRequest = request as HttpWebRequest; 
        if (httpRequest != null)
        {
            try
            { 
                string cookies = GetCookie(httpRequest.RequestUri, false/*throwIfNoCookie*/);
                if(!string.IsNullOrEmpty(cookies)) 
                { 
                    if (httpRequest.CookieContainer == null)
                    { 
                        httpRequest.CookieContainer = new CookieContainer();
                    }
                    // CookieContainer.SetCookies() expects multiple cookie definitions to be separated by
                    // comma, but GetCookie() returns them separated by ';', so we change that. 
                    // Comma is generally not valid within a cookie (except in the 'expires' date setting, but
                    // we don't get that from GetCookie()). 
                    // ClickOnce does the same in System.Deployment.Application.SystemNetDownloader.DownloadSingleFile(). 
                    httpRequest.CookieContainer.SetCookies(httpRequest.RequestUri, cookies.Replace(';', ','));
                } 
            }
            catch (Exception ex) // Attaching cookies shouldn't fail a web request.
            {
                if (CriticalExceptions.IsCriticalException(ex)) 
                    throw;
            } 
        } 
    }
 
    /// 
    /// Extracts cookies from a (Http)WebResponse and stores them.
    /// 
    ///  
    /// Critical: Calls SetCookieUnsafe().
    ///     An authentic WebResponse is expected, not altered by untrusted code. P3P headers fabricated by the 
    ///     application cannot be trusted. And the application should have been able to make the web request in 
    ///     the first place. Otherwise there is danger of overwriting someone else's cookies.
    ///  
    [SecurityCritical]
    internal static void HandleWebResponse(WebResponse response)
    {
        HttpWebResponse httpResponse = response as HttpWebResponse; 
        if (httpResponse != null)
        { 
            // Not relying on httpResponse.Cookies, because the original cookie header is needed, with all 
            // attributes. (A CookieCollection can be stuffed in a CookieContainer, but CookieContainer.
            // GetCookieHeader() returns only name=value pairs.) 
            WebHeaderCollection headers = httpResponse.Headers;
            // Further complication: headers["Set-cookie"] returns all cookies comma-separated. Splitting them
            // is not trivial, because expiration dates have commas.
            // Plan B fails too: headers.GetValues("Set-Cookie") returns the cookies broken: It does some 
            // "normalization" and munging and apparently confuses the commas in cookie expiration dates for
            // cookie separators... 
            // The working solution is to find the index of the header and get all individual raw values 
            // associated with it. (WebHeaderCollection's internal storage is a string->ArrayList(of string) map.)
            for (int i = headers.Count-1; i >= 0; i--) 
            {
                if (string.Compare(headers.Keys[i], "Set-Cookie", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    string p3pHeader = httpResponse.Headers["P3P"]; 
                    foreach (string cookie in headers.GetValues(i))
                    { 
                        try 
                        {
                            SetCookieUnsafe(httpResponse.ResponseUri, cookie, p3pHeader); 
                        }
                        catch (Exception ex) // A malformed cookie shouldn't fail the whole web request.
                        {
                            if (CriticalExceptions.IsCriticalException(ex)) 
                                throw;
                        } 
                    } 

                    break; 
                }
            }
        }
    } 

    ///  
    /// Critical: Calls the native InternetGetCookieEx(). There is potential for information disclosure. 
    /// Safe: A WebPermission demand is made for the given URI.
    ///  
    [SecurityCritical, SecurityTreatAsSafe]
    [FriendAccessAllowed] // called by PF.Application.GetCookie()
    [SuppressMessage("Microsoft.Interoperability", "CA1404:CallGetLastErrorImmediatelyAfterPInvoke",
        Justification="It's okay now. Be careful on change.")] 
    internal static string GetCookie(Uri uri, bool throwIfNoCookie)
    { 
        // Always demand in order to prevent any cross-domain information leak. 
        SecurityHelper.DemandWebPermission(uri);
 
        UInt32 size = 0;
        string uriString = BindUriHelper.UriToString(uri);
        if (UnsafeNativeMethods.InternetGetCookieEx(uriString, null, null, ref size, 0, IntPtr.Zero))
        { 
            Debug.Assert(size > 0);
            size++; 
            System.Text.StringBuilder sb = new System.Text.StringBuilder((int)size); 
            // PresentationHost intercepts InternetGetCookieEx(). It will set the INTERNET_COOKIE_THIRD_PARTY
            // flag if necessary. 
            if (UnsafeNativeMethods.InternetGetCookieEx(uriString, null, sb, ref size, 0, IntPtr.Zero))
            {
                return sb.ToString();
            } 
        }
        if (!throwIfNoCookie && Marshal.GetLastWin32Error() == NativeMethods.ERROR_NO_MORE_ITEMS) 
            return null; 
        throw new Win32Exception(/*uses last error code*/);
    } 

    /// 
    /// Critical: Calls SetCookieUnsafe().
    /// Safe: A WebPermission is demanded for the cookie URI, and no P3P header is passed. 
    /// 
    [SecurityCritical, SecurityTreatAsSafe] 
    [FriendAccessAllowed] // called by PF.Application.SetCookie() 
    internal static bool SetCookie(Uri uri, string cookieData)
    { 
        SecurityHelper.DemandWebPermission(uri);

        return SetCookieUnsafe(uri, cookieData, null);
    } 

    ///  
    /// Critical: Sets cookies via the native InternetSetCookieEx(); doesn't demand WebPermission for the given 
    ///     URI. This creates danger of overwriting someone else's cookies.
    ///     The P3P header has to be from an authentic web response in order to be trusted at all. 
    /// 
    [SecurityCritical]
    private static bool SetCookieUnsafe(Uri uri, string cookieData, string p3pHeader)
    { 
        string uriString = BindUriHelper.UriToString(uri);
        // PresentationHost intercepts InternetSetCookieEx(). It will set the INTERNET_COOKIE_THIRD_PARTY 
        // flag if necessary. (This doesn't look very elegant but is much simpler than having to make the 
        // 3rd party decision here as well or calling into the native code (from PresentationCore).)
        uint res = UnsafeNativeMethods.InternetSetCookieEx( 
            uriString, null, cookieData, UnsafeNativeMethods.INTERNET_COOKIE_EVALUATE_P3P, p3pHeader);
        if(res == 0)
            throw new Win32Exception(/*uses last error code*/);
        return res != UnsafeNativeMethods.COOKIE_STATE_REJECT; 
    }
 
}; 

} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK