public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            ValueProviderResult value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

            string stringValue = value.FirstValue;

            if (String.IsNullOrEmpty(stringValue))
            {
                bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Empty file identifier");
            }
            else
            {
                try {
                    FileIdentifier id = FileIdentifier.FromString(stringValue);

                    bindingContext.Model  = id;
                    bindingContext.Result = ModelBindingResult.Success(id);
                }
                catch (ArgumentException ex) {
                    bindingContext.ModelState.AddModelError(bindingContext.ModelName, ex.Message);
                }
            }

            return(Task.CompletedTask);
        }
Exemple #2
0
    public void FileStore_GetDataFile_ReadsCorrectFile()
    {
        // Given
        IFileProvider fileProvider = Substitute.For <IFileProvider>();
        IFileStore    store        = new FileStore(new FakeFileStoreFileProviderFactory(fileProvider));

        // When
        store.GetDataFile(FileIdentifier.FromString("aaaa"));

        // Then
        fileProvider.Received(1).GetFileInfo("aaaa.dat");
    }
Exemple #3
0
        public async Task ExecuteAsync(HttpContext context)
        {
            FileIdentifier identifier = FileIdentifier.FromString(context.GetRouteValue("fileIdentifier").ToString());

            this._logger.LogInformation(LogEvents.NewUpload, "New upload of file with id {0}", identifier);

            // We have already the ID, so we can set some progress
            UploadProgress progress = new UploadProgress {
                Current   = 0,
                StartTime = DateTime.UtcNow,
                Total     = context.Request.ContentLength ?? -1
            };

            this._uploadProgressManager.SetProgress(identifier, progress);

            // Initialize reading request
            MediaTypeHeaderValue contentType = GetContentType(context);
            string boundary = GetBoundary(contentType);

            MultipartReader reader = new MultipartReader(boundary, context.Request.Body);

            reader.BodyLengthLimit = (long?)this._fileStoreOptions.Value?.MaximumFileSize.Megabytes().Bytes;

            // Delegate actual request parsing
            // ... after the request "completes" we re-execute to send the final response to the browser
            try {
                using (context.RequestAborted.Register(context.Abort)) {
                    await this._uploadManager.StoreAsync(identifier, reader, context.RequestAborted);
                }

                PrepForReExecute(context, new UploadErrorsModel());
            } catch (Exception ex) {
                UploadErrorsModel errors = new UploadErrorsModel {
                    Errors = new[] {
                        ex.Message
                    }
                };

                this._logger.LogError(LogEvents.UploadFailed, "Detected failed upload - passing error to child handler: {0}", ex);

                PrepForReExecute(context, errors);
            }

            await ReExecuteAsync(context);
        }
Exemple #4
0
        public async Task <IList <UploadedFile> > GetFiles()
        {
            var fileIds = from fileInfo in this._fileStore.GetFiles()
                          let plainName = Path.GetFileNameWithoutExtension(fileInfo.Name)
                                          where plainName != null && FileIdentifier.IsValid(plainName)
                                          select FileIdentifier.FromString(plainName);

            List <UploadedFile> uploadedFiles = new List <UploadedFile>();

            foreach (FileIdentifier id in fileIds.Distinct())
            {
                UploadedFile file = await this.GetFileInternal(id).ConfigureAwait(false);

                if (file != null)
                {
                    uploadedFiles.Add(file);
                }
            }

            return(uploadedFiles);
        }
Exemple #5
0
        public async Task ExpiredFileRemovalJob_RemovesObsoleteFiles()
        {
            // Given
            List <UploadedFile> files = new List <UploadedFile>();

            var job = GetTestObject(files);

            files.Add(new UploadedFile(FileIdentifier.FromString("a"), new FakeFile(), new StoredMetadata {
                Expiration = DateTime.UtcNow.AddDays(1)
            }));
            files.Add(new UploadedFile(FileIdentifier.FromString("b"), new FakeFile(), new StoredMetadata {
                Expiration = DateTime.UtcNow.AddDays(-1)
            }));
            files.Add(new UploadedFile(FileIdentifier.FromString("c"), new FakeFile(), new StoredMetadata {
                Expiration = DateTime.UtcNow.AddMilliseconds(-1)
            }));

            // When
            await job.Execute(new JobCancellationToken(false));

            // Then
            Assert.That(files, ContainsFileIdentifier(FileIdentifier.FromString("a")));
            Assert.That(files, Has.Count.EqualTo(1));
        }
Exemple #6
0
        private async Task ProcessFormSectionAsync(FileIdentifier id, MultipartSection section, StoredMetadataFactory metadataFactory, ContentDispositionHeaderValue contentDisposition)
        {
            string cleanName = HeaderUtilities.RemoveQuotes(contentDisposition.Name).Value;

            async Task <string> ReadString()
            {
                using (StreamReader sr = new StreamReader(section.Body)) {
                    return(await sr.ReadToEndAsync());
                }
            }

            switch (cleanName)
            {
            case nameof(UploadModel.IsReservation):
                string isReservationRaw = await ReadString();

                metadataFactory.SetIsReservation(Boolean.Parse(isReservationRaw));
                break;

            case nameof(UploadModel.Expiration):
                string dateTimeRaw = await ReadString();

                // MVC we send date as roundtrip
                metadataFactory.SetExpiration(DateTime.ParseExact(dateTimeRaw, "o", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind));
                return;

            case nameof(UploadModel.FileIdentifier):
                string rawId = await ReadString();

                FileIdentifier formId = FileIdentifier.FromString(rawId);

                if (formId != id)
                {
                    throw new InvalidOperationException($"ID mismatch: '{formId}' (received) != '{id}' (expected)");
                }
                return;

            case nameof(UploadModel.Sender) + "." + nameof(ContactInformation.Name):
                string name = await ReadString();

                metadataFactory.SetSenderName(name);
                return;

            case nameof(UploadModel.Sender) + "." + nameof(ContactInformation.EmailAddress):
                string emailAddress = await ReadString();

                metadataFactory.SetSenderEmail(emailAddress);
                return;

            // Browsers don't actually send the file size in the request, but we can derive it from the Content-Length.
            // However, that is not very accurate and if we use some javascript to send a more accurate file size, we use that.
            case nameof(UploadModel.SuggestedFileSize):
                long size;
                if (Int64.TryParse(await ReadString(), out size) && size > 0)
                {
                    this.GetProgressObject(id).Total = size;
                }
                return;

            default:
                this._logger.LogWarning(LogEvents.UploadIncomplete, "{0}: Unknown form field '{1}'", id, contentDisposition.Name);
                break;
            }
        }
Exemple #7
0
    private async Task ProcessFormSectionAsync(UploadContext uploadContext, MultipartSection section, ContentDispositionHeaderValue contentDisposition)
    {
        string cleanName = HeaderUtilities.RemoveQuotes(contentDisposition.Name).Value;

        StoredMetadataFactory metadataFactory = uploadContext.MetadataFactory;
        UploadPassword        passwordSetting = uploadContext.PasswordSetting;

        switch (cleanName)
        {
        case nameof(UploadModel.IsReservation):
            string isReservationRaw = await ReadString();

            metadataFactory.SetIsReservation(Boolean.Parse(isReservationRaw));
            break;

        case nameof(UploadModel.Expiration):
            string dateTimeRaw = await ReadString();

            // MVC we send date as roundtrip
            metadataFactory.SetExpiration(DateTime.ParseExact(dateTimeRaw, "o", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind));
            return;

        case nameof(UploadModel.FileIdentifier):
            string rawId = await ReadString();

            FileIdentifier formId = FileIdentifier.FromString(rawId);

            if (formId != uploadContext.Identifier)
            {
                throw new InvalidOperationException($"ID mismatch: '{formId}' (received) != '{uploadContext.Identifier}' (expected)");
            }
            return;

        case nameof(UploadModel.Password):
            string password = await ReadString();

            metadataFactory.SetPassword(password);
            passwordSetting.Password = password;

            EnsureFileNotUploaded();
            return;

        case nameof(UploadModel.EnablePasswordProtection):
            bool passwordSettingWasSet = passwordSetting.IsSet;

            string enablePasswordProtectionRaw = await ReadString();

            bool enablePasswordProtection = String.Equals(Boolean.TrueString, enablePasswordProtectionRaw, StringComparison.OrdinalIgnoreCase);
            metadataFactory.SetEnablePasswordProtection(enablePasswordProtection);
            passwordSetting.SetEnabled(enablePasswordProtection);

            if (!passwordSettingWasSet)
            {
                EnsureFileNotUploaded();
            }
            return;

        case nameof(UploadModel.Sender) + "." + nameof(ContactInformation.Name):
            string name = await ReadString();

            metadataFactory.SetSenderName(name);
            return;

        case nameof(UploadModel.Sender) + "." + nameof(ContactInformation.EmailAddress):
            string emailAddress = await ReadString();

            metadataFactory.SetSenderEmail(emailAddress);
            return;

        // Browsers don't actually send the file size in the request, but we can derive it from the Content-Length.
        // However, that is not very accurate and if we use some javascript to send a more accurate file size, we use that.
        case nameof(UploadModel.SuggestedFileSize):
            if (Int64.TryParse(await ReadString(), out var size) && size > 0)
            {
                this.GetProgressObject(uploadContext.Identifier).Total = size;
            }
            return;

        default:
            this._logger.LogWarning(LogEvents.UploadIncomplete, "{Identifier}: Unknown form field '{Field}'", uploadContext.Identifier, contentDisposition.Name);
            break;
        }

        async Task <string> ReadString()
        {
            using (StreamReader sr = new StreamReader(section.Body)) {
                return(await sr.ReadToEndAsync());
            }
        }

        void EnsureFileNotUploaded()
        {
            bool needToValidate = !String.IsNullOrEmpty(passwordSetting.Password) && passwordSetting.Enable == true;

            if (needToValidate && uploadContext.HasUploadedFile)
            {
                this._logger.LogError(LogEvents.UploadPasswordAfterFileUpload, "{Identifier}: The upload password is set after the file is uploaded. The file is not encrypted. Terminating upload.", uploadContext.Identifier);

                throw new UploadCryptoArgumentOrderException("File uploaded before password has been set");
            }
        }
    }