//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ /* * ImplicitAsyncPreloadModule preloads the request entity for form posts. * * Copyright (c) 2010 Microsoft Corporation */ namespace System.Web { using System; using System.IO; using System.Web; using System.Web.Configuration; using System.Web.Handlers; using System.Web.Management; using System.Web.Util; internal class ImplicitAsyncPreloadModule { HttpApplication _app; AsyncCallback _callback; Stream _inputStream; internal void GetEventHandlers(out BeginEventHandler beginHandler, out EndEventHandler endHandler) { beginHandler = new BeginEventHandler(OnEnter); endHandler = new EndEventHandler(OnLeave); } private void Reset() { if (_inputStream != null) { _inputStream.Close(); _inputStream = null; } } private IAsyncResult OnEnter(Object sender, EventArgs e, AsyncCallback cb, Object state) { Debug.Assert(_inputStream == null); _app = (HttpApplication)sender; HttpContext context = _app.Context; HttpRequest request = context.Request; HttpWorkerRequest wr = context.WorkerRequest; HttpAsyncResult httpAsyncResult = new HttpAsyncResult(cb, state); AsyncPreloadModeFlags asyncPreloadMode = context.AsyncPreloadMode; int contentLength; bool isForm = false; bool isFormMultiPart = false; if (asyncPreloadMode == AsyncPreloadModeFlags.None || request.ReadEntityBodyMode != ReadEntityBodyMode.None || wr == null || !wr.SupportsAsyncRead || !wr.HasEntityBody() || wr.IsEntireEntityBodyIsPreloaded() || context.Handler == null || context.Handler is TransferRequestHandler || context.Handler is DefaultHttpHandler || (contentLength = request.ContentLength) > RuntimeConfig.GetConfig(context).HttpRuntime.MaxRequestLengthBytes || ((isForm = StringUtil.StringStartsWithIgnoreCase(request.ContentType, "application/x-www-form-urlencoded")) && (asyncPreloadMode & AsyncPreloadModeFlags.Form) != AsyncPreloadModeFlags.Form) || ((isFormMultiPart = StringUtil.StringStartsWithIgnoreCase(request.ContentType, "multipart/form-data")) && (asyncPreloadMode & AsyncPreloadModeFlags.FormMultiPart) != AsyncPreloadModeFlags.FormMultiPart) || !isForm && !isFormMultiPart && (asyncPreloadMode & AsyncPreloadModeFlags.NonForm) != AsyncPreloadModeFlags.NonForm ) { Debug.Trace("AsyncPreload", " *** AsyncPreload skipped *** "); httpAsyncResult.Complete(true, null, null); return httpAsyncResult; } Debug.Trace("AsyncPreload", " *** AsyncPreload started *** "); try { if (_callback == null) { _callback = new AsyncCallback(OnAsyncCompletion); } _inputStream = request.GetBufferedInputStream(); byte[] buffer = _app.EntityBuffer; int bytesRead = 0; // loop to prevent recursive calls and potential stack overflow if/when it completes synchronously do { IAsyncResult readAsyncResult = _inputStream.BeginRead(buffer, 0, buffer.Length, _callback, httpAsyncResult); if (!readAsyncResult.CompletedSynchronously) { return httpAsyncResult; } bytesRead = _inputStream.EndRead(readAsyncResult); } while (bytesRead != 0); } catch { Reset(); throw; } httpAsyncResult.Complete(true, null, null); return httpAsyncResult; } private void OnLeave(IAsyncResult httpAsyncResult) { Reset(); Debug.Trace("AsyncPreload", " *** AsyncPreload finished *** "); ((HttpAsyncResult)httpAsyncResult).End(); } private void OnAsyncCompletion(IAsyncResult readAsyncResult) { if (readAsyncResult.CompletedSynchronously) { return; } HttpAsyncResult httpAsyncResult = readAsyncResult.AsyncState as HttpAsyncResult; Exception error = null; try { int bytesRead = _inputStream.EndRead(readAsyncResult); byte[] buffer = _app.EntityBuffer; // loop to prevent recursive calls and potential stack overflow when it completes synchronously while (bytesRead != 0) { readAsyncResult = _inputStream.BeginRead(buffer, 0, buffer.Length, _callback, httpAsyncResult); if (!readAsyncResult.CompletedSynchronously) { return; } bytesRead = _inputStream.EndRead(readAsyncResult); } } catch(Exception e) { error = e; } httpAsyncResult.Complete(false, null, error); } } }