基于byte[]的HTTP协议头分析代码

基于byte[]的HTTP协议头分析代码

最近需要为组件实现一个HTTP的扩展包,所以简单地实现了HTTP协议分析。对于HTTP协议就不详细解说了网上的资料太丰富了,这里主要描述如何通过byte[]流分析出HTTP协议头信息。HTTP协议头有两个协议字符是比较重要的分别就是' '和':',前者要描述每个头信息的结束,而后则是属性名和属性值的分隔符号。

实现

由于并没有使用Stream来处理所以在分析的时候就不能使用ReadLine来的方便,只能通过分析byte来解决。估计有朋友会问直接把byte[]打包成Stream就方便了,其实主要是使用场问题,有可能一次过来的byte[]包括多个http请求。所以包装成stream用readline的方法成本高不划算。以下看下主体分析代码:

复制代码
 1         public bool Import(byte[] data, ref int offset, ref int count)
 2         {
 3             byte[] buffer = mBuffer;
 4             while (count > 0)
 5             {
 6                 buffer[mHeaderLength] = data[offset];
 7                 mHeaderLength++;
 8                 offset++;
 9                 count--;
10                 if (mHeaderLength >= HEADER_BUFFER_LENGT)
11                     throw new NetTcpException("header data too long!");
12                 if (mBuffer[mHeaderLength - 1] == mWrap[1] && mBuffer[mHeaderLength - 2] == mWrap[0])
13                 {
14                     if (Action == null)
15                     {
16                         Action = Encoding.UTF8.GetString(buffer, mStartIndex, mHeaderLength - mStartIndex - 2);
17                         mStartIndex = mHeaderLength;
18                     }
19                     else
20                     {
21                         if (mBuffer[mHeaderLength - 3] == mWrap[1] && mBuffer[mHeaderLength - 4] == mWrap[0])
22                         {
23                             if (mLastPropertyName != null)
24                             {
25                                 this[mLastPropertyName] = Encoding.UTF8.GetString(buffer, mStartIndex, mHeaderLength - mStartIndex - 2);
26                             }
27                             return true;
28                         }
29                         else
30                         {
31                             if (mLastPropertyName != null)
32                             {
33                                 this[mLastPropertyName] = Encoding.UTF8.GetString(buffer, mStartIndex, mHeaderLength - mStartIndex - 2);
34                                 mStartIndex = mHeaderLength;
35                                 mLastPropertyName = null;
36                             }
37                         }
38                     }
39                 }
40                 else if (mBuffer[mHeaderLength - 1] == mNameEof[0] && mLastPropertyName == null)
41                 {
42                     mLastPropertyName = Encoding.UTF8.GetString(buffer, mStartIndex, mHeaderLength - mStartIndex - 1);
43                     mStartIndex = mHeaderLength;
44                 }
45 
46             }
47             return false;
48 
49         }
复制代码

 代码比较简单,通过一次遍历buffer就把Http请求行为和相应用的头属性都分析出来的。由于一个byte[]有可能包括多个HTTP请求(特殊场景),所以参数上使用ref主要是通过外层这个byte[]是否有多个多header要处理。

单元测试

开发人员应该习惯写单元测试,好处是很明显就是实现的代码的可测性,如果可测性差那代码就要从设计上进行调整了。下面是针对以上代码的两种单元测试,主要测试分析代码在不同情况下是否可以良好地工作。
复制代码
 1 [TestMethod]
 2         public void HeaderImport()
 3         {
 4             string header = "Post
name:henry
email:

";
 5             byte[] data = Encoding.UTF8.GetBytes(header);
 6             int offset = 0;
 7             int count = data.Length;
 8             byte[] buffer = new byte[1024 * 4];
 9             HttpHeader hh = new HttpHeader(buffer);
10             if (hh.Import(data, ref offset, ref count))
11             {
12                 Assert.AreEqual(hh.RequestType, "Post");
13                 Assert.AreEqual(hh["name"], "henry");
14                 Assert.AreEqual(hh["email"], "");
15             }
16 
17         }
18 
19         [TestMethod]
20         public void HeaderImport1()
21         {
22             string header = "Post
name:henry
email:henryfan@msn.com

";
23             byte[] data = Encoding.UTF8.GetBytes(header);
24             int offset = 0;
25             int count = data.Length;
26             byte[] buffer = new byte[1024 * 4];
27             HttpHeader hh = new HttpHeader(buffer);
28 
29             if (hh.Import(data, ref offset, ref count))
30             {
31                 Assert.AreEqual(hh.RequestType, "Post");
32                 Assert.AreEqual(hh["name"], "henry");
33                 Assert.AreEqual(hh["email"], "henryfan@msn.com");
34                 hh = new HttpHeader(buffer);
35             }
36 
37 
38             header = "Get
name:henry
";
39             data = Encoding.UTF8.GetBytes(header);
40             offset = 0;
41             count = data.Length;
42             hh.Import(data, ref offset, ref count);
43 
44 
45             header = "email:henryfan@msn.com";
46             data = Encoding.UTF8.GetBytes(header);
47             offset = 0;
48             count = data.Length;
49             hh.Import(data, ref offset, ref count);
50 
51             header = "
";
52             data = Encoding.UTF8.GetBytes(header);
53             offset = 0;
54             count = data.Length;
55             hh.Import(data, ref offset, ref count);
56 
57             header = "

";
58             data = Encoding.UTF8.GetBytes(header);
59             offset = 0;
60             count = data.Length;
61 
62             if (hh.Import(data, ref offset, ref count))
63             {
64                 Assert.AreEqual(hh.RequestType, "Get");
65                 Assert.AreEqual(hh["name"], "henry");
66                 Assert.AreEqual(hh["email"], "henryfan@msn.com");
67             }
68 
69         }
70     }
复制代码

 HttpHeader完整代码

 View Code
原文地址:https://www.cnblogs.com/Leo_wl/p/3481306.html