-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Description
Steps to Reproduce
- Build MonoMultiPartRepro.csproj
- Run MonoMultiPartRepro.exe
MonoMultiPartBug.zip
Current Behavior
While self hosting a api and sending a http multipart request where the body boundary is not terminated by a CRLF pair the first part contains the body of the entire request. I have pulled out the System.Web code that is performing the boundary parsing in mono:
mono/mcs/class/System.Web/System.Web/HttpRequest.cs
Lines 2154 to 2224 in c5b88ec
| long MoveToNextBoundary () | |
| { | |
| long retval = 0; | |
| bool got_cr = false; | |
| int state = 0; | |
| int c = data.ReadByte (); | |
| while (true) { | |
| if (c == -1) | |
| return -1; | |
| if (state == 0 && c == LF) { | |
| retval = data.Position - 1; | |
| if (got_cr) | |
| retval--; | |
| state = 1; | |
| c = data.ReadByte (); | |
| } else if (state == 0) { | |
| got_cr = (c == CR); | |
| c = data.ReadByte (); | |
| } else if (state == 1 && c == '-') { | |
| c = data.ReadByte (); | |
| if (c == -1) | |
| return -1; | |
| if (c != '-') { | |
| state = 0; | |
| got_cr = false; | |
| continue; // no ReadByte() here | |
| } | |
| int nread = data.Read (buffer, 0, buffer.Length); | |
| int bl = buffer.Length; | |
| if (nread != bl) | |
| return -1; | |
| if (!CompareBytes (boundary_bytes, buffer)) { | |
| state = 0; | |
| data.Position = retval + 2; | |
| if (got_cr) { | |
| data.Position++; | |
| got_cr = false; | |
| } | |
| c = data.ReadByte (); | |
| continue; | |
| } | |
| if (buffer [bl - 2] == '-' && buffer [bl - 1] == '-') { | |
| at_eof = true; | |
| } else if (buffer [bl - 2] != CR || buffer [bl - 1] != LF) { | |
| state = 0; | |
| data.Position = retval + 2; | |
| if (got_cr) { | |
| data.Position++; | |
| got_cr = false; | |
| } | |
| c = data.ReadByte (); | |
| continue; | |
| } | |
| data.Position = retval + 2; | |
| if (got_cr) | |
| data.Position++; | |
| break; | |
| } else { | |
| // state == 1 | |
| state = 0; // no ReadByte() here | |
| } | |
| } | |
| return retval; | |
| } |
The First part of the Program outputs:
Part Length: 321
Value:text default
--9051914041544843365972754266
Content-Disposition: form-data; name="file1"; filename="a.txt"
Content-Type: text/plain
Content of a.txt.
--9051914041544843365972754266
Content-Disposition: form-data; name="file2"; filename="a.html"
Content-Type: text/html
<!DOCTYPE html><title>Content of a.html.</title>
Expected Behavior
I have identified the fix and have included it in the program as shown below:
Fixed MONO Implementation
Part Length: 12
Value:text default
Part Length: 18
Value:Content of a.txt.
Part Length: 49
Value:<!DOCTYPE html><title>Content of a.html.</title>
Here is the working .NET implementation which is also included in the program.
https://github.com/mono/mono/blob/c5b88ec4f323f2bdb7c7d0a595ece28dae66579c/mcs/class/referencesource/System.Web/MultipartContentParser.cs
NET Implementation
Part Length: 12
Value:text default
Part Length: 18
Value:Content of a.txt.
Part Length: 49
Value:<!DOCTYPE html><title>Content of a.html.</title>
On which platforms did you notice this
[x] macOS
[x] Linux
[ ] Windows
Version Used:
Mono JIT compiler version 6.4.0.208 (2019-06/07c23f2ca43 Wed Oct 2 04:52:23 EDT 2019)
Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
TLS:
SIGSEGV: altstack
Notification: kqueue
Architecture: amd64
Disabled: none
Misc: softdebug
Interpreter: yes
LLVM: yes(610)
Suspend: hybrid
GC: sgen (concurrent by default)