一、HTTP协议简介
超文本传输协议(Hypertext Transfer Protocol,简称HTTP)是应用层协议,自 1990 年起,HTTP 就已经被应用于 WWW 全球信息服务系统。
HTTP 是一种请求/响应式的协议。一个客户机与服务器建立连接后,发送一个请求给服务器;服务器接到请求后,给予相应的响应信息。
HTTP 的第一版本 HTTP/0.9是一种简单的用于网络间原始数据传输的协议;
HTTP/1.0由 RFC 1945 定义 ,在原 HTTP/0.9 的基础上,有了进一步的改进,允许消息以类 MIME 信息格式存 在,包括请求/响应范式中的已传输数据和修饰符等方面的信息;
HTTP/1.1(RFC2616) 的要求更加严格以确保服务的可靠性,增强了在HTTP/1.0 没有充分考虑到分层代理服务器、高速缓冲存储器、持久连接需求或虚拟主机等方面的效能;
安全增强版的 HTTP (即S-HTTP或HTTPS),则是HTTP协议与安全套接口层(SSL)的结合,使HTTP的协议数据在传输过程中更加安全
二、HTTP请求
http请求由三部分组成,分别是:请求行、消息报头、请求正文
请求行以一个方法符号开头,以空格分开,后面跟着请求的URI和协议的版本,格式如下:
Method Request-URI HTTP-Version CRLF 其中:
Method表示请求方法;
Request-URI是一个统一资源标识符;
HTTP-Version表示请求的HTTP协议版本;
CRLF表示回车和换行(除了作为结尾的CRLF外,不允许出现单独的CR或LF字符)。
http请求方法有多种,常见的有如下几个(请求方法名全为大写字母)
POST 在Request-URI所标识的资源后附加新的数据
HEAD 请求获取由Request-URI所标识的资源的响应消息报头
PUT 请求服务器存储一个资源,并用Request-URI作为其标识
DELETE 请求服务器删除Request-URI所标识的资源
TRACE 请求服务器回送收到的请求信息,主要用于测试或诊断
CONNECT 保留将来使用
OPTIONS 请求查询服务器的性能,或者查询与资源相关的选项和需求
下面是用于HTTP请求中的常用请求头字段:
Accept:用于高速服务器,客户机支持的数据类型
Accept-Charset:用于告诉服务器,客户机采用的编码格式
Accept-Encoding:用于告诉服务器,客户机支持的数据压缩格式
Accept-Language:客户机的语言环境
Host:客户机通过这个头高速服务器,想访问的主机名
If-Modified-Since:客户机通过这个头告诉服务器,资源的缓存时间
Referer:客户机通过这个头告诉服务器,它是从哪个资源来访问服务器的(防盗链)
User-Agent:客户机通过这个头告诉服务器,客户机的软件环境
Cookie:客户机通过这个头可以向服务器带数据
Connection:处理完这次请求后是否断开连接还是继续保持连接
Date:当前时间值
HTTP响应头:
Location:这个头配合302状态码使用,用于告诉客户找谁。
Server:服务器通过这个头告诉浏览器服务器的类型。
Content-Encoding:服务器通过这个头告诉浏览器数据的压缩格式。
Content-Length:服务器通过这个头告诉浏览器回送数据的长度
Content-Type:服务器通过这个头告诉浏览器回送数据的类型
Last-Modified:告诉浏览器当前资源的最后缓存时间
Refresh:告诉浏览器隔多久刷新一次
Content-Disposition:告诉浏览器以下载方式打开数据
Transfer-Encoding:告诉浏览器数据的传送格式
ETag:缓存相关的头
后面三种禁止浏览器缓存的头字段:
Expires:告诉浏览器把回送的资源缓存多长时间 -1或0则是不缓存
Cache-Control:no-cache
Pragma:no-cache
服务器通过以上两个头,也就是控制浏览器不要缓存数据
实体内容:代表服务器向客户端回送的数据
下面是HTTP GET 请求的请求头:
1 //请求url:http://down.360safe.com/inst.exe 2 3 /*Request*/ 4 HEAD /inst.exe HTTP/1.1\r\n" 5 "Host: down.360safe.com\r\n" 6 "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13\r\n" 7 "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" 8 "Accept-Language: zh-cn,zh;q=0.5\r\n" 9 "Accept-Encoding: gzip,deflate\r\n" 10 "Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7\r\n" 11 "Connection: close\r\n" 12 "\r\n 13 14 /*Reponse*/ 15 HTTP/1.1 200 OK 16 Server: nginx 17 Date: Sat, 23 Jul 2016 07:28:11 GMT 18 Content-Type: application/octet-stream 19 Content-Length: 1430256 20 Last-Modified: Fri, 22 Jan 2016 14:49:14 GMT 21 Connection: close 22 Expires: Sat, 23 Jul 2016 15:28:11 GMT 23 Cache-Control: max-age=28800 24 Accept-Ranges: bytes
三、组装HTTP HEAD报文
下面使我们自己组包HEAD报文从原站取head,下面贴出代码
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <stdbool.h> 5 #include <sys/socket.h> 6 #include <sys/types.h> 7 #include <netinet/in.h> 8 #include <unistd.h> 9 #include <net/if.h> 10 #include <netdb.h> //gethostbyname 11 12 #define STATUS_OK 0 13 #define STATUS_NOK 1 14 #define BUFF_MAX_LEN 1024 15 #define HOST_IP_LEN 32 16 17 #define HTTP_HEAD 18 "HEAD /%s HTTP/1.1\r\n" 19 "Host: %s\r\n" 20 "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13\r\n" 21 "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" 22 "Accept-Language: zh-cn,zh;q=0.5\r\n" 23 "Accept-Encoding: gzip,deflate\r\n" 24 "Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7\r\n" 25 "Connection: close\r\n" 26 "\r\n" 27 28 int getIPbyDomain(const char* domain, char* ip); 29 int parse_http_url(const char *url, char *domain, char *header); 30 31 /********************************************************** 32 * get host ip by domain 33 **********************************************************/ 34 int getIPbyDomain(const char* domain, char* ip) 35 { 36 struct hostent *answer; 37 38 answer = gethostbyname(domain); 39 if (NULL == answer) 40 { 41 return STATUS_NOK; 42 } 43 if (answer->h_addr_list[0]) 44 inet_ntop(AF_INET, (answer->h_addr_list)[0], ip, 16); 45 else 46 return STATUS_NOK; 47 return STATUS_OK; 48 } 49 50 /********************************************************** 51 * Send a http package to detect network connecting status 52 **********************************************************/ 53 int parse_http_url(const char *url, char *domain, char *header) 54 { 55 char *ptr = NULL; 56 char *host = NULL; 57 char *head = NULL; 58 char buff[BUFF_MAX_LEN] = {0}; 59 60 if (NULL == url || NULL == domain || NULL == header) 61 return STATUS_NOK; 62 63 memset(buff, 0, sizeof(buff)); 64 strcpy(buff, url); 65 66 host = strtok(buff + 7, "/"); 67 head = strtok(NULL, "\0"); 68 69 if (NULL == host) 70 return STATUS_NOK; 71 if (NULL == head) 72 head = "/"; 73 74 strcpy(domain, host); 75 strcpy(header, head); 76 77 return STATUS_OK; 78 } 79 80 int http_head_request(const char *url) 81 { 82 char *p = NULL; 83 unsigned int dport = 80; 84 int fd, oneopt = 1; 85 char buf[BUFF_MAX_LEN] = {0}; 86 char data[BUFF_MAX_LEN * 2] = {0}; 87 char host[BUFF_MAX_LEN] = {0}; 88 char head[BUFF_MAX_LEN] = {0}; 89 char hostip[HOST_IP_LEN] = {0}; 90 struct timeval timeout = {2,0}; 91 struct sockaddr_in client; 92 struct hostent *hptr; 93 struct in_addr addr; 94 95 if (url == NULL) 96 return STATUS_NOK; 97 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 98 return STATUS_NOK; 99 100 memset(&client, 0, sizeof(client)); 101 if (STATUS_NOK == parse_http_url(url, host, head)) 102 return STATUS_NOK; 103 104 if (getIPbyDomain(host, hostip) != STATUS_OK) 105 { 106 close(fd); 107 return STATUS_NOK; 108 } 109 110 client.sin_family = AF_INET; 111 client.sin_port = htons(dport); 112 client.sin_addr.s_addr = inet_addr(hostip); 113 114 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt)) < 0 || 115 setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(struct timeval)) < 0 || 116 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval)) < 0) 117 { 118 close(fd); 119 return STATUS_NOK; 120 } 121 122 if (connect(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) < 0) 123 { 124 close(fd); 125 return STATUS_NOK; 126 } 127 128 sprintf(data, HTTP_HEAD, head, host); 129 if (send(fd, (void*)data, strlen(data), 0) < 0) 130 { 131 close(fd); 132 return STATUS_NOK; 133 } 134 printf("-------------Request-----------------\n"); 135 printf("%s\n", data); 136 137 if (recv(fd, buf, sizeof(buf), 0) < 0 ) 138 { 139 close(fd); 140 return STATUS_NOK; 141 } 142 printf("-------------Reponse-----------------\n"); 143 printf("%s\n", buf); 144 145 close(fd); 146 return STATUS_OK; 147 } 148 149 int main(int argc, char **argv) 150 { 151 if (argc < 2) { 152 printf("using %s <url>\n", argv[0]); 153 return -1; 154 } 155 http_head_request(argv[1]); 156 157 return 0; 158 }
运行结果如下:
1 [[email protected]]# ./test http://down.360safe.com/inst.exe 2 3 -------------Request----------------- 4 HEAD /inst.exe HTTP/1.1 5 Host: down.360safe.com 6 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 7 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 8 Accept-Language: zh-cn,zh;q=0.5 9 Accept-Encoding: gzip,deflate 10 Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7 11 Connection: close 12 13 -------------Reponse----------------- 14 HTTP/1.1 200 OK 15 Server: nginx 16 Date: Sat, 23 Jul 2016 07:56:13 GMT 17 Content-Type: application/octet-stream 18 Content-Length: 1430256 19 Last-Modified: Fri, 22 Jan 2016 14:49:16 GMT 20 Connection: close 21 Expires: Sat, 23 Jul 2016 15:56:13 GMT 22 Cache-Control: max-age=28800 23 Accept-Ranges: bytes
GET方法与HEAD相同,只是将method改为GET,其他内容都一样
GET: 请求指定的页面信息,并返回实体主体。
HEAD: 只请求页面的首部。
下面贴几中HTTP 常见的返回状态
200:表示成功,正常结果;
302:表示重定向,转到别的站点;
304:表示未修改;
404:表示找不到资源;
500:表示内部服务器错误;