예제 #1
0
 public override string GetKnownRequestHeader(int index)
 {
     if (index == HttpWorkerRequest.HeaderContentLength)
     {
         ParseMultipart();
         return(preloadedEntityBody.Length.ToString());
     }
     return(OrigWorker.GetKnownRequestHeader(index));
 }
예제 #2
0
        private int ReadOrigEntityBody(byte[] destBuf, int count)
        {
            // If the upload was cancelled, return a 204 error code which tells the client that it
            // "SHOULD NOT change its document view from that which caused the request to be sent" (RFC 2616 10.2.5)
            if (UploadState != null && UploadState.Status == UploadStatus.Cancelled)
            {
                throw new HttpException(204, "Upload cancelled by user");
            }

            double secsToWait = 0;

            if (UploadState != null && Config.Current.MaxUploadRate > 0 &&
                UploadState.TimeElapsed != TimeSpan.MinValue)
            {
                double desiredSecs
                           = ((double)UploadState.BytesRead) / Config.Current.MaxUploadRate;
                secsToWait = Math.Max(0, desiredSecs - UploadState.TimeElapsed.TotalSeconds);
            }

            // NOTE: if secsToWait = 0, this will simply yield to other threads so that the progress bar
            // has a chance to update.
            System.Threading.Thread.Sleep((int)(1000 * secsToWait));

            int totalRead = 0;

            if (origPreloadedBody != null)
            {
                int read = Math.Min(count, origPreloadedBody.Length - origPreloadedBodyPos);
                if (read > 0)
                {
                    Buffer.BlockCopy(origPreloadedBody, origPreloadedBodyPos, destBuf, totalRead, read);
                }
                origPreloadedBodyPos += read;
                if (read < count)
                {
                    origPreloadedBody = null;
                }
                count     -= read;
                totalRead += read;
            }
            if (count > 0)
            {
                byte[] localBuffer = new byte[count];
                int    read        = OrigWorker.ReadEntityBody(localBuffer, count);
                if (Config.Current.DebugDirectory != null)
                {
                    LogEntityBodyStream.Write(localBuffer, 0, read);
                    LogEntityBodySizesStream.WriteLine(read);
                }
                if (read > 0)
                {
                    Buffer.BlockCopy(localBuffer, 0, destBuf, totalRead, read);
                }
                totalRead += read;
            }
            return(totalRead);
        }
예제 #3
0
        public override int ReadEntityBody(byte[] buffer, int size)
        {
            if (log.IsDebugEnabled)
            {
                log.Debug("In ReadEntityBody() with size=" + size);
            }
            int bytesRead = OrigWorker.ReadEntityBody(buffer, size);

            totalBytesRead += bytesRead;

            byte[] preloadedEntityBody = OrigWorker.GetPreloadedEntityBody();
            int    bytesPreloaded      = 0;

            if (preloadedEntityBody != null)
            {
                bytesPreloaded = preloadedEntityBody.Length;
            }

            if (totalBytesRead + bytesPreloaded > maxRequestLength)
            {
                IgnoreRemainingBodyAndThrow(new HttpException(413, "Request Entity Too Large"));
            }
            return(bytesRead);
        }
예제 #4
0
        private bool ParseOrThrow()
        {
            origPreloadedBody = OrigWorker.GetPreloadedEntityBody();
            string contentTypeHeader      = OrigWorker.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentType);
            string contentLengthHeader    = OrigWorker.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentLength);
            string transferEncodingHeader = OrigWorker.GetKnownRequestHeader(HttpWorkerRequest.HeaderTransferEncoding);

            if (contentLengthHeader != null)
            {
                origContentLength = Int64.Parse(contentLengthHeader);
            }

            if (Config.Current.DebugDirectory != null)
            {
                string logEntityBodyBaseName = Path.Combine(Config.Current.DebugDirectory.FullName,
                                                            DateTime.Now.Ticks.ToString());
                LogEntityBodyStream      = File.Create(logEntityBodyBaseName + ".body");
                LogEntityBodySizesStream = File.CreateText(logEntityBodyBaseName + ".sizes");
                LogEntityBodySizesStream.WriteLine(contentTypeHeader);
                LogEntityBodySizesStream.WriteLine(contentLengthHeader);
                if (origPreloadedBody != null)
                {
                    LogEntityBodyStream.Write(origPreloadedBody, 0, origPreloadedBody.Length);
                    LogEntityBodySizesStream.WriteLine(origPreloadedBody.Length);
                }
                else
                {
                    LogEntityBodySizesStream.WriteLine(0);
                }
            }

            FieldNameTranslator translator = new FieldNameTranslator();

            if (MultiRequestControlID == null && UploadState != null)
            {
                UploadState.BytesTotal += origContentLength;
            }
            if (log.IsDebugEnabled)
            {
                log.Debug("=" + contentLengthHeader + " -> " + origContentLength);
            }

            boundary = System.Text.Encoding.ASCII.GetBytes("--" + GetAttribute(contentTypeHeader, "boundary"));
            if (log.IsDebugEnabled)
            {
                log.Debug("boundary=" + System.Text.Encoding.ASCII.GetString(boundary));
            }

            string charset = GetAttribute(contentTypeHeader, "charset");

            if (charset != null)
            {
                try
                {
                    System.Text.Encoding encoding = System.Text.Encoding.GetEncoding(charset);
                    ContentEncoding = encoding;
                }
                catch (NotSupportedException)
                {
                    if (log.IsDebugEnabled)
                    {
                        log.Debug("Ignoring unsupported charset " + charset + ".  Using utf-8.");
                    }
                }
            }
            else
            {
                ContentEncoding = HttpContext.Current.Response.ContentEncoding;
            }
            preloadedEntityBodyStream = new MemoryStream();
            Hashtable storageConfigStreamTable = new Hashtable();
            Stream    postBackIDStream         = null;

            outputStream = preloadedEntityBodyStream;
            readPos      = writePos = parsePos = 0;
            while (CopyUntilBoundary())
            {
                // If we were writing to a file, close it
                if (outputStream == fileStream && outputStream != null)
                {
                    UploadState.Files.Add(controlID, uploadedFile);
                    outputStream.Close();
                }

                // If we were receiving the value generated by the HiddenPostBackID control, set the postback ID.
                if (postBackIDStream != null)
                {
                    postBackIDStream.Seek(0, System.IO.SeekOrigin.Begin);
                    StreamReader sr = new System.IO.StreamReader(postBackIDStream);
                    translator.PostBackID = sr.ReadToEnd();
                    postBackIDStream      = null;
                }

                // parse the headers
                string name = null, fileName = null, contentType = null;
                if (boundary[0] != (byte)'\r')
                {
                    byte[] newBoundary = new byte[boundary.Length + 2];
                    Buffer.BlockCopy(boundary, 0, newBoundary, 2, boundary.Length);
                    newBoundary[0] = (byte)'\r';
                    newBoundary[1] = (byte)'\n';
                    boundary       = newBoundary;
                }
                else
                {
                    GetLine();             // Blank line
                }
                GetLine();                 // boundary line
                string header;
                while (null != (header = GetLine()))
                {
                    if (log.IsDebugEnabled)
                    {
                        log.Debug("header=" + header);
                    }
                    int colonPos = header.IndexOf(':');
                    if (colonPos < 0)
                    {
                        break;
                    }
                    string headerName = header.Substring(0, colonPos);
                    if (String.Compare(headerName, "Content-Disposition", true) == 0)
                    {
                        name     = GetAttribute(header, "name");
                        fileName = GetAttribute(header, "filename");
                    }
                    else if (String.Compare(headerName, "Content-Type", true) == 0)
                    {
                        contentType = header.Substring(colonPos + 1).Trim();
                    }
                }
                if (log.IsDebugEnabled)
                {
                    log.Debug("name = " + name);
                }
                if (log.IsDebugEnabled)
                {
                    log.Debug("fileName = " + fileName);
                }
                if (log.IsDebugEnabled)
                {
                    log.DebugFormat("name = " + name);
                }
                if (log.IsDebugEnabled)
                {
                    log.DebugFormat("fileName = " + fileName);
                }
                controlID = null;
                if (name == Config.Current.PostBackIDQueryParam && postBackIDStream == null)
                {
                    postBackIDStream = outputStream = new System.IO.MemoryStream();
                    readPos          = parsePos;            // Skip past the boundary and headers
                }
                else if (name != null &&
                         null != (controlID = translator.ConfigFieldNameToControlID(name)))
                {
                    storageConfigStreamTable[controlID] = outputStream = new System.IO.MemoryStream();
                    readPos = parsePos;                     // Skip past the boundary and headers
                }
                else if (name != null &&
                         null != (controlID = translator.FileFieldNameToControlID(name)))
                {
                    if (log.IsDebugEnabled)
                    {
                        log.DebugFormat("name != null && controlID != null");
                    }
                    if (UploadState == null)
                    {
                        UploadState = UploadStateStore.OpenReadWriteOrCreate(translator.FileFieldNameToPostBackID(name));
                        if (transferEncodingHeader != "chunked")
                        {
                            UploadState.Status = UploadStatus.NormalInProgress;
                        }
                        else
                        {
                            UploadState.Status = UploadStatus.ChunkedInProgress;
                        }
                        UploadState.BytesTotal += origContentLength;
                        UploadState.BytesRead  += grandTotalBytesRead;
                    }

                    UploadStorageConfig storageConfig = null;

                    if (UploadState.MultiRequestObject != null)
                    {
                        string secureStorageConfigString = UploadState.MultiRequestObject as string;
                        if (secureStorageConfigString != null)
                        {
                            storageConfig = UploadStorage.CreateUploadStorageConfig();
                            storageConfig.Unprotect(secureStorageConfigString);
                            if (log.IsDebugEnabled)
                            {
                                log.DebugFormat("storageConfig[tempDirectory]={0}", storageConfig["tempDirectory"]);
                            }
                        }
                    }
                    string       configID            = translator.FileIDToConfigID(controlID);
                    MemoryStream storageConfigStream = storageConfigStreamTable[configID] as MemoryStream;
                    if (storageConfigStream != null)
                    {
                        storageConfigStream.Seek(0, System.IO.SeekOrigin.Begin);
                        StreamReader sr = new System.IO.StreamReader(storageConfigStream);
                        string       secureStorageConfigString = sr.ReadToEnd();
                        if (log.IsDebugEnabled)
                        {
                            log.Debug("storageConfigStream = " + secureStorageConfigString);
                        }
                        storageConfig = UploadStorage.CreateUploadStorageConfig();
                        storageConfig.Unprotect(secureStorageConfigString);

                        // Write out a part for the config hidden field
                        if (log.IsDebugEnabled)
                        {
                            log.DebugFormat("Calling WriteReplacementFormField({0}, {1})", configID, secureStorageConfigString);
                        }
                        WriteReplacementFormField(configID, secureStorageConfigString);
                        // Remove the stream from the table, so we don't write the replacement field again.
                        storageConfigStreamTable.Remove(configID);
                    }

                    if (fileName != null)
                    {
                        if (log.IsDebugEnabled)
                        {
                            log.DebugFormat("filename != null");
                        }
                        if (log.IsDebugEnabled)
                        {
                            log.Debug("Calling UploadContext.Current.CreateUploadedFile(" + controlID + "...)");
                        }
                        UploadContext tempUploadContext = new UploadContext();
                        tempUploadContext._ContentLength = origContentLength;
                        uploadedFile
                            = UploadStorage.CreateUploadedFile(tempUploadContext, controlID, fileName, contentType, storageConfig);
                        if (MultiRequestControlID == null)
                        {
                            UploadStorage.DisposeAtEndOfRequest(uploadedFile);
                        }
                        outputStream = fileStream = uploadedFile.CreateStream();
                        UploadState.CurrentFileName = uploadedFile.FileName;
                        readPos = parsePos; // Skip past the boundary and headers

                        // If the client-specified content length is too large, we set the status to
                        // RejectedRequestTooLarge so that progress displays will stop.  We do this after
                        // having created the UploadedFile because that is necessary for the progress display
                        // to find the uploadContext.
                        if (origContentLength > UploadHttpModule.MaxRequestLength)
                        {
                            if (log.IsDebugEnabled)
                            {
                                log.Debug("contentLength > MaxRequestLength");
                            }
                            throw new UploadTooLargeException(UploadHttpModule.MaxRequestLength, origContentLength);
                        }

                        // Write out a replacement part that just contains the filename as the value.
                        WriteReplacementFormField(controlID, fileName);
                    }
                    else
                    {
                        if (log.IsDebugEnabled)
                        {
                            log.DebugFormat("filename == null");
                        }
                        // Since filename==null this must just be a hidden field with a name that
                        // looks like a file field.  It is just an indication that when this request
                        // ends, the associated uploaded files should be disposed.
                        if (MultiRequestControlID == null)
                        {
                            if (log.IsDebugEnabled)
                            {
                                log.DebugFormat("MultiRequestControlID == null");
                            }
                            RegisterFilesForDisposal(controlID);
                        }
                        outputStream = preloadedEntityBodyStream;
                    }
                }
                else
                {
                    outputStream = preloadedEntityBodyStream;
                }
            }
            if (log.IsDebugEnabled)
            {
                log.Debug("Done parsing.");
            }
            outputStream.WriteByte(10);
            outputStream.Close();
            preloadedEntityBody       = preloadedEntityBodyStream.ToArray();
            preloadedEntityBodyStream = null;
            if (grandTotalBytesRead < origContentLength)
            {
                return(false);
            }
            return(true);
        }
예제 #5
0
        internal void ParseMultipart()
        {
            if (isParsed)
            {
                return;
            }
            isParsed = true;
            try
            {
                bool readEntireRequest = ParseOrThrow();
                if (!readEntireRequest)
                {
                    // Wait 5 seconds to see if the user cancelled the request.
                    System.Threading.Thread.Sleep(5000);
                    // Setting the status to Failed will force a MergeAndSave which
                    // will change the status to Cancelled if the user cancelled
                    // the request.
                    UploadState.Status = UploadStatus.Failed;
                    // If the user did cancel the request, then stop all further
                    // processing of the request so that no exceptions are logged.
                    if (UploadState.Status == UploadStatus.Cancelled)
                    {
                        // Make sure that all the files associated
                        // with a cancelled multi-request upload get disposed.
                        if (MultiRequestControlID != null)
                        {
                            RegisterFilesForDisposal(MultiRequestControlID);
                            UploadStorage.DisposeAtEndOfRequest(uploadedFile);
                        }
                        HttpContext.Current.ApplicationInstance.CompleteRequest();
                        return;
                    }
                    bool isClientConnected = false;
                    try
                    {
                        isClientConnected = OrigWorker.IsClientConnected();
                    }
                    catch (Exception)
                    {
                        // Mono throws an exception if the client is no longer connected.
                    }
                    if (isClientConnected)
                    {
                        throw new HttpException(400, String.Format("Data length ({0}) is shorter than Content-Length ({1}) and client is still connected after {2} secs.",
                                                                   grandTotalBytesRead, origContentLength, Math.Round(UploadState.TimeElapsed.TotalSeconds)));
                    }
                    else
                    {
                        throw new HttpException(400, String.Format("Client disconnected after receiving {0} of {1} bytes in {2} secs -- user probably cancelled upload.",
                                                                   grandTotalBytesRead, origContentLength, Math.Round(UploadState.TimeElapsed.TotalSeconds)));
                    }
                }
            }
            catch (Exception ex)
            {
                if (UploadState != null)
                {
                    // We need to remember the exception here because the
                    // FormsAuthenticationHttpModule in ASP.NET 1.1 will eat any exception we throw and
                    // the UploadHttpModule's RememberError handler will not get called.
                    this.Exception = ex;
                    if (ex is UploadException)
                    {
                        UploadState.Rejection = (UploadException)ex;
                        UploadState.Status    = UploadStatus.Rejected;
                        // Wait 5 seconds to give the client a chance to stop the request.  If the client
                        // stops the request, the user will see the original form instead of an error page.
                        // Regardless, the progress display will show the error so the user knows what went wrong.
                        System.Threading.Thread.Sleep(5000);
                    }
                    else if (UploadState.Status != UploadStatus.Cancelled)
                    {
                        UploadState.Failure = ex;
                        UploadState.Status  = UploadStatus.Failed;
                    }

                    // If an error occurs during the upload of one file during
                    // a multi-request upload, make sure that all the files associated
                    // with that upload get disposed.
                    if (MultiRequestControlID != null)
                    {
                        RegisterFilesForDisposal(MultiRequestControlID);
                        UploadStorage.DisposeAtEndOfRequest(uploadedFile);
                    }
                }

                try
                {
                    byte[] buffer = new byte[4096];
                    while (0 < OrigWorker.ReadEntityBody(buffer, buffer.Length))
                    {
                        ;                         // Ignore the remaining body
                    }
                }
                catch (Exception)
                {
                    // Ignore any errors that occur in the process.
                }

                log.Error("Rethrowing exception", ex);
                throw;
            }
            finally
            {
                if (fileStream != null)
                {
                    fileStream.Close();
                }
                if (preloadedEntityBodyStream != null)
                {
                    preloadedEntityBodyStream.Close();
                }
                if (LogEntityBodyStream != null)
                {
                    LogEntityBodyStream.Close();
                }
                if (LogEntityBodySizesStream != null)
                {
                    LogEntityBodySizesStream.Close();
                }
            }
        }