2015-07-05 01:29:35 +08:00
|
|
|
|
#include "stdafx.h"
|
|
|
|
|
#include "http_servlet.h"
|
|
|
|
|
|
|
|
|
|
http_servlet::http_servlet(const char* filepath)
|
|
|
|
|
{
|
|
|
|
|
if (filepath && *filepath)
|
|
|
|
|
filepath_ = filepath;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
http_servlet::~http_servlet(void)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool http_servlet::reply(acl::HttpServletRequest& req,
|
|
|
|
|
acl::HttpServletResponse& res, int status, const char* fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
|
acl::string buf;
|
|
|
|
|
buf.vformat(fmt, ap);
|
|
|
|
|
va_end(ap);
|
|
|
|
|
bool keep_alive = req.isKeepAlive();
|
|
|
|
|
res.setStatus(status)
|
|
|
|
|
.setKeepAlive(keep_alive)
|
|
|
|
|
.setContentType("text/html; charset=utf-8")
|
|
|
|
|
.setContentLength(buf.length());
|
|
|
|
|
return res.write(buf) && keep_alive;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool http_servlet::doError(acl::HttpServletRequest& req,
|
|
|
|
|
acl::HttpServletResponse& res)
|
|
|
|
|
{
|
|
|
|
|
acl::string hdr;
|
|
|
|
|
req.getClient()->sprint_header(hdr);
|
|
|
|
|
logger("error request head:\r\n%s\r\n", hdr.c_str());
|
|
|
|
|
|
|
|
|
|
(void) reply(req, res, 400, "unknown request method\r\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool http_servlet::doUnknown(acl::HttpServletRequest& req,
|
|
|
|
|
acl::HttpServletResponse& res)
|
|
|
|
|
{
|
|
|
|
|
acl::string hdr;
|
|
|
|
|
req.getClient()->sprint_header(hdr);
|
|
|
|
|
logger("request head:\r\n%s\r\n", hdr.c_str());
|
|
|
|
|
|
|
|
|
|
(void) reply(req, res, 400, "unknown request method\r\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool http_servlet::doGet(acl::HttpServletRequest& req,
|
|
|
|
|
acl::HttpServletResponse& res)
|
|
|
|
|
{
|
|
|
|
|
return doPost(req, res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool http_servlet::doPost(acl::HttpServletRequest& req,
|
|
|
|
|
acl::HttpServletResponse& res)
|
|
|
|
|
{
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ http session <20><><EFBFBD>ƣ<EFBFBD><C6A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ע<EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA>֤
|
|
|
|
|
// <20><> master_service.cpp <20>ĺ<EFBFBD><C4BA><EFBFBD> thread_on_read <20><><EFBFBD><EFBFBD><EFBFBD>õ<EFBFBD>
|
|
|
|
|
// memcached <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
/*
|
|
|
|
|
const char* sid = req.getSession().getAttribute("sid");
|
|
|
|
|
if (*sid == 0)
|
|
|
|
|
req.getSession().setAttribute("sid", "xxxxxx");
|
|
|
|
|
sid = req.getSession().getAttribute("sid");
|
|
|
|
|
*/
|
2015-07-05 22:51:31 +08:00
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>ԣ<EFBFBD><D4A3><EFBFBD><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7>¼<EFBFBD><C2BC><EFBFBD><EFBFBD>־<EFBFBD><D6BE>
|
2015-07-05 01:29:35 +08:00
|
|
|
|
acl::string hdr;
|
|
|
|
|
req.getClient()->sprint_header(hdr);
|
|
|
|
|
logger("request head:\r\n%s\r\n", hdr.c_str());
|
|
|
|
|
|
|
|
|
|
long long int range_from, range_to;
|
|
|
|
|
if (req.getRange(range_from, range_to) == false)
|
|
|
|
|
return transfer_file(req, res);
|
|
|
|
|
else
|
|
|
|
|
return transfer_file(req, res, range_from, range_to);
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-05 22:51:31 +08:00
|
|
|
|
// <20><>ͨ<EFBFBD><CDA8><EFBFBD>ع<EFBFBD><D8B9><EFBFBD>
|
2015-07-05 01:29:35 +08:00
|
|
|
|
bool http_servlet::transfer_file(acl::HttpServletRequest& req,
|
|
|
|
|
acl::HttpServletResponse& res)
|
|
|
|
|
{
|
|
|
|
|
acl::ifstream in;
|
|
|
|
|
|
|
|
|
|
// ֻ<><D6BB><EFBFBD><EFBFBD>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>
|
|
|
|
|
if (in.open_read(filepath_) == false)
|
|
|
|
|
{
|
|
|
|
|
logger_error("open file %s error %s", filepath_.c_str(),
|
|
|
|
|
acl::last_serror());
|
|
|
|
|
return reply(req, res, 500, "open %s error %s",
|
|
|
|
|
filepath_.c_str(), acl::last_serror());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
long long int fsize = in.fsize();
|
|
|
|
|
if (fsize <= 0)
|
|
|
|
|
return reply(req, res, 500, "invalid file size: %lld", fsize);
|
|
|
|
|
|
|
|
|
|
bool keep_alive = req.isKeepAlive();
|
|
|
|
|
|
2015-07-05 22:51:31 +08:00
|
|
|
|
acl::string hdr_entry;
|
|
|
|
|
acl::string filename;
|
|
|
|
|
filename.basename(in.file_path()); // <20><><EFBFBD>ļ<EFBFBD>ȫ·<C8AB><C2B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>
|
|
|
|
|
hdr_entry.format("attachment;filename=\"%s\"", filename.c_str());
|
|
|
|
|
|
2015-07-05 01:29:35 +08:00
|
|
|
|
// <20><><EFBFBD><EFBFBD> HTTP <20><>Ӧͷ<D3A6>е<EFBFBD><D0B5>ֶ<EFBFBD>
|
|
|
|
|
res.setStatus(200)
|
|
|
|
|
.setKeepAlive(keep_alive)
|
|
|
|
|
.setContentLength(fsize)
|
2015-07-05 22:51:31 +08:00
|
|
|
|
.setContentType("application/octet-stream")
|
|
|
|
|
// <20><><EFBFBD><EFBFBD> HTTP ͷ<>е<EFBFBD><D0B5>ļ<EFBFBD><C4BC><EFBFBD>
|
|
|
|
|
.setHeader("Content-Disposition", hdr_entry.c_str());
|
2015-07-05 01:29:35 +08:00
|
|
|
|
|
|
|
|
|
acl::string hdr;
|
|
|
|
|
res.getHttpHeader().build_response(hdr);
|
|
|
|
|
logger("response head:\r\n%s\r\n", hdr.c_str());
|
|
|
|
|
|
|
|
|
|
long long n = 0;
|
|
|
|
|
char buf[8192];
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>ж<EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD>ݲ<EFBFBD><DDB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݷ<EFBFBD><DDB7><EFBFBD><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD>
|
|
|
|
|
while (!in.eof())
|
|
|
|
|
{
|
|
|
|
|
int ret = in.read(buf, sizeof(buf), false);
|
|
|
|
|
if (ret == -1)
|
|
|
|
|
break;
|
|
|
|
|
if (res.write(buf, ret) == false)
|
|
|
|
|
return false;
|
|
|
|
|
n += ret;
|
|
|
|
|
//acl_doze(100); // <20><>Ϣ 100 ms <20><><EFBFBD>ڲ<EFBFBD><DAB2><EFBFBD>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return n == fsize ? true : false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ֧<>ֶϵ<D6B6><CFB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݴ<EFBFBD><DDB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
bool http_servlet::transfer_file(acl::HttpServletRequest& req,
|
2015-07-05 22:51:31 +08:00
|
|
|
|
acl::HttpServletResponse& res,
|
|
|
|
|
long long range_from, long long range_to)
|
2015-07-05 01:29:35 +08:00
|
|
|
|
{
|
|
|
|
|
if (range_from < 0)
|
|
|
|
|
return reply(req, res, 400, "invalid range_from: %lld",
|
|
|
|
|
range_from);
|
|
|
|
|
if (range_to > 0 && range_to < range_from)
|
|
|
|
|
return reply(req, res, 400, "range_from(%lld) > range_to(%lld)",
|
|
|
|
|
range_from, range_to);
|
|
|
|
|
|
|
|
|
|
long long length;
|
|
|
|
|
if (range_to >= range_from)
|
|
|
|
|
length = range_to - range_from + 1;
|
|
|
|
|
else
|
|
|
|
|
length = -1;
|
|
|
|
|
|
|
|
|
|
acl::ifstream in;
|
|
|
|
|
// ֻ<><D6BB><EFBFBD><EFBFBD>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>
|
|
|
|
|
if (in.open_read(filepath_) == false)
|
|
|
|
|
{
|
|
|
|
|
logger_error("open file %s error %s", filepath_.c_str(),
|
|
|
|
|
acl::last_serror());
|
|
|
|
|
return reply(req, res, 500, "open %s error %s",
|
|
|
|
|
filepath_.c_str(), acl::last_serror());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
long long int fsize = in.fsize();
|
|
|
|
|
if (fsize <= 0)
|
|
|
|
|
return reply(req, res, 500, "invalid file size: %lld", fsize);
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>ƫ<EFBFBD><C6AB>λ<EFBFBD>ó<EFBFBD><C3B3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC>ܳ<EFBFBD><DCB3>ȣ<EFBFBD><C8A3>ش<F2B7B5BB><D8B4><EFBFBD>
|
|
|
|
|
if (range_to >= fsize)
|
|
|
|
|
return reply(req, res, 400, "range_to(%lld) >= fsize(%lld)",
|
|
|
|
|
range_to, fsize);
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8>ƫ<EFBFBD><C6AB>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>β<EFBFBD><CEB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD>ݳ<EFBFBD><DDB3>ȣ<EFBFBD>
|
|
|
|
|
// <20><>ֵ<EFBFBD><D6B5>Ϊʵ<CEAA><CAB5>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͻ<EFBFBD><CDBB>˵ij<CBB5><C4B3><EFBFBD>
|
|
|
|
|
if (length == -1)
|
|
|
|
|
length = fsize - range_from;
|
|
|
|
|
|
|
|
|
|
// <20><>λ<EFBFBD>ļ<EFBFBD>ƫ<EFBFBD><C6AB>λ<EFBFBD><CEBB>
|
|
|
|
|
if (in.fseek(range_from, SEEK_SET) < 0)
|
|
|
|
|
return reply(req, res, 500, "fseek(%lld) error %s",
|
|
|
|
|
range_from, acl::last_serror());
|
|
|
|
|
|
|
|
|
|
bool keep_alive = req.isKeepAlive();
|
|
|
|
|
|
2015-07-05 22:51:31 +08:00
|
|
|
|
acl::string hdr_entry;
|
|
|
|
|
acl::string filename;
|
|
|
|
|
filename.basename(in.file_path()); // <20><><EFBFBD>ļ<EFBFBD>ȫ·<C8AB><C2B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>
|
|
|
|
|
hdr_entry.format("attachment;filename=\"%s\"", filename.c_str());
|
|
|
|
|
|
2015-07-05 01:29:35 +08:00
|
|
|
|
// <20><><EFBFBD><EFBFBD> HTTP <20><>Ӧͷ<D3A6>е<EFBFBD><D0B5>ֶ<EFBFBD>
|
2015-07-05 22:51:31 +08:00
|
|
|
|
res.setStatus(206) // <20><>Ӧ״̬ 206 <20><>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
2015-07-05 01:29:35 +08:00
|
|
|
|
.setKeepAlive(keep_alive) // <20>Ƿֳ<F1B1A3B3><D6B3><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
.setContentLength(length) // ʵ<><CAB5>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݳ<EFBFBD><DDB3><EFBFBD>
|
2015-07-05 22:51:31 +08:00
|
|
|
|
.setContentType("application/octet-stream") // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
// <20><><EFBFBD><EFBFBD> HTTP ͷ<>е<EFBFBD><D0B5>ļ<EFBFBD><C4BC><EFBFBD>
|
|
|
|
|
.setHeader("Content-Disposition", hdr_entry.c_str())
|
|
|
|
|
// <20><><EFBFBD>ñ<EFBFBD><C3B1>δ<EFBFBD><CEB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼƫ<CABC><C6AB>λ<EFBFBD>ü<EFBFBD><C3BC><EFBFBD><EFBFBD>ݵ<EFBFBD><DDB5>ܳ<EFBFBD><DCB3><EFBFBD>
|
|
|
|
|
.setRange(range_from, range_to > 0
|
|
|
|
|
? range_to : fsize - 1, fsize);
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>ԣ<EFBFBD><D4A3><EFBFBD> HTTP <20><>Ӧͷ<D3A6><CDB7><EFBFBD>ڱ<EFBFBD><DAB1><EFBFBD><EFBFBD><EFBFBD>־<EFBFBD><D6BE>
|
2015-07-05 01:29:35 +08:00
|
|
|
|
acl::string hdr;
|
|
|
|
|
res.getHttpHeader().build_response(hdr);
|
|
|
|
|
logger("response head:\r\n%s\r\n", hdr.c_str());
|
|
|
|
|
|
|
|
|
|
char buf[8192];
|
|
|
|
|
int ret;
|
|
|
|
|
size_t size;
|
|
|
|
|
|
2015-07-05 22:51:31 +08:00
|
|
|
|
// <20><><EFBFBD>ļ<EFBFBD>ָ<EFBFBD><D6B8>λ<EFBFBD>ö<EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD>ݣ<EFBFBD><DDA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݴ<EFBFBD><DDB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD>
|
2015-07-05 01:29:35 +08:00
|
|
|
|
while (!in.eof() && length > 0)
|
|
|
|
|
{
|
2015-07-05 22:51:31 +08:00
|
|
|
|
size = sizeof(buf) > (size_t) length ?
|
|
|
|
|
(size_t) length : sizeof(buf);
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ false <20><>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>ζ<EFBFBD><CEB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ش<EFBFBD><D8B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٷ<EFBFBD><D9B7><EFBFBD>
|
2015-07-05 01:29:35 +08:00
|
|
|
|
ret = in.read(buf, size, false);
|
|
|
|
|
if (ret == -1)
|
|
|
|
|
{
|
|
|
|
|
printf("read over: %s\r\n", acl::last_serror());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (res.write(buf, ret) == false)
|
|
|
|
|
return false;
|
|
|
|
|
length -= ret;
|
|
|
|
|
//acl_doze(100); // <20><>Ϣ 100 ms <20><><EFBFBD>ڲ<EFBFBD><DAB2><EFBFBD>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (length != 0)
|
2015-07-05 22:51:31 +08:00
|
|
|
|
{
|
|
|
|
|
logger_error("read file failed");
|
2015-07-05 01:29:35 +08:00
|
|
|
|
return false;
|
2015-07-05 22:51:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true && keep_alive;
|
2015-07-05 09:44:36 +08:00
|
|
|
|
}
|