HTTP协议解析及C/C++代码实现

超文本传输协议 (HTTP) 是分布式、协作、超媒体信息系统的应用层协议。 这是自 1990 年以来万维网数据通信的基础。HTTP 是一种通用且无状态的协议,它可以用于其他目的,也可以使用其请求方法、错误代码和标头的扩展。

基本上,HTTP 是一种基于 TCP/IP 的通信协议,用于通过 Web 传递 HTML 文件、图像文件、查询结果等数据。 它为计算机之间的通信提供了一种标准化的方式。 HTTP 规范指定了客户端请求的数据如何发送到服务器,以及服务器如何响应这些请求。

HTTP客户端和服务器通信

客户端和服务器通过交换单独的消息(而不是数据流)进行通信。 客户端(通常是 Web 浏览器)发送的消息称为请求,服务器发送的作为应答的消息称为响应。

HTTP协议解析及C/C++代码实现_第1张图片

HTTP通过 TCP 或 TLS 加密的 TCP 连接发送的应用层协议,尽管理论上可以使用任何可靠的传输协议。 由于其可扩展性,它不仅用于获取超文本文档,还用于获取图像和视频或将内容发布到服务器,例如 HTML 表单结果。 HTTP 还可用于获取部分文档以按需更新网页。

HTTP 和 连接

连接是在传输层控制的,因此基本上超出了 HTTP 的范围。 HTTP 不要求底层传输协议是基于连接的;

它只要求它是可靠的,或者不丢失消息。在 Internet 上最常见的两种传输协议中,TCP 是可靠的,而 UDP 则不是。因此,HTTP 依赖于基于连接的 TCP 标准。

在客户端和服务器可以交换 HTTP 请求/响应对之前,它们必须建立 TCP 连接,这个过程需要多次往返。

HTTP协议解析及C/C++代码实现_第2张图片
HTTP/1.0 的默认行为是为每个 HTTP 请求/响应对打开一个单独的 TCP 连接。当多个请求连续发送时,这比共享单个 TCP 连接效率低。

HTTP 消息

HTTP/1.1 及更早版本中定义的 HTTP 消息是人类可读的。 在 HTTP/2 中,这些消息被嵌入到二进制结构中,即一个帧,允许像压缩头和多路复用这样的优化。 即使在这个版本的 HTTP 中只发送原始 HTTP 消息的一部分,每个消息的语义都不会改变,客户端会(实际上)重构原始 HTTP/1.1 请求。 因此,理解 HTTP/1.1 格式的对 HTTP/2 消息很有用。

HTTP 消息有两种类型,请求和响应,每种都有自己的格式。

HTTP请求消息

请求由以下元素组成:

HTTP协议解析及C/C++代码实现_第3张图片

HTTP 方法,通常是 GET、POST 之类的动词或 OPTIONS 或 HEAD 之类的名词,用于定义客户端想要执行的操作。 通常,客户端想要获取资源(使用 GET)或发布 HTML 表单的值(使用 POST),但在其他情况下可能需要更多操作。

要获取的资源的路径; 从上下文中明显的元素中剥离的资源的 URL。

HTTP响应消息

HTTP协议解析及C/C++代码实现_第4张图片
响应由以下元素组成:

他们遵循的 HTTP 协议的版本。
状态码,指示请求是否成功以及原因。
状态消息,状态代码的非权威简短描述。
HTTP 标头,例如用于请求的标头。
可选地,包含获取的资源的主体。

HTTP 状态

一些常见的 HTTP 状态代码包括:

 200 - 请求成功(网页存在)
 301 - 永久移动(通常转发到新 URL)
 401 - 未经授权的请求(需要授权)
 403 - 禁止(不允许访问页面或目录)
 500 - 内部服务器错误(通常由不正确的服务器配置引起)

HTTP协议解析及C/C++代码实现

...
void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{

    ...

	/* print source and destination IP addresses */
	printf("       From: %s\n", inet_ntoa(ip->ip_src));
	printf("         To: %s\n", inet_ntoa(ip->ip_dst));
	
	/* determine protocol */	
	switch(ip->ip_p) 
	{
		case IPPROTO_TCP:
			printf("   Protocol: TCP\n");
			break;
		case IPPROTO_UDP:
			printf("   Protocol: UDP\n");
			break;
		case IPPROTO_ICMP:
			printf("   Protocol: ICMP\n");
			return;
		case IPPROTO_IP:
			printf("   Protocol: IP\n");
			return;
		default:
			printf("   Protocol: unknown\n");
			return;
	}
	
	/*
	 *  OK, this packet is TCP.
	 */
	
	/* define/compute tcp header offset */
	if(ip->ip_p == IPPROTO_TCP)
	{
        ...
	
		printf("   Src port: %d\n", ntohs(tcp->th_sport));
		printf("   Dst port: %d\n", ntohs(tcp->th_dport));
		int sport = ntohs(tcp->th_sport);
		int dport = ntohs(tcp->th_dport);

        ...
		if (size_payload > 0) 
		{
			printf("   Payload (%d bytes):\n", size_payload);
			//print_payload(payload, size_payload);
		
            if ((sport == 80) || (dport == 80))
			{
				printf("   HTTP prase:\n");
				prase_http(payload, size_payload);
			}
			else if(sport == 443 || dport == 443)
			{
				printf("   SSL/TLS prase:\n");
				prase_ssl_tls(payload, size_payload);
			}
		}
	}
	...

}

int main(int argc, char *argv[])
{
    	
	char errbuf[100];
	pcap_t *desc = 0;
    char *filename = argv[1];
    if (argc != 2)
    {
        printf("usage: ./dissect_http [pcap file]\n");
        return -1;
    }

    printf("ProcessFile: process file: %s\n", filename);
    if ((desc = pcap_open_offline(filename, errbuf)) == NULL)
    {   
        printf("pcap_open_offline: %s error!\n", filename);
        return -1; 
    }   	
	
	
    pcap_loop(desc, -1, got_packet, NULL);

    pcap_close(desc);
    return 0;
}

运行结果:

HTTP协议解析及C/C++代码实现_第5张图片

HTTP协议解析及C/C++代码实现_第6张图片HTTP协议解析及C/C++代码实现_第7张图片

总结

HTTP 是一种易于使用的可扩展协议。 客户端-服务器结构与添加标头的能力相结合,允许 HTTP 与 Web 的扩展功能一起发展。

尽管 HTTP/2 通过在帧中嵌入 HTTP 消息来提高性能增加了一些复杂性,但消息的基本结构自 HTTP/1.0 以来一直保持不变。 会话流保持简单,允许使用简单的 HTTP 消息监视器对其进行调查和调试。

以“http://”开头的 URL 通过标准超文本传输​​协议访问,默认使用端口 80。以“https://”开头的 URL 通过安全的 HTTPS 连接访问,通常使用端口 443。

欢迎关注微信公众号【程序猿编码】,需要HTTP协议解析完整源码的添加本人微信号(c17865354792)

参考:
RFC1945、RFC2616、RFC2660

你可能感兴趣的:(网络协议,http,c语言,c++,HTTP,HTTP协议)