1 Star 0 Fork 0

beihangya/Linux

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
HttpServer.hpp 6.82 KB
一键复制 编辑 原始数据 按行查看 历史
beihangya 提交于 9个月前 . 测试HTTP的临时重定向
#pragma once
#include "Socket.hpp"
#include "Log.hpp"
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
static const int defaultport = 8082;
const std::string sep = "\r\n";
const std::string wwwroot = "./wwwroot"; // web 根目录
const std::string homepage = "index.html"; // 首页
class ThreadData
{
public:
ThreadData(int fd) : sockfd(fd) //,svr(s)
{
}
public:
int sockfd;
// HttpServer *svr;
};
class HttpRequest
{
public:
void Deserialize(std::string req)
{
// 用空格将req打散 ,提取报头和正文(有效载荷)
while (true)
{
// 提取报头
size_t pos = req.find(sep);
if (pos == std::string::npos)
break;
std::string temp = req.substr(0, pos);
if (temp.empty())
break;
req_header.push_back(temp);
req.erase(0, pos + sep.size());
}
// 提取正文
text = req;
}
void Parse() // 解析请求行 ,将 Method URL HTTP Version 解析出来
{
std::stringstream ss(req_header[0]);
//std::cout << "req_header[0]: " << req_header[0] << std::endl;
ss >> method >> url >> http_version; // method、url、http_version顺序不能颠倒
file_path = wwwroot;
if (url == "/" || url == "/index.html")
{
file_path += "/";
file_path += homepage; // ./wwwroot/index.html
}
else // 不是/ ,是/a/b/c.html的这种常规路径
file_path += url; // /a/b/c/d.html->./wwwroot/a/b/c/d.html
}
void DebugPrint()
{
for (auto &line : req_header)
{
std::cout << "--------------------------------" << std::endl;
std::cout << line << "\n\n";
}
std::cout << "method: " << method << std::endl;
std::cout << "url: " << url << std::endl;
std::cout << "http_version: " << http_version << std::endl;
std::cout << "file_path: " << file_path << std::endl;
std::cout << text << std::endl;
}
public:
std::vector<std::string> req_header; // 请求报头
std::string text; // 请求正文
// 解析之后的结果
std::string method;
std::string url;
std::string http_version;
std::string file_path; // ./wwwroot/a/b/c.html 2.png
// std::string suffix;
};
class HttpServer
{
public:
HttpServer(uint16_t port = defaultport) : port_(port)
{
}
~HttpServer()
{
}
public:
static std::string ReadHtmlContent(const std::string &htmlpath) // 打开htmlpath文件
{
std::ifstream in(htmlpath);
// 打开文件
if (!in.is_open())
return " ";
std::string content;
std::string line;
while (getline(in, line))
{
content += line;
}
in.close();
return content;
}
static void HandlerHttp(int sockfd)
{
char buffer[10240];
// 接受请求
ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0); // 与read函数类似
if (n > 0) // 接受成功
{
buffer[n] = 0; // 将buffer当成字符串处理
std::cout << buffer << std::endl; // 假设我们读取到的就是一个完整的,独立的http 请求
HttpRequest req;
// 将Http请求反序列化
req.Deserialize(buffer);
req.Parse();
// lg(Info, "DebugPrint sucess");
// req.DebugPrint() ;
// std::string url = "/a/a/b";
// std::string path = wwwroot;
// path += url; // ./wwwroot/a/a/b
// 构建响应
std::string text;
text = ReadHtmlContent(req.file_path);
// 打开文件失败
bool ok = true; // 标致位
// if(text.empty())
// {
// ok =false ;
// std::string err_html ;
// err_html= wwwroot ;
// err_html+="/" ;
// err_html += "err.html"; // ./wwwroot/err.html
// text= ReadHtmlContent(err_html );
// lg(Info , "./wwwroot/err.html sucess");
// }
if (text.empty())
{
ok = false;
std::string err_html = wwwroot;
err_html += "/";
err_html += "err.html";
text = ReadHtmlContent(err_html);
}
std::string response_line;
if (ok)
{
response_line = "HTTP/1.0 200 OK\r\n";
}
else
{
response_line = "HTTP/1.0 404 Not Found\r\n";
}
//测试302状态码
response_line = "HTTP/1.0 302 Found\r\n";
std::string response_header = "Content-Length:";
response_header += std::to_string(text.size()); // Content-Length:11
response_header += "\r\n";
response_header += "Location: https://www.qq.com\r\n";
std::string blank_line = "\r\n"; // 空行,表示头部和正文的分隔
std::string response = response_line;
response += response_header;
response += blank_line;
response += text;
// 返回响应
send(sockfd, response.c_str(), response.size(), 0); // send函数类似于write
}
close(sockfd);
}
// 不加static ,ThreadRun函数是类的成员函数 ,void *ThreadRun(HttpServer * this ,void *args)
// 与pthread_create的参数 ,void *(*start_routine) (void *) ,参数个数不一致
// 加了static,ThreadRun就不是类的成员函数
static void *ThreadRun(void *args)
{
pthread_detach(pthread_self());
ThreadData *td = (ThreadData *)args;
HandlerHttp(td->sockfd);
close(td->sockfd);
delete td;
return nullptr;
}
bool Start()
{
// 创建套接字
listensock_.Socket();
// 绑定端口
listensock_.Bind(port_);
// 监听
listensock_.Lisenten();
// 服务
for (;;)
{
// 服务器需要获取到客户端的连接请求
std::string clientip;
uint16_t clientport;
int sockfd = listensock_.Accept(&clientip, &clientport);
if (sockfd < 0)
continue;
lg(Info, " HttpServer.cc:get a new connect, sockfd: %d", sockfd);
// 线程
pthread_t tid;
ThreadData *td = new ThreadData(sockfd);
pthread_create(&tid, nullptr, ThreadRun, td);
}
}
private:
Sock listensock_; // 监听套接字
uint16_t port_;
};
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/beihangya/linux.git
git@gitee.com:beihangya/linux.git
beihangya
linux
Linux
master

搜索帮助