public static async Task<IMultipartCollection> ReadMultipartAsync(this HttpRequest request, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); request.EnableRewind(); var parts = new MultipartCollection(); using(cancellationToken.Register(request.HttpContext.Abort)) { var contentType = GetContentType(request); var boundary = GetBoundary(contentType); var multipartReader = new MultipartReader(boundary, request.Body); var section = await multipartReader.ReadNextSectionAsync(cancellationToken); while(section != null) { var headers = new HeaderDictionary(section.Headers); var contentDisposition = headers.GetContentDisposition(); await section.Body.DrainAsync(cancellationToken); var part = new Multipart(request.Body, section.BaseStreamOffset.Value, section.Body.Length) { Headers = headers }; parts.Add(part); section = await multipartReader.ReadNextSectionAsync(cancellationToken); } } request.Body.Seek(0, SeekOrigin.Begin); return parts; }
public async Task MutipartReader_ReadSinglePartBody_Success() { var stream = MakeStream(OnePartBody); var reader = new MultipartReader(Boundary, stream); var section = await reader.ReadNextSectionAsync(); Assert.NotNull(section); Assert.Equal(1, section.Headers.Count); Assert.Equal("form-data; name=\"text\"", section.Headers["Content-Disposition"][0]); var buffer = new MemoryStream(); await section.Body.CopyToAsync(buffer); Assert.Equal("text default", Encoding.ASCII.GetString(buffer.ToArray())); Assert.Null(await reader.ReadNextSectionAsync()); }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); app.UseIISPlatformHandler(); app.Use(async (context, next) => { if (!IsMultipartContentType(context.Request.ContentType)) { await next(); return; } var boundary = GetBoundary(context.Request.ContentType); var reader = new MultipartReader(boundary, context.Request.Body); var section = await reader.ReadNextSectionAsync(); while (section != null) { // process each image const int chunkSize = 1024; var buffer = new byte[chunkSize]; var bytesRead = 0; var fileName = GetFileName(section.ContentDisposition); using (var stream = new FileStream(fileName, FileMode.Append)) { do { bytesRead = await section.Body.ReadAsync(buffer, 0, buffer.Length); stream.Write(buffer, 0, bytesRead); } while (bytesRead > 0); } section = await reader.ReadNextSectionAsync(); } //context.Response.Body.WriteAsync("Done."); }); app.UseStaticFiles(); app.UseMvc(); }
public async Task MutipartReader_ReadSinglePartBody_Success() { var stream = MakeStream(OnePartBody); var reader = new MultipartReader(Boundary, stream); var section = await reader.ReadNextSectionAsync(); Assert.NotNull(section); Assert.Equal(1, section.Headers.Count); Assert.Equal("form-data; name=\"text\"", section.Headers["Content-Disposition"][0]); var buffer = new MemoryStream(); await section.Body.CopyToAsync(buffer); Assert.Equal("text default", Encoding.ASCII.GetString(buffer.ToArray())); Assert.Null(await reader.ReadNextSectionAsync()); }
public async Task MutipartReader_ThreePartBody_Success() { var stream = MakeStream(ThreePartBody); var reader = new MultipartReader(Boundary, stream); var section = await reader.ReadNextSectionAsync(); Assert.NotNull(section); Assert.Equal(1, section.Headers.Count); Assert.Equal("form-data; name=\"text\"", section.Headers["Content-Disposition"][0]); var buffer = new MemoryStream(); await section.Body.CopyToAsync(buffer); Assert.Equal("text default", Encoding.ASCII.GetString(buffer.ToArray())); section = await reader.ReadNextSectionAsync(); Assert.NotNull(section); Assert.Equal(2, section.Headers.Count); Assert.Equal("form-data; name=\"file1\"; filename=\"a.txt\"", section.Headers["Content-Disposition"][0]); Assert.Equal("text/plain", section.Headers["Content-Type"][0]); buffer = new MemoryStream(); await section.Body.CopyToAsync(buffer); Assert.Equal("Content of a.txt.\r\n", Encoding.ASCII.GetString(buffer.ToArray())); section = await reader.ReadNextSectionAsync(); Assert.NotNull(section); Assert.Equal(2, section.Headers.Count); Assert.Equal("form-data; name=\"file2\"; filename=\"a.html\"", section.Headers["Content-Disposition"][0]); Assert.Equal("text/html", section.Headers["Content-Type"][0]); buffer = new MemoryStream(); await section.Body.CopyToAsync(buffer); Assert.Equal("<!DOCTYPE html><title>Content of a.html.</title>\r\n", Encoding.ASCII.GetString(buffer.ToArray())); Assert.Null(await reader.ReadNextSectionAsync()); }
public async Task MutipartReader_ReadInvalidUtf8SurrogateHeader_ReplacementCharacters() { var body1 = "--9051914041544843365972754266\r\n" + "Content-Disposition: form-data; name=\"text\" filename=\"a"; var body2 = ".txt\"\r\n" + "\r\n" + "text default\r\n" + "--9051914041544843365972754266--\r\n"; var stream = new MemoryStream(); var bytes = Encoding.UTF8.GetBytes(body1); stream.Write(bytes, 0, bytes.Length); // Write an invalid utf-8 segment in the middle stream.Write(new byte[] { 0xED, 0xA0, 85 }, 0, 3); bytes = Encoding.UTF8.GetBytes(body2); stream.Write(bytes, 0, bytes.Length); stream.Seek(0, SeekOrigin.Begin); var reader = new MultipartReader(Boundary, stream); var section = await reader.ReadNextSectionAsync(); Assert.NotNull(section); Assert.Equal(1, section.Headers.Count); Assert.Equal("form-data; name=\"text\" filename=\"a\uFFFDU.txt\"", section.Headers["Content-Disposition"][0]); var buffer = new MemoryStream(); await section.Body.CopyToAsync(buffer); Assert.Equal("text default", Encoding.ASCII.GetString(buffer.ToArray())); Assert.Null(await reader.ReadNextSectionAsync()); }
public async Task<IFormCollection> ReadFormAsync(CancellationToken cancellationToken) { if (Form != null) { return Form; } if (!HasFormContentType) { throw new InvalidOperationException("Incorrect Content-Type: " + _request.ContentType); } cancellationToken.ThrowIfCancellationRequested(); _request.EnableRewind(); IDictionary<string, StringValues> formFields = null; var files = new FormFileCollection(); // Some of these code paths use StreamReader which does not support cancellation tokens. using (cancellationToken.Register(_request.HttpContext.Abort)) { var contentType = ContentType; // Check the content-type if (HasApplicationFormContentType(contentType)) { var encoding = FilterEncoding(contentType.Encoding); formFields = await FormReader.ReadFormAsync(_request.Body, encoding, cancellationToken); } else if (HasMultipartFormContentType(contentType)) { var formAccumulator = new KeyValueAccumulator(); var boundary = GetBoundary(contentType); var multipartReader = new MultipartReader(boundary, _request.Body); var section = await multipartReader.ReadNextSectionAsync(cancellationToken); while (section != null) { var headers = new HeaderDictionary(section.Headers); ContentDispositionHeaderValue contentDisposition; ContentDispositionHeaderValue.TryParse(headers[HeaderNames.ContentDisposition], out contentDisposition); if (HasFileContentDisposition(contentDisposition)) { // Find the end await section.Body.DrainAsync(cancellationToken); var file = new FormFile(_request.Body, section.BaseStreamOffset.Value, section.Body.Length) { Headers = headers, }; files.Add(file); } else if (HasFormDataContentDisposition(contentDisposition)) { // Content-Disposition: form-data; name="key" // // value var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name); MediaTypeHeaderValue mediaType; MediaTypeHeaderValue.TryParse(headers[HeaderNames.ContentType], out mediaType); var encoding = FilterEncoding(mediaType?.Encoding); using (var reader = new StreamReader(section.Body, encoding, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { var value = await reader.ReadToEndAsync(); formAccumulator.Append(key, value); } } else { System.Diagnostics.Debug.Assert(false, "Unrecognized content-disposition for this section: " + headers[HeaderNames.ContentDisposition]); } section = await multipartReader.ReadNextSectionAsync(cancellationToken); } formFields = formAccumulator.GetResults(); } } // Rewind so later readers don't have to. _request.Body.Seek(0, SeekOrigin.Begin); Form = new FormCollection(formFields, files); return Form; }
public void Configure(IApplicationBuilder app) { app.Use(async (context, next) => { if (!IsMultipartContentType(context.Request.ContentType)) { await next(); return; } context.Response.ContentType = "text/html"; await context.Response.WriteAsync("<html><body>Multipart received<br>"); // Read the request body as multipart sections. This does not buffer the content of each section. If you want to buffer the data // then that needs to be added either to the request body before you start or to the individual segments afterward. var boundary = GetBoundary(context.Request.ContentType); var reader = new MultipartReader(boundary, context.Request.Body); var section = await reader.ReadNextSectionAsync(); while (section != null) { await context.Response.WriteAsync("- Header count: " + section.Headers.Count + "<br>"); foreach (var headerPair in section.Headers) { await context.Response.WriteAsync("-- " + headerPair.Key + ": " + string.Join(", ", headerPair.Value) + "<br>"); } // Consume the section body here. // Nested? if (IsMultipartContentType(section.ContentType)) { await context.Response.WriteAsync("-- Nested Multipart<br>"); var subBoundary = GetBoundary(section.ContentType); var subReader = new MultipartReader(subBoundary, section.Body); var subSection = await subReader.ReadNextSectionAsync(); while (subSection != null) { await context.Response.WriteAsync("--- Header count: " + subSection.Headers.Count + "<br>"); foreach (var headerPair in subSection.Headers) { await context.Response.WriteAsync("---- " + headerPair.Key + ": " + string.Join(", ", headerPair.Value) + "<br>"); } subSection = await subReader.ReadNextSectionAsync(); } } // Drains any remaining section body that has not been consumed and reads the headers for the next section. section = await reader.ReadNextSectionAsync(); } await context.Response.WriteAsync("</body></html>"); }); app.Use(async (context, next) => { if (context.Request.Path != new PathString("/SendMultipart")) { await next(); return; } // For the purposes of the sample we're going to issue a multipart request to ourselves and then tunnel the response to the user. var client = new HttpClient(); client.BaseAddress = new Uri("http://localhost:" + context.GetFeature<IHttpConnectionFeature>().LocalPort); var content = new MultipartContent("stuff"); content.Add(new StringContent("Hello World")); content.Add(new FormUrlEncodedContent(new Dictionary<string, string>())); content.Add(new MultipartContent("nested") { new StringContent("Nested Hello World") }); var response = await client.PostAsync("", content); context.Response.StatusCode = (int)response.StatusCode; context.Response.ContentType = response.Content.Headers.ContentType.ToString(); await response.Content.CopyToAsync(context.Response.Body); }); app.Run(async context => { context.Response.ContentType = "text/html"; await context.Response.WriteAsync("<html><body>Normal request.<br>"); await context.Response.WriteAsync("<a href=\"/SendMultipart\">Send Multipart Request</a><br>"); await context.Response.WriteAsync("</body></html>"); }); }
private async Task SaveFiles(IOwinContext context, Group boundary, List<UploadedFile> uploadedFiles) { // get the file store var fileStore = configuration.ServiceLocator.GetService<IUploadedFileStorage>(); // parse the stream var multiPartReader = new MultipartReader(boundary.Value, context.Request.Body); MultipartSection section; while ((section = await multiPartReader.ReadNextSectionAsync()) != null) { // process the section var result = await StoreFile(section, fileStore); if (result != null) { uploadedFiles.Add(result); } } }
public async Task MutipartReader_ReadInvalidUtf8SurrogateHeader_ReplacementCharacters() { var body1 = "--9051914041544843365972754266\r\n" + "Content-Disposition: form-data; name=\"text\" filename=\"a"; var body2 = ".txt\"\r\n" + "\r\n" + "text default\r\n" + "--9051914041544843365972754266--\r\n"; var stream = new MemoryStream(); var bytes = Encoding.UTF8.GetBytes(body1); stream.Write(bytes, 0, bytes.Length); // Write an invalid utf-8 segment in the middle stream.Write(new byte[] { 0xED, 0xA0, 85 }, 0, 3); bytes = Encoding.UTF8.GetBytes(body2); stream.Write(bytes, 0, bytes.Length); stream.Seek(0, SeekOrigin.Begin); var reader = new MultipartReader(Boundary, stream); var section = await reader.ReadNextSectionAsync(); Assert.NotNull(section); Assert.Equal(1, section.Headers.Count); Assert.Equal("form-data; name=\"text\" filename=\"a\uFFFDU.txt\"", section.Headers["Content-Disposition"][0]); var buffer = new MemoryStream(); await section.Body.CopyToAsync(buffer); Assert.Equal("text default", Encoding.ASCII.GetString(buffer.ToArray())); Assert.Null(await reader.ReadNextSectionAsync()); }
public async Task MutipartReader_ThreePartBody_Success() { var stream = MakeStream(ThreePartBody); var reader = new MultipartReader(Boundary, stream); var section = await reader.ReadNextSectionAsync(); Assert.NotNull(section); Assert.Equal(1, section.Headers.Count); Assert.Equal("form-data; name=\"text\"", section.Headers["Content-Disposition"][0]); var buffer = new MemoryStream(); await section.Body.CopyToAsync(buffer); Assert.Equal("text default", Encoding.ASCII.GetString(buffer.ToArray())); section = await reader.ReadNextSectionAsync(); Assert.NotNull(section); Assert.Equal(2, section.Headers.Count); Assert.Equal("form-data; name=\"file1\"; filename=\"a.txt\"", section.Headers["Content-Disposition"][0]); Assert.Equal("text/plain", section.Headers["Content-Type"][0]); buffer = new MemoryStream(); await section.Body.CopyToAsync(buffer); Assert.Equal("Content of a.txt.\r\n", Encoding.ASCII.GetString(buffer.ToArray())); section = await reader.ReadNextSectionAsync(); Assert.NotNull(section); Assert.Equal(2, section.Headers.Count); Assert.Equal("form-data; name=\"file2\"; filename=\"a.html\"", section.Headers["Content-Disposition"][0]); Assert.Equal("text/html", section.Headers["Content-Type"][0]); buffer = new MemoryStream(); await section.Body.CopyToAsync(buffer); Assert.Equal("<!DOCTYPE html><title>Content of a.html.</title>\r\n", Encoding.ASCII.GetString(buffer.ToArray())); Assert.Null(await reader.ReadNextSectionAsync()); }
public async Task MutipartReader_ReadTwoPartBodyWithUnicodeFileName_Success() { var stream = MakeStream(TwoPartBodyWithUnicodeFileName); var reader = new MultipartReader(Boundary, stream); var section = await reader.ReadNextSectionAsync(); Assert.NotNull(section); Assert.Equal(1, section.Headers.Count); Assert.Equal("form-data; name=\"text\"", section.Headers["Content-Disposition"][0]); var buffer = new MemoryStream(); await section.Body.CopyToAsync(buffer); Assert.Equal("text default", Encoding.ASCII.GetString(buffer.ToArray())); section = await reader.ReadNextSectionAsync(); Assert.NotNull(section); Assert.Equal(2, section.Headers.Count); Assert.Equal("form-data; name=\"file1\"; filename=\"a色.txt\"", section.Headers["Content-Disposition"][0]); Assert.Equal("text/plain", section.Headers["Content-Type"][0]); buffer = new MemoryStream(); await section.Body.CopyToAsync(buffer); Assert.Equal("Content of a.txt.\r\n", Encoding.ASCII.GetString(buffer.ToArray())); Assert.Null(await reader.ReadNextSectionAsync()); }