Last active
March 19, 2019 14:11
-
-
Save cristipufu/b2f0a73809d76e40d34f47a68c3bc5c9 to your computer and use it in GitHub Desktop.
MultiPartFormData Streaming
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] | |
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter | |
{ | |
public void OnResourceExecuting(ResourceExecutingContext context) | |
{ | |
var factories = context.ValueProviderFactories; | |
factories.RemoveType<FormValueProviderFactory>(); | |
factories.RemoveType<JQueryFormValueProviderFactory>(); | |
} | |
public void OnResourceExecuted(ResourceExecutedContext context) | |
{ | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static class MultipartRequestHelper | |
{ | |
// Content-Type: multipart/form-data; boundary="----WebKitFormBoundarymx2fSWqWSd0OxQqq" | |
// The spec says 70 characters is a reasonable limit. | |
public static string GetBoundary(MediaTypeHeaderValue contentType, int lengthLimit) | |
{ | |
var boundary = HeaderUtilities.RemoveQuotes(contentType.Boundary).ToString(); | |
if (string.IsNullOrWhiteSpace(boundary)) | |
{ | |
throw new InvalidDataException("Missing content-type boundary."); | |
} | |
if (boundary.Length > lengthLimit) | |
{ | |
throw new InvalidDataException( | |
$"Multipart boundary length limit {lengthLimit} exceeded."); | |
} | |
return boundary; | |
} | |
public static bool IsMultipartContentType(string contentType) | |
{ | |
return !string.IsNullOrEmpty(contentType) | |
&& contentType.IndexOf("multipart/", StringComparison.OrdinalIgnoreCase) >= 0; | |
} | |
public static bool HasFormDataContentDisposition(ContentDispositionHeaderValue contentDisposition) | |
{ | |
// Content-Disposition: form-data; name="key"; | |
return contentDisposition != null | |
&& contentDisposition.DispositionType.Equals("form-data") | |
&& string.IsNullOrEmpty(contentDisposition.FileName.Value) | |
&& string.IsNullOrEmpty(contentDisposition.FileNameStar.Value); | |
} | |
public static bool HasFileContentDisposition(ContentDispositionHeaderValue contentDisposition) | |
{ | |
// Content-Disposition: form-data; name="myfile1"; filename="Misc 002.jpg" | |
return contentDisposition != null | |
&& contentDisposition.DispositionType.Equals("form-data") | |
&& (!string.IsNullOrEmpty(contentDisposition.FileName.Value) | |
|| !string.IsNullOrEmpty(contentDisposition.FileNameStar.Value)); | |
} | |
public static Encoding GetEncoding(MultipartSection section) | |
{ | |
var hasMediaTypeHeader = MediaTypeHeaderValue.TryParse(section.ContentType, out var mediaType); | |
// UTF-7 is insecure and should not be honored. UTF-8 will succeed in | |
// most cases. | |
if (!hasMediaTypeHeader || Encoding.UTF7.Equals(mediaType.Encoding)) | |
{ | |
return Encoding.UTF8; | |
} | |
return mediaType.Encoding; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var boundary = MultipartRequestHelper.GetBoundary( | |
MediaTypeHeaderValue.Parse(Request.ContentType), | |
DefaultFormOptions.MultipartBoundaryLengthLimit); | |
var reader = new MultipartReader(boundary, HttpContext.Request.Body); | |
var section = await reader.ReadNextSectionAsync(cancellationToken); | |
while (section != null) | |
{ | |
var hasContentDispositionHeader = | |
ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition); | |
if (hasContentDispositionHeader) | |
{ | |
if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition)) | |
{ | |
// await section.Body.CopyToAsync(storageStream, cancellationToken); | |
} | |
else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition)) | |
{ | |
var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); | |
var encoding = MultipartRequestHelper.GetEncoding(section); | |
using (var streamReader = new StreamReader(section.Body, encoding, true, 1024, true)) | |
{ | |
var value = await streamReader.ReadToEndAsync(); | |
form.Add(key.Value, value); | |
} | |
} | |
} | |
section = await reader.ReadNextSectionAsync(cancellationToken); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment