public async Task <MultipartRequestParsedObjects <TModel> > ParseMultipartRequest <TModel>(HttpRequest request) where TModel : new() { var boundary = GetBoundary(MediaTypeHeaderValue.Parse(request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, request.Body); var section = await reader.ReadNextSectionAsync(); if (section == null) { return(null); } var apiModelTypeProperties = typeof(TModel).GetProperties(); var response = new MultipartRequestParsedObjects <TModel>(); do { var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out ContentDispositionHeaderValue contentDisposition); if (hasContentDispositionHeader) { if (contentDisposition.IsFileDisposition()) { response.FileUploadRequest = new FileUploadRequest { Bytes = section.Body.ToByteArray(), FileName = section.AsFileSection().FileName }; } else if (contentDisposition.IsFormDisposition()) { var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name).Value; var encoding = GetEncoding(section); using (var streamReader = new StreamReader( section.Body, encoding, true, 1024, true)) { // The value length limit is enforced by MultipartBodyLengthLimit var stringedValue = await streamReader.ReadToEndAsync(); if (!(string.IsNullOrEmpty(stringedValue) || string.IsNullOrWhiteSpace(stringedValue))) { var prop = apiModelTypeProperties.FirstOrDefault(p => string.Equals(p.Name, key, StringComparison.OrdinalIgnoreCase)); if (prop != null) { var converter = _converterManager.Get(prop.PropertyType); if (converter.CanConvertFrom(typeof(string))) { var value = converter.TypeConverter.ConvertFrom(stringedValue); prop.SetValue(response.Model, value); } } } } } } section = await reader.ReadNextSectionAsync(); } while (section != null); // Drains any remaining section body that has not been consumed and // reads the headers for the next section. return(response); }
public async Task <IActionResult> Post() { if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) { return(BadRequest($"Expected a multipart request, but got {Request.ContentType}")); } // Used to accumulate all the form url encoded key value pairs in the // request. var formAccumulator = new KeyValueAccumulator(); string targetFilePath = null; var boundary = MultipartRequestHelper.GetBoundary( MediaTypeHeaderValue.Parse(Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, HttpContext.Request.Body); var section = await reader.ReadNextSectionAsync(); while (section != null) { ContentDispositionHeaderValue contentDisposition; var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition); if (hasContentDispositionHeader) { if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { targetFilePath = Path.GetTempFileName(); using (var targetStream = System.IO.File.Create(targetFilePath)) { await section.Body.CopyToAsync(targetStream); Console.WriteLine($"Copied the uploaded file '{targetFilePath}'"); } } else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { // Content-Disposition: form-data; name="key" // // value // Do not limit the key name length here because the // multipart headers length limit is already in effect. var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); var encoding = GetEncoding(section); using (var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { // The value length limit is enforced by MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = String.Empty; } formAccumulator.Append(key.ToString(), value); if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit) { throw new InvalidDataException($"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded."); } } } } // Drains any remaining section body that has not been consumed and // reads the headers for the next section. section = await reader.ReadNextSectionAsync(); } IDictionary <string, StringValues> parameters = formAccumulator.GetResults(); if (parameters.ContainsKey(PARAM_ID_CONCEPT_LIE)) { Debugger.Log((int)LogLevel.Information, "Info", parameters[PARAM_ID_CONCEPT_LIE].ToString()); } else { Debugger.Log((int)LogLevel.Error, "Info", $"La requête ne contenait pas le paramètre {PARAM_ID_CONCEPT_LIE}"); } return(Ok(new { FilePath = targetFilePath })); }
public static async Task <string?> GetDigestTokenForCredential(NetworkCredential credential, HttpRequestMessage request, DigestResponse digestResponse) { StringBuilder sb = StringBuilderCache.Acquire(); // It is mandatory for servers to implement sha-256 per RFC 7616 // Keep MD5 for backward compatibility. string?algorithm; bool isAlgorithmSpecified = digestResponse.Parameters.TryGetValue(Algorithm, out algorithm); if (isAlgorithmSpecified) { if (!algorithm !.Equals(Sha256, StringComparison.OrdinalIgnoreCase) && !algorithm.Equals(Md5, StringComparison.OrdinalIgnoreCase) && !algorithm.Equals(Sha256Sess, StringComparison.OrdinalIgnoreCase) && !algorithm.Equals(MD5Sess, StringComparison.OrdinalIgnoreCase)) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(digestResponse, $"Algorithm not supported: {algorithm}"); } return(null); } } else { algorithm = Md5; } // Check if nonce is there in challenge string?nonce; if (!digestResponse.Parameters.TryGetValue(Nonce, out nonce)) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(digestResponse, "Nonce missing"); } return(null); } // opaque token may or may not exist string?opaque; digestResponse.Parameters.TryGetValue(Opaque, out opaque); string?realm; if (!digestResponse.Parameters.TryGetValue(Realm, out realm)) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(digestResponse, "Realm missing"); } return(null); } // Add username string?userhash; if (digestResponse.Parameters.TryGetValue(UserHash, out userhash) && userhash == "true") { sb.AppendKeyValue(Username, ComputeHash(credential.UserName + ":" + realm, algorithm)); sb.AppendKeyValue(UserHash, userhash, includeQuotes: false); } else { if (HeaderUtilities.ContainsNonAscii(credential.UserName)) { string usernameStar = HeaderUtilities.Encode5987(credential.UserName); sb.AppendKeyValue(UsernameStar, usernameStar, includeQuotes: false); } else { sb.AppendKeyValue(Username, credential.UserName); } } // Add realm sb.AppendKeyValue(Realm, realm); // Add nonce sb.AppendKeyValue(Nonce, nonce); Debug.Assert(request.RequestUri != null); // Add uri sb.AppendKeyValue(Uri, request.RequestUri.PathAndQuery); // Set qop, default is auth string qop = Auth; bool isQopSpecified = digestResponse.Parameters.ContainsKey(Qop); if (isQopSpecified) { // Check if auth-int present in qop string int index1 = digestResponse.Parameters[Qop].IndexOf(AuthInt, StringComparison.Ordinal); if (index1 != -1) { // Get index of auth if present in qop string int index2 = digestResponse.Parameters[Qop].IndexOf(Auth, StringComparison.Ordinal); // If index2 < index1, auth option is available // If index2 == index1, check if auth option available later in string after auth-int. if (index2 == index1) { index2 = digestResponse.Parameters[Qop].IndexOf(Auth, index1 + AuthInt.Length, StringComparison.Ordinal); if (index2 == -1) { qop = AuthInt; } } } } // Set cnonce string cnonce = GetRandomAlphaNumericString(); // Calculate response string a1 = credential.UserName + ":" + realm + ":" + credential.Password; if (algorithm.EndsWith("sess", StringComparison.OrdinalIgnoreCase)) { a1 = ComputeHash(a1, algorithm) + ":" + nonce + ":" + cnonce; } string a2 = request.Method.Method + ":" + request.RequestUri.PathAndQuery; if (qop == AuthInt) { string content = request.Content == null ? string.Empty : await request.Content.ReadAsStringAsync().ConfigureAwait(false); a2 = a2 + ":" + ComputeHash(content, algorithm); } string response; if (isQopSpecified) { response = ComputeHash(ComputeHash(a1, algorithm) + ":" + nonce + ":" + DigestResponse.NonceCount + ":" + cnonce + ":" + qop + ":" + ComputeHash(a2, algorithm), algorithm); } else { response = ComputeHash(ComputeHash(a1, algorithm) + ":" + nonce + ":" + ComputeHash(a2, algorithm), algorithm); } // Add response sb.AppendKeyValue(Response, response, includeComma: opaque != null || isAlgorithmSpecified || isQopSpecified); // Add opaque if (opaque != null) { sb.AppendKeyValue(Opaque, opaque, includeComma: isAlgorithmSpecified || isQopSpecified); } if (isAlgorithmSpecified) { // Add algorithm sb.AppendKeyValue(Algorithm, algorithm, includeQuotes: false, includeComma: isQopSpecified); } if (isQopSpecified) { // Add qop sb.AppendKeyValue(Qop, qop, includeQuotes: false); // Add nc sb.AppendKeyValue(NC, DigestResponse.NonceCount, includeQuotes: false); // Add cnonce sb.AppendKeyValue(CNonce, cnonce, includeComma: false); } return(StringBuilderCache.GetStringAndRelease(sb)); }
public virtual bool AllowCacheStorage(ResponseCachingContext context) { // Check request no-store return(!HeaderUtilities.ContainsCacheDirective(context.HttpContext.Request.Headers.CacheControl, CacheControlHeaderValue.NoStoreString)); }
public async Task PostImportAsync() { using (ContextPool.AllocateOperationContext(out DocumentsOperationContext context)) { if (HttpContext.Request.HasFormContentType == false) { HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest; // Bad request using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream())) { context.Write(writer, new DynamicJsonValue { ["Type"] = "Error", ["Error"] = "This endpoint requires form content type" }); return; } } var operationId = GetLongQueryString("operationId", false) ?? Database.Operations.GetNextOperationId(); var token = CreateOperationToken(); var result = new SmugglerResult(); await Database.Operations.AddOperation(Database, "Import to: " + Database.Name, Operations.OperationType.DatabaseImport, onProgress => { return(Task.Run(async() => { try { var boundary = MultipartRequestHelper.GetBoundary( MediaTypeHeaderValue.Parse(HttpContext.Request.ContentType), MultipartRequestHelper.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, HttpContext.Request.Body); DatabaseSmugglerOptionsServerSide options = null; while (true) { var section = await reader.ReadNextSectionAsync().ConfigureAwait(false); if (section == null) { break; } if (ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out ContentDispositionHeaderValue contentDisposition) == false) { continue; } if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); if (key != "importOptions") { continue; } BlittableJsonReaderObject blittableJson; if (section.Headers.ContainsKey("Content-Encoding") && section.Headers["Content-Encoding"] == "gzip") { using (var gzipStream = new GZipStream(section.Body, CompressionMode.Decompress)) { blittableJson = await context.ReadForMemoryAsync(gzipStream, "importOptions"); } } else { blittableJson = await context.ReadForMemoryAsync(section.Body, "importOptions"); } options = JsonDeserializationServer.DatabaseSmugglerOptions(blittableJson); continue; } if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition) == false) { continue; } var stream = new GZipStream(section.Body, CompressionMode.Decompress); DoImportInternal(context, stream, options, result, onProgress, token); } } catch (Exception e) { result.AddError($"Error occurred during import. Exception: {e.Message}"); onProgress.Invoke(result.Progress); throw; } return (IOperationResult)result; })); }, operationId, token).ConfigureAwait(false); WriteImportResult(context, result, ResponseBodyStream()); }
/// <summary> /// Finalize cache headers. /// </summary> /// <param name="context"></param> /// <returns><c>true</c> if a vary by entry needs to be stored in the cache; otherwise <c>false</c>.</returns> private bool OnFinalizeCacheHeaders(ResponseCachingContext context) { if (_policyProvider.IsResponseCacheable(context)) { var storeVaryByEntry = false; context.ShouldCacheResponse = true; // Create the cache entry now var response = context.HttpContext.Response; var headers = response.Headers; var varyHeaders = new StringValues(headers.GetCommaSeparatedValues(HeaderNames.Vary)); var varyQueryKeys = new StringValues(context.HttpContext.Features.Get <IResponseCachingFeature>()?.VaryByQueryKeys); context.CachedResponseValidFor = context.ResponseSharedMaxAge ?? context.ResponseMaxAge ?? (context.ResponseExpires - context.ResponseTime !.Value) ?? DefaultExpirationTimeSpan; // Generate a base key if none exist if (string.IsNullOrEmpty(context.BaseKey)) { context.BaseKey = _keyProvider.CreateBaseKey(context); } // Check if any vary rules exist if (!StringValues.IsNullOrEmpty(varyHeaders) || !StringValues.IsNullOrEmpty(varyQueryKeys)) { // Normalize order and casing of vary by rules var normalizedVaryHeaders = GetOrderCasingNormalizedStringValues(varyHeaders); var normalizedVaryQueryKeys = GetOrderCasingNormalizedStringValues(varyQueryKeys); // Update vary rules if they are different if (context.CachedVaryByRules == null || !StringValues.Equals(context.CachedVaryByRules.QueryKeys, normalizedVaryQueryKeys) || !StringValues.Equals(context.CachedVaryByRules.Headers, normalizedVaryHeaders)) { context.CachedVaryByRules = new CachedVaryByRules { VaryByKeyPrefix = FastGuid.NewGuid().IdString, Headers = normalizedVaryHeaders, QueryKeys = normalizedVaryQueryKeys }; } // Always overwrite the CachedVaryByRules to update the expiry information _logger.VaryByRulesUpdated(normalizedVaryHeaders.ToString(), normalizedVaryQueryKeys.ToString()); storeVaryByEntry = true; context.StorageVaryKey = _keyProvider.CreateStorageVaryByKey(context); } // Ensure date header is set if (!context.ResponseDate.HasValue) { context.ResponseDate = context.ResponseTime !.Value; // Setting the date on the raw response headers. headers.Date = HeaderUtilities.FormatDate(context.ResponseDate.Value); } // Store the response on the state context.CachedResponse = new CachedResponse { Created = context.ResponseDate.Value, StatusCode = response.StatusCode, Headers = new HeaderDictionary() }; foreach (var header in headers) { if (!string.Equals(header.Key, HeaderNames.Age, StringComparison.OrdinalIgnoreCase)) { context.CachedResponse.Headers[header.Key] = header.Value; } } return(storeVaryByEntry); } context.ResponseCachingStream.DisableBuffering(); return(false); }
private static string FormatInt64(long input) { return(HeaderUtilities.FormatNonNegativeInt64(input)); }
/// <summary> /// Initializes a new instance of <see cref="StringWithQualityHeaderValue"/>. /// </summary> /// <param name="value">The <see cref="StringSegment"/> used to initialize the new instance.</param> public StringWithQualityHeaderValue(StringSegment value) { HeaderUtilities.CheckValidToken(value, nameof(value)); _value = value; }
public override async Task <InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context) { if (context is null) { throw new ArgumentNullException(nameof(context)); } try { var request = context.HttpContext.Request; if (request.Body.CanSeek) { request.Body.Seek(0, SeekOrigin.Begin); } object model = context.ModelType.GetConstructor(Type.EmptyTypes).Invoke(null); string boundary = MultipartRequestHelper.GetBoundary(MediaTypeHeaderValue.Parse(request.ContentType), DefaultFormOptions.MultipartBoundaryLengthLimit); MultipartReader reader = new MultipartReader(boundary, request.Body); bool isSuccess = false; bool isReadable = true; do { MultipartSection section = await reader.ReadNextSectionAsync(); isReadable = section != null; if (isReadable && ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out ContentDispositionHeaderValue contentDisposition)) { if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { SetProperty(model, FileNamePropertyName, HeaderUtilities.RemoveQuotes(contentDisposition.FileName).ToString()); SetProperty(model, StreamPropertyName, section.Body, false); isSuccess = true; isReadable = false; } else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { string key = HeaderUtilities.RemoveQuotes(contentDisposition.Name).ToString(); Encoding encoding = GetEncoding(section); string value = null; using (StreamReader streamReader = new StreamReader(section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { value = await streamReader.ReadToEndAsync(); if (string.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = string.Empty; } } SetProperty(model, key, value); isSuccess = true; } } }while (isReadable); if (!isSuccess && !context.TreatEmptyInputAsDefaultValue) { return(InputFormatterResult.NoValue()); } return(InputFormatterResult.Success(model)); } catch { return(InputFormatterResult.Failure()); } }
public async Task <IActionResult> UploadFiles() { if (!IsMultipartContentType(Request.ContentType)) { return(new UnsupportedMediaTypeResult()); } Log.Information($"POSTing files..."); var boundary = HeaderUtilities.RemoveQuotes(MediaTypeHeaderValue.Parse(Request.ContentType).Boundary); var reader = new MultipartReader(boundary.Value, Request.Body); MultipartSection section; IList <Image> imagesRequest = null; var result = new List <FileImages>(); while ((section = await reader.ReadNextSectionAsync()) != null) { var contentDisposition = section.GetContentDispositionHeader(); if (contentDisposition.IsFormDisposition() && imagesRequest is null) { var formSection = section.AsFormDataSection(); string formValue = await formSection.GetValueAsync(); imagesRequest = JsonConvert.DeserializeObject <IList <Image> >(formValue, new JsonSerializerSettings { Error = delegate(object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args) { args.ErrorContext.Handled = true; } }); } if (contentDisposition.IsFileDisposition()) { var fileSection = section.AsFileSection(); if (string.IsNullOrEmpty(fileSection.FileName)) { Log.Information($"Empty file section"); continue; } Log.Information($"Saving file {fileSection.FileName}"); var blobId = await _blobStorage.AddFileAsync(Path.GetFileName(fileSection.FileName), fileSection.FileStream, fileSection.Section.ContentType, _bucket); if (imagesRequest is null || !imagesRequest.Any()) { imagesRequest = new Image[] { new Image { Width = int.Parse(_configuration["DefaultImage:Width"]), Format = _configuration["DefaultImage:Format"], Height = int.Parse(_configuration["DefaultImage:Height"]) } }; } foreach (var requestedImage in imagesRequest) { requestedImage.Id = NewId.Next().ToGuid(); if (requestedImage.Width <= 0) { requestedImage.Width = int.Parse(_configuration["DefaultImage:Width"]); } if (requestedImage.Height <= 0) { requestedImage.Height = int.Parse(_configuration["DefaultImage:Height"]); } } var fileImages = new FileImages { Id = blobId, Images = imagesRequest, Bucket = _bucket }; //await _imagesMetaCollection.InsertOneAsync(fileImages); foreach (var requestedImage in imagesRequest) { await _bus.Publish <GenerateImage>(new { Id = requestedImage.Id, Bucket = _bucket, BlobId = blobId, Image = requestedImage, UserId = new Guid(_bucket) }); } result.Add(fileImages); } } return(Ok(result)); }
static bool AllowCacheStorage(HttpContext context) { // cache-control: no-store ? return(!HeaderUtilities.ContainsCacheDirective(context.Request.Headers[HeaderNames.CacheControl], CacheControlHeaderValue.NoStoreString)); }
public async Task <IActionResult> UploadDatabase() { var returner = new BaseDeveloperResponse(); if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) { ModelState.AddModelError("File", $"The request couldn't be processed (Error 1)."); // Log error return(BadRequest(ModelState)); } // Accumulate the form data key-value pairs in the request (formAccumulator). var formAccumulator = new KeyValueAccumulator(); var trustedFileNameForDisplay = string.Empty; var untrustedFileNameForStorage = string.Empty; var streamedFileContent = new byte[0]; var boundary = MultipartRequestHelper.GetBoundary( MediaTypeHeaderValue.Parse(Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, HttpContext.Request.Body); var section = await reader.ReadNextSectionAsync(); while (section != null) { var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse( section.ContentDisposition, out var contentDisposition); if (hasContentDispositionHeader) { if (MultipartRequestHelper .HasFileContentDisposition(contentDisposition)) { untrustedFileNameForStorage = contentDisposition.FileName.Value; // Don't trust the file name sent by the client. To display // the file name, HTML-encode the value. trustedFileNameForDisplay = WebUtility.HtmlEncode( contentDisposition.FileName.Value); streamedFileContent = await FileHelpers.ProcessStreamedFile(section, contentDisposition, ModelState, _permittedExtensions, _fileSizeLimit); if (!ModelState.IsValid) { return(BadRequest(ModelState)); } } else if (MultipartRequestHelper .HasFormDataContentDisposition(contentDisposition)) { // Don't limit the key name length because the // multipart headers length limit is already in effect. var key = HeaderUtilities .RemoveQuotes(contentDisposition.Name).Value; var encoding = GetEncoding(section); if (encoding == null) { ModelState.AddModelError("File", $"The request couldn't be processed (Error 2)."); // Log error return(BadRequest(ModelState)); } using (var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { // The value length limit is enforced by // MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (string.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = string.Empty; } formAccumulator.Append(key, value); if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit) { // Form key count limit of // _defaultFormOptions.ValueCountLimit // is exceeded. ModelState.AddModelError("File", $"The request couldn't be processed (Error 3)."); // Log error return(BadRequest(ModelState)); } } } } // Drain any remaining section body that hasn't been consumed and // read the headers for the next section. section = await reader.ReadNextSectionAsync(); } // Bind form data to the model var formData = new MultiPartTestRequestMultiple(); var formValueProvider = new FormValueProvider( BindingSource.Form, new FormCollection(formAccumulator.GetResults()), CultureInfo.CurrentCulture); var bindingSuccessful = await TryUpdateModelAsync(formData, prefix : "", valueProvider : formValueProvider); if (!bindingSuccessful) { ModelState.AddModelError("File", "The request couldn't be processed (Error 5)."); // Log error return(BadRequest(ModelState)); } // **WARNING!** // In the following example, the file is saved without // scanning the file's contents. In most production // scenarios, an anti-virus/anti-malware scanner API // is used on the file before making the file available // for download or for use by other systems. // For more information, see the topic that accompanies // this sample app. var check = formData.FormFiles.ToList().Count; return(Ok(returner.Stop())); }
public static async Task <string> ExtractJsonString(this HttpRequest request, string jsonPartName) { if (!IsMultipartContentType(request.ContentType)) { throw new Exception($"Expected a multipart request, but got {request.ContentType}"); } var boundary = GetBoundary( MediaTypeHeaderValue.Parse(request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, request.Body); var section = await reader.ReadNextSectionAsync(); while (section != null) { ContentDispositionHeaderValue contentDisposition; var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition); if (hasContentDispositionHeader) { if (HasFileContentDisposition(contentDisposition)) { // skip } else if (HasFormDataContentDisposition(contentDisposition)) { // Content-Disposition: form-data; name="key" // // value // Do not limit the key name length here because the // multipart headers length limit is already in effect. var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); if (key.Value == jsonPartName) { var encoding = GetEncoding(section) ?? System.Text.Encoding.UTF8; using (var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { // The value length limit is enforced by MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = String.Empty; } return(value); } } else { // skip } } } // Drains any remaining section body that has not been consumed and // reads the headers for the next section. section = await reader.ReadNextSectionAsync(); } // did not find the part return(string.Empty); }
private static void CheckNameValueFormat(StringSegment name, StringSegment value) { HeaderUtilities.CheckValidToken(name, nameof(name)); CheckValueFormat(value); }
public static async Task <FormValueProvider> StreamFile(this HttpRequest request, Stream targetStream, int bufferSize) { if (!MultipartRequestHelper.IsMultipartContentType(request.ContentType)) { throw new Exception($"Expected a multipart request, but got {request.ContentType}"); } // Used to accumulate all the form url encoded key value pairs in the // request. KeyValueAccumulator formAccumulator = new KeyValueAccumulator(); // string targetFilePath = null; string boundary = MultipartRequestHelper.GetBoundary( MediaTypeHeaderValue.Parse(request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit); 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 (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { await section.Body.CopyToAsync(targetStream); } else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { // Content-Disposition: form-data; name="key" // // value // Do not limit the key name length here because the // multipart headers length limit is already in effect. Microsoft.Extensions.Primitives.StringSegment key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); Encoding encoding = GetEncoding(section); using (StreamReader streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: bufferSize, 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; } formAccumulator.Append(key.Value, value); // For .NET Core <2.0 remove ".Value" from key if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit) { throw new InvalidDataException($"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded."); } } } } // Drains any remaining section body that has not been consumed and // reads the headers for the next section. section = await reader.ReadNextSectionAsync(); } // Bind form data to a model FormValueProvider formValueProvider = new FormValueProvider( BindingSource.Form, new FormCollection(formAccumulator.GetResults()), CultureInfo.CurrentCulture); return(formValueProvider); }
public static async Task <string> GetDigestTokenForCredential(NetworkCredential credential, HttpRequestMessage request, DigestResponse digestResponse) { StringBuilder sb = StringBuilderCache.Acquire(); // It is mandatory for servers to implement sha-256 per RFC 7616 // Keep MD5 for backward compatibility. string algorithm; if (digestResponse.Parameters.TryGetValue(Algorithm, out algorithm)) { if (algorithm != Sha256 && algorithm != Md5 && algorithm != Sha256Sess && algorithm != MD5Sess) { return(null); } } else { algorithm = Md5; } // Check if nonce is there in challenge string nonce; if (!digestResponse.Parameters.TryGetValue(Nonce, out nonce)) { return(null); } // opaque token may or may not exist string opaque; digestResponse.Parameters.TryGetValue(Opaque, out opaque); string realm; if (!digestResponse.Parameters.TryGetValue(Realm, out realm)) { return(null); } // Add username string userhash; if (digestResponse.Parameters.TryGetValue(UserHash, out userhash) && userhash == "true") { sb.AppendKeyValue(Username, ComputeHash(credential.UserName + ":" + realm, algorithm)); sb.AppendKeyValue(UserHash, userhash, includeQuotes: false); } else { string usernameStar; if (HeaderUtilities.IsInputEncoded5987(credential.UserName, out usernameStar)) { sb.AppendKeyValue(UsernameStar, usernameStar, includeQuotes: false); } else { sb.AppendKeyValue(Username, credential.UserName); } } // Add realm if (realm != string.Empty) { sb.AppendKeyValue(Realm, realm); } // Add nonce sb.AppendKeyValue(Nonce, nonce); // Add uri sb.AppendKeyValue(Uri, request.RequestUri.PathAndQuery); // Set qop, default is auth string qop = Auth; if (digestResponse.Parameters.ContainsKey(Qop)) { // Check if auth-int present in qop string int index1 = digestResponse.Parameters[Qop].IndexOf(AuthInt); if (index1 != -1) { // Get index of auth if present in qop string int index2 = digestResponse.Parameters[Qop].IndexOf(Auth); // If index2 < index1, auth option is available // If index2 == index1, check if auth option available later in string after auth-int. if (index2 == index1) { index2 = digestResponse.Parameters[Qop].IndexOf(Auth, index1 + AuthInt.Length); if (index2 == -1) { qop = AuthInt; } } } } // Set cnonce string cnonce = GetRandomAlphaNumericString(); // Calculate response string a1 = credential.UserName + ":" + realm + ":" + credential.Password; if (algorithm.IndexOf("sess") != -1) { a1 = ComputeHash(a1, algorithm) + ":" + nonce + ":" + cnonce; } string a2 = request.Method.Method + ":" + request.RequestUri.PathAndQuery; if (qop == AuthInt) { string content = request.Content == null ? string.Empty : await request.Content.ReadAsStringAsync().ConfigureAwait(false); a2 = a2 + ":" + ComputeHash(content, algorithm); } string response = ComputeHash(ComputeHash(a1, algorithm) + ":" + nonce + ":" + DigestResponse.NonceCount + ":" + cnonce + ":" + qop + ":" + ComputeHash(a2, algorithm), algorithm); // Add response sb.AppendKeyValue(Response, response); // Add algorithm sb.AppendKeyValue(Algorithm, algorithm, includeQuotes: false); // Add opaque if (opaque != null) { sb.AppendKeyValue(Opaque, opaque); } // Add qop sb.AppendKeyValue(Qop, qop, includeQuotes: false); // Add nc sb.AppendKeyValue(NC, DigestResponse.NonceCount, includeQuotes: false); // Add cnonce sb.AppendKeyValue(CNonce, cnonce, includeComma: false); return(StringBuilderCache.GetStringAndRelease(sb)); }
internal async Task <bool> TryServeCachedResponseAsync(ResponseCachingContext context, IResponseCacheEntry?cacheEntry) { if (!(cacheEntry is CachedResponse cachedResponse)) { return(false); } context.CachedResponse = cachedResponse; context.CachedResponseHeaders = cachedResponse.Headers; context.ResponseTime = _options.SystemClock.UtcNow; var cachedEntryAge = context.ResponseTime.Value - context.CachedResponse.Created; context.CachedEntryAge = cachedEntryAge > TimeSpan.Zero ? cachedEntryAge : TimeSpan.Zero; if (_policyProvider.IsCachedEntryFresh(context)) { // Check conditional request rules if (ContentIsNotModified(context)) { _logger.NotModifiedServed(); context.HttpContext.Response.StatusCode = StatusCodes.Status304NotModified; if (context.CachedResponseHeaders != null) { foreach (var key in HeadersToIncludeIn304) { if (context.CachedResponseHeaders.TryGetValue(key, out var values)) { context.HttpContext.Response.Headers[key] = values; } } } } else { var response = context.HttpContext.Response; // Copy the cached status code and response headers response.StatusCode = context.CachedResponse.StatusCode; foreach (var header in context.CachedResponse.Headers) { response.Headers[header.Key] = header.Value; } // Note: int64 division truncates result and errors may be up to 1 second. This reduction in // accuracy of age calculation is considered appropriate since it is small compared to clock // skews and the "Age" header is an estimate of the real age of cached content. response.Headers.Age = HeaderUtilities.FormatNonNegativeInt64(context.CachedEntryAge.Value.Ticks / TimeSpan.TicksPerSecond); // Copy the cached response body var body = context.CachedResponse.Body; if (body.Length > 0) { try { await body.CopyToAsync(response.BodyWriter, context.HttpContext.RequestAborted); } catch (OperationCanceledException) { context.HttpContext.Abort(); } } _logger.CachedResponseServed(); } return(true); } return(false); }
public async Task <IActionResult> UpLoad() { if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) { return(BadRequest($"Expected a multipart request, but got {Request.ContentType}")); } // Used to accumulate all the form url encoded key value pairs in the // request. var formAccumulator = new KeyValueAccumulator(); string targetFilePath = null; var boundary = MultipartRequestHelper.GetBoundary( MediaTypeHeaderValue.Parse(Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, HttpContext.Request.Body); //读取表单内容的对象 var section = await reader.ReadNextSectionAsync(); //读取 while (section != null) { ContentDispositionHeaderValue contentDisposition; var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition); if (hasContentDispositionHeader) { if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { targetFilePath = Path.GetTempFileName(); //换下路径 using (var targetStream = System.IO.File.Create(targetFilePath)) { await section.Body.CopyToAsync(targetStream); ; } } else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); var encoding = GetEncoding(section); using (var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { var value = await streamReader.ReadToEndAsync(); if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = String.Empty; } formAccumulator.Append(key.Value.Trim('"'), value); if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit) { throw new InvalidDataException($"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded."); } } } } section = await reader.ReadNextSectionAsync(); } var user = new User(); var formValueProvider = new FormValueProvider( BindingSource.Form, new FormCollection(formAccumulator.GetResults()), CultureInfo.CurrentCulture); var bindingSuccessful = await TryUpdateModelAsync(user, prefix : "", valueProvider : formValueProvider); if (!bindingSuccessful) { if (!ModelState.IsValid) { return(BadRequest(ModelState)); } } var uploadedData = new UploadedData() { Name = user.Name, Age = user.Age, Zipcode = user.Zipcode, FilePath = targetFilePath }; return(Json(uploadedData)); }
private static bool TryParseInt64(string input, out long value) { return(HeaderUtilities.TryParseNonNegativeInt64(input, out value)); }
public static async Task <FormValueProvider> StreamFile(this HttpRequest request, Func <FileMultipartSection, Stream> createStream) { if (!MultipartRequestHelper.IsMultipartContentType(request.ContentType)) { throw new Exception($"Expected a multipart request, but got {request.ContentType}"); } // 把 request 中的 Form 依照 Key 及 Value 存到此物件 var formAccumulator = new KeyValueAccumulator(); var boundary = MultipartRequestHelper.GetBoundary( MediaTypeHeaderValue.Parse(request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, request.Body); var section = await reader.ReadNextSectionAsync(); while (section != null) { // 把 Form 的欄位內容逐一取出 ContentDispositionHeaderValue contentDisposition; var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition); if (hasContentDispositionHeader) { if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { // 若此欄位是檔案,就寫入至 Stream; using (var targetStream = createStream(section.AsFileSection())) { await section.Body.CopyToAsync(targetStream); } } else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { // 若此欄位不是檔案,就把 Key 及 Value 取出,存入 formAccumulator var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name).Value; var encoding = GetEncoding(section); using (var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { var value = await streamReader.ReadToEndAsync(); if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = String.Empty; } formAccumulator.Append(key, value); if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit) { throw new InvalidDataException($"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded."); } } } } // 取得 Form 的下一個欄位 section = await reader.ReadNextSectionAsync(); } // Bind form data to a model var formValueProvider = new FormValueProvider( BindingSource.Form, new FormCollection(formAccumulator.GetResults()), CultureInfo.CurrentCulture); return(formValueProvider); }
public virtual bool IsCachedEntryFresh(ResponseCachingContext context) { var age = context.CachedEntryAge !.Value; var cachedCacheControlHeaders = context.CachedResponseHeaders[HeaderNames.CacheControl]; var requestCacheControlHeaders = context.HttpContext.Request.Headers.CacheControl; // Add min-fresh requirements if (HeaderUtilities.TryParseSeconds(requestCacheControlHeaders, CacheControlHeaderValue.MinFreshString, out var minFresh)) { age += minFresh.Value; context.Logger.ExpirationMinFreshAdded(minFresh.Value); } // Validate shared max age, this overrides any max age settings for shared caches TimeSpan?cachedSharedMaxAge; HeaderUtilities.TryParseSeconds(cachedCacheControlHeaders, CacheControlHeaderValue.SharedMaxAgeString, out cachedSharedMaxAge); if (age >= cachedSharedMaxAge) { // shared max age implies must revalidate context.Logger.ExpirationSharedMaxAgeExceeded(age, cachedSharedMaxAge.Value); return(false); } else if (!cachedSharedMaxAge.HasValue) { TimeSpan?requestMaxAge; HeaderUtilities.TryParseSeconds(requestCacheControlHeaders, CacheControlHeaderValue.MaxAgeString, out requestMaxAge); TimeSpan?cachedMaxAge; HeaderUtilities.TryParseSeconds(cachedCacheControlHeaders, CacheControlHeaderValue.MaxAgeString, out cachedMaxAge); var lowestMaxAge = cachedMaxAge < requestMaxAge ? cachedMaxAge : requestMaxAge ?? cachedMaxAge; // Validate max age if (age >= lowestMaxAge) { // Must revalidate or proxy revalidate if (HeaderUtilities.ContainsCacheDirective(cachedCacheControlHeaders, CacheControlHeaderValue.MustRevalidateString) || HeaderUtilities.ContainsCacheDirective(cachedCacheControlHeaders, CacheControlHeaderValue.ProxyRevalidateString)) { context.Logger.ExpirationMustRevalidate(age, lowestMaxAge.Value); return(false); } TimeSpan?requestMaxStale; var maxStaleExist = HeaderUtilities.ContainsCacheDirective(requestCacheControlHeaders, CacheControlHeaderValue.MaxStaleString); HeaderUtilities.TryParseSeconds(requestCacheControlHeaders, CacheControlHeaderValue.MaxStaleString, out requestMaxStale); // Request allows stale values with no age limit if (maxStaleExist && !requestMaxStale.HasValue) { context.Logger.ExpirationInfiniteMaxStaleSatisfied(age, lowestMaxAge.Value); return(true); } // Request allows stale values with age limit if (requestMaxStale.HasValue && age - lowestMaxAge < requestMaxStale) { context.Logger.ExpirationMaxStaleSatisfied(age, lowestMaxAge.Value, requestMaxStale.Value); return(true); } context.Logger.ExpirationMaxAgeExceeded(age, lowestMaxAge.Value); return(false); } else if (!cachedMaxAge.HasValue && !requestMaxAge.HasValue) { // Validate expiration DateTimeOffset expires; if (HeaderUtilities.TryParseDate(context.CachedResponseHeaders[HeaderNames.Expires].ToString(), out expires) && context.ResponseTime !.Value >= expires) { context.Logger.ExpirationExpiresExceeded(context.ResponseTime.Value, expires); return(false); } } } return(true); }
private static bool TrySetOptionalTokenList( NameValueHeaderValue nameValue, ref bool boolField, ref ICollection <StringSegment>?destination) { if (nameValue.Value == null) { boolField = true; return(true); } // We need the string to be at least 3 chars long: 2x quotes and at least 1 character. Also make sure we // have a quoted string. Note that NameValueHeaderValue will never have leading/trailing whitespaces. var valueString = nameValue.Value; if ((valueString.Length < 3) || (valueString[0] != '\"') || (valueString[valueString.Length - 1] != '\"')) { return(false); } // We have a quoted string. Now verify that the string contains a list of valid tokens separated by ','. var current = 1; // skip the initial '"' character. var maxLength = valueString.Length - 1; // -1 because we don't want to parse the final '"'. var originalValueCount = destination == null ? 0 : destination.Count; while (current < maxLength) { current = HeaderUtilities.GetNextNonEmptyOrWhitespaceIndex(valueString, current, true, out var separatorFound); if (current == maxLength) { break; } var tokenLength = HttpRuleParser.GetTokenLength(valueString, current); if (tokenLength == 0) { // We already skipped whitespaces and separators. If we don't have a token it must be an invalid // character. return(false); } if (destination == null) { destination = new ObjectCollection <StringSegment>(CheckIsValidTokenAction); } destination.Add(valueString.Subsegment(current, tokenLength)); current = current + tokenLength; } // After parsing a valid token list, we expect to have at least one value if ((destination != null) && (destination.Count > originalValueCount)) { boolField = true; return(true); } return(false); }
public virtual bool IsResponseCacheable(ResponseCachingContext context) { var responseCacheControlHeader = context.HttpContext.Response.Headers.CacheControl; // Only cache pages explicitly marked with public if (!HeaderUtilities.ContainsCacheDirective(responseCacheControlHeader, CacheControlHeaderValue.PublicString)) { context.Logger.ResponseWithoutPublicNotCacheable(); return(false); } // Check response no-store if (HeaderUtilities.ContainsCacheDirective(responseCacheControlHeader, CacheControlHeaderValue.NoStoreString)) { context.Logger.ResponseWithNoStoreNotCacheable(); return(false); } // Check no-cache if (HeaderUtilities.ContainsCacheDirective(responseCacheControlHeader, CacheControlHeaderValue.NoCacheString)) { context.Logger.ResponseWithNoCacheNotCacheable(); return(false); } var response = context.HttpContext.Response; // Do not cache responses with Set-Cookie headers if (!StringValues.IsNullOrEmpty(response.Headers.SetCookie)) { context.Logger.ResponseWithSetCookieNotCacheable(); return(false); } // Do not cache responses varying by * var varyHeader = response.Headers.Vary; if (varyHeader.Count == 1 && string.Equals(varyHeader, "*", StringComparison.OrdinalIgnoreCase)) { context.Logger.ResponseWithVaryStarNotCacheable(); return(false); } // Check private if (HeaderUtilities.ContainsCacheDirective(responseCacheControlHeader, CacheControlHeaderValue.PrivateString)) { context.Logger.ResponseWithPrivateNotCacheable(); return(false); } // Check response code if (response.StatusCode != StatusCodes.Status200OK) { context.Logger.ResponseWithUnsuccessfulStatusCodeNotCacheable(response.StatusCode); return(false); } // Check response freshness if (!context.ResponseDate.HasValue) { if (!context.ResponseSharedMaxAge.HasValue && !context.ResponseMaxAge.HasValue && context.ResponseTime !.Value >= context.ResponseExpires) { context.Logger.ExpirationExpiresExceeded(context.ResponseTime.Value, context.ResponseExpires.Value); return(false); } } else { var age = context.ResponseTime !.Value - context.ResponseDate.Value; // Validate shared max age if (age >= context.ResponseSharedMaxAge) { context.Logger.ExpirationSharedMaxAgeExceeded(age, context.ResponseSharedMaxAge.Value); return(false); } else if (!context.ResponseSharedMaxAge.HasValue) { // Validate max age if (age >= context.ResponseMaxAge) { context.Logger.ExpirationMaxAgeExceeded(age, context.ResponseMaxAge.Value); return(false); } else if (!context.ResponseMaxAge.HasValue) { // Validate expiration if (context.ResponseTime.Value >= context.ResponseExpires) { context.Logger.ExpirationExpiresExceeded(context.ResponseTime.Value, context.ResponseExpires.Value); return(false); } } } } return(true); }
private static void CheckIsValidToken(StringSegment item) { HeaderUtilities.CheckValidToken(item, nameof(item)); }
public async Task <IActionResult> UploadDatabase() { if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) { ModelState.AddModelError("File", $"The request couldn't be processed (Error 1)."); // Log error return(BadRequest(ModelState)); } // Accumulate the form data key-value pairs in the request (formAccumulator). var formAccumulator = new KeyValueAccumulator(); var trustedFileNameForDisplay = string.Empty; var untrustedFileNameForStorage = string.Empty; var trustedFilePathStorage = string.Empty; var trustedFileNameForFileStorage = string.Empty; var streamedFileContent = new byte[0]; var streamedFilePhysicalContent = new byte[0]; // List Byte for file storage List <byte[]> filesByteStorage = new List <byte[]>(); List <string> filesNameStorage = new List <string>(); var fileStoredData = new Dictionary <string, byte[]>(); List <string> storedPaths = new List <string>(); List <string> storedPathDictionaryKeys = new List <string>(); // List to Submit List <ClamSectionTVShowSubCategorySeasonItem> episodeList = new List <ClamSectionTVShowSubCategorySeasonItem>(); var boundary = MultipartRequestHelper.GetBoundary( MediaTypeHeaderValue.Parse(Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, HttpContext.Request.Body); var section = await reader.ReadNextSectionAsync(); while (section != null) { var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse( section.ContentDisposition, out var contentDisposition); if (hasContentDispositionHeader) { if (MultipartRequestHelper .HasFileContentDisposition(contentDisposition)) { untrustedFileNameForStorage = contentDisposition.FileName.Value; // Don't trust the file name sent by the client. To display // the file name, HTML-encode the value. trustedFileNameForDisplay = WebUtility.HtmlEncode( contentDisposition.FileName.Value); //streamedFileContent = // await FileHelpers.ProcessStreamedFile(section, contentDisposition, // ModelState, _permittedExtentions, _fileSizeLimit); streamedFilePhysicalContent = await FileHelpers.ProcessStreamedFile( section, contentDisposition, ModelState, _permittedExtentions, _fileSizeLimit); filesNameStorage.Add(trustedFileNameForDisplay); filesByteStorage.Add(streamedFilePhysicalContent); fileStoredData.Add(trustedFileNameForDisplay, streamedFilePhysicalContent); if (!ModelState.IsValid) { return(BadRequest(ModelState)); } } else if (MultipartRequestHelper .HasFormDataContentDisposition(contentDisposition)) { // Don't limit the key name length because the // multipart headers length limit is already in effect. var key = HeaderUtilities .RemoveQuotes(contentDisposition.Name).Value; var encoding = GetEncoding(section); if (encoding == null) { ModelState.AddModelError("File", $"The request couldn't be processed (Error 2)."); // Log error return(BadRequest(ModelState)); } using (var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { // The value length limit is enforced by // MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (string.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = string.Empty; } formAccumulator.Append(key, value); if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit) { // Form key count limit of // _defaultFormOptions.ValueCountLimit // is exceeded. ModelState.AddModelError("File", $"The request couldn't be processed (Error 3)."); // Log error return(BadRequest(ModelState)); } } } } // Drain any remaining section body that hasn't been consumed and // read the headers for the next section. section = await reader.ReadNextSectionAsync(); } // Bind form data to the model var formData = new StreamFormData(); var formValueProvider = new FormValueProvider( BindingSource.Form, new FormCollection(formAccumulator.GetResults()), CultureInfo.CurrentCulture); var bindingSuccessful = await TryUpdateModelAsync(formData, prefix : "", valueProvider : formValueProvider); //trustedFilePathStorage = String.Format("{0}\\{1}\\{2}\\{3}\\{4}", // //_targetFilePath, // _targetFolderPath, // formData.CategoryId, // formData.TVShowId, // formData.SeasonId, // Path.GetRandomFileName()); if (!bindingSuccessful) { ModelState.AddModelError("File", "The request couldn't be processed (Error 5)."); // Log error return(BadRequest(ModelState)); } // **WARNING!** // In the following example, the file is saved without // scanning the file's contents. In most production // scenarios, an anti-virus/anti-malware scanner API // is used on the file before making the file available // for download or for use by other systems. // For more information, see the topic that accompanies // this sample app. //Directory.CreateDirectory(trustedFilePathStorage); //using (var targetStream = System.IO.File.Create( // Path.Combine(trustedFilePathStorage, trustedFileNameForDisplay))) //{ // await targetStream.WriteAsync(streamedFilePhysicalContent); // _logger.LogInformation( // "Uploaded file '{TrustedFileNameForDisplay}' saved to " + // "'{TargetFilePath}' as {TrustedFileNameForFileStorage}", // trustedFileNameForDisplay, trustedFilePathStorage, // trustedFileNameForDisplay); //} foreach (var item in fileStoredData) { trustedFilePathStorage = String.Format("{0}\\{1}\\{2}\\{3}\\{4}", //_targetFilePath, _targetFolderPath, formData.CategoryId, formData.TVShowId, formData.SeasonId, Path.GetRandomFileName()); Directory.CreateDirectory(trustedFilePathStorage); using (var targetStream = System.IO.File.Create( Path.Combine(trustedFilePathStorage, item.Key))) { await targetStream.WriteAsync(item.Value); _logger.LogInformation( "Uploaded file '{TrustedFileNameForDisplay}' saved to " + "'{TargetFilePath}' as {TrustedFileNameForFileStorage}", item.Key, trustedFilePathStorage, item.Key); } //storedPaths.Add(Path.Combine(trustedFilePathStorage, item.Key)); //storedPathDictionaryKeys.Add(item.Key); episodeList.Add(new ClamSectionTVShowSubCategorySeasonItem() { ItemPath = Path.Combine(trustedFilePathStorage, item.Key), ItemTitle = item.Key, Size = item.Value.Length, DateCreated = DateTime.Now, CategoryId = formData.CategoryId, TVShowId = formData.TVShowId, SeasonId = formData.SeasonId }); } //var file = new ClamSectionTVShowSubCategorySeasonItem() //{ // ItemPath = Path.Combine(trustedFilePathStorage, trustedFileNameForDisplay), // ItemTitle = untrustedFileNameForStorage, // Size = streamedFilePhysicalContent.Length, // DateCreated = DateTime.Now, // CategoryId = formData.CategoryId, // TVShowId = formData.TVShowId, // SeasonId = formData.SeasonId //}; //_context.Add(file); await _context.AddRangeAsync(episodeList); await _context.SaveChangesAsync(); var url = String.Format("{0}/{1}/season/{2}/episodes/{3}", formData.UrlCategory, formData.UrlSection, formData.UrlSubSection, formData.CategoryId ); return(RedirectToAction("Episode", "TVShow", new { id = formData.CategoryId, show = formData.TVShowId, season = formData.SeasonId, category = formData.UrlCategory, section = formData.UrlSection, subsection = formData.UrlSubSection })); }
public async Task <IActionResult> UploadDatabase() { if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) { ModelState.AddModelError("File", $"The request couldn't be processed (Error 1)."); // Log error return(BadRequest(ModelState)); } // Accumulate the form data key-value pairs in the request (formAccumulator). var formAccumulator = new KeyValueAccumulator(); var trustedFileName = string.Empty; var streamedFileContent = new byte[0]; var boundary = MultipartRequestHelper.GetBoundary( MediaTypeHeaderValue.Parse(Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, HttpContext.Request.Body); var section = await reader.ReadNextSectionAsync(); while (section != null) { var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse( section.ContentDisposition, out var contentDisposition); if (hasContentDispositionHeader) { if (MultipartRequestHelper .HasFileContentDisposition(contentDisposition)) { // Don't trust the file name sent by the client. Use Linq to // remove invalid characters. Another option is to use // Path.GetRandomFileName to generate a safe random // file name. var invalidFileNameChars = Path.GetInvalidFileNameChars(); trustedFileName = invalidFileNameChars.Aggregate( contentDisposition.FileName.Value, (current, c) => current.Replace(c, '_')); streamedFileContent = await FileHelpers.ProcessStreamedFile(section, contentDisposition, ModelState, _permittedExtensions, _fileSizeLimit); if (!ModelState.IsValid) { return(BadRequest(ModelState)); } } else if (MultipartRequestHelper .HasFormDataContentDisposition(contentDisposition)) { // Don't limit the key name length because the // multipart headers length limit is already in effect. var key = HeaderUtilities .RemoveQuotes(contentDisposition.Name).Value; var encoding = GetEncoding(section); if (encoding == null) { ModelState.AddModelError("File", $"The request couldn't be processed (Error 2)."); // Log error return(BadRequest(ModelState)); } using (var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { // The value length limit is enforced by // MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = String.Empty; } formAccumulator.Append(key, value); if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit) { // Form key count limit of // _defaultFormOptions.ValueCountLimit // is exceeded. ModelState.AddModelError("File", $"The request couldn't be processed (Error 3)."); // Log error return(BadRequest(ModelState)); } } } } // Drain any remaining section body that hasn't been consumed and // read the headers for the next section. section = await reader.ReadNextSectionAsync(); } // Bind form data to the model var formData = new FormData(); var formValueProvider = new FormValueProvider( BindingSource.Form, new FormCollection(formAccumulator.GetResults()), CultureInfo.CurrentCulture); var bindingSuccessful = await TryUpdateModelAsync(formData, prefix : "", valueProvider : formValueProvider); if (!bindingSuccessful) { ModelState.AddModelError("File", "The request couldn't be processed (Error 5)."); // Log error return(BadRequest(ModelState)); } var uploadedFormData = new FormData() { Note = formData.Note, }; // **WARNING!** // In the following example, the file is saved without // scanning the file's contents. In most production // scenarios, an anti-virus/anti-malware scanner API // is used on the file before making the file available // for download or for use by other systems. // For more information, see the topic that accompanies // this sample app. var file = new AppFile() { Content = streamedFileContent, Name = trustedFileName, Note = formData.Note, Size = streamedFileContent.Length, UploadDT = DateTime.UtcNow }; _context.File.Add(file); await _context.SaveChangesAsync(); return(Created(nameof(StreamingController), null)); }
public async Task <IActionResult> Upload() { if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) { return(BadRequest("Expected a multipart request, but got " + Request.ContentType)); } // Used to accumulate all the form url encoded key value pairs in the request. var formAccumulator = new KeyValueAccumulator(); string targetFilePath = null; var boundary = MultipartRequestHelper.GetBoundary( MediaTypeHeaderValue.Parse(Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, HttpContext.Request.Body); var section = await reader.ReadNextSectionAsync(); while (section != null) { ContentDispositionHeaderValue contentDisposition; var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition); if (hasContentDispositionHeader && MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { targetFilePath = Path.GetTempFileName(); using (var targetStream = System.IO.File.Create(targetFilePath)) { await section.Body.CopyToAsync(targetStream); _logger.LogInformation($"Copied the uploaded file '{targetFilePath}'"); } } else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { // Content-Disposition: form-data; name="key" // // value // Do not limit the key name length here because the multipart headers length // limit is already in effect. var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); var encoding = GetEncoding(section); using (var streamReader = new StreamReader( section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { // The value length limit is enforced by MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = String.Empty; } formAccumulator.Append(key, value); if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit) { throw new InvalidDataException( "Form key count limit " + _defaultFormOptions.ValueCountLimit + " exceeded."); } } } // Drains any remaining section body that has not been consumed and // reads the headers for the next section. section = await reader.ReadNextSectionAsync(); } // Bind form data to a model var user = new User(); var formValueProvider = new FormValueProvider( BindingSource.Form, new FormCollection(formAccumulator.GetResults()), CultureInfo.CurrentCulture); var bindingSuccessful = await TryUpdateModelAsync(user, prefix : "", valueProvider : formValueProvider); if (!bindingSuccessful) { if (!ModelState.IsValid) { return(BadRequest(ModelState)); } } var uploadedData = new UploadedData() { Name = user.Name, Age = user.Age, Zipcode = user.Zipcode, FilePath = targetFilePath }; return(Json(uploadedData)); }
private async Task <Procedure> ProcessProcedureRequestAsync(string targetPath) { try { Procedure result = null; if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType)) { throw new BadRequestException($"Expected a multipart request, but got {Request.ContentType}"); } // Used to accumulate all the form url encoded key value pairs in the // request. var formAccumulator = new KeyValueAccumulator(); var boundary = MultipartRequestHelper.GetBoundary(MediaTypeHeaderValue.Parse(Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, HttpContext.Request.Body); var section = await reader.ReadNextSectionAsync(); while (section != null) { ContentDispositionHeaderValue contentDisposition; var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition); if (hasContentDispositionHeader) { if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) { if (section.ContentType == "application/json") { var serializer = new JsonSerializer(); using (var sr = new StreamReader(section.Body)) using (var jsonTextReader = new JsonTextReader(sr)) result = serializer.Deserialize <Procedure>(jsonTextReader); } else // is file { using (var targetStream = new FileStream(Path.Combine(targetPath, contentDisposition.FileName.ToString()), FileMode.Create)) await section.Body.CopyToAsync(targetStream); } //end if } //end if else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) { // Content-Disposition: form-data; name="key" // Do not limit the key name length here because the // multipart headers length limit is already in effect. var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); using (var streamReader = new StreamReader(section.Body, GetEncoding(section), detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { // The value length limit is enforced by MultipartBodyLengthLimit var value = await streamReader.ReadToEndAsync(); if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = String.Empty; } if (isJson(value)) { result = JsonConvert.DeserializeObject <Procedure>(value); } else { formAccumulator.Append(key.ToString(), value); if (formAccumulator.ValueCount > _defaultFormOptions.ValueCountLimit) { throw new InvalidDataException($"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded."); } } } //end using } //endif } // Drains any remaining section body that has not been consumed and // reads the headers for the next section. section = await reader.ReadNextSectionAsync(); }//next if (formAccumulator.HasValues) { // Bind form data to a model result = new Procedure(); var formValueProvider = new FormValueProvider( BindingSource.Form, new FormCollection(formAccumulator.GetResults()), CultureInfo.CurrentCulture); var bindingSuccessful = await TryUpdateModelAsync(result, prefix : "", valueProvider : formValueProvider); if (!bindingSuccessful) { if (!ModelState.IsValid) { throw new BadRequestException(ModelState.ValidationState.ToString()); } } }//end if return(result); } catch (Exception) { throw; } }
public async Task <MultiPartRequestDto> HandleMultiPartRequest(HttpRequest request) { if (!IsMultipartContentType(request.ContentType)) { throw new Exception($"Expected a multipart request, but got {request.ContentType}"); } var formAccumulator = new KeyValueAccumulator(); var boundary = GetBoundary( MediaTypeHeaderValue.Parse(request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit); var reader = new MultipartReader(boundary, request.Body); var section = await reader.ReadNextSectionAsync(); var media = new List <AddFileDto>(); while (section != null) { var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition); if (hasContentDispositionHeader) { if (HasFileContentDisposition(contentDisposition)) { var processedMedia = await _fileService.ProcessStreamedFileAsync(section, contentDisposition); var mediaDto = new AddFileDto { File = processedMedia, FileExtension = Path.GetExtension(contentDisposition.FileName.Value), }; media.Add(mediaDto); } else if (HasFormDataContentDisposition(contentDisposition)) { var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name).Value; var encoding = GetEncoding(section); using (var streamReader = new StreamReader(section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { var value = await streamReader.ReadToEndAsync(); if (string.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase)) { value = string.Empty; } formAccumulator.Append(key, value); if (formAccumulator.ValueCount > int.MaxValue) { throw new InvalidDataException($"Form key count limit {_defaultFormOptions.ValueCountLimit} exceeded."); } } } } section = await reader.ReadNextSectionAsync(); } //request.Body.Position = 0; var formAccumulatorResults = formAccumulator.GetResults(); var formValueProvider = new FormValueProvider( BindingSource.Form, new FormCollection(formAccumulatorResults), CultureInfo.CurrentCulture); return(new MultiPartRequestDto { FormValueProvider = formValueProvider, File = media, }); }
// name=value; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite={Strict|Lax|None}; httponly private static int GetSetCookieLength(StringSegment input, int startIndex, out SetCookieHeaderValue?parsedValue) { Contract.Requires(startIndex >= 0); var offset = startIndex; parsedValue = null; if (StringSegment.IsNullOrEmpty(input) || (offset >= input.Length)) { return(0); } var result = new SetCookieHeaderValue(); // The caller should have already consumed any leading whitespace, commas, etc.. // Name=value; // Name var itemLength = HttpRuleParser.GetTokenLength(input, offset); if (itemLength == 0) { return(0); } result._name = input.Subsegment(offset, itemLength); offset += itemLength; // = (no spaces) if (!ReadEqualsSign(input, ref offset)) { return(0); } // value or "quoted value" // The value may be empty result._value = CookieHeaderParserShared.GetCookieValue(input, ref offset); // *(';' SP cookie-av) while (offset < input.Length) { if (input[offset] == ',') { // Divider between headers break; } if (input[offset] != ';') { // Expecting a ';' between parameters return(0); } offset++; offset += HttpRuleParser.GetWhitespaceLength(input, offset); // cookie-av = expires-av / max-age-av / domain-av / path-av / secure-av / samesite-av / httponly-av / extension-av itemLength = HttpRuleParser.GetTokenLength(input, offset); if (itemLength == 0) { // Trailing ';' or leading into garbage. Let the next parser fail. break; } var token = input.Subsegment(offset, itemLength); offset += itemLength; // expires-av = "Expires=" sane-cookie-date if (StringSegment.Equals(token, ExpiresToken, StringComparison.OrdinalIgnoreCase)) { // = (no spaces) if (!ReadEqualsSign(input, ref offset)) { return(0); } // We don't want to include comma, becouse date may contain it (eg. Sun, 06 Nov...) var dateString = ReadToSemicolonOrEnd(input, ref offset, includeComma: false); DateTimeOffset expirationDate; if (!HttpRuleParser.TryStringToDate(dateString, out expirationDate)) { // Invalid expiration date, abort return(0); } result.Expires = expirationDate; } // max-age-av = "Max-Age=" non-zero-digit *DIGIT else if (StringSegment.Equals(token, MaxAgeToken, StringComparison.OrdinalIgnoreCase)) { // = (no spaces) if (!ReadEqualsSign(input, ref offset)) { return(0); } itemLength = HttpRuleParser.GetNumberLength(input, offset, allowDecimal: false); if (itemLength == 0) { return(0); } var numberString = input.Subsegment(offset, itemLength); long maxAge; if (!HeaderUtilities.TryParseNonNegativeInt64(numberString, out maxAge)) { // Invalid expiration date, abort return(0); } result.MaxAge = TimeSpan.FromSeconds(maxAge); offset += itemLength; } // domain-av = "Domain=" domain-value // domain-value = <subdomain> ; defined in [RFC1034], Section 3.5, as enhanced by [RFC1123], Section 2.1 else if (StringSegment.Equals(token, DomainToken, StringComparison.OrdinalIgnoreCase)) { // = (no spaces) if (!ReadEqualsSign(input, ref offset)) { return(0); } // We don't do any detailed validation on the domain. result.Domain = ReadToSemicolonOrEnd(input, ref offset); } // path-av = "Path=" path-value // path-value = <any CHAR except CTLs or ";"> else if (StringSegment.Equals(token, PathToken, StringComparison.OrdinalIgnoreCase)) { // = (no spaces) if (!ReadEqualsSign(input, ref offset)) { return(0); } // We don't do any detailed validation on the path. result.Path = ReadToSemicolonOrEnd(input, ref offset); } // secure-av = "Secure" else if (StringSegment.Equals(token, SecureToken, StringComparison.OrdinalIgnoreCase)) { result.Secure = true; } // samesite-av = "SameSite=" samesite-value // samesite-value = "Strict" / "Lax" / "None" else if (StringSegment.Equals(token, SameSiteToken, StringComparison.OrdinalIgnoreCase)) { if (!ReadEqualsSign(input, ref offset)) { result.SameSite = SameSiteMode.Unspecified; } else { var enforcementMode = ReadToSemicolonOrEnd(input, ref offset); if (StringSegment.Equals(enforcementMode, SameSiteStrictToken, StringComparison.OrdinalIgnoreCase)) { result.SameSite = SameSiteMode.Strict; } else if (StringSegment.Equals(enforcementMode, SameSiteLaxToken, StringComparison.OrdinalIgnoreCase)) { result.SameSite = SameSiteMode.Lax; } else if (StringSegment.Equals(enforcementMode, SameSiteNoneToken, StringComparison.OrdinalIgnoreCase)) { result.SameSite = SameSiteMode.None; } else { result.SameSite = SameSiteMode.Unspecified; } } } // httponly-av = "HttpOnly" else if (StringSegment.Equals(token, HttpOnlyToken, StringComparison.OrdinalIgnoreCase)) { result.HttpOnly = true; } // extension-av = <any CHAR except CTLs or ";"> else { var tokenStart = offset - itemLength; ReadToSemicolonOrEnd(input, ref offset, includeComma: true); result.Extensions.Add(input.Subsegment(tokenStart, offset - tokenStart)); } } parsedValue = result; return(offset - startIndex); }