Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Core / System / IO / Packaging / PackWebResponse.cs / 3 / PackWebResponse.cs
//------------------------------------------------------------------------------
//
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//
// Description:
// WebResponse class to handle pack-specific URI's
//
// History:
// 10/09/2003: [....]: Created.
// 01/05/2004: [....]: Rearchitect to return a new stream for each GetResponseStream call.
// 01/08/2004: [....]: Disable serialization
// 05/10/2004: [....]: Port to pack scheme
//
//-----------------------------------------------------------------------------
#if DEBUG
#define TRACE
#endif
using System;
using System.IO;
using System.Net;
using System.Runtime.Serialization;
using System.Diagnostics; // For Assert
using System.Threading; // for ManualResetEvent
using System.Globalization; // for CultureInfo
using MS.Internal.PresentationCore; // for ExceptionStringTable
using MS.Internal.IO.Packaging; // for ResponseStream
using System.Security;
using System.Security.Permissions;
using System.Windows.Navigation;
using MS.Utility;
using MS.Internal;
#pragma warning disable 1634, 1691 // disable warning about unknown Presharp warnings
namespace System.IO.Packaging
{
///
/// Pack-specific WebRequest handler
///
///
/// This WebRequest overload exists to handle Pack-specific URI's based on our custom schema
///
public sealed class PackWebResponse: WebResponse
{
//-----------------------------------------------------
//
// Constructors
//
//-----------------------------------------------------
///
/// Critical as the BooleanSwitch has a LinkDemand
/// TreatAsSafe as this is just a diag switch, Debug-only and internal-only, no input data
/// is passed to BooleanSwitch, and the overall operation is considered safe.
///
[SecurityCritical, SecurityTreatAsSafe]
static PackWebResponse()
{
#if DEBUG
_forceWebResponseLengthFailureSwitch = new BooleanSwitch("PackWebResponseBadServerLength", "Simulate PackWebResponse handling of server that returns bogus content length");
#endif
}
///
/// Constructor
///
/// real web request
/// full uri
/// inner uri
/// part name in the container - null if uri is to entire container only
/// intended for use only by PackWebRequest
///
/// Critical
/// 1) assigns Critical member _webRequest and calls BeginGetResponse() on it.
///
[SecurityCritical]
internal PackWebResponse(Uri uri, Uri innerUri, Uri partName, WebRequest innerRequest)
{
if (uri == null)
throw new ArgumentNullException("uri");
if (innerUri == null)
throw new ArgumentNullException("innerUri");
if (innerRequest == null)
throw new ArgumentNullException("innerRequest");
_lockObject = new Object(); // required for synchronization
_uri = uri;
#if DEBUG
if (PackWebRequestFactory._traceSwitch.Enabled)
System.Diagnostics.Trace.TraceInformation(
DateTime.Now.ToLongTimeString() + " " + DateTime.Now.Millisecond + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId + ": " +
"PackWebResponse - Creating response ");
#endif
_innerUri = innerUri;
_partName = partName; // may be null
_webRequest = innerRequest;
_mimeType = null; // until we find out the real value
// only create these in non-cache case
// Create before any Timeout timer to prevent a race condition with the Timer callback
// (that expects _responseAvailable to exist)
_responseAvailable = new ManualResetEvent(false);
// do we need a timer?
// if the TimeOut has been set on the innerRequest, we need to simulate this behavior for
// our synchronous clients
if (innerRequest.Timeout != Timeout.Infinite)
{
#if DEBUG
if (PackWebRequestFactory._traceSwitch.Enabled)
System.Diagnostics.Trace.TraceInformation(
DateTime.Now.ToLongTimeString() + " " + DateTime.Now.Millisecond + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId + ": " +
"PackWebResponse() starting timeout timer " + innerRequest.Timeout + " ms");
#endif
_timeoutTimer = new Timer(new TimerCallback(TimeoutCallback), null, innerRequest.Timeout, Timeout.Infinite);
}
#if DEBUG
if (PackWebRequestFactory._traceSwitch.Enabled)
System.Diagnostics.Trace.TraceInformation(
DateTime.Now.ToLongTimeString() + " " + DateTime.Now.Millisecond + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId + ": " +
"PackWebResponse() BeginGetResponse()");
#endif
// Issue the async request to get our "real" WebResponse
// don't access this value until we set the ManualResetEvent
_webRequest.BeginGetResponse(new AsyncCallback(ResponseCallback), this);
}
///
/// Constructor: Cache-entry overload
///
///
///
///
/// entry from cache
/// is entry thread safe?
internal PackWebResponse(Uri uri, Uri innerUri, Uri partName, Package cacheEntry,
bool cachedPackageIsThreadSafe)
{
_lockObject = new Object(); // required for synchronization
if (uri == null)
throw new ArgumentNullException("uri");
if (innerUri == null)
throw new ArgumentNullException("innerUri");
if (partName == null)
throw new ArgumentNullException("partName");
if (cacheEntry == null)
throw new ArgumentNullException("cacheEntry");
#if DEBUG
if (PackWebRequestFactory._traceSwitch.Enabled)
System.Diagnostics.Trace.TraceInformation(
DateTime.Now.ToLongTimeString() + " " + DateTime.Now.Millisecond + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId + ": " +
"PackWebResponse - Creating response from Package Cache");
#endif
_uri = uri;
_innerUri = innerUri;
_partName = partName; // may not be null
_mimeType = null; // until we find out the real value
// delegate work to private class
_cachedResponse = new CachedResponse(this, cacheEntry, cachedPackageIsThreadSafe);
}
//------------------------------------------------------
//
// Public Methods
//
//-----------------------------------------------------
#region WebResponse Overloads
///
/// Retrieves a stream for reading bytes from the requested resource
///
/// stream
///
/// Critical
/// 1) Passes Critical member _webRequest to NetStream constructor
/// Safe
/// 1) Providing _webRequest to NetStream is safe because NetStream treats _webRequest as Critical
///
[SecurityCritical, SecurityTreatAsSafe]
public override Stream GetResponseStream()
{
CheckDisposed();
// redirect
if (FromPackageCache)
return _cachedResponse.GetResponseStream();
if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.normal))
{
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.DRXGETSTREAMGUID), EventType.StartEvent);
}
#if DEBUG
if (PackWebRequestFactory._traceSwitch.Enabled)
System.Diagnostics.Trace.TraceInformation(
DateTime.Now.ToLongTimeString() + " " + DateTime.Now.Millisecond + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId + ": " +
"PackWebResponse - GetResponseStream()");
#endif
// create and return only a single stream for multiple calls
if (_responseStream == null)
{
// can't do this until the response is available
WaitForResponse(); // after this call, we have a viable _fullResponse object because WaitForResponse would have thrown otherwise
// determine content length
long streamLength = _fullResponse.ContentLength;
#if DEBUG
if (_forceWebResponseLengthFailureSwitch.Enabled)
streamLength = -1;
// special handling for servers that won't or can't give us the length of the resource - byte-range downloading is impossible
if (streamLength <= 0)
{
if (PackWebRequestFactory._traceSwitch.Enabled)
System.Diagnostics.Trace.TraceInformation(
DateTime.Now.ToLongTimeString() + " " + DateTime.Now.Millisecond + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId + ": " +
"PackWebResponse - GetResponseStream() - stream length not available - disabling progressive download");
}
#endif
// Start reading data from the response stream.
_responseStream = _fullResponse.GetResponseStream();
// require NetStream for progressivity and for network streams that don't
// directly support seeking.
if (!_responseStream.CanSeek || !_innerUri.IsFile)
{
// Create a smart stream that will spawn byte-range requests as needed
// and support seeking. Each read has overhead of Mutex and many of the
// reads come through asking for 4 bytes at a time
_responseStream = new NetStream(
_responseStream, streamLength,
_innerUri, _webRequest, _fullResponse);
// wrap our stream for efficiency (short reads are expanded)
_responseStream = new BufferedStream(_responseStream);
}
// handle degenerate case where there is no part name
if (_partName == null)
{
_fullStreamLength = streamLength; // entire container
_mimeType = WpfWebRequestHelper.GetContentType(_fullResponse);
// pass this so that ResponseStream holds a reference to us until the stream is closed
_responseStream = new ResponseStream(_responseStream, this);
}
else
{
// open container on netStream
Package c = Package.Open(_responseStream);
if (!c.PartExists(_partName))
throw new WebException(SR.Get(SRID.WebResponsePartNotFound));
PackagePart p = c.GetPart(_partName);
Stream s = p.GetStream(FileMode.Open, FileAccess.Read);
_mimeType = new MS.Internal.ContentType(p.ContentType); // save this for use in ContentType property - may still be null
_fullStreamLength = s.Length; // just this stream
// Wrap in a ResponseStream so that this container will be released
// when the stream is closed
_responseStream = new ResponseStream(s, this, _responseStream, c);
}
// length available? (-1 means the server chose not to report it)
if (_fullStreamLength >= 0)
{
_lengthAvailable = true;
}
}
EventTrace.NormalTraceEvent(EventTraceGuidId.DRXGETSTREAMGUID, EventType.EndEvent);
return _responseStream;
}
///
/// Close stream
///
public override void Close()
{
Dispose(true);
}
#endregion
//------------------------------------------------------
//
// Public Properties
//
//------------------------------------------------------
///
/// InnerResponse
///
/// inner WebResponse
public WebResponse InnerResponse
{
get
{
CheckDisposed();
// no inner response
if (FromPackageCache)
return null;
// can't do this until the response is available
WaitForResponse();
return _fullResponse;
}
}
///
/// Headers
///
/// web headers
public override WebHeaderCollection Headers
{
get
{
CheckDisposed();
// redirect
if (FromPackageCache)
return _cachedResponse.Headers;
// can't do this until the response is available
WaitForResponse();
return _fullResponse.Headers;
}
}
///
/// ResponseUri
///
/// Fully-qualified pack uri reflecting any server redirection.
/// For the inner ResponseUri access the InnerResponse like this:
/// Uri innerResponseUri = packResponse.InnerResponse.ResponseUri
public override Uri ResponseUri
{
get
{
CheckDisposed();
// If data is served from a cached package, we simply return the original, fully-qualified
// pack uri.
if (FromPackageCache)
return _uri;
else
{
// If data is served from an actual webResponse, we need to re-compose the original pack uri
// with the responseUri provided by the real webResponse to account for server redirects.
// We can't do this until the response is available so we wait.
WaitForResponse();
// create new pack uri with webResponse and original part name uri
return PackUriHelper.Create(_fullResponse.ResponseUri, _partName);
}
}
}
///
/// IsFromCache
///
/// true if result is from the cache
public override bool IsFromCache
{
get
{
CheckDisposed();
// quick answer
if (FromPackageCache)
return true;
// can't do this until the response is available
WaitForResponse();
return _fullResponse.IsFromCache;
}
}
///
/// ContentType
///
/// string
/// There are four separate results possible from this property. If the PartName is
/// empty, then the container MIME type is returned. If it is not, we return the MIME type of the
/// stream in the following order or preference:
/// 1. If the PackagePart offers a MIME type, we return that
/// 2. If the stream name has an extension, we determine the MIME type from that using a lookup table
/// 3. We return String.Empty if no extension is found.
public override string ContentType
{
get
{
CheckDisposed();
// No need to wait if working from cache
// But we can share the logic as none of it hits the _webResponse
if (!FromPackageCache)
{
// can't do this until the response is available
WaitForResponse();
}
// cache the value - if it's empty that means we already tried (and failed) to find a real type
if (_mimeType == null)
{
// Get the response stream which has the side effect of setting the _mimeType member.
GetResponseStream();
}
return _mimeType.ToString();
}
}
///
/// ContentLength
///
/// length of response stream
public override long ContentLength
{
get
{
CheckDisposed();
// redirect
if (FromPackageCache)
return _cachedResponse.ContentLength;
// can't do this until the response is available
WaitForResponse();
// is the length available?
if (!_lengthAvailable)
{
_fullStreamLength = GetResponseStream().Length;
_lengthAvailable = true;
}
// use the stored value
return _fullStreamLength;
}
}
//-----------------------------------------------------
//
// Internal Properties
//
//------------------------------------------------------
//-----------------------------------------------------
//
// Private Methods
//
//-----------------------------------------------------
///
/// AbortResponse - called only from Close()
///
/// assumes caller has locked the syncObject and that we are not disposed
///
/// Critical
/// 1) accesses Critical _webRequest
/// Safe
/// 1) Not modifying WebRequest.Proxy member which is what is really Critical
///
[SecurityCritical, SecurityTreatAsSafe]
private void AbortResponse()
{
// Disable the PreSharp warning about empty catch blocks - we need this one because sub-classes of WebResponse may or may
// not implement Abort() and we want to silently ignore this if they don't.
#pragma warning disable 56502
// Close was called - abort the response if necessary
try
{
// Only abort if the response is still "outstanding".
// Non-blocking "peek" at the event to see if it is set or not.
if (!_responseAvailable.WaitOne(0, false))
{
_webRequest.Abort(); // response not back yet so abort it
}
}
catch (NotImplementedException)
{
// Ignore - innerRequest class chose to implement BeginGetResponse but not Abort. This is allowed.
}
#pragma warning restore 56502
}
///
/// This is private instead of protected because this class is sealed - if it is ever unsealed, this method should
/// be made protected and GC.SuppressFinalize() should be enabled at the end of Dispose call.
///
///
private void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
// ignore multiple calls to Close()
// no lock required here because the only place where _disposed is changed is later in this same function and this
// function is never entered by more than one thread
if (_disposed)
return;
// redirect for cache case
// NOTE: FromPackageCache need not be synchronized because it is only set once in the constructor and never
// changes.
if (FromPackageCache)
{
_cachedResponse.Close(); // indirectly sets _disposed on this class
_cachedResponse = null; // release
return;
}
#if DEBUG
if (PackWebRequestFactory._traceSwitch.Enabled)
System.Diagnostics.Trace.TraceInformation(
DateTime.Now.ToLongTimeString() + " " + DateTime.Now.Millisecond + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId + ": " +
"PackWebResponse.Close()");
#endif
// prevent async callback from accessing these resources while we are disposing them
lock (_lockObject)
{
try
{
// abort any outstanding response
AbortResponse();
// prevent recursion in our call to _responseStream.Close()
_disposed = true;
if (_responseStream != null)
{
#if DEBUG
if (PackWebRequestFactory._traceSwitch.Enabled)
System.Diagnostics.Trace.TraceInformation(
DateTime.Now.ToLongTimeString() + " " + DateTime.Now.Millisecond + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId + ": " +
"PackWebResponse.Close() - close stream");
#endif
_responseStream.Close();
}
// FullResponse
if (_fullResponse != null)
{
#if DEBUG
if (PackWebRequestFactory._traceSwitch.Enabled)
System.Diagnostics.Trace.TraceInformation(
DateTime.Now.ToLongTimeString() + " " + DateTime.Now.Millisecond + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId + ": " +
"PackWebResponse.Close() - close response");
#endif
// always call Dispose to satisfy FxCop
((IDisposable)_fullResponse).Dispose();
}
// must free this regardless of whether GetResponseStream was invoked
_responseAvailable.Close(); // this call can not throw an exception
// timer
if (_timeoutTimer != null)
{
_timeoutTimer.Dispose();
}
}
finally
{
_timeoutTimer = null;
_responseStream = null;
_fullResponse = null;
_responseAvailable = null;
#if DEBUG
if (PackWebRequestFactory._traceSwitch.Enabled)
System.Diagnostics.Trace.TraceInformation(
DateTime.Now.ToLongTimeString() + " " + DateTime.Now.Millisecond + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId + ": " +
"PackWebResponse.Close() - exiting");
#endif
}
} // lock
}
}
}
//-----------------------------------------------------
//
// Private Properties
//
//------------------------------------------------------
private bool FromPackageCache
{
get
{
return (_cachedResponse != null);
}
}
//-----------------------------------------------------
//
// Private Classes
//
//------------------------------------------------------
///
/// CachedResponse class
///
/// Isolate cache-specific functionality to reduce complexity
private class CachedResponse
{
//------------------------------------------------------
//
// Internal Methods
//
//-----------------------------------------------------
internal CachedResponse(PackWebResponse parent, Package cacheEntry, bool cachedPackageIsThreadSafe)
{
_parent = parent;
_cacheEntry = cacheEntry;
_cachedPackageIsThreadSafe = cachedPackageIsThreadSafe;
}
///
/// Cache version of GetResponseStream
///
///
internal Stream GetResponseStream()
{
// prevent concurrent access to GetPart() which is not thread-safe
lock (_cacheEntry)
{
#if DEBUG
if (PackWebRequestFactory._traceSwitch.Enabled)
System.Diagnostics.Trace.TraceInformation(
DateTime.Now.ToLongTimeString() + " " + DateTime.Now.Millisecond + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId + ": " +
"CachedResponse - Getting response stream");
#endif
// only one copy
if (_parent._responseStream == null)
{
// full container request?
if (_parent._partName == null)
{
Debug.Assert(false, "Cannot return full-container stream from cached container object");
}
else
{
#if DEBUG
if (PackWebRequestFactory._traceSwitch.Enabled)
System.Diagnostics.Trace.TraceInformation(
DateTime.Now.ToLongTimeString() + " " + DateTime.Now.Millisecond + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId + ": " +
"CachedResponse - Getting part " + _parent._partName);
#endif
// open the requested stream
PackagePart p = _cacheEntry.GetPart(_parent._partName);
#if DEBUG
if (PackWebRequestFactory._traceSwitch.Enabled)
System.Diagnostics.Trace.TraceInformation(
DateTime.Now.ToLongTimeString() + " " + DateTime.Now.Millisecond + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId + ": " +
"CachedResponse - Getting part stream ");
#endif
Stream s = p.GetStream(FileMode.Open, FileAccess.Read);
// Unless package is thread-safe, wrap the returned stream so that
// package access is serialized
if (!_cachedPackageIsThreadSafe)
{
// Return a stream that provides thread-safe access
// to the cached package by locking on the cached Package
s = new SynchronizingStream(s, _cacheEntry);
}
#if DEBUG
if (PackWebRequestFactory._traceSwitch.Enabled)
System.Diagnostics.Trace.TraceInformation(
DateTime.Now.ToLongTimeString() + " " + DateTime.Now.Millisecond + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId + ": " +
"CachedResponse - Getting part contenttype");
#endif
_parent._mimeType = new MS.Internal.ContentType(p.ContentType);
// cache this in case they ask for it after the stream has been closed
_parent._lengthAvailable = s.CanSeek;
if (s.CanSeek)
{
#if DEBUG
if (PackWebRequestFactory._traceSwitch.Enabled)
System.Diagnostics.Trace.TraceInformation(
DateTime.Now.ToLongTimeString() + " " + DateTime.Now.Millisecond + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId + ": " +
"CachedResponse - Length is available from stream");
#endif
_parent._fullStreamLength = s.Length;
}
#if DEBUG
else
{
if (PackWebRequestFactory._traceSwitch.Enabled)
System.Diagnostics.Trace.TraceInformation(
DateTime.Now.ToLongTimeString() + " " + DateTime.Now.Millisecond + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId + ": " +
"CachedResponse - Length is not available from stream" + _parent._partName);
}
#endif
// re-use existing member variable
_parent._responseStream = s;
}
}
}
return _parent._responseStream;
}
///
/// Release some resources
///
internal void Close()
{
try
{
// Prevent recursion - this sync-protected member is safe to set in a CachedResponse
// mode because we have no other thread in operation.
_parent._disposed = true;
if (_parent._responseStream != null)
_parent._responseStream.Close();
}
finally
{
_cacheEntry = null;
_parent._uri = null;
_parent._mimeType = null;
_parent._innerUri = null;
_parent._partName = null;
_parent._responseStream = null;
_parent = null;
}
}
//------------------------------------------------------
//
// Internal Properties
//
//-----------------------------------------------------
internal WebHeaderCollection Headers
{
get
{
// empty - bogus collection - prevents exceptions for callers
return new WebHeaderCollection();
}
}
public long ContentLength
{
get
{
// if fullStreamLength not already set, get the stream which has
// the side effect of updating the length
if (!_parent._lengthAvailable)
GetResponseStream();
return _parent._fullStreamLength;
}
}
// fields
private PackWebResponse _parent;
private Package _cacheEntry;
private bool _cachedPackageIsThreadSafe;
}
///
/// Throw exception if we are already closed
///
private void CheckDisposed()
{
// no need to lock here because only Close() sets this variable and we are not ThreadSafe
if (_disposed)
throw new ObjectDisposedException("PackWebResponse");
}
///
/// ResponseCallBack
///
/// async result
/// static method not necessary
///
/// Critical
/// 1) calls EndGetResponse() on Critical member _webRequest
///
[SecurityCritical]
private void ResponseCallback(IAsyncResult ar)
{
lock (_lockObject) // prevent race condition accessing _timeoutTimer, _disposed, _responseAvailable
{
try
{
// If disposed, the message is too late
// Exit early and don't access members as they have been disposed
if (!_disposed)
{
// dispose the timer - it is no longer needed
if (_timeoutTimer != null)
_timeoutTimer.Dispose();
#if DEBUG
if (PackWebRequestFactory._traceSwitch.Enabled)
System.Diagnostics.Trace.TraceInformation(
DateTime.Now.ToLongTimeString() + " " + DateTime.Now.Millisecond + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId + ": " +
"PackWebResponse.ResponseCallBack()");
#endif
// Dispose/Close waits on _responseAvailable so we know that these are available
// No need to lock.
// Call EndGetResponse, which produces the WebResponse object
// that came from the request issued above.
_fullResponse = MS.Internal.WpfWebRequestHelper.EndGetResponse(_webRequest, ar);
}
}
catch (WebException e)
{
// web exceptions are meaningful to our client code - keep these to re-throw on the other thread
_responseException = e;
_responseError = true;
}
catch // catch (and re-throw) all kinds of exceptions so we can inform the other thread
{
#if DEBUG
if (PackWebRequestFactory._traceSwitch.Enabled)
System.Diagnostics.Trace.TraceError(
DateTime.Now.ToLongTimeString() + " " + DateTime.Now.Millisecond + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId + ": " +
"PackWebResponse.ResponseCallBack() exception");
#endif
// inform other thread of error condition
_responseError = true;
throw;
}
finally
{
_timeoutTimer = null; // harmless if already null, and removes need for extra try/finally block above
#if DEBUG
if (PackWebRequestFactory._traceSwitch.Enabled)
System.Diagnostics.Trace.TraceInformation(
DateTime.Now.ToLongTimeString() + " " + DateTime.Now.Millisecond + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId + ": " +
"PackWebResponse.ResponseCallBack() - signal response available");
#endif
// We need the original webRequest to get HttpStack information so that they can be used to make
// additional byte range request; So we cannot null it out anymore
// _webRequest = null; // don't need this anymore so release
// this must be set even when there is an exception so that our client
// can be unblocked
// make sure this wasn't already free'd when the Timercallback thread released
// the blocked Close() thread
if (!_disposed)
_responseAvailable.Set();
}
}
}
///
/// All methods that need to access variables only available after the response callback has been
/// handled should call this to block. Doing it in one place simplifies our need to respond to any
/// exceptions encountered in the other thread and rethrow these.
///
private void WaitForResponse()
{
#if DEBUG
if (PackWebRequestFactory._traceSwitch.Enabled)
System.Diagnostics.Trace.TraceInformation(
DateTime.Now.ToLongTimeString() + " " + DateTime.Now.Millisecond + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId + ": " +
"PackWebResponse.WaitForResponse()");
#endif
// wait for the response callback
_responseAvailable.WaitOne();
// We get here only when the other thread signals.
// Need to inspect for errors and throw if there was trouble on the other thread.
if (_responseError)
{
if (_responseException == null)
throw new WebException(SR.Get(SRID.WebResponseFailure));
else
throw _responseException; // throw literal exception if there is one
}
}
///
/// Timeout callback
///
///
private void TimeoutCallback(Object stateInfo)
{
lock (_lockObject) // prevent race condition accessing _timeoutTimer, _disposed, _responseAvailable
{
// If disposed, the message is too late
// Exit early and don't access members as they have been disposed
// Let Close() method clean up our Timer object
if (_disposed)
return;
try
{
// If we get called, need to check if response is available before escalating
// just in case it arrived "just now". If the event is already signalled, we can ignore
// the callback as no "timeout" occurred.
if (!_responseAvailable.WaitOne(0, false))
{
#if DEBUG
if (PackWebRequestFactory._traceSwitch.Enabled)
System.Diagnostics.Trace.TraceError(
DateTime.Now.ToLongTimeString() + " " + DateTime.Now.Millisecond + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId + ": " +
"PackWebResponse.TimerCallback() timeout - throwing exception");
#endif
// caller is still blocked so need to throw to indicate timeout
// create exception to be thrown on client thread, then unblock the caller
// thread will be discovered and re-thrown in WaitForResponse() method
_responseError = true;
_responseException = new WebException(SR.Get(SRID.WebRequestTimeout, null), WebExceptionStatus.Timeout);
}
#if DEBUG
else
{
if (PackWebRequestFactory._traceSwitch.Enabled)
System.Diagnostics.Trace.TraceInformation(
DateTime.Now.ToLongTimeString() + " " + DateTime.Now.Millisecond + " " +
System.Threading.Thread.CurrentThread.ManagedThreadId + ": " +
"PackWebResponse.TimerCallback() no timeout - ignoring callback");
}
#endif
// clean up
if (_timeoutTimer != null)
{
_timeoutTimer.Dispose();
}
}
finally
{
_timeoutTimer = null;
if (!_disposed)
{
// this must be set so that our client can be unblocked and then discover the exception
_responseAvailable.Set();
}
}
} // lock
}
//-----------------------------------------------------
//
// Private Fields
//
//-----------------------------------------------------
private MS.Internal.ContentType _mimeType; // type of the returned stream - cached because it never changes
private const int _bufferSize = 0x1000; // 4k
private Uri _uri; // full uri
private Uri _innerUri; // inner uri
private Uri _partName; // path to stream
private bool _disposed; // closed?
///
/// Critical
/// 1) Proxy member is Critical because we use it under Unrestricted assert
///
[SecurityCritical] // only WebRequest.Proxy member is Critical
private WebRequest _webRequest; // the real web request
private WebResponse _fullResponse; // the real web response
private long _fullStreamLength; // need to return this in call to get_Length
private Stream _responseStream; // mimic existing Response behavior by creating and returning
// one and only one stream
private bool _responseError; // will be true if exception occurs calling EndGetResponse()
private Exception _responseException; // actual exception to throw (if any)
private Timer _timeoutTimer; // used if Timeout specified
// OS event used to signal that the response is available
private ManualResetEvent _responseAvailable; // protects access to _fullResponse object
// flag to signal that _fullStreamLength is valid - needed because some servers don't return
// the length (usually FTP servers) so calls to Stream.Length must block until we know the actual length.
private bool _lengthAvailable;
// PackageCache response?
private CachedResponse _cachedResponse; // null if cache not used
// private object to prevent deadlock (should not lock(_lockObject) based on PreSharp rule 6517)
private Object _lockObject; // Serialize access to _disposed, _timoutTimer and _responseAvailable because even though the main client
// thread blocks on WaitForResponse (_responseAvailable event) the optional Timer thread and the
// Response callback thread may arrive independently at any time.
#if DEBUG
// toggle this switch to force execution of code that handles servers that return bogus content length
internal static System.Diagnostics.BooleanSwitch _forceWebResponseLengthFailureSwitch;
#endif
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ToolStripPanelDesigner.cs
- TreeNodeStyleCollection.cs
- ConfigPathUtility.cs
- BuildProviderUtils.cs
- XmlSerializerVersionAttribute.cs
- BStrWrapper.cs
- TrackingStringDictionary.cs
- SpeechRecognizer.cs
- TextCharacters.cs
- SHA256Managed.cs
- CodeComment.cs
- ObjectCache.cs
- Cell.cs
- UserControlParser.cs
- NetworkStream.cs
- BufferBuilder.cs
- MessageFault.cs
- PermissionToken.cs
- DataObject.cs
- RuntimeIdentifierPropertyAttribute.cs
- HttpCapabilitiesSectionHandler.cs
- IPAddress.cs
- FixedSchema.cs
- QueryCacheKey.cs
- SymbolEqualComparer.cs
- KeyboardNavigation.cs
- CodeNamespaceCollection.cs
- HttpResponse.cs
- HtmlInputCheckBox.cs
- TemplateControl.cs
- ProfileManager.cs
- DocumentSchemaValidator.cs
- FtpWebRequest.cs
- ConvertEvent.cs
- CircleHotSpot.cs
- HttpModuleActionCollection.cs
- SqlXmlStorage.cs
- TimerEventSubscription.cs
- odbcmetadatacollectionnames.cs
- PagesChangedEventArgs.cs
- PreProcessInputEventArgs.cs
- X509UI.cs
- HelpProvider.cs
- sqlstateclientmanager.cs
- XComponentModel.cs
- CapabilitiesSection.cs
- AttachInfo.cs
- Buffer.cs
- CommonProperties.cs
- CheckPair.cs
- WindowsProgressbar.cs
- LabelEditEvent.cs
- Rotation3DKeyFrameCollection.cs
- NumericPagerField.cs
- MethodBuilder.cs
- TextParaClient.cs
- ConcatQueryOperator.cs
- CompModSwitches.cs
- NumberFormatInfo.cs
- SchemaCollectionCompiler.cs
- EventEntry.cs
- LinearGradientBrush.cs
- UIElement.cs
- ManagementDateTime.cs
- CodeSnippetTypeMember.cs
- ContentHostHelper.cs
- ChildTable.cs
- RequestCachePolicyConverter.cs
- DoubleLink.cs
- ApplicationActivator.cs
- AppDomainFactory.cs
- WindowsSolidBrush.cs
- validationstate.cs
- HitTestWithGeometryDrawingContextWalker.cs
- EdmComplexPropertyAttribute.cs
- CoTaskMemUnicodeSafeHandle.cs
- DataControlFieldCollection.cs
- HtmlInputImage.cs
- RenderContext.cs
- StyleXamlParser.cs
- BaseParagraph.cs
- MsmqOutputMessage.cs
- VirtualizingStackPanel.cs
- SafeNativeMethods.cs
- FileLoadException.cs
- DictionaryBase.cs
- UnsafeNativeMethods.cs
- BaseCollection.cs
- AdapterSwitches.cs
- AudioBase.cs
- BitmapSizeOptions.cs
- PathParser.cs
- _ServiceNameStore.cs
- Int16AnimationUsingKeyFrames.cs
- MatrixTransform.cs
- QuadraticBezierSegment.cs
- TypefaceMap.cs
- PathGeometry.cs
- SimpleFileLog.cs
- IncrementalReadDecoders.cs