private void RememberError(object sender, EventArgs e) { if (!IsInited) { return; } if (!Config.Current.UseHttpModule) { return; } DecoratedWorkerRequest decoratedWorker = GetCurrentWorkerRequest() as DecoratedWorkerRequest; HttpApplication app = sender as HttpApplication; if (decoratedWorker != null) { Exception ex = app.Server.GetLastError(); if (ex != null) { // We are here because an exception was thrown while the subrequest was being proceessed. // Ideally, we'd like it to appear as though the exception was thrown in the context of the // original request so that thigs which rely on the original context (e.g. custom error pages) // operate properly. To achieve that, we'd like to end the subrequest without sending any // response, and remember the exception so that we can rethrow it in the original // request context. However, if some headers or content have been already been sent to the // client, then that is impossible. In that case we'll continue processing normally which // will mean that the exception is handled in the context of the subrequest. // Try to clear the headers. This will throw an HttpException if headers have already been // sent to the client. try { app.Response.ClearHeaders(); } catch (HttpException) { if (log.IsDebugEnabled) { log.DebugFormat("The following error will be processed in NeatUpload's subrequest context because the response has already been at least partially sent {0}", ex); } return; } // Clear any buffered content as well so that it isn't // written when we end the subrequest. app.Response.ClearContent(); decoratedWorker.Exception = ex; if (log.IsDebugEnabled) { log.DebugFormat("Remembering error: {0}", decoratedWorker.Exception); } // For the remainder of the subrequest, act as though there was no error. app.Server.ClearError(); // Finish the subrequest. app.CompleteRequest(); } } }
private void MakeChildRequest(HttpApplication app, DecoratedWorkerRequest subWorker) { // Process the subrequest. HttpContext savedContext = HttpContext.Current; try { subWorker.ProcessRequest(null); if (log.IsDebugEnabled) { log.Debug("Called ProcessRequest(). Calling subWorker.WaitForEndOfRequest()."); } subWorker.WaitForEndOfRequest(); if (log.IsDebugEnabled) { log.Debug("subWorker.WaitForEndOfRequest() returned."); } } finally { HttpContext.Current = savedContext; string rawUrl = app.Context.Request.RawUrl; log4net.ThreadContext.Properties["url"] = rawUrl; // Workaround for bug in mod_mono (at least rev 1.0.9) where the response status // is overwritten with 200 when app.CompleteRequest() is called. Status (and headers) // *should* be ignored because they were already sent when the subrequest was processed... app.Response.StatusCode = subWorker.StatusCode; app.Response.StatusDescription = subWorker.StatusDescription; // If there was an error, rethrow it so that ASP.NET uses any custom error pages. if (subWorker.Exception != null) { HttpException httpException = subWorker.Exception as HttpException; if (httpException != null) { throw new HttpException(httpException.GetHttpCode(), "Unhandled HttpException while processing NeatUpload child request", httpException); } UploadException uploadException = subWorker.Exception as UploadException; if (uploadException != null) { throw new HttpException(uploadException.HttpCode, "Unhandled UploadException while processing NeatUpload child request", uploadException); } throw new Exception("Unhandled Exception while processing NeatUpload child request", subWorker.Exception); } // Otherwise call CompleteRequest() to prevent further processing of the original request. app.CompleteRequest(); } }
internal static HttpWorkerRequest GetOrigWorkerRequest() { HttpWorkerRequest worker = GetCurrentWorkerRequest(); DecoratedWorkerRequest decoratedWorker = worker as DecoratedWorkerRequest; if (decoratedWorker != null) { worker = decoratedWorker.OrigWorker; } return(worker); }
private bool ReplaceWorkerRequest(HttpApplication app, DecoratedWorkerRequest subWorker) { BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic; HttpRequest request = app.Request; FieldInfo wrField = request.GetType().GetField("_wr", bindingFlags); // In Mono, the field has a different name. if (wrField == null) { wrField = request.GetType().GetField("worker_request", bindingFlags); } if (wrField == null) { return(false); } wrField.SetValue(request, subWorker); app.Context.Items[WorkerRequestKey] = subWorker; return(true); }
private void Application_BeginRequest(object sender, EventArgs e) { if (log.IsDebugEnabled) { log.Debug("In Application_BeginRequest"); } // When tracing is enabled at the application level ASP.NET reads the entire request before // BeginRequest is fired. So, we should not use our module at all. We can't do this // check from Init() when using Integrated Pipeline Mode because the following line // will throw an exception if tracing is enabled. lock (StaticSync) { _isInited = !HttpContext.Current.Trace.IsEnabled; if (!IsInited) { return; } } HttpApplication app = sender as HttpApplication; // Restore the cookies for the MultiRequestUploadModule.UploadPath page. HttpWorkerRequest wr = GetCurrentWorkerRequest(); string filePath = wr.GetFilePath().ToLower(); string multiRequestUploadPath = MultiRequestUploadModule.UploadPath; multiRequestUploadPath = app.Response.ApplyAppPathModifier(multiRequestUploadPath); if (log.IsDebugEnabled) { log.DebugFormat("filePath={0}", filePath); } string qs = wr.GetQueryString(); if (filePath.StartsWith(multiRequestUploadPath.ToLower())) { // The module should always be used for the multi-request upload handler // Note that for compatibility reasons we can't set useHttpModule="true" // in the NeatUpload folder's Web.config because we can't be sure where // the app put the top-level <neatUpload> section and if guess wrong we // won't inherit the top-level settings (e.g. validationKey and // encryptionKey) HttpContext.Current.Items["NeatUpload_UseHttpModule"] = true; if (qs != null) { HttpCookieCollection cookies = UploadHttpModule.GetCookiesFromQueryString(qs); if (log.IsDebugEnabled) { log.DebugFormat("cookies={0}", cookies); } if (cookies != null) { foreach (string k in cookies.AllKeys) { HttpCookie c = cookies[k]; if (log.IsDebugEnabled) { log.DebugFormat("Calling SetCookie({0}, {1})", c.Name, c.Value); } SetCookie(c.Name, c.Value); } } } } if (!Config.Current.UseHttpModule) { return; } HttpWorkerRequest origWorker = GetCurrentWorkerRequest(); if (origWorker == null) { if (log.IsDebugEnabled) { log.Debug("origWorker = null"); } return; } if (log.IsDebugEnabled) { log.Debug(origWorker.GetType() + " for " + origWorker.GetRawUrl() + " with AspFilterSessionId = " + origWorker.GetUnknownRequestHeader("AspFilterSessionId")); } string rawUrl = app.Context.Request.RawUrl; log4net.ThreadContext.Properties["url"] = rawUrl; if (origWorker is DecoratedWorkerRequest) { // If an unhandled error occurs, we want to remember it so that we can rethrow it // in the original context. if (RememberErrorHandler != null) { app.Error += RememberErrorHandler; } // Save a reference to the original HttpContext in the subrequest context so that // AppendToLog() can use it. DecoratedWorkerRequest decoratedWorkerRequest = origWorker as DecoratedWorkerRequest; if (decoratedWorkerRequest.OrigContext != null) { HttpContext.Current.Items["NeatUpload_origContext"] = decoratedWorkerRequest.OrigContext; } // Ignore the subrequests to avoid infinite recursion... return; } // Get the Content-Length header and parse it if we find it. If it's not present we might // still be OK. long contentLength = 0; string contentLengthHeader = origWorker.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentLength); if (contentLengthHeader != null) { try { contentLength = Int64.Parse(contentLengthHeader); } catch (Exception ex) { throw new HttpException(400, "Bad Request", ex); } } DecoratedWorkerRequest subWorker = null; // Create a subrequest for each request. For multipart/form-data requests, we use a // FilteringWorkerRequest which filters the file parts into temp files. For all other // requests that could contain a body, we use a SizeLimitingWorkerRequest to ensure that the // size of the request is within // the user configured limit. We need the SizeLimitingWorkerRequest, because httpRuntime's // maxRequestLength attribute needs to be set to a large value to allow large file upload request // to get to this module at all. That means that large normal requests will also get to this // module. SizeLimitingWorkerRequest ensures that normal requests which are too large are // rejected. string contentTypeHeader = origWorker.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentType); string transferEncodingHeader = origWorker.GetKnownRequestHeader(HttpWorkerRequest.HeaderTransferEncoding); if (contentTypeHeader != null && contentTypeHeader.ToLower().StartsWith("multipart/form-data")) { // If this is a multi-request upload get the post-back ID from the query string if (qs != null && UploadHttpModule.GetMultiRequestControlIDFromQueryString(qs) != null) { CurrentUploadState = UploadStateStore.OpenReadWriteOrCreate(UploadHttpModule.GetPostBackIDFromQueryString(qs)); if (transferEncodingHeader != "chunked") { CurrentUploadState.Status = UploadStatus.NormalInProgress; } else { CurrentUploadState.Status = UploadStatus.ChunkedInProgress; } } subWorker = new FilteringWorkerRequest(origWorker); } else { // If the client-specified content length is too large, we reject the request // immediately. If it's not, the client could be lying so we need to use // SizeLimitingWorkerRequest to actually count the bytes. if (contentLength > MaxNormalRequestLength) { throw new HttpException(413, "Request Entity Too Large"); } // Only requests which match the following criteria could contain a body. if ((transferEncodingHeader != null && transferEncodingHeader != "identity") || (contentLengthHeader != null && contentLengthHeader != "0") || (contentTypeHeader != null && contentTypeHeader.StartsWith("multipart/byteranges"))) { subWorker = new SizeLimitingWorkerRequest(origWorker, MaxNormalRequestLength); } else { if (origWorker.HasEntityBody()) { throw new HttpException(400, "Unexpected body in request for " + rawUrl); } } } if (subWorker != null) { if (!ReplaceWorkerRequest(app, subWorker)) { MakeChildRequest(app, subWorker); } } }