示例#1
0
        internal void ReportFileCompleted(long contentPosition, byte[] hash)
        {
#if (TRACE)
            ThreadLog.WriteLine("File completed " + contentPosition.ToString(CultureInfo.InvariantCulture));
#endif

            // Create a new Stringbuilder to collect the bytes and create a string.
            StringBuilder objStringBuilder = new StringBuilder();

            // Loop through each byte of the hashed data
            // and format each one as a hexadecimal string.
            for (int i = 0; i < hash.Length; i++)
            {
                objStringBuilder.Append(hash[i].ToString("x2", CultureInfo.InvariantCulture));
            }

            _ContentPosition = contentPosition;
            this.UploadFileInProgress.HashValue  = objStringBuilder.ToString();
            this.UploadFileInProgress.IsComplete = true;

            if (HttpContext.Current != null) //Support for unit tests
            {
                System.Diagnostics.Debug.Assert(((UploadData)HttpContext.Current.Cache.Get(UploadMonitor.UPLOAD_DATA_PREFIX + _UploadId)).ContentPosition == contentPosition);
                System.Diagnostics.Debug.Assert(((UploadData)HttpContext.Current.Cache.Get(UploadMonitor.UPLOAD_DATA_PREFIX + _UploadId)).ProgressStatus == UploadProgressStatus.InProgress);
            }
        }
示例#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
        internal void ReportPosition(long contentPosition)
        {
#if (TRACE)
            ThreadLog.WriteLine("Content position = " + contentPosition.ToString(CultureInfo.InvariantCulture));
#endif

            _ContentPosition = contentPosition;

            if (HttpContext.Current != null) //Support for unit tests
            {
                System.Diagnostics.Debug.Assert(((UploadData)HttpContext.Current.Cache.Get(UploadMonitor.UPLOAD_DATA_PREFIX + _UploadId)).ContentPosition == contentPosition);
                System.Diagnostics.Debug.Assert(((UploadData)HttpContext.Current.Cache.Get(UploadMonitor.UPLOAD_DATA_PREFIX + _UploadId)).ProgressStatus == UploadProgressStatus.InProgress);
            }
        }
示例#4
0
        internal void ReportFailed(Exception exception)
        {
#if (TRACE)
            ThreadLog.WriteLine("Parsing failed: " + exception.Message);
#endif

            _EndDate        = DateTime.UtcNow;
            _ProgressStatus = UploadProgressStatus.Failed;
            _Exception      = exception;

            if (HttpContext.Current != null) //Support for unit tests
            {
                //System.Diagnostics.Debug.Assert(((UploadData)HttpContext.Current.Cache.Get(UploadMonitor.UPLOAD_DATA_PREFIX + _UploadId)).ContentPosition == contentPosition);
                System.Diagnostics.Debug.Assert(((UploadData)HttpContext.Current.Cache.Get(UploadMonitor.UPLOAD_DATA_PREFIX + _UploadId)).ProgressStatus == UploadProgressStatus.Failed);
            }
        }
示例#5
0
        internal void ReportFileCreated(long contentPosition, string htmlInputID, string fileName, string contentType, object providerFileKey)
        {
#if (TRACE)
            ThreadLog.WriteLine("New file = " + fileName);
#endif

            _ContentPosition = contentPosition;
            UploadFile objUploadFile = new UploadFile(htmlInputID, fileName, contentType, providerFileKey);
            _UploadFiles.Add(objUploadFile);

            if (HttpContext.Current != null) //Support for unit tests
            {
                System.Diagnostics.Debug.Assert(((UploadData)HttpContext.Current.Cache.Get(UploadMonitor.UPLOAD_DATA_PREFIX + _UploadId)).ContentPosition == contentPosition);
                System.Diagnostics.Debug.Assert(((UploadData)HttpContext.Current.Cache.Get(UploadMonitor.UPLOAD_DATA_PREFIX + _UploadId)).ProgressStatus == UploadProgressStatus.InProgress);
            }
        }
示例#6
0
        internal void ReportStart(long contentLength)
        {
#if (TRACE)
            ThreadLog.WriteLine("Upload started with Content-Length = " + contentLength.ToString(CultureInfo.InvariantCulture));
#endif

            _ContentLength   = contentLength;
            _ContentPosition = 0;
            _StartDate       = DateTime.UtcNow;
            _ProgressStatus  = UploadProgressStatus.InProgress;

            if (HttpContext.Current != null) //Support for unit tests
            {
                System.Diagnostics.Debug.Assert(((UploadData)HttpContext.Current.Cache.Get(UploadMonitor.UPLOAD_DATA_PREFIX + _UploadId)).ContentLength == contentLength);
                System.Diagnostics.Debug.Assert(((UploadData)HttpContext.Current.Cache.Get(UploadMonitor.UPLOAD_DATA_PREFIX + _UploadId)).ProgressStatus == UploadProgressStatus.InProgress);
            }
        }
示例#7
0
        internal void ReportCanceled()
        {
#if (TRACE)
            ThreadLog.WriteLine("Upload canceled");
#endif

            _EndDate        = DateTime.UtcNow;
            _ProgressStatus = UploadProgressStatus.Canceled;

            if (HttpContext.Current != null) //Support for unit tests
            {
                //System.Diagnostics.Debug.Assert(((UploadData)HttpContext.Current.Cache.Get(UploadMonitor.UPLOAD_DATA_PREFIX + _UploadId)).ContentPosition == contentPosition);
                System.Diagnostics.Debug.Assert(((UploadData)HttpContext.Current.Cache.Get(UploadMonitor.UPLOAD_DATA_PREFIX + _UploadId)).ProgressStatus == UploadProgressStatus.Canceled);
            }

            HealthMonitoringManager.LogErrorEvent(
                Resources.ExceptionRequestCanceled,
                this,
                UploadRequestErrorEvent.RuntimeErrorRequestAbort,
                null);
        }
示例#8
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
            }
        }
示例#9
0
        public override int Read(byte[] buffer, int offset, int count)
        {
#if (TRACE)
            ThreadLog.WriteLine(String.Format(CultureInfo.InvariantCulture, "Start reading {0} bytes", count));
#endif

            if (!_IsOpen)
            {
                throw new ObjectDisposedException(null);
            }
            if (buffer == null)
            {
                throw new ArgumentNullException("buffer");
            }
            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException("offset");
            }
            if (count < 0)
            {
                throw new ArgumentOutOfRangeException("count");
            }
            if (offset + count > buffer.Length)
            {
                throw new ArgumentException(Resources.ExceptionEndOfBufferReached);
            }

            int iBytesRead = 0;
            //bool bRetry = true;

            //LABEL_RETRY:
            if (this._IsEntireEntityBodyIsPreloaded)
            {
                iBytesRead = this.ReadPreloadedEntityBody(buffer, offset, count);
#if (TRACE)
                ThreadLog.WriteLine(String.Format(CultureInfo.InvariantCulture, "Just read {0} preloaded bytes", iBytesRead));
#endif

                if (iBytesRead < count)
                {
                    if (this._HttpWorkerRequest.IsClientConnected() && !this._HttpWorkerRequest.IsEntireEntityBodyIsPreloaded())
                    {
                        iBytesRead += this.ReadEntityBody(buffer, offset + iBytesRead, count - iBytesRead);
#if (TRACE)
                        ThreadLog.WriteLine(String.Format(CultureInfo.InvariantCulture, "Just read {0} more bytes", iBytesRead));
#endif
                    }
                    this._IsEntireEntityBodyIsPreloaded = false;
                }
            }
            else if (this._HttpWorkerRequest.IsClientConnected() && !this._HttpWorkerRequest.IsEntireEntityBodyIsPreloaded())
            {
                iBytesRead = this.ReadEntityBody(buffer, offset, count);
#if (TRACE)
                ThreadLog.WriteLine(String.Format(CultureInfo.InvariantCulture, "Just read {0} bytes", iBytesRead));
#endif
            }
            this._Position += iBytesRead;
            if (iBytesRead == 0)
            {
#if (TRACE)
                ThreadLog.WriteLine("Houston, we have a problem: no bytes to read ...................");
#endif
                //if (bRetry)
                //{
                //    bRetry = false;
                //    goto LABEL_RETRY;
                //}
                //else
                throw new System.Net.WebException(Resources.ExceptionConnectionClosed, System.Net.WebExceptionStatus.ConnectionClosed);
            }
            return(iBytesRead);
        }
示例#10
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);
        }