Exemple #1
0
		void do_work(const boost::asio::yield_context& yield)
		{
			//FIXME: 拆分成多个子函数..
			for (;;)
			{
				try
				{
					std::array<char, 8192> buffer;
					RequestParser parser;

					std::size_t total_size = 0;
					for (;;)
					{
						std::size_t n = socket_.async_read_some(boost::asio::buffer(buffer), yield);
						total_size += n;
						if (total_size > 2 * 1024 * 1024)
						{
							throw std::runtime_error("Request toooooooo large");
						}
						auto ret = parser.parse(buffer.data(), buffer.data() + n);
						if (ret == RequestParser::good)
						{
							break;
						}
						if (ret == RequestParser::bad)
						{
							throw std::runtime_error("HTTP Parser error");
						}
					}

					/*
					如果是http1.0,规则是这样的:
					如果request里面的connection是keep-alive,那就说明浏览器想要长连接,服务器如果也同意长连接,
					那么返回的response的connection也应该有keep-alive通知浏览器,如果不想长链接,response里面就不应该有keep-alive;
					如果是1.1的,规则是这样的:
					如果request里面的connection是close,那就说明浏览器不希望长连接,如果没有close,就是默认保持长链接,
					本来是跟keep-alive没关系,但是如果浏览器发了keep-alive,那你返回的时候也应该返回keep-alive;
					惯例是根据有没有close判断是否长链接,但是如果没有close但是有keep-alive,你response也得加keep-alive;
					如果没有close也没有keep-alive
					那就是长链接但是不用返回keep-alive
					*/

					Request req = parser.get_request();
					Response res;
					LOG_DBG << "New request,path:" << req.path();

					auto self = shared_from_this();
					res.direct_write_func_ = 
						[&yield, self, this]
					(const char* data, std::size_t len)->bool
					{
						boost::system::error_code ec;
						boost::asio::async_write(socket_, boost::asio::buffer(data, len), yield[ec]);
						if (ec)
						{
							// TODO: log ec.message().
							std::cout << "direct_write_func error" << ec.message() << std::endl;
							return false;
						}
						return true;
					};

					// 是否已经处理了这个request.
					bool found = false;

					bool keep_alive{};
					bool close_connection{};
					if (parser.check_version(1, 0))
					{
						// HTTP/1.0
						LOG_DBG << "http/1.0";
						if (req.header().val_ncase_equal("Connetion", "Keep-Alive"))
						{
							LOG_DBG << "Keep-Alive";
							keep_alive = true;
							close_connection = false;
						}
						else
						{
							keep_alive = false;
							close_connection = true;
						}

						res.set_version(1, 0);
					}
					else if (parser.check_version(1, 1))
					{
						// HTTP/1.1
						LOG_DBG << "http/1.1";
						if (req.header().val_ncase_equal("Connetion", "close"))
						{
							keep_alive = false;
							close_connection = true;
						}
						else if (req.header().val_ncase_equal("Connetion", "Keep-Alive"))
						{
							keep_alive = true;
							close_connection = false;
						}
						else
						{
							keep_alive = false;
							close_connection = false;
						}

						if (req.header().get_count("host") == 0)
						{
							found = error_handler_(400,"", req, res);
						}

						res.set_version(1, 1);
					}
					else
					{
						LOG_DBG << "Unsupported http version";
						found = error_handler_(400, "Unsupported HTTP version.", req, res);
					}

					if (!found && request_handler_)
					{
						found = request_handler_(req, res);
					}
					if (!found && response_file(req, keep_alive, yield))
					{
						continue;
					}

					//如果都没有找到,404
					if (!found)
					{
						LOG_DBG << "404 Not found";
						error_handler_(404, "", req, res);
					}

					if (keep_alive)
					{
						res.header.add("Connetion", "Keep-Alive");
					}

					//用户没有指定Content-Type,默认设置成text/html
					if (res.header.get_count("Content-Type") == 0)
					{
						res.header.add("Content-Type", "text/html");
					}

					if (!res.is_complete_)
					{
						res.end();
					}

					if (!res.is_chunked_encoding_)
					{
						// 如果是chunked编码数据应该都发完了.
						std::string header_str = res.get_header_str();
						boost::asio::async_write(socket_, boost::asio::buffer(header_str), yield);
						boost::asio::async_write(socket_, res.buffer_, 
							boost::asio::transfer_exactly(res.buffer_.size()), yield);
					}

					if (close_connection)
					{
						shutdown();
					}
				}
				catch (boost::system::system_error& e)
				{
					//网络通信异常,关socket.
					if (e.code() == boost::asio::error::eof)
					{
						LOG_DBG << "Socket shutdown";
					}
					else
					{
						LOG_DBG << "Network exception: " << e.code().message();
					}
					boost::system::error_code ignored_ec;
					socket_.close(ignored_ec);
					return;
				}
				catch (std::exception& e)
				{
					LOG_ERR << "Error occurs,response 500: " << e.what();
					response_5xx(e.what(), yield);
				}
				catch (...)
				{
					response_5xx("", yield);
				}
			}
		}
Exemple #2
0
// request against us
int8_t GSwifi::dispatchRequestHandler (int8_t cid, int8_t routeid, GSREQUESTSTATE state) {
    return request_handler_(cid, routeid, state);
}