private AutoWebProxyState DownloadAndCompile(Uri location, out AutoWebProxyScriptWrapper newScriptInstance, ref int syncStatus)
{
GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::DownloadAndCompile() location:" + ValidationHelper.ToString(location));
AutoWebProxyState newState = AutoWebProxyState.DownloadFailure;
WebResponse response = null;
TimerThread.Timer timer = null;
newScriptInstance = null;
// Can't assert this in declarative form (DCR?). This Assert() is needed to be able to create the request to download the proxy script.
ExceptionHelper.WebPermissionUnrestricted.Assert();
try {
// here we have a reentrance issue due to config load.
WebRequest request = WebRequest.Create(location);
request.Timeout = Timeout.Infinite;
request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.Default);
request.ConnectionGroupName = "__WebProxyScript";
// We have an opportunity here, if caching is disabled AppDomain-wide, to override it with a
// custom, trivial cache-provider to get a similar semantic.
//
// We also want to have a backup caching key in the case when IE has locked an expired script response
//
if (request.CacheProtocol != null)
{
GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::DownloadAndCompile() Using backup caching.");
request.CacheProtocol = new RequestCacheProtocol(backupCache, request.CacheProtocol.Validator);
}
HttpWebRequest httpWebRequest = request as HttpWebRequest;
if (httpWebRequest!=null)
{
httpWebRequest.Accept = "*/*";
httpWebRequest.UserAgent = this.GetType().FullName + "/" + Environment.Version;
httpWebRequest.KeepAlive = false;
httpWebRequest.Pipelined = false;
httpWebRequest.InternalConnectionGroup = true;
}
else
{
FtpWebRequest ftpWebRequest = request as FtpWebRequest;
if (ftpWebRequest!=null)
{
ftpWebRequest.KeepAlive = false;
}
}
// Use no proxy, default cache - initiate the download.
request.Proxy = null;
request.Credentials = webProxy.Credentials;
// Set this up with the abortable lock to abort this too.
LockRequest(request, ref syncStatus);
if (syncStatus != SyncStatus.RequestOwner)
{
throw new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), WebExceptionStatus.RequestCanceled);
}
// Use our own timeout timer so that it can encompass the whole request, not just the headers.
if (s_TimerQueue == null)
{
s_TimerQueue = TimerThread.GetOrCreateQueue(SettingsSectionInternal.Section.DownloadTimeout);
}
timer = s_TimerQueue.CreateTimer(s_TimerCallback, request);
response = request.GetResponse();
// Check Last Modified.
DateTime lastModified = DateTime.MinValue;
HttpWebResponse httpResponse = response as HttpWebResponse;
if (httpResponse != null)
{
lastModified = httpResponse.LastModified;
}
else
{
FtpWebResponse ftpResponse = response as FtpWebResponse;
if (ftpResponse != null)
{
lastModified = ftpResponse.LastModified;
}
}
GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::DownloadAndCompile() lastModified:" + lastModified.ToString() + " (script):" + (scriptInstance == null ? "(null)" : scriptInstance.LastModified.ToString()));
if (scriptInstance != null && lastModified != DateTime.MinValue && scriptInstance.LastModified == lastModified)
{
newScriptInstance = scriptInstance;
newState = AutoWebProxyState.CompilationSuccess;
}
else
{
string scriptBody = null;
byte[] scriptBuffer = null;
using (Stream responseStream = response.GetResponseStream())
{
SingleItemRequestCache.ReadOnlyStream ros = responseStream as SingleItemRequestCache.ReadOnlyStream;
if (ros != null)
{
scriptBuffer = ros.Buffer;
}
if (scriptInstance != null && scriptBuffer != null && scriptBuffer == scriptInstance.Buffer)
{
scriptInstance.LastModified = lastModified;
newScriptInstance = scriptInstance;
newState = AutoWebProxyState.CompilationSuccess;
GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::DownloadAndCompile() Buffer matched - reusing engine.");
}
else
{
using (StreamReader streamReader = new StreamReader(responseStream))
{
scriptBody = streamReader.ReadToEnd();
}
}
}
WebResponse tempResponse = response;
response = null;
tempResponse.Close();
timer.Cancel();
timer = null;
if (newState != AutoWebProxyState.CompilationSuccess)
{
newState = AutoWebProxyState.DownloadSuccess;
GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::DownloadAndCompile() IsFromCache:" + tempResponse.IsFromCache.ToString() + " scriptInstance:" + ValidationHelper.HashString(scriptInstance));
if (scriptInstance != null && scriptBody == scriptInstance.ScriptBody)
{
GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::DownloadAndCompile() Script matched - using existing engine.");
scriptInstance.LastModified = lastModified;
if (scriptBuffer != null)
{
scriptInstance.Buffer = scriptBuffer;
}
newScriptInstance = scriptInstance;
newState = AutoWebProxyState.CompilationSuccess;
}
else
{
GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::DownloadAndCompile() Creating AutoWebProxyScriptWrapper.");
newScriptInstance = new AutoWebProxyScriptWrapper();
newScriptInstance.LastModified = lastModified;
newState = newScriptInstance.Compile(location, scriptBody, scriptBuffer);
}
}
}
}
catch (Exception exception)
{
if (NclUtilities.IsFatal(exception)) throw;
if(Logging.On)Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_log_proxy_script_download_compile_error, exception));
GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::DownloadAndCompile() Download() threw:" + ValidationHelper.ToString(exception));
}
finally
{
if (timer != null)
{
timer.Cancel();
}
//
try
{
if (response != null)
{
response.Close();
}
}
finally
{
WebPermission.RevertAssert();
}
}
if (newState!=AutoWebProxyState.CompilationSuccess) {
newScriptInstance = null;
}
GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::DownloadAndCompile() retuning newState:" + ValidationHelper.ToString(newState));
return newState;
}