CookieHandler.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Core / CSharp / MS / Internal / AppModel / CookieHandler.cs / 1 / 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   ChangoV     Created
// 
//-----------------------------------------------------------------------
 
using System; 
using System.Net;
using System.Security; 
using System.Diagnostics;
using System.ComponentModel;
using System.Runtime.InteropServices;
 
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 before returning data. 
    /// 
    [SecurityCritical, SecurityTreatAsSafe] 
    [FriendAccessAllowed] // called by PF.Application.GetCookie()
    internal static string GetCookie(Uri uri, bool throwIfNoCookie)
    {
        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)) 
            {
                SecurityHelper.DemandWebPermission(uri); 
                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   ChangoV     Created
// 
//-----------------------------------------------------------------------
 
using System; 
using System.Net;
using System.Security; 
using System.Diagnostics;
using System.ComponentModel;
using System.Runtime.InteropServices;
 
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 before returning data. 
    /// 
    [SecurityCritical, SecurityTreatAsSafe] 
    [FriendAccessAllowed] // called by PF.Application.GetCookie()
    internal static string GetCookie(Uri uri, bool throwIfNoCookie)
    {
        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)) 
            {
                SecurityHelper.DemandWebPermission(uri); 
                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