コード例 #1
0
        /// <summary>
        /// Logs a success event either through the health monitoring framework or directly to the event log
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="data"></param>
        /// <param name="eventCode"></param>
        public static void LogSucessEvent(string msg, UploadData data, int eventCode)
        {
            if (HealthMonitoringManager.Enabled)
            {
                UploadRequestSuccessEvent objUploadRequestSuccessEvent = new UploadRequestSuccessEvent(msg, data, eventCode);
                objUploadRequestSuccessEvent.Raise();
            }
            else
            {
                try
                {
                    if (!EventLog.SourceExists(HealthMonitoringManager.Source))
                    {
                        System.Diagnostics.EventLog.CreateEventSource(HealthMonitoringManager.Source, HealthMonitoringManager.Log);
                    }

                    System.Diagnostics.EventLog.WriteEntry(
                        HealthMonitoringManager.Source,
                        String.Format("{0}\r\n\r\n{1}", msg, data),
                        EventLogEntryType.Information,
                        eventCode);
                }
                catch { }
            }
        }
コード例 #2
0
        /// <summary>
        /// Gets upload data from context cache
        /// </summary>
        /// <param name="context"></param>
        /// <param name="uploadId"></param>
        /// <returns></returns>
        public static UploadData GetUploadData(HttpContext context, string uploadId)
        {
#if (TRACE)
            ThreadLog.WriteLine("Getting upload data for " + uploadId);
#endif

#if (DEBUG)
            //DEBUG mode should support unit tests
            if ((context == null) || (String.IsNullOrEmpty(uploadId)))
            {
                return(new UploadData(String.Empty, String.Empty, false));
            }
#endif

            if (context == null)
            {
                throw new ArgumentNullException("context", Resources.ExceptionNullContext);
            }

            if (String.IsNullOrEmpty(uploadId))
            {
                throw new ArgumentNullException("uploadId", Resources.ExceptionNullOrEmptyUploadId);
            }

            //Try first to retrieve upload context data from context cache
            UploadData objUploadDataRet = HttpRuntime.Cache.Get(UPLOAD_DATA_PREFIX + uploadId) as UploadData;

            //If upload context data is available in application state/context cache, check user provided download has started
            if (objUploadDataRet != null)
            {
#if (TRACE)
                ThreadLog.WriteLine("Upload status is " + objUploadDataRet.ProgressStatus.ToString());
#endif
                //We need to test for Flash applets, because the Flash applet works in anonymous mode
                //but passes cookies which may contain the authentication from previous sessions on the web site
                //implying a failure of the test below
                if (!context.Request.UrlReferrer.AbsolutePath.ToLowerInvariant().EndsWith(".swf"))
                {
                    if ((objUploadDataRet.IsAuthenticated != context.User.Identity.IsAuthenticated) ||
                        (objUploadDataRet.UserName != context.User.Identity.Name))
                    {
                        throw new System.Security.SecurityException(Resources.ExceptionUnauthorizedAccessToUploadData);
                    }
                }
            }
            else
            {
                //Upload context data could be null, for example when the uploadId requested does not exist
#if (TRACE)
                ThreadLog.WriteLine("Upload data is null");
#endif
            }

            return(objUploadDataRet);
        }
コード例 #3
0
        /// <summary>
        /// Constructor
        /// </summary>
        /// <remarks>The request stream is passed as a Stream instead of a RequestStream to allow unit testing from dump files.</remarks>
        /// <param name="requestStream">A Stream representing the request stream</param>
        /// <param name="hashAlgorithm">The hash algorithm used to hash file upload data</param>
        /// <param name="contentLength"></param>
        /// <param name="encoding"></param>
        /// <param name="multipartBoundary"></param>
        /// <param name="uploadData"></param>
        public RequestFilter(Stream requestStream, HashAlgorithm hashAlgorithm, long contentLength, Encoding encoding, string multipartBoundary, UploadData uploadData)
        {
            if (requestStream == null)
            {
                throw new ArgumentNullException("requestStream");
            }
            if (hashAlgorithm == null)
            {
                throw new ArgumentNullException("hashAlgorithm");
            }
            if (contentLength < 0)
            {
                throw new ArgumentOutOfRangeException("contentLength");
            }
            if (encoding == null)
            {
                throw new ArgumentNullException("encoding");
            }
            if (multipartBoundary == null)
            {
                throw new ArgumentNullException("multipartBoundary");
            }
            //Note: Even for unit testing we should have an uploadData object
            if (uploadData == null)
            {
                throw new ArgumentNullException("uploadData");
            }

            _RequestStream = requestStream;
            //_CryptoStream = null; //CA1805
            _HashAlgorithm      = hashAlgorithm;
            _Encoding           = encoding;
            _MultiPartBoundary  = _Encoding.GetBytes(multipartBoundary);
            _MultiPartBoundary2 = _Encoding.GetBytes(Constants.LineSeparator + multipartBoundary);
            _MultiPartRegex     = new Regex(@".*name=\""(?<name>.*)\"".*filename=\""(?<filename>.*)\"".*\r\nContent-Type:\s(?<contenttype>.*)",
                                            RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture | RegexOptions.Compiled);
            _FilteredRequestStringBuilder = new StringBuilder(Constants.StringBuilderCapacity);
            _FilteredRequestStringBuilder.Append(multipartBoundary);
            //_IsProcessingUploadedFile = false; //CA1805

            _UploadData = uploadData;
            _UploadData.ReportStart(contentLength);
        }
コード例 #4
0
        /// <summary>
        /// Called by user from page to cancel an upload
        /// </summary>
        public static void CancelUpload(HttpContext context, string uploadId)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context", Resources.ExceptionNullContext);
            }

            if (String.IsNullOrEmpty(uploadId))
            {
                throw new ArgumentNullException("uploadId", Resources.ExceptionNullOrEmptyUploadId);
            }

            UploadData objUploadData = GetUploadData(context, uploadId);

            if ((objUploadData != null) &&
                (objUploadData.ProgressStatus != UploadProgressStatus.Canceled) &&
                (objUploadData.ProgressStatus != UploadProgressStatus.Completed))
            {
                objUploadData.ReportCanceled();
            }
        }
コード例 #5
0
        /// <summary>
        /// Outputs a string representation of a upload data, which is used in health monitoring and event log entries
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            StringBuilder objStringBuilderRet = new StringBuilder();

            objStringBuilderRet.AppendLine(Properties.Resources.UploadData_Title);
            if (HttpContext.Current != null)
            {
                objStringBuilderRet.AppendLine(String.Format(Properties.Resources.UploadData_Request, HttpContext.Current.Request.RawUrl));
            }
            objStringBuilderRet.AppendLine(String.Format(Properties.Resources.UploadData_UploadId, this.UploadId));
            objStringBuilderRet.AppendLine(String.Format(Properties.Resources.UploadData_UserName, this.UserName));
            objStringBuilderRet.AppendLine(String.Format(Properties.Resources.UploadData_UploadProgressStatus, UploadData.Format(this.ProgressStatus), this.ProgressRatio));
            objStringBuilderRet.AppendLine(String.Format(Properties.Resources.UploadData_BytesProgress, this.ContentPosition, this.ContentLength, this.BytesPerSecond));
            objStringBuilderRet.AppendLine(String.Format(Properties.Resources.UploadData_TimeProgress, this.TimeElapsed, this.TimeLeftEstimated, this.TimeTotalEstimated));
            objStringBuilderRet.AppendLine(Properties.Resources.UploadData_Files);
            foreach (UploadFile objUploadFile in this.UploadFiles)
            {
                objStringBuilderRet.AppendLine(String.Format(
                                                   Properties.Resources.UploadData_UploadFile,
                                                   objUploadFile.OriginalPath,
                                                   objUploadFile.ContentType,
                                                   objUploadFile.ContentLength,
                                                   objUploadFile.ProviderFileKey));
            }
            if (this.Exception != null)
            {
                objStringBuilderRet.AppendLine(String.Format(Properties.Resources.UploadData_Exception, this.Exception));
            }
            return(objStringBuilderRet.ToString());
        }
コード例 #6
0
        private void OnPreRequestHandlerExecute(object sender, EventArgs e)
        {
            HttpApplication objHttpApplication = sender as HttpApplication;

            System.Diagnostics.Debug.Assert(objHttpApplication != null);
            HttpRequest objHttpRequest = objHttpApplication.Request;

            System.Diagnostics.Debug.Assert(objHttpRequest != null);

            if (objHttpRequest != null && UploadHttpModule.IsUploadRequest(objHttpRequest))
            {
#if (TRACE)
                ThreadLog.WriteLine("Entered OnPreRequestHandlerExecute for an upload request");
#endif

                HttpContext objHttpContext = objHttpApplication.Context;
                System.Diagnostics.Debug.Assert(objHttpContext != null);

                HttpWorkerRequest objHttpWorkerRequest = UploadHttpModule.GetWorkerRequest(objHttpContext);
                System.Diagnostics.Debug.Assert(objHttpWorkerRequest != null);

                if (objHttpWorkerRequest != null)
                {
                    //long lContentLength = objHttpRequest.ContentLength;
                    long lContentLength = long.Parse(objHttpWorkerRequest.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentLength), CultureInfo.InvariantCulture);

                    if (lContentLength <= 0) //This is for Flash 8 FileReference which tests an empty post before sending a large upload
                    {
#if (TRACE)
                        ThreadLog.WriteLine("No content, maybe Flash");
#endif

                        HealthMonitoringManager.LogSucessEvent(
                            Resources.ExceptionZeroContentLength,
                            null, //<- no upload data yet
                            UploadRequestSuccessEvent.RuntimeUploadSuccessZeroContentLength);

                        objHttpApplication.Response.StatusCode = 200; //OK
                        objHttpApplication.CompleteRequest();
                        //See: http://support.microsoft.com/kb/312629
                        //objHttpApplication.Response.End();
                        return;
                    }

                    //Initialize an upload monitor
                    string sUploadID = UploadHttpModule.GetUploadID(objHttpRequest);
                    if (String.IsNullOrEmpty(sUploadID))
                    {
#if (TRACE)
                        ThreadLog.WriteLine("No upload ID");
#endif

                        HttpException objHttpException = new HttpException(400, Resources.ExceptionNullOrEmptyUploadId);

                        HealthMonitoringManager.LogErrorEvent(
                            Resources.ExceptionNullOrEmptyUploadId,
                            null, //<- no upload data yet
                            UploadRequestErrorEvent.RuntimeErrorMissingUploadID,
                            objHttpException);

                        UploadHttpModule.CloseConnectionAfterError(objHttpApplication.Response);
                        throw objHttpException;

                        //See comment in relation with MaxRequestLength here below
                        //objHttpApplication.Response.StatusCode = 400; //Bad request
                        //objHttpApplication.Response.StatusDescription = Resources.ExceptionNullOrEmptyUploadId;
                        //objHttpApplication.Response.Write(String.Format(Resources.Culture, Resources.ErrorPage, 400, Resources.ExceptionNullOrEmptyUploadId));
                        //objHttpApplication.CompleteRequest();
                        //See: http://support.microsoft.com/kb/312629
                        //objHttpApplication.Response.End();
                    }

                    UploadData objUploadData = UploadMonitor.SetUploadData(objHttpContext, sUploadID);
                    System.Diagnostics.Debug.Assert(objUploadData != null);

                    //Check whether we should read MaxRequestLength from httpRuntime section of web.config (true)
                    bool bMaximizeRequestLength = UploadHttpModule.GetForceHttpMaxRequestLength(objHttpRequest);
                    //Check the upload size and end request if file is too big
                    long lMaxRequestLength = UploadHttpModule.GetMaxRequestLengthBytes(objHttpContext, bMaximizeRequestLength);
                    if ((lMaxRequestLength >= 0) && (lContentLength > lMaxRequestLength))
                    {
#if (TRACE)
                        ThreadLog.WriteLine("Post request is too large");
#endif

                        HttpException objHttpException = new HttpException(413, Resources.ExceptionPostTooLarge);

                        HealthMonitoringManager.LogErrorEvent(
                            Resources.ExceptionPostTooLarge,
                            objUploadData,
                            UploadRequestErrorEvent.RuntimeErrorPostTooLarge,
                            objHttpException);

                        objUploadData.ReportFailed(objHttpException);

                        UploadHttpModule.CloseConnectionAfterError(objHttpApplication.Response);
                        throw objHttpException;

                        //There are 3 possible options
                        //1) Do nothing and let httpRuntime/maxRequestlength do its job
                        //2) Do something like
                        //      objHttpApplication.Response.StatusCode = 413;
                        //      objHttpApplication.Response.StatusDescription = Resources.ExceptionPostTooLarge;
                        //      objHttpApplication.Response.Write(String.Format(Resources.Culture, Resources.ErrorPage, 413, Resources.ExceptionPostTooLarge));
                        //      objHttpApplication.CompleteRequest();
                        //      See: http://support.microsoft.com/kb/312629
                        //      //objHttpApplication.Response.End();
                        //      return;
                        //3) Raise an HttpException

                        //Option 1 is no more an option since we have implemented uploadRuntime

                        //Option 2 sometimes aborts and closes the connection with an IE error page,
                        //sometimes displays a blank page. When the IE page appears, we get
                        //an ERROR_INTERNET_CONNECTION_ABORTED, when the blank page is displayed
                        //the post returns a 413 status code. To get some content we would need
                        //to write to the response _Input using something like objHttpApplication.Response.Write

                        //HttpRequest.GetEntireRawContent implements option 3). Actually it triggers
                        //throw new HttpException(SR.GetString("Max_request_length_exceeded"), null, 0xbbc);
                        //after calling HttpResponse.CloseConnectionAfterError(). In this case an unhdandled
                        //exception is thrown abd we can rely on Application_Error and Custom Errors which
                        //is the best option.
                    }

#if (TRACE)
                    ThreadLog.WriteLine("Start parsing upload _Input");
#endif

                    Encoding objEncoding = objHttpRequest.ContentEncoding;

                    string sContentType = objHttpRequest.ContentType;
                    int    iPos         = sContentType.ToLowerInvariant().IndexOf(Constants.MultiPartBoundary);
                    if (iPos < 0)
                    {
#if (TRACE)
                        ThreadLog.WriteLine("Bad request");
#endif

                        HttpException objHttpException = new HttpException(400, Resources.ExceptionMalformedContentType);

                        HealthMonitoringManager.LogErrorEvent(
                            Resources.ExceptionMalformedContentType,
                            objUploadData,
                            UploadRequestErrorEvent.RuntimeErrorMalformedContentType,
                            objHttpException
                            );

                        objUploadData.ReportFailed(objHttpException);

                        UploadHttpModule.CloseConnectionAfterError(objHttpApplication.Response);
                        throw objHttpException;

                        //See comment in relation with MaxRequestLength here above
                        //objHttpApplication.Response.StatusCode = 400; //Bad request
                        //objHttpApplication.Response.StatusDescription = Resources.ExceptionMultipartBoundaryNotFound;
                        //objHttpApplication.Response.Write(String.Format(Resources.Culture, Resources.ErrorPage, 400, Resources.ExceptionMultipartBoundaryNotFound));
                        //objHttpApplication.CompleteRequest();
                        //See: http://support.microsoft.com/kb/312629
                        //objHttpApplication.Response.End();
                        //return;
                    }
                    string sMultiPartBoundary = Constants.BoundaryPrefix + sContentType.Substring(iPos + Constants.MultiPartBoundary.Length);
#if (TRACE)
                    ThreadLog.WriteLine("Identified boundary = " + sMultiPartBoundary);
#endif

                    RequestStream objRequestStream = null;
                    RequestFilter objRequestFilter = null;

                    try
                    {
                        HashAlgorithm objHashAlgorithm = CryptoConfig.CreateFromName(Constants.HashAlgorithmName) as HashAlgorithm;
                        //objHashAlgorithm.Initialize(); Done in RequestFilter
                        objRequestStream = new RequestStream(objHttpWorkerRequest);
                        objRequestFilter = new RequestFilter(objRequestStream, objHashAlgorithm, lContentLength, objEncoding, sMultiPartBoundary, objUploadData);

#if (TRACE)
                        ThreadLog.WriteLine("Started parsing");
#endif

                        //Parse the request to filter input files
                        MimeParser objMimeParser = new MimeParser(objRequestFilter);
                        objMimeParser.Parse();
                        //Get the filtered request
                        byte[] arrFilteredRequest = objRequestFilter.Encoding.GetBytes(objRequestFilter.FilteredRequest);
                        //Redirect the filtered request
                        RedirectFilteredRequest(objHttpApplication, objHttpWorkerRequest, arrFilteredRequest);

#if (TRACE)
                        ThreadLog.WriteLine("Filtered request redirected");
#endif

                        HealthMonitoringManager.LogSucessEvent(
                            Resources.MessageUploadCompleted,
                            objUploadData,
                            UploadRequestSuccessEvent.RuntimeUploadSuccessCompleted
                            );
                    }
                    catch (Exception Ex)
                    {
#if (TRACE)
                        ThreadLog.WriteLine("Parsing error");
#endif
                        HealthMonitoringManager.LogErrorEvent(
                            Resources.ExceptionUnhandled + "\r\n" + objHttpWorkerRequest.GetKnownRequestHeader(HttpWorkerRequest.HeaderUserAgent),
                            objUploadData,
                            UploadRequestErrorEvent.RuntimeErrorExceptionUnhandled,
                            Ex);

                        objUploadData.ReportFailed(Ex);

                        UploadHttpModule.CloseConnectionAfterError(objHttpApplication.Response);
                        if ((Ex is HttpException) || (Ex is System.Net.WebException))
                        {
                            throw;
                        }
                        else
                        {
                            throw new HttpException(500, Resources.ExceptionUnhandled, Ex);
                        }

                        //objHttpApplication.Response.StatusCode = 500; //Error
                        //objHttpApplication.Response.StatusDescription = Resources.ExceptionUnhandled;
                        //objHttpApplication.Response.Write(String.Format(Resources.Culture, Resources.ErrorPage, 500, Ex.Message));
                        //objHttpApplication.CompleteRequest();
                        //See: http://support.microsoft.com/kb/312629
                        //objHttpApplication.Response.End();
                    }
                    finally
                    {
#if (TRACE)
                        ThreadLog.WriteLine("Disposing of resources");
#endif

                        if (objRequestFilter != null)
                        {
                            objRequestFilter.Dispose();
                        }
                        if (objRequestStream != null)
                        {
                            objRequestStream.Dispose();
                        }

                        if (objUploadData != null)
                        {
                            if (objUploadData.ProgressStatus != UploadProgressStatus.Completed)
                            {
                                this.DeleteUploadFiles(objUploadData.UploadFiles);
                            }

                            //Too soon to release here: let sliding expiration work for us
                            //UploadMonitor.Release(objHttpContext, objUploadData.UploadId);
                        }
                    }
                }
#if (TRACE)
                ThreadLog.WriteLine("Exit OnPreRequestHandlerExecute");
#endif
            }
        }
コード例 #7
0
        private const int CACHE_SLIDINGEXPIRATION          = 1;       //in Days

        #region Other Members

        #region SetUploadData
        /// <summary>
        /// Sets upload data in context cache
        /// </summary>
        /// <param name="context"></param>
        /// <param name="uploadId"></param>
        /// <returns></returns>
        public static UploadData SetUploadData(HttpContext context, string uploadId)
        {
#if (TRACE)
            ThreadLog.WriteLine("Setting upload data with " + uploadId);
#endif

            //Note:
            //Adding UploadData to HttpContext.Items is not a possible option considering HttpContext.Items are only available during the lifetime and scope of a single request
            //Adding UploadData to HttpSessionState is a reasonable choice to share data between requests and prevent other users to access uploaded files but the server hangs the connection
            //So we are left with two options:
            // 1) storing UploadData in HttpApplicationState.
            // 2) storing UploadData in HttpRuntime.Cache
            //Note that HttpApplicationState is a legacy of ASP, and the use of HttpRuntime.Cache is recommended in ASP.NET

            //Also note:
            //Because HttpRuntime.Cache is global, we need to prevent unauthorized access and check the context user each time UploadData is requested.

#if (DEBUG)
            //DEBUG mode should support unit tests
            if ((context == null) || (String.IsNullOrEmpty(uploadId)))
            {
                return(new UploadData((String.IsNullOrEmpty(uploadId) ? String.Empty : uploadId), String.Empty, false));
            }
#endif

            if (context == null)
            {
                throw new ArgumentNullException("context", Resources.ExceptionNullContext);
            }

            if (String.IsNullOrEmpty(uploadId))
            {
                throw new ArgumentNullException("uploadId", Resources.ExceptionNullOrEmptyUploadId);
            }

            //Needs to be removed before it can be added
            if (context.Items.Contains(UploadMonitor.UploadIdParam))
            {
                context.Items.Remove(UploadMonitor.UploadIdParam);
            }
            context.Items.Add(UploadMonitor.UploadIdParam, uploadId);

            UploadData objUploadDataRet = new UploadData(uploadId, context.User.Identity.Name, context.User.Identity.IsAuthenticated);

            if (HttpRuntime.Cache.Get(UPLOAD_DATA_PREFIX + uploadId) != null)
            {
                HttpRuntime.Cache.Remove(UPLOAD_DATA_PREFIX + uploadId);
            }

            //TODO: Not sure we could create an event callback because we need teh data after the module has completed its part of the request
            //See: http://blogs.msdn.com/tess/archive/2006/08/11/asp-net-quiz-answers-does-page-cache-leak-memory.aspx
            HttpRuntime.Cache.Add(
                UPLOAD_DATA_PREFIX + uploadId,
                objUploadDataRet,
                null,
                Cache.NoAbsoluteExpiration,
                new TimeSpan(CACHE_SLIDINGEXPIRATION, 0, 0, 0),
                CacheItemPriority.AboveNormal, //Make it above normal just in case scavenging is triggered because some caching space is needed
                null
                );

            return(objUploadDataRet);
        }