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

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

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

实现

由于并没有使用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\r\nname:henry\r\nemail:\r\n\r\n";

 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\r\nname:henry\r\nemail:[email protected]\r\n\r\n";

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"], "[email protected]");

34                 hh = new HttpHeader(buffer);

35             }

36 

37 

38             header = "Get\r\nname:henry\r\n";

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:[email protected]";

46             data = Encoding.UTF8.GetBytes(header);

47             offset = 0;

48             count = data.Length;

49             hh.Import(data, ref offset, ref count);

50 

51             header = "\r";

52             data = Encoding.UTF8.GetBytes(header);

53             offset = 0;

54             count = data.Length;

55             hh.Import(data, ref offset, ref count);

56 

57             header = "\n\r\n";

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"], "[email protected]");

67             }

68 

69         }

70     }
复制代码

 HttpHeader完整代码

  View Code

 

你可能感兴趣的:(http协议)