问题
Problem description:
I have an HttpListener
within my C# program that takes a POST request with a posted file (jpg, doc, zip or alike). I am sending and receiving the file on the same Windows machine.
I took the code from https://stackoverflow.com/a/8468520/241475 (coming from the Java world, I'm fairly new to C#/.Net), which is said to just be a proof of concept, and the upload and storing of data on the server side almost works fine, except that the stored files is always 2 bytes larger than the original.
This does not matter for jpg, doc or single zip files - I can still open them and they display fine - but when I upload a zip file that is part of a multi-volume zip, unzipping usually fails for one file inside the zip, while the rest gets unzipped fine.
Example:
In this example, you can see the original file (import_filesystem.kmumitkst.z01.ORIGINAL
), which was 10485760
bytes large, which I posted to my HttpListener and which stored the version named import_filesystem.kmumitkst.z01
, which is 10485762
bytes large.
When I then unzip it via WinRar, it tells me that the CRC/checksum isn't correct and one file in it is corrupt due to these two extra bytes.
Code:
This is the code storing the received file:
while (_listener.IsListening)
{
ThreadPool.QueueUserWorkItem((c) =>
{
var ctx = c as HttpListenerContext;
SaveFile(ctx.Request.ContentEncoding, GetBoundary(ctx.Request.ContentType),
ctx.Request.InputStream, targetFilePath);
...
}
}
// =====================================
private static void SaveFile(Encoding enc, String boundary, Stream input, string targetPath)
{
Byte[] boundaryBytes = enc.GetBytes(boundary);
Int32 boundaryLen = boundaryBytes.Length;
using (FileStream output = new FileStream(targetPath, FileMode.Create, FileAccess.Write))
{
Byte[] buffer = new Byte[1024];
Int32 len = input.Read(buffer, 0, 1024);
Int32 startPos = -1;
// Find start boundary
while (true)
{
if (len == 0)
{
throw new Exception("Start Boundaray Not Found");
}
startPos = IndexOf(buffer, len, boundaryBytes);
if (startPos >= 0)
{
break;
}
else
{
Array.Copy(buffer, len - boundaryLen, buffer, 0, boundaryLen);
len = input.Read(buffer, boundaryLen, 1024 - boundaryLen);
}
}
// Skip four lines (Boundary, Content-Disposition, Content-Type, and a blank)
for (Int32 i = 0; i < 4; i++)
{
while (true)
{
if (len == 0)
{
throw new Exception("Preamble not Found.");
}
startPos = Array.IndexOf(buffer, enc.GetBytes("\n")[0], startPos);
if (startPos >= 0)
{
startPos++;
break;
}
else
{
len = input.Read(buffer, 0, 1024);
}
}
}
Array.Copy(buffer, startPos, buffer, 0, len - startPos);
len = len - startPos;
while (true)
{
Int32 endPos = IndexOf(buffer, len, boundaryBytes);
if (endPos >= 0)
{
if (endPos > 0) output.Write(buffer, 0, endPos);
break;
}
else if (len <= boundaryLen)
{
throw new Exception("End Boundaray Not Found");
}
else
{
output.Write(buffer, 0, len - boundaryLen);
Array.Copy(buffer, len - boundaryLen, buffer, 0, boundaryLen);
len = input.Read(buffer, boundaryLen, 1024 - boundaryLen) + boundaryLen;
}
}
}
}
private static String GetBoundary(String ctype)
{
return "--" + ctype.Split(';')[1].Split('=')[1];
}
private static Int32 IndexOf(Byte[] buffer, Int32 len, Byte[] boundaryBytes)
{
for (Int32 i = 0; i <= len - boundaryBytes.Length; i++)
{
Boolean match = true;
for (Int32 j = 0; j < boundaryBytes.Length && match; j++)
{
match = buffer[i + j] == boundaryBytes[j];
}
if (match)
{
return i;
}
}
return -1;
}
Question:
Where do these two extra bytes come from? Regardless of what kind of file or file size I sent, it's always exactly 2 bytes too much.
Is there any other way to save a received file through the HttpListener
? Thanks for any hint.
回答1:
Found the solution, had to change
while (true)
{
Int32 endPos = IndexOf(buffer, len, boundaryBytes);
if (endPos >= 0)
{
if (endPos > 0) output.Write(buffer, 0, endPos);
break;
}
to
while (true)
{
Int32 endPos = IndexOf(buffer, len, boundaryBytes);
if (endPos >= 0)
{
if (endPos > 0) output.Write(buffer, 0, endPos-2);
break;
}
adding a -2
to the endPos
, to avoid extra line break at the end.
来源:https://stackoverflow.com/questions/37744879/c-sharp-httplistener-storing-posted-file-is-always-2-byte-larger-than-original