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

本文关键字:偶尔 出错 C#HTTP 服务器 简单 | 更新日期: 2023-09-27 18:06:48

对于一些实验,在这里使用简单的HTTP服务器代码

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

示例代码:

输出流初始化:

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

HTTP获取的处理:

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));   
              }

对于我测试过的大多数文件来说,内容长度是正确的。然而,当使用HTTP调试工具Fiddler进行测试时,有时会在Content-Length上报告违反协议的情况。

例如fiddler说:

请求计数:1发送的字节数:303(标头:303;正文:0(接收的字节数:29847(标头:224;正文:29623(

因此内容长度应为29623。但是生成的HTTP头是

Content-Length: 29617

我保存了Fiddler的HTTP内容,并明显地比较了文件,没有注意到任何差异。然后将它们加载到BeyondCompare Hex compare中,这样的文件有几个问题:

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。

我通过用字节序列修改文件的部分内容,使文件的内容长度正确。在文件的三个部分中进行了更改:

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

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

根据粘贴的字节数,这里似乎出现了一些问题。首先,您的输入文件(0D 0A(中的CRLF似乎正在被转换为LF(0A(。其次,当将文件读取到stringWrite将字符串发送到HTTP客户端时,字符编码似乎正在发生变化。

HTTP内容长度表示流中的字节数,而字符串。长度提供字符串中的字符数。除非您的文件只使用前128个ASCII字符(这排除了非英语字符以及特殊的windows-1252字符,如欧元符号(,否则该字符串不太可能出现。长度将完全等于UTF-8或ISO-8859-1编码的字符串的长度。

如果在将字符串发送到客户端之前将其转换为byte[],则可以获得"true"内容长度。然而,如果你没有使用正确的编码读取文件,你仍然会收到混乱的文本。(无论是否指定编码,在将文件读取为Unicode字符的string时都会发生转换。(

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