基于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
专注于高并发网络和大型网站架规划设计, 提供.NET平台下高吞吐的网络通讯应用技术咨询和支持
开源多台平通讯组件
个性化网站信息收录和订阅平台
c#组件设计交流群:47164588
c# socket :136485198 微博http://weibo.com/ikende
开源多台平通讯组件
个性化网站信息收录和订阅平台
c#组件设计交流群:47164588
c# socket :136485198 微博http://weibo.com/ikende