简单C#HTTP服务器上的内容长度偶尔会出错

时间:2016-09-13 23:56:38

标签: c# http character-encoding fiddler

对于某些实验,使用简单HTTP服务器代码here

在一个案例中,我希望它能够提供一些ANSI编码的文本配置文件。我知道此代码存在更多问题,但我目前唯一关注的是内容长度错误,但仅适用于某些文本文件。

示例代码:

输出流初始化:

outputStream = new StreamWriter(new BufferedStream(socket.GetStream()));

处理HTTP get:

public override void handleGETRequest(HttpProcessor p)
{

    if (p.http_url.EndsWith(".pac"))
    {
        string filename = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), p.http_url.Substring(1));
        Console.WriteLine(string.Format("HTTP request for : {0}", filename));
        if (File.Exists(filename))
        {
            FileInfo fi = new FileInfo(filename);
            DateTime lastWrite = fi.LastWriteTime;

            Stream fs = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
            StreamReader sr = new StreamReader(fs);
            string result = sr.ReadToEnd().Trim();
            Console.WriteLine(fi.Length);
            Console.WriteLine(result.Length);
            p.writeSuccess("application/x-javascript-config",result.Length,lastWrite);
            p.outputStream.Write(result);
            // fs.CopyTo(p.outputStream.BaseStream);
            p.outputStream.BaseStream.Flush();
            fs.Close();
        }
        else
        {
            Console.WriteLine("404 - FILE not found!");
            p.writeFailure();
        }
    }

}  

   public void writeSuccess(string content_type,long length,DateTime lastModified) {
            outputStream.Write("HTTP/1.0 200 OK\r\n");            
            outputStream.Write("Content-Type: " + content_type + "\r\n");
            outputStream.Write("Last-Modified: {0}\r\n", lastModified.ToUniversalTime().ToString("r"));
            outputStream.Write("Accept-Range: bytes\r\n");
            outputStream.Write("Server: FlakyHTTPServer/1.3\r\n");
            outputStream.Write("Date: {0}\r\n", DateTime.Now.ToUniversalTime().ToString("r"));
            outputStream.Write(string.Format("Content-Length: {0}\r\n\r\n", length));   
              }

对于我使用Content-Length测试的大多数文件都是正确的。但是,在使用HTTP调试工具Fiddler进行测试时,有时会在Content-Length上报告协议违规。

例如fiddler说:

请求数:1 发送的字节数:303(标题:303;正文:0) 收到的字节数:29,847(标题:224;正文:29,623)

所以Content-Length应该是29623.但生成的HTTP头是

Content-Length: 29617

我从Fiddler保存了HTTP内容的主体并且明显地比较了文件,无法发现任何差异。然后将它们加载到BeyondCompare Hex比较中,这样的文件有几个问题:

Original File: 2D 2D 96       20 2A 2F
HTTP Content : 2D 2D EF BF BD 20 2A 2F

Original File: 27 3B 0D 0A 09 7D 0D 0A 0D 0A 09
HTTP Content : 27 3B    0A 09 7D    0A    0A 09

我怀疑问题与编码有关但不完全确定。仅提供ANSI编码文件,不提供Unicode。

通过使用字节序列修改文件的部分,我使用正确的Content-Length使文件正确服务。在文件的3个部分中进行了此更改:

2D 2D 96 (--–) to 2D 2D 2D (---)

1 个答案:

答案 0 :(得分:4)

根据您粘贴的字节数,看起来这里有一些问题。首先,输入文件(0D 0A)中的CRLF似乎正在转换为LF(0A)。其次,看起来字符编码正在改变,无论是将文件读入string,还是将Write字符串写入HTTP客户端。

HTTP Content-Length表示流中的字节数,而string.Length表示字符串中的字符数。除非您的文件专门使用前128个ASCII字符(排除非英文字符以及特殊窗口-1252字符,如欧元符号),否则string.Length不太可能完全等于字符串的长度以UTF-8或ISO-8859-1编码。

如果您在将字符串发送到客户端之前将其转换为byte[],那么您将能够获得" true"内容长度。但是,如果您没有使用正确的编码读取文件,那么您仍然会遇到损坏的文本。 (无论您是否指定编码,在将文件读取为string个Unicode字符时都会发生转换。)

我强烈建议在Content-Type标头中指定字符集(例如application/x-javascript-config;charset=utf-8)。您的字符集是utf-8,utf-16,iso-8859-1,windows-1251等也无关紧要,只要它与转换字符串时使用的字符编码相同即可到一个字节[]。