|
2 | 2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
3 | 3 |
|
4 | 4 | using System;
|
| 5 | +using System.Collections.Generic; |
5 | 6 | using System.IO;
|
6 | 7 | using System.Text;
|
7 | 8 | using System.Threading.Tasks;
|
8 |
| -using Microsoft.AspNetCore.Http.Internal; |
9 | 9 | using Xunit;
|
10 | 10 |
|
11 | 11 | namespace Microsoft.AspNetCore.Http.Features
|
@@ -48,33 +48,35 @@ public async Task ReadFormAsync_SimpleData_ReturnsParsedFormCollection(bool buff
|
48 | 48 | }
|
49 | 49 |
|
50 | 50 | private const string MultipartContentType = "multipart/form-data; boundary=WebKitFormBoundary5pDRpGheQXaM8k3T";
|
51 |
| - private const string EmptyMultipartForm = |
52 |
| -"--WebKitFormBoundary5pDRpGheQXaM8k3T--"; |
| 51 | + |
| 52 | + private const string EmptyMultipartForm = "--WebKitFormBoundary5pDRpGheQXaM8k3T--"; |
| 53 | + |
53 | 54 | // Note that CRLF (\r\n) is required. You can't use multi-line C# strings here because the line breaks on Linux are just LF.
|
54 |
| - private const string MultipartFormWithField = |
55 |
| -"--WebKitFormBoundary5pDRpGheQXaM8k3T\r\n" + |
| 55 | + private const string MultipartFormEnd = "--WebKitFormBoundary5pDRpGheQXaM8k3T--\r\n"; |
| 56 | + |
| 57 | + private const string MultipartFormField = "--WebKitFormBoundary5pDRpGheQXaM8k3T\r\n" + |
56 | 58 | "Content-Disposition: form-data; name=\"description\"\r\n" +
|
57 | 59 | "\r\n" +
|
58 |
| -"Foo\r\n" + |
59 |
| -"--WebKitFormBoundary5pDRpGheQXaM8k3T--"; |
60 |
| - private const string MultipartFormWithFile = |
61 |
| -"--WebKitFormBoundary5pDRpGheQXaM8k3T\r\n" + |
| 60 | +"Foo\r\n"; |
| 61 | + |
| 62 | + private const string MultipartFormFile = "--WebKitFormBoundary5pDRpGheQXaM8k3T\r\n" + |
62 | 63 | "Content-Disposition: form-data; name=\"myfile1\"; filename=\"temp.html\"\r\n" +
|
63 | 64 | "Content-Type: text/html\r\n" +
|
64 | 65 | "\r\n" +
|
65 |
| -"<html><body>Hello World</body></html>\r\n" + |
66 |
| -"--WebKitFormBoundary5pDRpGheQXaM8k3T--"; |
| 66 | +"<html><body>Hello World</body></html>\r\n"; |
| 67 | + |
| 68 | + private const string MultipartFormWithField = |
| 69 | + MultipartFormField + |
| 70 | + MultipartFormEnd; |
| 71 | + |
| 72 | + private const string MultipartFormWithFile = |
| 73 | + MultipartFormFile + |
| 74 | + MultipartFormEnd; |
| 75 | + |
67 | 76 | private const string MultipartFormWithFieldAndFile =
|
68 |
| -"--WebKitFormBoundary5pDRpGheQXaM8k3T\r\n" + |
69 |
| -"Content-Disposition: form-data; name=\"description\"\r\n" + |
70 |
| -"\r\n" + |
71 |
| -"Foo\r\n" + |
72 |
| -"--WebKitFormBoundary5pDRpGheQXaM8k3T\r\n" + |
73 |
| -"Content-Disposition: form-data; name=\"myfile1\"; filename=\"temp.html\"\r\n" + |
74 |
| -"Content-Type: text/html\r\n" + |
75 |
| -"\r\n" + |
76 |
| -"<html><body>Hello World</body></html>\r\n" + |
77 |
| -"--WebKitFormBoundary5pDRpGheQXaM8k3T--"; |
| 77 | + MultipartFormField + |
| 78 | + MultipartFormFile + |
| 79 | + MultipartFormEnd; |
78 | 80 |
|
79 | 81 | [Theory]
|
80 | 82 | [InlineData(true)]
|
@@ -243,6 +245,55 @@ public async Task ReadFormAsync_MultipartWithFieldAndFile_ReturnsParsedFormColle
|
243 | 245 | await responseFeature.CompleteAsync();
|
244 | 246 | }
|
245 | 247 |
|
| 248 | + [Theory] |
| 249 | + [InlineData(true)] |
| 250 | + [InlineData(false)] |
| 251 | + public async Task ReadFormAsync_ValueCountLimitExceeded_Throw(bool bufferRequest) |
| 252 | + { |
| 253 | + var formContent = new List<byte>(); |
| 254 | + formContent.AddRange(Encoding.UTF8.GetBytes(MultipartFormField)); |
| 255 | + formContent.AddRange(Encoding.UTF8.GetBytes(MultipartFormField)); |
| 256 | + formContent.AddRange(Encoding.UTF8.GetBytes(MultipartFormField)); |
| 257 | + formContent.AddRange(Encoding.UTF8.GetBytes(MultipartFormEnd)); |
| 258 | + |
| 259 | + var context = new DefaultHttpContext(); |
| 260 | + var responseFeature = new FakeResponseFeature(); |
| 261 | + context.Features.Set<IHttpResponseFeature>(responseFeature); |
| 262 | + context.Request.ContentType = MultipartContentType; |
| 263 | + context.Request.Body = new NonSeekableReadStream(formContent.ToArray()); |
| 264 | + |
| 265 | + IFormFeature formFeature = new FormFeature(context.Request, new FormOptions() { BufferBody = bufferRequest, ValueCountLimit = 2 }); |
| 266 | + context.Features.Set<IFormFeature>(formFeature); |
| 267 | + |
| 268 | + var exception = await Assert.ThrowsAsync<InvalidDataException> (() => context.Request.ReadFormAsync()); |
| 269 | + Assert.Equal(exception.Message, "Form value count limit 2 exceeded."); |
| 270 | + } |
| 271 | + |
| 272 | + [Theory] |
| 273 | + [InlineData(true)] |
| 274 | + [InlineData(false)] |
| 275 | + public async Task ReadFormAsync_ValueCountLimitExceededWithFiles_Throw(bool bufferRequest) |
| 276 | + { |
| 277 | + var formContent = new List<byte>(); |
| 278 | + formContent.AddRange(Encoding.UTF8.GetBytes(MultipartFormFile)); |
| 279 | + formContent.AddRange(Encoding.UTF8.GetBytes(MultipartFormFile)); |
| 280 | + formContent.AddRange(Encoding.UTF8.GetBytes(MultipartFormFile)); |
| 281 | + formContent.AddRange(Encoding.UTF8.GetBytes(MultipartFormEnd)); |
| 282 | + |
| 283 | + |
| 284 | + var context = new DefaultHttpContext(); |
| 285 | + var responseFeature = new FakeResponseFeature(); |
| 286 | + context.Features.Set<IHttpResponseFeature>(responseFeature); |
| 287 | + context.Request.ContentType = MultipartContentType; |
| 288 | + context.Request.Body = new NonSeekableReadStream(formContent.ToArray()); |
| 289 | + |
| 290 | + IFormFeature formFeature = new FormFeature(context.Request, new FormOptions() { BufferBody = bufferRequest, ValueCountLimit = 2 }); |
| 291 | + context.Features.Set<IFormFeature>(formFeature); |
| 292 | + |
| 293 | + var exception = await Assert.ThrowsAsync<InvalidDataException> (() => context.Request.ReadFormAsync()); |
| 294 | + Assert.Equal(exception.Message, "Form value count limit 2 exceeded."); |
| 295 | + } |
| 296 | + |
246 | 297 | [Theory]
|
247 | 298 | // FileBufferingReadStream transitions to disk storage after 30kb, and stops pooling buffers at 1mb.
|
248 | 299 | [InlineData(true, 1024)]
|
@@ -313,10 +364,7 @@ private Stream CreateMultipartWithFormAndFile(Stream fileContents)
|
313 | 364 | {
|
314 | 365 | var stream = new MemoryStream();
|
315 | 366 | var header =
|
316 |
| -"--WebKitFormBoundary5pDRpGheQXaM8k3T\r\n" + |
317 |
| -"Content-Disposition: form-data; name=\"description\"\r\n" + |
318 |
| -"\r\n" + |
319 |
| -"Foo\r\n" + |
| 367 | +MultipartFormField + |
320 | 368 | "--WebKitFormBoundary5pDRpGheQXaM8k3T\r\n" +
|
321 | 369 | "Content-Disposition: form-data; name=\"myfile1\"; filename=\"temp.html\"\r\n" +
|
322 | 370 | "Content-Type: text/html\r\n" +
|
|
0 commit comments