记录使用libevent实现上传和下载文件
上传采用表单的形式
该函数只能完成表单上传一个文件的功能
void apiUploadFile(struct evhttp_request* req, void* arg) {
if(!checkCmdAndUrl(req , EVHTTP_REQ_POST)) {
return;
}
int nCode = -1;
std::string strResp;
// 消息报头
evkeyvalq *headers = evhttp_request_get_input_headers(req);
std::cout << "====== headers ======" << std::endl;
for (evkeyval *p = headers->tqh_first; p != NULL; p = p->next.tqe_next)
{
cout << p->key << ":" << p->value << endl;
}
std::cout << "======headers end====\n";
char* pBoundary = (char*)evhttp_find_header(headers , "Content-Type");
pBoundary = strstr(pBoundary , "boundary=");
pBoundary += 9;
printf("pBoundary: %s\n", pBoundary); // 需要提取boundary
char strtemp[260] = {0};
char name[256] = {0};
char fileName[256] = {0};
char filePath[256] = {0};
do
{
if(pBoundary != NULL) {
int iBoundaryLen = strlen(pBoundary);
size_t post_size = evbuffer_get_length(req->input_buffer); //获取数据长度
if(post_size > 0) {
char *search = (char*)(evbuffer_pullup(req->input_buffer, -1));
char* pSearch = search;
char* end = search + post_size;
pSearch = strstr(pSearch, "\r\n"); // 跳过第一行boundary
pSearch += 4;
// name
char* pName = strstr(pSearch , "name=");
pName += 6;
char* ptemp = strstr(pName , ";");
snprintf(name , ptemp - pName , "%s" , pName);
printf("pName : %s\n" , name);
// file name
pName = strstr(pSearch , "filename=");
pName += 10;
ptemp = strstr(pName , "\r\n");
snprintf(fileName , ptemp - pName , "%s" , pName);
printf("filename = %s\n" , fileName);
//
printf("body :\n%s\n" , search);
char* pstart = strstr(search, "\r\n\r\n");
char *pend = NULL;
if(pstart != NULL && pstart < end) {
pstart += 4;
sprintf(strtemp,"\r\n%s--\r\n\r\n", pBoundary);
int file_size = post_size - (pstart - search) - strlen(strtemp); // 要剪掉最后boundary的长度
// 读取文件内容
sprintf(filePath , "/data/project/work/config/update/%s" , fileName);
FILE* fp = fopen(filePath , "w");
fwrite(pstart , file_size , 1 , fp);
fclose(fp);
}
}
}
}while(0);
nCode = -1;
rapidjson::StringBuffer s;
rapidjson::Writer<rapidjson::StringBuffer> writer(s);
writer.StartObject();
writer.Key("code"); writer.Int(nCode);
writer.Key("msg"); writer.String(strResp.c_str());
writer.EndObject();
SendJsonReponse(req , s.GetString());
}
下载
void apiDownFile(struct evhttp_request* req, void* arg) {
if(!checkCmdAndUrl(req , EVHTTP_REQ_GET)) {
return;
}
int nCode = -1;
std::string strResp;
//消息报头
evkeyvalq* headers = evhttp_request_get_input_headers(req);
cout << "======headers: =======\n";
for (evkeyval* p = headers->tqh_first; p != NULL; p = p->next.tqe_next) {
std::cout << p->key << ":" << p->value << std::endl;
}
//请求正文(GET=NULL, POST有表单信息)
evbuffer* inbuf = evhttp_request_get_input_buffer(req);
char buf[1024] = { 0 };
cout << "=============inbuf==============" << endl;
while (evbuffer_get_length(inbuf))
{
int n = evbuffer_remove(inbuf, buf, sizeof(buf) - 1);
if (n > 0)
{
buf[n] = '\0';
cout << buf << endl;
}
}
std::string filepath = "/data/project";
const char* uri = evhttp_request_get_uri(req);
filepath += uri;
//消息报头
evkeyvalq* outhead = evhttp_request_get_output_headers(req);
// 支持图片,js,css,下载普通zip文件
// 获取文件的后缀名
// ./root/index.html
int pos = filepath.rfind('.');
std::string postfix = filepath.substr(pos + 1, filepath.size() - (pos + 1));
printf("filepath: %s , postfix: %s\n" , filepath.c_str() , postfix.c_str());
if (postfix == "jpg"|| postfix == "gif"|| postfix == "png")
{
string tmp = "image/" + postfix;
evhttp_add_header(outhead, "Content-Type", tmp.c_str());
}
else if (postfix == "zip")
{
evhttp_add_header(outhead, "Content-Type", "application/zip");
}
else if (postfix == "html")
{
//evhttp_add_header(outhead, "Content-Type", "text/html; charset=UTF8");
evhttp_add_header(outhead, "Content-Type", "text/html");
}
else if (postfix == "css")
{
evhttp_add_header(outhead, "Content-Type", "text/css");
}
else if (postfix == "js")
{
evhttp_add_header(outhead, "Content-Type", "text/js");
}
else if (postfix == "log")
{
evhttp_add_header(outhead, "Content-Type", "text/plain");
}
// 类型 描述 典型示例
// text 表明文件是普通文本,理论上是人类可读 text/plain, text/html, text/css, text/javascript
// image 表明是某种图像。不包括视频,但是动态图(比如动态 gif)也使用 image 类型 image/gif, image/png, image/jpeg, image/bmp, image/webp, image/x-icon, image/vnd.microsoft.icon
// audio 表明是某种音频文件 audio/midi, audio/mpeg, audio/webm, audio/ogg, audio/wav
// video 表明是某种视频文件 video/webm, video/ogg
// application 表明是某种二进制数据 application/octet-stream, application/pkcs12, application/vnd.mspowerpoint, application/xhtml+xml, application/xml, application/pdf
//读取html文件返回正文
FILE* fp = fopen(filepath.c_str(), "r");
if (!fp)
{
evhttp_send_reply(req , HTTP_NOTFOUND , "" , 0);
return;
}
evbuffer* outbuf = evhttp_request_get_output_buffer(req);
for (;;) {
int len = fread(buf, 1, sizeof(buf), fp);
if (len <= 0) break;
evbuffer_add(outbuf, buf, len);
}
fclose(fp);
evhttp_send_reply(req , HTTP_OK , "" , outbuf);
}