Ejemplo n.º 1
0
        private async Task Save(Stream source, Stream dest, FileUploadStatus status, Action <FileUploadStatus> statusUpdate)
        {
            try
            {
                status.StartedAt = DateTime.UtcNow;
                if (statusUpdate != null)
                {
                    statusUpdate.Invoke(status);
                }

                byte[] buffer      = new byte[4096];
                int    bytes       = 0;
                long   totalBlocks = 0;

                do
                {
                    bytes = await source.ReadAsync(buffer, 0, buffer.Length);

                    await dest.WriteAsync(buffer, 0, bytes);

                    totalBlocks  += 1;
                    status.Count += bytes;
                    if (totalBlocks % 1024 == 0 && statusUpdate != null)
                    {
                        statusUpdate.Invoke(status);
                    }
                } while (bytes > 0);

                status.Count     = status.Size;
                status.StoppedAt = DateTime.UtcNow;
                _logger.LogInformation("File upload complete: {0} {1}b {2}s {3}b/s", status.Key, status.Count, status.Duration, status.Rate);
            }
            catch (Exception ex)
            {
                status.Error = ex;
                _logger.LogError(0, ex, "File upload failed: {0}", status.Key);
                throw ex;
            }
            finally
            {
                await dest.FlushAsync();

                dest.Dispose();
                statusUpdate.Invoke(status);  //give caller chance to clean up
            }
        }
Ejemplo n.º 2
0
        public async Task Process(
            HttpRequest request,
            Action <FormOptions> optionsAction,
            Func <NameValueCollection, Stream> getDestinationStream,
            Action <FileUploadStatus> statusUpdate,
            Action <NameValueCollection> postProcess = null
            )
        {
            if (!request.ContentType.IsMultipartContentType())
            {
                throw new InvalidOperationException($"Expected a multipart request, but got {request.ContentType}");
            }

            if (optionsAction != null)
            {
                optionsAction.Invoke(_formOptions);
            }

            string boundary = request.ContentType.GetBoundary();

            NameValueCollection metadata = new NameValueCollection();
            MultipartReader     reader   = new MultipartReader(boundary, request.Body);
            MultipartSection    section  = await reader.ReadNextSectionAsync();

            while (section != null)
            {
                bool hasContentDispositionHeader = ContentDispositionHeaderValue
                                                   .TryParse(section.ContentDisposition, out ContentDispositionHeaderValue contentDisposition);

                if (hasContentDispositionHeader)
                {
                    if (contentDisposition.HasFormDataContentDisposition())
                    {
                        //add form values to metadata collection
                        var encoding = section.GetEncoding();
                        using (var streamReader = new StreamReader(
                                   section.Body,
                                   encoding,
                                   detectEncodingFromByteOrderMarks: true,
                                   bufferSize: 1024,
                                   leaveOpen: true))
                        {
                            // The value length limit is enforced by MultipartBodyLengthLimit
                            string value = await streamReader.ReadToEndAsync();

                            if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase))
                            {
                                value = String.Empty;
                            }
                            metadata = value.ParseFormValues();
                        }
                    }

                    if (contentDisposition.HasFileContentDisposition())
                    {
                        metadata.Add("filename", HeaderUtilities.RemoveQuotes(contentDisposition.FileName).Value);
                        if (!metadata["size"].HasValue())
                        {
                            metadata.Add("size", "1000000000");
                        }
                        if (!metadata["upload-key"].HasValue())
                        {
                            metadata.Add("upload-key", Guid.NewGuid().ToString());
                        }
                        Stream           targetStream = getDestinationStream.Invoke(metadata);
                        FileUploadStatus status       = new FileUploadStatus
                        {
                            Metadata = metadata,
                            Key      = metadata["upload-key"],
                            Size     = Int64.Parse(metadata["size"])
                        };

                        await Save(section.Body, targetStream, status, statusUpdate);

                        if (postProcess != null)
                        {
                            postProcess.Invoke(metadata);
                        }
                    }
                }

                // Drains any remaining section body that has not been consumed and
                // reads the headers for the next section.
                section = await reader.ReadNextSectionAsync();
            }
        }