Пример #1
0
        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();
                }
            }
        }
Пример #2
0
        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();
            }
        }
Пример #3
0
        internal static HttpWorkerRequest GetOrigWorkerRequest()
        {
            HttpWorkerRequest      worker          = GetCurrentWorkerRequest();
            DecoratedWorkerRequest decoratedWorker = worker as DecoratedWorkerRequest;

            if (decoratedWorker != null)
            {
                worker = decoratedWorker.OrigWorker;
            }
            return(worker);
        }
Пример #4
0
        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);
        }
Пример #5
0
        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);
                }
            }
        }