目录
一、HTTP基本概念
1、HTTP是什么
2、HTTP客户端是什么
3、HTTP消息结构
4、服务器响应信息
二、相关概念
1、网址 URL
2、IP地址
3、域名
4、域名与IP关系
5、域名解析
6、DNS
三、设计请求、响应类基本数据结构
1、请求类定义
2、响应类定义
一、HTTP基本概念
1、HTTP是什么
HTTP(HyperText Transfer Protocol)是一种用于从互联网服务器传输超文本到本地浏览器的传输协议。它是一个应用层协议,是一种发布和接收HTML页面的标准。
2、HTTP客户端是什么
HTTP客户端是一个应用程序,用于发送HTTP请求并接收响应。它可以是一个Web浏览器,如Google Chrome或Mozilla Firefox,也可以是一个命令行工具,如curl或wget。
3、HTTP消息结构
HTTP消息由请求行、请求头、空行和请求体4部分组成。
1). 请求行:包含请求方法、URL和HTTP协议版本;
2). 请求头:包含客户端信息、内容信息等;
3). 空行:用来分隔请求头和请求体;
4). 请求体:包含客户端发送的数据。
消息请求实例如下:
POST / HTTP/1.1
Host: www.example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 32
Connection: keep-alive
Accept: */*
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: _ga=GA1.2.2045678901234567890; _gid=GA1.2.2045678901234567890; _gat_gtag_UA_1234567890_1=1
name=John&age=20
4、服务器响应信息
服务器响应由以下几部分组成:
1). 状态行:包含HTTP协议版本、状态码和描述信息,例如:HTTP/1.1 200 OK
2). 响应头:包含服务器端的一些信息,例如Content-Type、Content-Length等。
3). 空行:用来分隔响应头和响应体。
4). 响应体:包含客户端请求的资源内容。
响应消息实例如下:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 1234
Connection: keep-alive
<html>
<head>
<title>Example</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
二、相关概念
1、网址 URL
URL(Uniform Resource Locator)是一种资源定位符,用于定位互联网上的资源。
它是一个全球通用的字符串,可以用来标识一个特定的网页、图像、文件或其他资源。
一个完整的URL包括:
协议(Protocol)、域名(Domain Name)、端口号(Port Number)、路径(Path)和参数(Parameters)。
例如:https://www.example.com:8080/path/to/file?param1=value1¶m2=value2
2、IP地址
IP 地址(Internet Protocol Address)是一种用于在计算机网络中定位设备的地址。
它是一个32位的二进制数字,通常表示为4个以句号分隔的十进制数字(例如192.168.1.1)。
3、域名
IP 地址不好记忆,因此出现了域名(Domain Name)
4、域名与IP关系
IP 地址是一个由四个数字组成的字符串,用于标识计算机在 Internet 上的位置。而域名则是一个可以被人们记忆的名字,它可以把 IP 地址映射到一个可读性更强的名字上。
IP 地址与域名是一对多的关系。一个 IP 地址可以对应多个域名,但一个域名只有一个 IP 地址。
5、域名解析
域名虽然便于人们记忆,但机器之间互相只认识 IP 地址,它们之间的转换工作称为域名解析,由专门的域名解析服务器DNS完成。
6、DNS
DNS(Domain Name System)是一种用于将域名转换成IP地址的分布式数据库系统。它是一个分布式的、层次化的、可扩展的数据库,用于存储和检索域名与IP地址之间的映射关系。
三、设计请求、响应类基本数据结构
以下是我项目中使用的数据结构,只是为了帮助理解其中主要思想,并不一定适合别的项目。
1、请求类定义
typedef std::map<std::string,std::string> MAPSTRSTR;
class HTTPD_API CHttpRequest
{
char m_host[64];
char m_method[8];
char m_uri[1023];
char m_ssl;
MAPSTRSTR* m_map;
MAPSTRSTR* m_mParam;
public:
CHttpRequest() {
m_ssl=0;
m_map=m_mParam=0;
}
// host:port, GET|POST, /aaa/aaa.html?query_string
CHttpRequest(const char* host,const char* method,const char* uri) {
m_ssl=0;
m_map=m_mParam=0;
Set(host,method,uri);
}
~CHttpRequest() {
if(m_map) {
delete m_map;
m_map=0;
}
if(m_mParam) {
delete m_mParam;
m_mParam=0;
}
}
// http[s]://host:port/abc.html?query_string, GET|POST
void Set(const char* url,const char* method);
// host:port, GET|POST, /aaa/aaa.html?query_string
void Set(const char* host,const char* method,const char* uri) {
strcpyN(m_host,host,sizeof(m_host));
strcpyN(m_method,method,sizeof(m_method));
strcpyN(m_uri,uri,sizeof(m_uri));
}
int IsSsl() const { return m_ssl; }
void SetSsl(int ssl) { m_ssl = ssl; }
int GetHostPort(char* szHost, int size) const;
// header
void AddPair(const char* key,const char* v) {
if(!m_map) m_map=new MAPSTRSTR;
(*m_map)[key]=v;
}
// query_string
void AddParam(const char* key,const char* v) {
if(!m_mParam) m_mParam=new MAPSTRSTR;
(*m_mParam)[key]=v;
}
const char* Format(CBinBuf& req,const char* ctype,const char* data,int l);
const char* GetURL()
{
return m_uri;
}
const char* GetHost()
{
return m_host;
}
const char* Method()
{
return m_method;
}
};
// return
// 0: http
// 1: https
HTTPD_API int http_parse_hostport(const char* url, char* host, int hsize, int& port, char* uri, int usize);
void CHttpRequest::Set(const char* url,const char* method)
{
char host[128],uri[256];
int port;
int ssl = http_parse_hostport(url,host,sizeof(host),port,uri,sizeof(uri));
if(!method) method="GET";
char szHost[256];
if(port==80 || port==443) strcpy(szHost,host);
else sprintf(szHost,"%s:%d",host,port);
Set(szHost,method,uri);
m_ssl = ssl;
}
2、响应类定义
// when act as http client or http server.
class HTTPD_API CHttpResponse
{
MAPSTRSTR m_map;
#ifdef ENABLE_HTTP2
const char* FormatV2(int code,MAPSTRSTR& mheader,const char* data=0,int len=0,int bHead=0,uint64_t ctlen=0);
public:
CBinBuf m_v2Body;
#endif
public:
char m_v2;
CBinBuf m_bf;
public:
CHttpResponse(int v2=0) {
m_v2 = v2;
}
void AddPair(const char* key,const char* v) {
m_map[key]=v;
}
const char* Format(int code,const char* reason,int keepalive,const char* data=0,int len=0,int bHead=0,uint64_t ctlen=0);
const char* Format(int code,const char* reason,int keepalive,MAPSTRSTR& mheader,const char* data=0,int len=0,int bHead=0,uint64_t ctlen=0);
};
Format主要用于格式化响应信息
const char* CHttpResponse::Format(int code,const char* reason,int keepalive,MAPSTRSTR& mheader,const char* data,int len,int bHead,uint64_t ctlen)
{
if(!ctlen) ctlen=len;
#ifdef ENABLE_HTTP2
if(m_v2) {
return FormatV2(code, mheader, data, len, bHead, ctlen);
}
#endif
// Status-Line
m_bf.Format("HTTP/1.1 %03d %s\r\n",code,reason);
// Date
char szTm[32];
m_bf.AppendFormat("Date: %s\r\n",rfc1123_date(time(0),szTm));
// Server
m_bf.AppendFormat("Server: banhttpd/%s\r\n",g_httpd_ver);
m_bf.AppendFormat("X-Frame-Options: SAMEORIGIN\r\n");
if(keepalive) {
m_bf.Append("Connection: Keep-Alive\r\nKeep-Alive: timeout=5, max=100\r\n");
} else {
m_bf.Append("Connection: close\r\n");
}
// Content-Type
if(mheader.find("Content-Type")!=mheader.end()) {
m_bf.AppendFormat("Content-Type: %s\r\n",mheader["Content-Type"].c_str());
}
// Content-Length
m_bf.AppendFormat("Content-Length: %llu\r\n",ctlen);
for(MAPSTRSTR::iterator it=mheader.begin();it!=mheader.end();++it) {
if( strcmp(it->first.c_str(),"Content-Type")==0
|| strcmp(it->first.c_str(),"Content-Length")==0)
{
continue;
}
m_bf.AppendFormat("%s: %s\r\n",it->first.c_str(),it->second.c_str());
}
// end header
m_bf.Append("\r\n",2);
// body
if(!bHead) m_bf.Append(data,len);
m_bf.ReleaseBuffer();
return m_bf.GetPtr();
}