上传图片
void UploadFile(struct evhttp_request* req, void* arg)
{
if (req == nullptr)
{
printf("input params is nullptr.\n");
return;
}
if (evhttp_request_get_command(req) == EVHTTP_REQ_OPTIONS) {
struct evbuffer* buf;
buf = evbuffer_new();
evbuffer_add_printf(buf, "111");
MyHttpServer* pService = MyHttpServer::GetInstance();
pService->SendReply((evhttp_request*)req, HTTP_OK, nullptr, buf);
return;
}
if (evhttp_request_get_command(req) == EVHTTP_REQ_POST)
{
struct evkeyvalq params = { 0 };
MyHttpServer* pService = MyHttpServer::GetInstance();
const char* path = pService->find_http_path(req, ¶ms);
string m_strPath = path;
if (m_strPath != "/Power/upload")
{
cout << "wrong path\n";
return;
}
int boundarylength = 0;
struct evkeyvalq http_query_post;
int buffer_data_len = EVBUFFER_LENGTH(req->input_buffer);
char* post_data = new char[buffer_data_len + 1];
memset(post_data, 0, buffer_data_len + 1);
memcpy(post_data, EVBUFFER_DATA(req->input_buffer), buffer_data_len);
string data1 = post_data;
string filename;
int nPos = 0;
smatch result;
//按逗号分割
stringstream subStrSplit(data1);
string temp;
vector<string>v;
//获取接口
while (getline(subStrSplit, temp, ';')) {
v.push_back(temp);
}
const std::string strValueReg = "\"(.*)\"";
//提取值
for (auto& it : v) {
nPos = it.find("=");
if (nPos != string::npos) {
string strLeft = it.substr(0, nPos);
string strRight = it.substr(nPos + 1, it.length() - nPos);
regex reg_Realm(strValueReg);
if (regex_search(strRight, result, reg_Realm)) {
if (strLeft.find("filename") != string::npos) {
filename = result[1];
}
}
}
}
//获取文件名称filename="a"
filename = UTF8ToGBK(filename.c_str());
int var = 0;
int count = 0;
char* data = NULL;
for (var = 0; var < buffer_data_len; var++)
{
if (post_data[var] == '\n')
{
++count;
if (count == 4)// 找到文件头
{
data = &post_data[var];
break;
}
if (count == 1) {
boundarylength = var;
}
}
}
FILE* file = fopen(filename.c_str(), "wb+");//&fname_buf[10]这个是提取的文件名
if (file == NULL) //判断如果文件指针为空
{
printf("File cannot open! ");
}
else {
int fileLen = buffer_data_len - var - 1 - boundarylength;
fwrite(data + 1, 1, fileLen, file);
fclose(file);
}
delete[] post_data;
struct evbuffer* evbuf = evbuffer_new();
if (!evbuf) {
printf("create evbuffer failed!\n");
return;
}
Json::Value rootRes;
rootRes["code"] = Json::Value(200);
rootRes["msg"] = Json::Value("上传成功");
rootRes["url"] = Json::Value(filename.c_str());
struct evbuffer* buf;
buf = evbuffer_new();
string strJson = rootRes.toStyledString();
evbuffer_add_printf(buf, GBKToUTF8(strJson.c_str()).c_str());
pService = MyHttpServer::GetInstance();
pService->SendReply((evhttp_request*)req, HTTP_OK, nullptr, buf);
}
}
图片上传的原理
post传输图片文件的原始报文如下,首先通过正则表达式匹配找到文件名。找到文件名后定位图片文件流的开始。代码是通过搜索换行符来确定图片文件流的位置。从图片可以看出,从Boundary开始,第四个换行符+1就是图片流的起点。图片流的长度是req->input_buffer的长度减去Boundary到第四个换行符的长度减去尾部的Boundary的长度。这个长度即是图片流的实际长度。
图片下载
evhttp_set_gencb(httpd, DownLoadFile, NULL);
void DownLoadFile(struct evhttp_request* req, void* arg)
{
if (req == nullptr)
{
printf("input params is nullptr.\n");
return;
}
if (evhttp_request_get_command(req) == EVHTTP_REQ_OPTIONS) {
struct evbuffer* buf;
buf = evbuffer_new();
evbuffer_add_printf(buf, "111");
MyHttpServer* pService = MyHttpServer::GetInstance();
pService->SendReply((evhttp_request*)req, HTTP_OK, nullptr, buf);
}
if (evhttp_request_get_command(req) == EVHTTP_REQ_GET)
{
struct evkeyvalq params = { 0 };
MyHttpServer* pService = MyHttpServer::GetInstance();
const char* path = pService->find_http_path(req, ¶ms);
string m_strPath = UTF8ToGBK(acl_url_decode(path));
string filename = m_strPath.substr(1, m_strPath.length() - 1);
if (!m_strPath.empty())
{
FILE* fp = fopen(filename.c_str(), "rb");
if (!fp)
{
evhttp_send_reply(req, HTTP_NOTFOUND, "", 0);
return;
}
char buf[1024] = { 0 };
evbuffer* outbuf = evhttp_request_get_output_buffer(req);
for (;;)
{
int len = fread(buf, 1, 1024, fp);
if (len <= 0)break;
evbuffer_add(outbuf, buf, len);
}
fclose(fp);
evhttp_add_header(req->output_headers, "Content-Type", "image/png");
evhttp_add_header(req->output_headers, "Access-Control-Allow-Origin", "*");
evhttp_add_header(req->output_headers, "Access-Control-Allow-Methods", "POST,GET,OPTIONS");
evhttp_add_header(req->output_headers, "Access-Control-Allow-Credentials", "true");
evhttp_add_header(req->output_headers, "Access-Control-Allow-Headers", "authorization,Origin,Content-Type,Accept,token,X-Requested-With");
evhttp_send_reply(req, HTTP_OK, "", outbuf);
return;
}
}
}
定位接口token
BOOLFindToken(struct evhttp_request* pstReq)
{
struct evkeyvalq* headers = evhttp_request_get_input_headers(pstReq);
// 获取请求标头
const char* token111 = evhttp_find_header(headers, "token");
if (token111 == NULL)
{
return FALSE;
}
}