acl/app/wizard_demo/httpd_fiber_upload/http_servlet.cpp
2023-05-05 14:18:50 +08:00

422 lines
10 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "stdafx.h"
#include "http_servlet.h"
static acl::atomic_long __counter = 0;
http_servlet::http_servlet(acl::socket_stream* stream, acl::session* session)
: acl::HttpServlet(stream, session)
, fsize1_(-1)
, fsize2_(-1)
, fsize3_(-1)
{
handlers_["/upload"] = &http_servlet::onUpload;
}
http_servlet::~http_servlet(void)
{
}
bool http_servlet::doError(request_t&, response_t& res)
{
res.setStatus(400);
res.setContentType("text/xml; charset=utf-8");
// ·¢ËÍ http ÏìÓ¦Ìå
acl::string buf;
buf.format("<root error='some error happened!' />\r\n");
res.write(buf);
res.write(NULL, 0);
return false;
}
bool http_servlet::doOther(request_t&, response_t& res, const char* method)
{
res.setStatus(400);
res.setContentType("text/xml; charset=utf-8");
// ·¢ËÍ http ÏìÓ¦Ìå
acl::string buf;
buf.format("<root error='unkown request method %s' />\r\n", method);
res.write(buf);
res.write(NULL, 0);
return false;
}
bool http_servlet::doGet(request_t& req, response_t& res)
{
return doPost(req, res);
}
bool http_servlet::doPut(request_t& req, response_t& res)
{
const char* filename = "./test.tmp";
long long length = req.getContentLength();
if (length <= 0) {
printf("invalid length=%lld\r\n", length);
return false;
}
const char* expect = req.getHeader("Expect");
if (expect && strcasecmp(expect, "100-continue") == 0) {
const char* reply = "HTTP/1.1 100 Continue\r\n\r\n";
acl::ostream& out = res.getOutputStream();
if (out.write(reply, strlen(reply)) == -1) {
printf("writer %s error\r\n", reply);
return false;
}
printf("reply: [%s]\r\n", reply);
}
acl::ofstream fp;
if (!fp.open_write(filename, true)) {
printf("open file %s error %s\r\n", filename, acl::last_serror());
return false;
}
acl::istream& in = req.getInputStream();
char buf[4096];
long long read_length = 0;
while (length > read_length) {
size_t size = (size_t) (length - read_length);
if (size > sizeof(buf)) {
size = sizeof(buf);
}
int ret = in.read(buf, size);
if (ret <= 0) {
break;
}
if (fp.write(buf, ret) == -1) {
logger_error("write error %s", acl::last_serror());
(void) doReplyPlain(req, res, "write to local file error");
return false;
}
read_length += ret;
}
if (in.eof()) {
logger_error("read error from http client");
return false;
}
printf("read over, total read=%lld\r\n", read_length);
return doReplyPlain(req, res, "+ok");
}
bool http_servlet::doPost(request_t& req, response_t& res)
{
const char* ptr = req.getPathInfo();
if (ptr == NULL || *ptr == 0) {
logger_error("path null");
return doError(req, res);
}
acl::string path(ptr);
path.lower();
// ¸ù¾Ý uri path ²éÕÒ¶ÔÓ¦µÄ´¦Àí¾ä±ú£¬´Ó¶øʵÏÖ HTTP ·Óɹ¦ÄÜ
std::map<std::string, handler_t>::iterator it =
handlers_.find(path.c_str());
if (it == handlers_.end()) {
return onPage(req, res);
}
return (this->*it->second)(req, res);
}
// ȱʡ HTTP ÇëÇ󣬽« upload.html Ò³Ãæ·µ»Ø¸ø HTTP ¿Í»§¶Ë
bool http_servlet::onPage(request_t& req, response_t& res)
{
res.setContentType("text/html; charset=utf-8") // ÉèÖÃÏìÓ¦×Ö·û¼¯
.setKeepAlive(req.isKeepAlive()) // ÉèÖÃÊÇ·ñ±£³Ö³¤Á¬½Ó
.setContentEncoding(true) // ×Ô¶¯Ö§³ÖѹËõ´«Êä
.setChunkedTransferEncoding(true); // ²ÉÓà chunk ´«Ê䷽ʽ
const char* page_html = "upload.html";
acl::string buf;
if (!acl::ifstream::load(page_html, &buf)) {
buf.format("load %s error %s", page_html, acl::last_serror());
}
res.setContentLength(buf.size());
return res.write(buf) && res.write(NULL, 0);
}
bool http_servlet::onUpload(request_t& req, response_t& res)
{
res.setContentType("text/xml; charset=utf-8") // ÉèÖÃÏìÓ¦×Ö·û¼¯
.setKeepAlive(req.isKeepAlive()) // ÉèÖÃÊÇ·ñ±£³Ö³¤Á¬½Ó
.setContentEncoding(true) // ×Ô¶¯Ö§³ÖѹËõ´«Êä
.setChunkedTransferEncoding(true); // ²ÉÓà chunk ´«Ê䷽ʽ
// »ñµÃ HTTP ÇëÇóµÄÊý¾ÝÀàÐÍ£¬Õý³£µÄ²ÎÊýÀàÐÍ£¬¼´ name&value ·½Ê½
// »¹ÊÇ MIME Êý¾ÝÀàÐÍ£¬»¹ÊÇÊý¾ÝÁ÷ÀàÐÍ
acl::http_request_t request_type = req.getRequestType();
if (request_type != acl::HTTP_REQUEST_MULTIPART_FORM) {
logger_warn("should be acl::HTTP_REQUEST_MULTIPART_FORM");
return onPage(req, res);
}
// ÏÈ»ñµÃ Content-Type ¶ÔÓ¦µÄ http_ctype ¶ÔÏó
acl::http_mime* mime = req.getHttpMime();
if (mime == NULL) {
logger_error("http_mime null");
return onPage(req, res);
}
// »ñµÃÊý¾ÝÌåµÄ³¤¶È
long long content_length = req.getContentLength();
if (content_length <= 0) {
logger_error("body empty");
return onPage(req, res);
}
acl::string path;
long long n = ++__counter;
long long i = __counter.value();
printf("i=%lld, n=%lld\r\n", i, n);
#if defined(_WIN32) || defined(_WIN64)
path.format("%s\\mime_file.%u.%lld",
var_cfg_var_path, (unsigned) _getpid(), n);
#else
path.format("%s/mime_file.%u.%lld",
var_cfg_var_path, (unsigned) getpid(), n);
#endif
acl::meter_time(__FUNCTION__, __LINE__, "begin");
acl::ofstream fp;
if (!fp.open_write(path)) {
logger_error("open %s error %s",
path.c_str(), acl::last_serror());
return doReplyXml(req, res, "open file error");
}
// ÉèÖÃԭʼÎļþ´æÈë·¾¶
mime->set_saved_path(path);
if (!upload(req, res, content_length, fp, *mime)) {
reset();
return false;
}
if (!parse(req, res, *mime)) {
reset();
return false;
}
reset();
return true;
}
bool http_servlet::upload(request_t& req, response_t& res,
long long content_length, acl::ofstream& fp, acl::http_mime& mime)
{
// »ñµÃÊäÈëÁ÷
acl::istream& in = req.getInputStream();
bool finish = false;
char buf[8192];
//logger(">>>>>>>>>>read: %lld, total: %lld<<<<<",
// read_length_, content_length_);
long long read_length = 0;
// ¶ÁÈ¡ HTTP ¿Í»§¶ËÇëÇóÊý¾Ý
while (content_length > read_length) {
size_t size = (size_t) (content_length - read_length);
if (size > sizeof(buf)) {
size = sizeof(buf);
}
int ret = in.read(buf, size);
if (ret <= 0) {
break;
}
//printf(">>>size: %d\r\n", ret);
if (fp.write(buf, ret) == -1) {
logger_error("write error %s", acl::last_serror());
(void) doReplyXml(req, res, "write error");
return false;
}
read_length += ret;
// ½«¶ÁµÃµ½µÄÊý¾ÝÊäÈëÖÁ½âÎöÆ÷½øÐнâÎö
// Èç¹ûÔÙ¶Áµ½¶àÓàÊý¾Ý£¬¿ÉÒÔÖ±½Ó¶ªµô£¬²»±ØÔÙ·ÅÈë mime ½âÎöÆ÷ÖÐ
if (!finish && mime.update(buf, (size_t) ret)) {
finish = true;
}
}
if (in.eof()) {
logger_error("read error from http client");
return false;
}
return true;
}
bool http_servlet::parse(request_t& req, response_t& res, acl::http_mime& mime)
{
const char* ptr = req.getParameter("name1");
if (ptr) {
param1_ = ptr;
}
ptr = req.getParameter("name2");
if (ptr) {
param2_ = ptr;
}
ptr = req.getParameter("name3");
if (ptr) {
param3_ = ptr;
}
acl::string path;
// ±éÀúËùÓÐµÄ MIME ½áµã£¬ÕÒ³öÆäÖÐΪÎļþ½áµãµÄ²¿·Ö½øÐÐת´¢
const std::list<acl::http_mime_node*>& nodes = mime.get_nodes();
std::list<acl::http_mime_node*>::const_iterator cit = nodes.begin();
for (; cit != nodes.end(); ++cit) {
const char* name = (*cit)->get_name();
if (name == NULL) {
continue;
}
acl::http_mime_t mime_type = (*cit)->get_mime_type();
if (mime_type == acl::HTTP_MIME_FILE) {
const char* filename = (*cit)->get_filename();
if (filename == NULL) {
logger("filename null");
continue;
}
// ÓеÄä¯ÀÀÆ÷£¨ÈçIE£©ÉÏ´«Îļþʱ»á´ø×ÅÎļþ·¾¶£¬ËùÒÔ
// ÐèÒªÏȽ«Â·¾¶È¥µô
filename = acl_safe_basename(filename);
#if defined(_WIN32) || defined(_WIN64)
path.format("%s\\%s", var_cfg_var_path, filename);
#else
path.format("%s/%s", var_cfg_var_path, filename);
#endif
(void) (*cit)->save(path.c_str());
if (strcmp(name, "file1") == 0) {
file1_ = filename;
fsize1_ = get_fsize(var_cfg_var_path, filename);
} else if (strcmp(name, "file2") == 0) {
file2_ = filename;
fsize2_ = get_fsize(var_cfg_var_path, filename);
} else if (strcmp(name, "file3") == 0) {
file3_ = filename;
fsize3_ = get_fsize(var_cfg_var_path, filename);
}
}
}
// ²éÕÒÉÏÔصÄij¸öÎļþ²¢×ª´¢
const acl::http_mime_node* node = mime.get_node("file1");
if (node && node->get_mime_type() == acl::HTTP_MIME_FILE) {
ptr = node->get_filename();
if (ptr) {
// ÓеÄä¯ÀÀÆ÷£¨ÈçIE£©ÉÏ´«Îļþʱ»á´ø×ÅÎļþ·¾¶£¬ËùÒÔ
// ÐèÒªÏȽ«Â·¾¶È¥µô
ptr = acl_safe_basename(ptr);
#if defined(_WIN32) || defined(_WIN64)
path.format("%s\\1_%s", var_cfg_var_path, ptr);
#else
path.format("%s/1_%s", var_cfg_var_path, ptr);
#endif
(void) node->save(path.c_str());
}
}
return doReplyXml(req, res, "OK");
}
bool http_servlet::doReplyXml(request_t& req, response_t& res, const char* info)
{
// ´´½¨ xml ¸ñʽµÄÊý¾ÝÌå
acl::xml1 body;
body.get_root().add_child("root", true)
.add_child("content_type", true)
.add_attr("type", (int) req.getRequestType())
.get_parent()
.add_child("info", true)
.set_text(info)
.get_parent()
.add_child("params", true)
.add_child("param", true)
.add_attr("name1", param1_)
.get_parent()
.add_child("param", true)
.add_attr("name2", param2_)
.get_parent()
.add_child("param", true)
.add_attr("name3", param3_)
.get_parent()
.add_child("files", true)
.add_child("file", true)
.add_attr("filename", file1_)
.add_attr("fsize", fsize1_)
.get_parent()
.add_child("file", true)
.add_attr("filename", file2_)
.add_attr("fsize", fsize2_)
.get_parent()
.add_child("file", true)
.add_attr("filename", file3_)
.add_attr("fsize", fsize3_);
acl::string buf;
body.build_xml(buf);
logger(">>%s<<", buf.c_str());
return res.write(buf) && res.write(NULL, 0);
}
bool http_servlet::doReplyPlain(request_t&, response_t& res, const char* info)
{
size_t len = strlen(info);
res.setContentLength(len);
if (res.write(info, len) && res.write(NULL, 0)) {
printf("reply to client ok!\r\n");
return true;
}
printf("reply to client error!\r\n");
return false;
}
long long http_servlet::get_fsize(const char* dir, const char* filename)
{
acl::string path;
#if defined(_WIN32) || defined(_WIN64)
path.format("%s\\%s", dir, filename);
#else
path.format("%s/%s", dir, filename);
#endif
acl::ifstream in;
if (in.open_read(path) == false) {
logger_error("open %s error %s", path.c_str(), acl::last_serror());
return -1;
}
return in.fsize();
}
void http_servlet::reset(void)
{
param1_.clear();
param2_.clear();
param3_.clear();
file1_.clear();
file2_.clear();
file3_.clear();
fsize1_ = -1;
fsize2_ = -1;
fsize3_ = -1;
}