├── README ├── README.md ├── code ├── connection.cpp ├── connection.hpp ├── header.hpp ├── index.html ├── log.cpp ├── log.hpp ├── main.cpp ├── makefile ├── memcache.cpp ├── memcache.hpp ├── mime_types.cpp ├── mime_types.hpp ├── reply.cpp ├── reply.hpp ├── request.hpp ├── request_handler.cpp ├── request_handler.hpp ├── request_parser.cpp ├── request_parser.hpp ├── server.cpp └── server.hpp ├── lecture 3.pdf ├── 看pdf获得的一点小知识.docx └── 看pdf获得的一点小知识.odt /README: -------------------------------------------------------------------------------- 1 | HPS 2 | 3 | 编程实验第三次,高性能web服务器,用c++编写一个支持高并发的web服务器,用于提供静态文件访问和日志管理,用到多线程与线程池、网络编程框架 4 | 5 | HPS 6 | 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | HPS 2 | === 3 | 4 | 编程实验第三次,高性能web服务器,用c++编写一个支持高并发的web服务器,用于提供静态文件访问和日志管理,用到多线程与线程池、网络编程框架 -------------------------------------------------------------------------------- /code/connection.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // connection.cpp 3 | // ~~~~~~~~~~~~~~ 4 | // 5 | // Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 | // 7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 | // 10 | 11 | #include "connection.hpp" 12 | #include 13 | #include 14 | #include "request_handler.hpp" 15 | 16 | namespace http { 17 | namespace server3 { 18 | 19 | connection::connection(boost::asio::io_service& io_service, request_handler& handler, Log& log_name) 20 | : strand_(io_service), socket_(io_service), request_handler_(handler), server_log_(log_name) 21 | { 22 | } 23 | 24 | boost::asio::ip::tcp::socket& connection::socket() 25 | { 26 | return socket_; 27 | } 28 | 29 | void connection::start() 30 | { 31 | socket_.async_read_some(boost::asio::buffer(buffer_), 32 | strand_.wrap(boost::bind(&connection::handle_read, shared_from_this(), 33 | boost::asio::placeholders::error, 34 | boost::asio::placeholders::bytes_transferred))); 35 | } 36 | 37 | void connection::handle_read(const boost::system::error_code& e, std::size_t bytes_transferred) 38 | { 39 | if (!e) 40 | { 41 | boost::tribool result; 42 | boost::tie(result, boost::tuples::ignore) = request_parser_.parse(request_, buffer_.data(), buffer_.data() + bytes_transferred); 43 | 44 | if (result) 45 | { 46 | server_log_.log_for_request(socket_.remote_endpoint().address().to_string(), socket_.remote_endpoint().port(), request_.uri); 47 | request_handler_.handle_request(request_, reply_); 48 | if (reply_.status == reply::bad_request) 49 | server_log_.log_for_error(socket_.remote_endpoint().address().to_string(), socket_.remote_endpoint().port(), request_.uri, "bad request"); 50 | else if (reply_.status == reply::not_found) 51 | server_log_.log_for_error(socket_.remote_endpoint().address().to_string(), socket_.remote_endpoint().port(), request_.uri, "not found"); 52 | boost::asio::async_write(socket_, reply_.to_buffers(), 53 | strand_.wrap(boost::bind(&connection::handle_write, shared_from_this(), 54 | boost::asio::placeholders::error))); 55 | } 56 | else if (!result) 57 | { 58 | reply_ = reply::stock_reply(reply::bad_request); 59 | boost::asio::async_write(socket_, reply_.to_buffers(), 60 | strand_.wrap(boost::bind(&connection::handle_write, shared_from_this(), 61 | boost::asio::placeholders::error))); 62 | } 63 | else 64 | { 65 | socket_.async_read_some(boost::asio::buffer(buffer_), 66 | strand_.wrap(boost::bind(&connection::handle_read, shared_from_this(), 67 | boost::asio::placeholders::error, 68 | boost::asio::placeholders::bytes_transferred))); 69 | } 70 | } 71 | 72 | // If an error occurs then no new asynchronous operations are started. This 73 | // means that all shared_ptr references to the connection object will 74 | // disappear and the object will be destroyed automatically after this 75 | // handler returns. The connection class's destructor closes the socket. 76 | } 77 | 78 | void connection::handle_write(const boost::system::error_code& e) 79 | { 80 | if (!e) 81 | { 82 | if (reply_.status == reply::ok) 83 | server_log_.log_for_send(socket_.remote_endpoint().address().to_string(), socket_.remote_endpoint().port(), request_.uri, reply_.content.size(), reply_timer.elapsed() * 1000); 84 | // Initiate graceful connection closure. 85 | boost::system::error_code ignored_ec; 86 | socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); 87 | } 88 | 89 | // No new asynchronous operations are started. This means that all shared_ptr 90 | // references to the connection object will disappear and the object will be 91 | // destroyed automatically after this handler returns. The connection class's 92 | // destructor closes the socket. 93 | } 94 | 95 | } // namespace server3 96 | } // namespace http 97 | -------------------------------------------------------------------------------- /code/connection.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // connection.hpp 3 | // ~~~~~~~~~~~~~~ 4 | // 5 | // Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 | // 7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 | // 10 | 11 | #ifndef HTTP_SERVER3_CONNECTION_HPP 12 | #define HTTP_SERVER3_CONNECTION_HPP 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "reply.hpp" 21 | #include "request.hpp" 22 | #include "request_handler.hpp" 23 | #include "request_parser.hpp" 24 | #include "log.hpp" 25 | 26 | namespace http { 27 | namespace server3 { 28 | 29 | /// Represents a single connection from a client. 30 | class connection 31 | : public boost::enable_shared_from_this, 32 | private boost::noncopyable 33 | { 34 | public: 35 | /// Construct a connection with the given io_service. 36 | explicit connection(boost::asio::io_service& io_service, 37 | request_handler& handler, Log& log_name); 38 | 39 | /// Get the socket associated with the connection. 40 | boost::asio::ip::tcp::socket& socket(); 41 | 42 | /// Start the first asynchronous operation for the connection. 43 | void start(); 44 | 45 | private: 46 | /// Handle completion of a read operation. 47 | void handle_read(const boost::system::error_code& e, 48 | std::size_t bytes_transferred); 49 | 50 | /// Handle completion of a write operation. 51 | void handle_write(const boost::system::error_code& e); 52 | 53 | /// Strand to ensure the connection's handlers are not called concurrently. 54 | boost::asio::io_service::strand strand_; 55 | 56 | /// Socket for the connection. 57 | boost::asio::ip::tcp::socket socket_; 58 | 59 | /// The handler used to process the incoming request. 60 | request_handler& request_handler_; 61 | 62 | /// Buffer for incoming data. 63 | boost::array buffer_; 64 | 65 | /// The incoming request. 66 | request request_; 67 | 68 | /// The parser for the incoming request. 69 | request_parser request_parser_; 70 | 71 | /// The reply to be sent back to the client. 72 | reply reply_; 73 | 74 | //Log 75 | Log& server_log_; 76 | 77 | ///timer 78 | boost::timer reply_timer; 79 | }; 80 | 81 | typedef boost::shared_ptr connection_ptr; 82 | 83 | } // namespace server3 84 | } // namespace http 85 | 86 | #endif // HTTP_SERVER3_CONNECTION_HPP 87 | -------------------------------------------------------------------------------- /code/header.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // header.hpp 3 | // ~~~~~~~~~~ 4 | // 5 | // Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 | // 7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 | // 10 | 11 | #ifndef HTTP_SERVER3_HEADER_HPP 12 | #define HTTP_SERVER3_HEADER_HPP 13 | 14 | #include 15 | 16 | namespace http { 17 | namespace server3 { 18 | 19 | struct header 20 | { 21 | std::string name; 22 | std::string value; 23 | }; 24 | 25 | } // namespace server3 26 | } // namespace http 27 | 28 | #endif // HTTP_SERVER3_HEADER_HPP 29 | -------------------------------------------------------------------------------- /code/index.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kobe6672823/HPS/12e04af553887d1655aac850fc39759c4f3d0acd/code/index.html -------------------------------------------------------------------------------- /code/log.cpp: -------------------------------------------------------------------------------- 1 | #include "log.hpp" 2 | 3 | Log::Log(string file_name = "") 4 | { 5 | ofile.open(file_name.c_str(), ofstream::app); 6 | } 7 | 8 | void Log::log_for_request(string ip, int port, string file_name) 9 | { 10 | output_current_time(); 11 | ofile << "Client [" << ip << " : " << port << "] request file: " << file_name << endl; 12 | } 13 | 14 | void Log::log_for_send(string ip, int port, string file_name, size_t file_size, int delay) 15 | { 16 | output_current_time(); 17 | ofile << "Successful send file " << file_name << " with " << file_size << "bytes to client [" << ip << " : " << port << "] after " << delay << "ms from receiving its request." << endl; 18 | } 19 | 20 | void Log::log_for_error(string ip, int port, string file_name, string err) 21 | { 22 | output_current_time(); 23 | ofile << "Fail to send file " << file_name << " to client [" << ip << " : " << port << "] due to error: " << err << "." << endl; 24 | } 25 | 26 | 27 | -------------------------------------------------------------------------------- /code/log.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTTP_SERVER3_LOG_HPP 2 | #define HTTP_SERVER3_LOG_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | class Log 11 | { 12 | public : 13 | Log(string file_name); 14 | void log_for_request(string ip, int port, string file_name); 15 | void log_for_send(string ip, int port, string file_name, size_t file_size, int delay); 16 | void log_for_error(string ip, int port, string file_name, string err); 17 | ~Log() { ofile.close(); } 18 | 19 | private : 20 | ofstream ofile; 21 | void output_current_time() 22 | { 23 | struct timeb tp; 24 | struct tm *tm; 25 | 26 | ftime ( &tp ); 27 | tm = localtime(&(tp.time)); 28 | ofile << tm->tm_year + 1900 << "-" << tm->tm_mon + 1 << "-" << tm->tm_mday << " " << tm->tm_hour << ":" << tm->tm_min << ":" << tm->tm_sec << "." << tp.millitm << " "; 29 | } 30 | }; 31 | #endif 32 | -------------------------------------------------------------------------------- /code/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // main.cpp 3 | // ~~~~~~~~ 4 | // 5 | // Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 | // 7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 | // 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "server.hpp" 17 | 18 | int main(int argc, char* argv[]) 19 | { 20 | try 21 | { 22 | // Check command line arguments. 23 | if (argc != 6) 24 | { 25 | std::cerr << "Usage: http_server
\n"; 26 | std::cerr << " For IPv4, try:\n"; 27 | std::cerr << " receiver 0.0.0.0 80 1 . server_log\n"; 28 | std::cerr << " For IPv6, try:\n"; 29 | std::cerr << " receiver 0::0 80 1 . server_log\n"; 30 | return 1; 31 | } 32 | 33 | // Initialise the server. 34 | std::size_t num_threads = boost::lexical_cast(argv[3]); 35 | http::server3::server s(argv[1], argv[2], argv[4], num_threads, argv[5]); 36 | 37 | // Run the server until stopped. 38 | s.run(); 39 | } 40 | catch (std::exception& e) 41 | { 42 | std::cerr << "exception: " << e.what() << "\n"; 43 | } 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /code/makefile: -------------------------------------------------------------------------------- 1 | all: hps 2 | 3 | hps: main.o server.o connection.o reply.o request_handler.o request_parser.o mime_types.o log.o memcache.o 4 | g++ -o hps -L/usr/local/lib main.o server.o connection.o reply.o request_handler.o request_parser.o mime_types.o -lboost_thread -lboost_system log.o memcache.o 5 | 6 | main.o: main.cpp server.hpp 7 | g++ -o main.o -c -g main.cpp 8 | 9 | server.o: server.cpp server.hpp connection.hpp request_handler.hpp log.hpp 10 | g++ -o server.o -c -g server.cpp 11 | 12 | connection.o: connection.cpp connection.hpp reply.hpp request.hpp request_handler.hpp request_parser.hpp log.hpp 13 | g++ -o connection.o -c -g connection.cpp 14 | 15 | reply.o: reply.cpp reply.hpp header.hpp 16 | g++ -o reply.o -c -g reply.cpp 17 | 18 | request_handler.o: request_handler.cpp request_handler.hpp mime_types.hpp reply.hpp request.hpp memcache.hpp 19 | g++ -o request_handler.o -c -g request_handler.cpp 20 | 21 | request_parser.o: request_parser.cpp request_parser.hpp request.hpp 22 | g++ -o request_parser.o -c -g request_parser.cpp 23 | 24 | mime_types.o: mime_types.cpp mime_types.hpp 25 | g++ -o mime_types.o -c -g mime_types.cpp 26 | 27 | clear: 28 | rm *.o hps 29 | -------------------------------------------------------------------------------- /code/memcache.cpp: -------------------------------------------------------------------------------- 1 | #include "memcache.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | void memcache::update_cache(const std::string& full_path, const std::string content) 7 | { 8 | if (file_cache.size() == memcache_size) 9 | { 10 | std::map::iterator tag_iter; 11 | std::string old_path;//the path needed to be replace: because it has the least time_tag 12 | long least_tag = 1000000000; 13 | for (tag_iter = time_tag.begin(); tag_iter != time_tag.end(); tag_iter++) 14 | { 15 | if (tag_iter->second < least_tag) 16 | { 17 | least_tag = tag_iter->second; 18 | old_path = tag_iter->first; 19 | } 20 | } 21 | time_tag.erase(old_path); 22 | file_cache.erase(old_path); 23 | } 24 | file_cache[full_path] = content; 25 | time_tag[full_path] = current_time_tag(); 26 | } 27 | 28 | long memcache::current_time_tag() 29 | { 30 | struct timeb tp; 31 | long ttag; 32 | 33 | ftime(&tp); 34 | ttag = (tp.time) * 1000 + tp.millitm;//1354287198 is the seconds from 1970-1-1 0:0:0 to 2012-11-23 14:31:0 35 | return ttag; 36 | } 37 | 38 | void memcache::print_cache() 39 | { 40 | std::map::iterator tag_iter; 41 | for (tag_iter = time_tag.begin(); tag_iter != time_tag.end(); tag_iter++) 42 | { 43 | std::cout << tag_iter->first << "\t" << file_cache[tag_iter->first] << "\t" << tag_iter->second << std::endl; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /code/memcache.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HTTP_SERVER3_MEMCACHE_HPP 2 | #define HTTP_SERVER3_MEMCACHE_HPP 3 | 4 | #include 5 | #include 6 | 7 | class memcache 8 | { 9 | public: 10 | bool in_cache(const std::string& full_path) 11 | { 12 | return file_cache.count(full_path); 13 | } 14 | std::string content_in_cache(const std::string& full_path) 15 | { 16 | //update time_tag then return the content 17 | time_tag[full_path] = current_time_tag(); 18 | return file_cache[full_path]; 19 | } 20 | void update_cache(const std::string& full_path, const std::string content); 21 | long current_time_tag(); 22 | void print_cache(); 23 | private: 24 | std::map file_cache; 25 | std::map time_tag;//tag design needs to be changed 26 | const static int memcache_size = 10; 27 | }; 28 | #endif 29 | -------------------------------------------------------------------------------- /code/mime_types.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // mime_types.cpp 3 | // ~~~~~~~~~~~~~~ 4 | // 5 | // Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 | // 7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 | // 10 | 11 | #include "mime_types.hpp" 12 | 13 | namespace http { 14 | namespace server3 { 15 | namespace mime_types { 16 | 17 | struct mapping 18 | { 19 | const char* extension; 20 | const char* mime_type; 21 | } mappings[] = 22 | { 23 | { "gif", "image/gif" }, 24 | { "htm", "text/html" }, 25 | { "html", "text/html" }, 26 | { "jpg", "image/jpeg" }, 27 | { "png", "image/png" }, 28 | { 0, 0 } // Marks end of list. 29 | }; 30 | 31 | std::string extension_to_type(const std::string& extension) 32 | { 33 | for (mapping* m = mappings; m->extension; ++m) 34 | { 35 | if (m->extension == extension) 36 | { 37 | return m->mime_type; 38 | } 39 | } 40 | 41 | return "text/plain"; 42 | } 43 | 44 | } // namespace mime_types 45 | } // namespace server3 46 | } // namespace http 47 | -------------------------------------------------------------------------------- /code/mime_types.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // mime_types.hpp 3 | // ~~~~~~~~~~~~~~ 4 | // 5 | // Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 | // 7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 | // 10 | 11 | #ifndef HTTP_SERVER3_MIME_TYPES_HPP 12 | #define HTTP_SERVER3_MIME_TYPES_HPP 13 | 14 | #include 15 | 16 | namespace http { 17 | namespace server3 { 18 | namespace mime_types { 19 | 20 | /// Convert a file extension into a MIME type. 21 | std::string extension_to_type(const std::string& extension); 22 | 23 | } // namespace mime_types 24 | } // namespace server3 25 | } // namespace http 26 | 27 | #endif // HTTP_SERVER3_MIME_TYPES_HPP 28 | -------------------------------------------------------------------------------- /code/reply.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // reply.cpp 3 | // ~~~~~~~~~ 4 | // 5 | // Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 | // 7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 | // 10 | 11 | #include "reply.hpp" 12 | #include 13 | #include 14 | 15 | namespace http { 16 | namespace server3 { 17 | 18 | namespace status_strings { 19 | 20 | const std::string ok = 21 | "HTTP/1.0 200 OK\r\n"; 22 | const std::string created = 23 | "HTTP/1.0 201 Created\r\n"; 24 | const std::string accepted = 25 | "HTTP/1.0 202 Accepted\r\n"; 26 | const std::string no_content = 27 | "HTTP/1.0 204 No Content\r\n"; 28 | const std::string multiple_choices = 29 | "HTTP/1.0 300 Multiple Choices\r\n"; 30 | const std::string moved_permanently = 31 | "HTTP/1.0 301 Moved Permanently\r\n"; 32 | const std::string moved_temporarily = 33 | "HTTP/1.0 302 Moved Temporarily\r\n"; 34 | const std::string not_modified = 35 | "HTTP/1.0 304 Not Modified\r\n"; 36 | const std::string bad_request = 37 | "HTTP/1.0 400 Bad Request\r\n"; 38 | const std::string unauthorized = 39 | "HTTP/1.0 401 Unauthorized\r\n"; 40 | const std::string forbidden = 41 | "HTTP/1.0 403 Forbidden\r\n"; 42 | const std::string not_found = 43 | "HTTP/1.0 404 Not Found\r\n"; 44 | const std::string internal_server_error = 45 | "HTTP/1.0 500 Internal Server Error\r\n"; 46 | const std::string not_implemented = 47 | "HTTP/1.0 501 Not Implemented\r\n"; 48 | const std::string bad_gateway = 49 | "HTTP/1.0 502 Bad Gateway\r\n"; 50 | const std::string service_unavailable = 51 | "HTTP/1.0 503 Service Unavailable\r\n"; 52 | 53 | boost::asio::const_buffer to_buffer(reply::status_type status) 54 | { 55 | switch (status) 56 | { 57 | case reply::ok: 58 | return boost::asio::buffer(ok); 59 | case reply::created: 60 | return boost::asio::buffer(created); 61 | case reply::accepted: 62 | return boost::asio::buffer(accepted); 63 | case reply::no_content: 64 | return boost::asio::buffer(no_content); 65 | case reply::multiple_choices: 66 | return boost::asio::buffer(multiple_choices); 67 | case reply::moved_permanently: 68 | return boost::asio::buffer(moved_permanently); 69 | case reply::moved_temporarily: 70 | return boost::asio::buffer(moved_temporarily); 71 | case reply::not_modified: 72 | return boost::asio::buffer(not_modified); 73 | case reply::bad_request: 74 | return boost::asio::buffer(bad_request); 75 | case reply::unauthorized: 76 | return boost::asio::buffer(unauthorized); 77 | case reply::forbidden: 78 | return boost::asio::buffer(forbidden); 79 | case reply::not_found: 80 | return boost::asio::buffer(not_found); 81 | case reply::internal_server_error: 82 | return boost::asio::buffer(internal_server_error); 83 | case reply::not_implemented: 84 | return boost::asio::buffer(not_implemented); 85 | case reply::bad_gateway: 86 | return boost::asio::buffer(bad_gateway); 87 | case reply::service_unavailable: 88 | return boost::asio::buffer(service_unavailable); 89 | default: 90 | return boost::asio::buffer(internal_server_error); 91 | } 92 | } 93 | 94 | } // namespace status_strings 95 | 96 | namespace misc_strings { 97 | 98 | const char name_value_separator[] = { ':', ' ' }; 99 | const char crlf[] = { '\r', '\n' }; 100 | 101 | } // namespace misc_strings 102 | 103 | std::vector reply::to_buffers() 104 | { 105 | std::vector buffers; 106 | buffers.push_back(status_strings::to_buffer(status)); 107 | for (std::size_t i = 0; i < headers.size(); ++i) 108 | { 109 | header& h = headers[i]; 110 | buffers.push_back(boost::asio::buffer(h.name)); 111 | buffers.push_back(boost::asio::buffer(misc_strings::name_value_separator)); 112 | buffers.push_back(boost::asio::buffer(h.value)); 113 | buffers.push_back(boost::asio::buffer(misc_strings::crlf)); 114 | } 115 | buffers.push_back(boost::asio::buffer(misc_strings::crlf)); 116 | buffers.push_back(boost::asio::buffer(content)); 117 | return buffers; 118 | } 119 | 120 | namespace stock_replies { 121 | 122 | const char ok[] = ""; 123 | const char created[] = 124 | "" 125 | "Created" 126 | "

201 Created

" 127 | ""; 128 | const char accepted[] = 129 | "" 130 | "Accepted" 131 | "

202 Accepted

" 132 | ""; 133 | const char no_content[] = 134 | "" 135 | "No Content" 136 | "

204 Content

" 137 | ""; 138 | const char multiple_choices[] = 139 | "" 140 | "Multiple Choices" 141 | "

300 Multiple Choices

" 142 | ""; 143 | const char moved_permanently[] = 144 | "" 145 | "Moved Permanently" 146 | "

301 Moved Permanently

" 147 | ""; 148 | const char moved_temporarily[] = 149 | "" 150 | "Moved Temporarily" 151 | "

302 Moved Temporarily

" 152 | ""; 153 | const char not_modified[] = 154 | "" 155 | "Not Modified" 156 | "

304 Not Modified

" 157 | ""; 158 | const char bad_request[] = 159 | "" 160 | "Bad Request" 161 | "

400 Bad Request

" 162 | ""; 163 | const char unauthorized[] = 164 | "" 165 | "Unauthorized" 166 | "

401 Unauthorized

" 167 | ""; 168 | const char forbidden[] = 169 | "" 170 | "Forbidden" 171 | "

403 Forbidden

" 172 | ""; 173 | const char not_found[] = 174 | "" 175 | "Not Found" 176 | "

404 Not Found

" 177 | ""; 178 | const char internal_server_error[] = 179 | "" 180 | "Internal Server Error" 181 | "

500 Internal Server Error

" 182 | ""; 183 | const char not_implemented[] = 184 | "" 185 | "Not Implemented" 186 | "

501 Not Implemented

" 187 | ""; 188 | const char bad_gateway[] = 189 | "" 190 | "Bad Gateway" 191 | "

502 Bad Gateway

" 192 | ""; 193 | const char service_unavailable[] = 194 | "" 195 | "Service Unavailable" 196 | "

503 Service Unavailable

" 197 | ""; 198 | 199 | std::string to_string(reply::status_type status) 200 | { 201 | switch (status) 202 | { 203 | case reply::ok: 204 | return ok; 205 | case reply::created: 206 | return created; 207 | case reply::accepted: 208 | return accepted; 209 | case reply::no_content: 210 | return no_content; 211 | case reply::multiple_choices: 212 | return multiple_choices; 213 | case reply::moved_permanently: 214 | return moved_permanently; 215 | case reply::moved_temporarily: 216 | return moved_temporarily; 217 | case reply::not_modified: 218 | return not_modified; 219 | case reply::bad_request: 220 | return bad_request; 221 | case reply::unauthorized: 222 | return unauthorized; 223 | case reply::forbidden: 224 | return forbidden; 225 | case reply::not_found: 226 | return not_found; 227 | case reply::internal_server_error: 228 | return internal_server_error; 229 | case reply::not_implemented: 230 | return not_implemented; 231 | case reply::bad_gateway: 232 | return bad_gateway; 233 | case reply::service_unavailable: 234 | return service_unavailable; 235 | default: 236 | return internal_server_error; 237 | } 238 | } 239 | 240 | } // namespace stock_replies 241 | 242 | reply reply::stock_reply(reply::status_type status) 243 | { 244 | reply rep; 245 | rep.status = status; 246 | rep.content = stock_replies::to_string(status); 247 | rep.headers.resize(2); 248 | rep.headers[0].name = "Content-Length"; 249 | rep.headers[0].value = boost::lexical_cast(rep.content.size()); 250 | rep.headers[1].name = "Content-Type"; 251 | rep.headers[1].value = "text/html"; 252 | return rep; 253 | } 254 | 255 | } // namespace server3 256 | } // namespace http 257 | -------------------------------------------------------------------------------- /code/reply.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // reply.hpp 3 | // ~~~~~~~~~ 4 | // 5 | // Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 | // 7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 | // 10 | 11 | #ifndef HTTP_SERVER3_REPLY_HPP 12 | #define HTTP_SERVER3_REPLY_HPP 13 | 14 | #include 15 | #include 16 | #include 17 | #include "header.hpp" 18 | 19 | namespace http { 20 | namespace server3 { 21 | 22 | /// A reply to be sent to a client. 23 | struct reply 24 | { 25 | /// The status of the reply. 26 | enum status_type 27 | { 28 | ok = 200, 29 | created = 201, 30 | accepted = 202, 31 | no_content = 204, 32 | multiple_choices = 300, 33 | moved_permanently = 301, 34 | moved_temporarily = 302, 35 | not_modified = 304, 36 | bad_request = 400, 37 | unauthorized = 401, 38 | forbidden = 403, 39 | not_found = 404, 40 | internal_server_error = 500, 41 | not_implemented = 501, 42 | bad_gateway = 502, 43 | service_unavailable = 503 44 | } status; 45 | 46 | /// The headers to be included in the reply. 47 | std::vector
headers; 48 | 49 | /// The content to be sent in the reply. 50 | std::string content; 51 | 52 | /// Convert the reply into a vector of buffers. The buffers do not own the 53 | /// underlying memory blocks, therefore the reply object must remain valid and 54 | /// not be changed until the write operation has completed. 55 | std::vector to_buffers(); 56 | 57 | /// Get a stock reply. 58 | static reply stock_reply(status_type status); 59 | }; 60 | 61 | } // namespace server3 62 | } // namespace http 63 | 64 | #endif // HTTP_SERVER3_REPLY_HPP 65 | -------------------------------------------------------------------------------- /code/request.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // request.hpp 3 | // ~~~~~~~~~~~ 4 | // 5 | // Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 | // 7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 | // 10 | 11 | #ifndef HTTP_SERVER3_REQUEST_HPP 12 | #define HTTP_SERVER3_REQUEST_HPP 13 | 14 | #include 15 | #include 16 | #include "header.hpp" 17 | 18 | namespace http { 19 | namespace server3 { 20 | 21 | /// A request received from a client. 22 | struct request 23 | { 24 | std::string method; 25 | std::string uri; 26 | int http_version_major; 27 | int http_version_minor; 28 | std::vector
headers; 29 | }; 30 | 31 | } // namespace server3 32 | } // namespace http 33 | 34 | #endif // HTTP_SERVER3_REQUEST_HPP 35 | -------------------------------------------------------------------------------- /code/request_handler.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // request_handler.cpp 3 | // ~~~~~~~~~~~~~~~~~~~ 4 | // 5 | // Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 | // 7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 | // 10 | 11 | #include "request_handler.hpp" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "mime_types.hpp" 17 | #include "reply.hpp" 18 | #include "request.hpp" 19 | 20 | namespace http { 21 | namespace server3 { 22 | 23 | request_handler::request_handler(const std::string& doc_root) 24 | : doc_root_(doc_root) 25 | { 26 | } 27 | 28 | void request_handler::handle_request(const request& req, reply& rep) 29 | { 30 | // Decode url to path. 31 | std::string request_path; 32 | if (!url_decode(req.uri, request_path)) 33 | { 34 | rep = reply::stock_reply(reply::bad_request); 35 | return; 36 | } 37 | 38 | // Request path must be absolute and not contain "..". 39 | if (request_path.empty() || request_path[0] != '/' 40 | || request_path.find("..") != std::string::npos) 41 | { 42 | rep = reply::stock_reply(reply::bad_request); 43 | return; 44 | } 45 | 46 | // If path ends in slash (i.e. is a directory) then add "index.html". 47 | if (request_path[request_path.size() - 1] == '/') 48 | { 49 | request_path += "index.html"; 50 | } 51 | 52 | // Determine the file extension. 53 | std::size_t last_slash_pos = request_path.find_last_of("/"); 54 | std::size_t last_dot_pos = request_path.find_last_of("."); 55 | std::string extension; 56 | if (last_dot_pos != std::string::npos && last_dot_pos > last_slash_pos) 57 | { 58 | extension = request_path.substr(last_dot_pos + 1); 59 | } 60 | 61 | // Open the file to send back. 62 | std::string full_path = doc_root_ + request_path; 63 | if (server_cache.in_cache(full_path)) 64 | { 65 | rep.content = server_cache.content_in_cache(full_path); 66 | } 67 | else 68 | { 69 | std::ifstream is(full_path.c_str(), std::ios::in | std::ios::binary); 70 | if (!is) 71 | { 72 | rep = reply::stock_reply(reply::not_found); 73 | return; 74 | } 75 | char buf[512]; 76 | while (is.read(buf, sizeof(buf)).gcount() > 0) 77 | rep.content.append(buf, is.gcount()); 78 | server_cache.update_cache(full_path, rep.content); 79 | } 80 | 81 | // Fill out the reply to be sent to the client. 82 | rep.status = reply::ok; 83 | rep.headers.resize(2); 84 | rep.headers[0].name = "Content-Length"; 85 | rep.headers[0].value = boost::lexical_cast(rep.content.size()); 86 | rep.headers[1].name = "Content-Type"; 87 | rep.headers[1].value = mime_types::extension_to_type(extension); 88 | } 89 | 90 | bool request_handler::url_decode(const std::string& in, std::string& out) 91 | { 92 | out.clear(); 93 | out.reserve(in.size()); 94 | for (std::size_t i = 0; i < in.size(); ++i) 95 | { 96 | if (in[i] == '%') 97 | { 98 | if (i + 3 <= in.size()) 99 | { 100 | int value = 0; 101 | std::istringstream is(in.substr(i + 1, 2)); 102 | if (is >> std::hex >> value) 103 | { 104 | out += static_cast(value); 105 | i += 2; 106 | } 107 | else 108 | { 109 | return false; 110 | } 111 | } 112 | else 113 | { 114 | return false; 115 | } 116 | } 117 | else if (in[i] == '+') 118 | { 119 | out += ' '; 120 | } 121 | else 122 | { 123 | out += in[i]; 124 | } 125 | } 126 | return true; 127 | } 128 | 129 | } // namespace server3 130 | } // namespace http 131 | -------------------------------------------------------------------------------- /code/request_handler.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // request_handler.hpp 3 | // ~~~~~~~~~~~~~~~~~~~ 4 | // 5 | // Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 | // 7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 | // 10 | 11 | #ifndef HTTP_SERVER3_REQUEST_HANDLER_HPP 12 | #define HTTP_SERVER3_REQUEST_HANDLER_HPP 13 | 14 | #include 15 | #include 16 | #include "memcache.hpp" 17 | 18 | namespace http { 19 | namespace server3 { 20 | 21 | struct reply; 22 | struct request; 23 | 24 | /// The common handler for all incoming requests. 25 | class request_handler 26 | : private boost::noncopyable 27 | { 28 | public: 29 | /// Construct with a directory containing files to be served. 30 | explicit request_handler(const std::string& doc_root); 31 | 32 | /// Handle a request and produce a reply. 33 | void handle_request(const request& req, reply& rep); 34 | 35 | private: 36 | /// The directory containing the files to be served. 37 | std::string doc_root_; 38 | 39 | /// Perform URL-decoding on a string. Returns false if the encoding was 40 | /// invalid. 41 | static bool url_decode(const std::string& in, std::string& out); 42 | 43 | ///memcache 44 | memcache server_cache; 45 | }; 46 | 47 | } // namespace server3 48 | } // namespace http 49 | 50 | #endif // HTTP_SERVER3_REQUEST_HANDLER_HPP 51 | -------------------------------------------------------------------------------- /code/request_parser.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // request_parser.cpp 3 | // ~~~~~~~~~~~~~~~~~~ 4 | // 5 | // Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 | // 7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 | // 10 | 11 | #include "request_parser.hpp" 12 | #include "request.hpp" 13 | 14 | namespace http { 15 | namespace server3 { 16 | 17 | request_parser::request_parser() 18 | : state_(method_start) 19 | { 20 | } 21 | 22 | void request_parser::reset() 23 | { 24 | state_ = method_start; 25 | } 26 | 27 | boost::tribool request_parser::consume(request& req, char input) 28 | { 29 | switch (state_) 30 | { 31 | case method_start: 32 | if (!is_char(input) || is_ctl(input) || is_tspecial(input)) 33 | { 34 | return false; 35 | } 36 | else 37 | { 38 | state_ = method; 39 | req.method.push_back(input); 40 | return boost::indeterminate; 41 | } 42 | case method: 43 | if (input == ' ') 44 | { 45 | state_ = uri; 46 | return boost::indeterminate; 47 | } 48 | else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) 49 | { 50 | return false; 51 | } 52 | else 53 | { 54 | req.method.push_back(input); 55 | return boost::indeterminate; 56 | } 57 | case uri: 58 | if (input == ' ') 59 | { 60 | state_ = http_version_h; 61 | return boost::indeterminate; 62 | } 63 | else if (is_ctl(input)) 64 | { 65 | return false; 66 | } 67 | else 68 | { 69 | req.uri.push_back(input); 70 | return boost::indeterminate; 71 | } 72 | case http_version_h: 73 | if (input == 'H') 74 | { 75 | state_ = http_version_t_1; 76 | return boost::indeterminate; 77 | } 78 | else 79 | { 80 | return false; 81 | } 82 | case http_version_t_1: 83 | if (input == 'T') 84 | { 85 | state_ = http_version_t_2; 86 | return boost::indeterminate; 87 | } 88 | else 89 | { 90 | return false; 91 | } 92 | case http_version_t_2: 93 | if (input == 'T') 94 | { 95 | state_ = http_version_p; 96 | return boost::indeterminate; 97 | } 98 | else 99 | { 100 | return false; 101 | } 102 | case http_version_p: 103 | if (input == 'P') 104 | { 105 | state_ = http_version_slash; 106 | return boost::indeterminate; 107 | } 108 | else 109 | { 110 | return false; 111 | } 112 | case http_version_slash: 113 | if (input == '/') 114 | { 115 | req.http_version_major = 0; 116 | req.http_version_minor = 0; 117 | state_ = http_version_major_start; 118 | return boost::indeterminate; 119 | } 120 | else 121 | { 122 | return false; 123 | } 124 | case http_version_major_start: 125 | if (is_digit(input)) 126 | { 127 | req.http_version_major = req.http_version_major * 10 + input - '0'; 128 | state_ = http_version_major; 129 | return boost::indeterminate; 130 | } 131 | else 132 | { 133 | return false; 134 | } 135 | case http_version_major: 136 | if (input == '.') 137 | { 138 | state_ = http_version_minor_start; 139 | return boost::indeterminate; 140 | } 141 | else if (is_digit(input)) 142 | { 143 | req.http_version_major = req.http_version_major * 10 + input - '0'; 144 | return boost::indeterminate; 145 | } 146 | else 147 | { 148 | return false; 149 | } 150 | case http_version_minor_start: 151 | if (is_digit(input)) 152 | { 153 | req.http_version_minor = req.http_version_minor * 10 + input - '0'; 154 | state_ = http_version_minor; 155 | return boost::indeterminate; 156 | } 157 | else 158 | { 159 | return false; 160 | } 161 | case http_version_minor: 162 | if (input == '\r') 163 | { 164 | state_ = expecting_newline_1; 165 | return boost::indeterminate; 166 | } 167 | else if (is_digit(input)) 168 | { 169 | req.http_version_minor = req.http_version_minor * 10 + input - '0'; 170 | return boost::indeterminate; 171 | } 172 | else 173 | { 174 | return false; 175 | } 176 | case expecting_newline_1: 177 | if (input == '\n') 178 | { 179 | state_ = header_line_start; 180 | return boost::indeterminate; 181 | } 182 | else 183 | { 184 | return false; 185 | } 186 | case header_line_start: 187 | if (input == '\r') 188 | { 189 | state_ = expecting_newline_3; 190 | return boost::indeterminate; 191 | } 192 | else if (!req.headers.empty() && (input == ' ' || input == '\t')) 193 | { 194 | state_ = header_lws; 195 | return boost::indeterminate; 196 | } 197 | else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) 198 | { 199 | return false; 200 | } 201 | else 202 | { 203 | req.headers.push_back(header()); 204 | req.headers.back().name.push_back(input); 205 | state_ = header_name; 206 | return boost::indeterminate; 207 | } 208 | case header_lws: 209 | if (input == '\r') 210 | { 211 | state_ = expecting_newline_2; 212 | return boost::indeterminate; 213 | } 214 | else if (input == ' ' || input == '\t') 215 | { 216 | return boost::indeterminate; 217 | } 218 | else if (is_ctl(input)) 219 | { 220 | return false; 221 | } 222 | else 223 | { 224 | state_ = header_value; 225 | req.headers.back().value.push_back(input); 226 | return boost::indeterminate; 227 | } 228 | case header_name: 229 | if (input == ':') 230 | { 231 | state_ = space_before_header_value; 232 | return boost::indeterminate; 233 | } 234 | else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) 235 | { 236 | return false; 237 | } 238 | else 239 | { 240 | req.headers.back().name.push_back(input); 241 | return boost::indeterminate; 242 | } 243 | case space_before_header_value: 244 | if (input == ' ') 245 | { 246 | state_ = header_value; 247 | return boost::indeterminate; 248 | } 249 | else 250 | { 251 | return false; 252 | } 253 | case header_value: 254 | if (input == '\r') 255 | { 256 | state_ = expecting_newline_2; 257 | return boost::indeterminate; 258 | } 259 | else if (is_ctl(input)) 260 | { 261 | return false; 262 | } 263 | else 264 | { 265 | req.headers.back().value.push_back(input); 266 | return boost::indeterminate; 267 | } 268 | case expecting_newline_2: 269 | if (input == '\n') 270 | { 271 | state_ = header_line_start; 272 | return boost::indeterminate; 273 | } 274 | else 275 | { 276 | return false; 277 | } 278 | case expecting_newline_3: 279 | return (input == '\n'); 280 | default: 281 | return false; 282 | } 283 | } 284 | 285 | bool request_parser::is_char(int c) 286 | { 287 | return c >= 0 && c <= 127; 288 | } 289 | 290 | bool request_parser::is_ctl(int c) 291 | { 292 | return (c >= 0 && c <= 31) || (c == 127); 293 | } 294 | 295 | bool request_parser::is_tspecial(int c) 296 | { 297 | switch (c) 298 | { 299 | case '(': case ')': case '<': case '>': case '@': 300 | case ',': case ';': case ':': case '\\': case '"': 301 | case '/': case '[': case ']': case '?': case '=': 302 | case '{': case '}': case ' ': case '\t': 303 | return true; 304 | default: 305 | return false; 306 | } 307 | } 308 | 309 | bool request_parser::is_digit(int c) 310 | { 311 | return c >= '0' && c <= '9'; 312 | } 313 | 314 | } // namespace server3 315 | } // namespace http 316 | -------------------------------------------------------------------------------- /code/request_parser.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // request_parser.hpp 3 | // ~~~~~~~~~~~~~~~~~~ 4 | // 5 | // Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 | // 7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 | // 10 | 11 | #ifndef HTTP_SERVER3_REQUEST_PARSER_HPP 12 | #define HTTP_SERVER3_REQUEST_PARSER_HPP 13 | 14 | #include 15 | #include 16 | 17 | namespace http { 18 | namespace server3 { 19 | 20 | struct request; 21 | 22 | /// Parser for incoming requests. 23 | class request_parser 24 | { 25 | public: 26 | /// Construct ready to parse the request method. 27 | request_parser(); 28 | 29 | /// Reset to initial parser state. 30 | void reset(); 31 | 32 | /// Parse some data. The tribool return value is true when a complete request 33 | /// has been parsed, false if the data is invalid, indeterminate when more 34 | /// data is required. The InputIterator return value indicates how much of the 35 | /// input has been consumed. 36 | template 37 | boost::tuple parse(request& req, InputIterator begin, InputIterator end) 38 | { 39 | while (begin != end) 40 | { 41 | boost::tribool result = consume(req, *begin++); 42 | if (result || !result) 43 | return boost::make_tuple(result, begin); 44 | } 45 | boost::tribool result = boost::indeterminate; 46 | return boost::make_tuple(result, begin); 47 | } 48 | 49 | private: 50 | /// Handle the next character of input. 51 | boost::tribool consume(request& req, char input); 52 | 53 | /// Check if a byte is an HTTP character. 54 | static bool is_char(int c); 55 | 56 | /// Check if a byte is an HTTP control character. 57 | static bool is_ctl(int c); 58 | 59 | /// Check if a byte is defined as an HTTP tspecial character. 60 | static bool is_tspecial(int c); 61 | 62 | /// Check if a byte is a digit. 63 | static bool is_digit(int c); 64 | 65 | /// The current state of the parser. 66 | enum state 67 | { 68 | method_start, 69 | method, 70 | uri, 71 | http_version_h, 72 | http_version_t_1, 73 | http_version_t_2, 74 | http_version_p, 75 | http_version_slash, 76 | http_version_major_start, 77 | http_version_major, 78 | http_version_minor_start, 79 | http_version_minor, 80 | expecting_newline_1, 81 | header_line_start, 82 | header_lws, 83 | header_name, 84 | space_before_header_value, 85 | header_value, 86 | expecting_newline_2, 87 | expecting_newline_3 88 | } state_; 89 | }; 90 | 91 | } // namespace server3 92 | } // namespace http 93 | 94 | #endif // HTTP_SERVER3_REQUEST_PARSER_HPP 95 | -------------------------------------------------------------------------------- /code/server.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // server.cpp 3 | // ~~~~~~~~~~ 4 | // 5 | // Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 | // 7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 | // 10 | 11 | #include "server.hpp" 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace http { 18 | namespace server3 { 19 | 20 | server::server(const std::string& address, const std::string& port, 21 | const std::string& doc_root, std::size_t thread_pool_size, const std::string& log_name) 22 | : thread_pool_size_(thread_pool_size), 23 | signals_(io_service_), 24 | acceptor_(io_service_), 25 | new_connection_(), 26 | request_handler_(doc_root), 27 | server_log_(log_name) 28 | { 29 | // Register to handle the signals that indicate when the server should exit. 30 | // It is safe to register for the same signal multiple times in a program, 31 | // provided all registration for the specified signal is made through Asio. 32 | signals_.add(SIGINT); 33 | signals_.add(SIGTERM); 34 | #if defined(SIGQUIT) 35 | signals_.add(SIGQUIT); 36 | #endif // defined(SIGQUIT) 37 | signals_.async_wait(boost::bind(&server::handle_stop, this)); 38 | 39 | // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR). 40 | boost::asio::ip::tcp::resolver resolver(io_service_); 41 | boost::asio::ip::tcp::resolver::query query(address, port); 42 | boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query); 43 | acceptor_.open(endpoint.protocol()); 44 | acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); 45 | acceptor_.bind(endpoint); 46 | acceptor_.listen(); 47 | 48 | start_accept(); 49 | } 50 | 51 | void server::run() 52 | { 53 | // Create a pool of threads to run all of the io_services. 54 | std::vector > threads; 55 | for (std::size_t i = 0; i < thread_pool_size_; ++i) 56 | { 57 | boost::shared_ptr thread(new boost::thread( 58 | boost::bind(&boost::asio::io_service::run, &io_service_))); 59 | threads.push_back(thread); 60 | } 61 | 62 | // Wait for all threads in the pool to exit. 63 | for (std::size_t i = 0; i < threads.size(); ++i) 64 | threads[i]->join(); 65 | } 66 | 67 | void server::start_accept() 68 | { 69 | new_connection_.reset(new connection(io_service_, request_handler_, server_log_)); 70 | acceptor_.async_accept(new_connection_->socket(), 71 | boost::bind(&server::handle_accept, this, 72 | boost::asio::placeholders::error)); 73 | } 74 | 75 | void server::handle_accept(const boost::system::error_code& e) 76 | { 77 | if (!e) 78 | { 79 | new_connection_->start(); 80 | } 81 | 82 | start_accept(); 83 | } 84 | 85 | void server::handle_stop() 86 | { 87 | io_service_.stop(); 88 | } 89 | 90 | } // namespace server3 91 | } // namespace http 92 | -------------------------------------------------------------------------------- /code/server.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // server.hpp 3 | // ~~~~~~~~~~ 4 | // 5 | // Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 | // 7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 | // 10 | 11 | #ifndef HTTP_SERVER3_SERVER_HPP 12 | #define HTTP_SERVER3_SERVER_HPP 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "connection.hpp" 20 | #include "request_handler.hpp" 21 | #include "log.hpp" 22 | 23 | namespace http { 24 | namespace server3 { 25 | 26 | /// The top-level class of the HTTP server. 27 | class server 28 | : private boost::noncopyable 29 | { 30 | public: 31 | /// Construct the server to listen on the specified TCP address and port, and 32 | /// serve up files from the given directory. 33 | explicit server(const std::string& address, const std::string& port, 34 | const std::string& doc_root, std::size_t thread_pool_size, const std::string& log_name); 35 | 36 | /// Run the server's io_service loop. 37 | void run(); 38 | 39 | private: 40 | /// Initiate an asynchronous accept operation. 41 | void start_accept(); 42 | 43 | /// Handle completion of an asynchronous accept operation. 44 | void handle_accept(const boost::system::error_code& e); 45 | 46 | /// Handle a request to stop the server. 47 | void handle_stop(); 48 | 49 | /// The number of threads that will call io_service::run(). 50 | std::size_t thread_pool_size_; 51 | 52 | /// The io_service used to perform asynchronous operations. 53 | boost::asio::io_service io_service_; 54 | 55 | /// The signal_set is used to register for process termination notifications. 56 | boost::asio::signal_set signals_; 57 | 58 | /// Acceptor used to listen for incoming connections. 59 | boost::asio::ip::tcp::acceptor acceptor_; 60 | 61 | /// The next connection to be accepted. 62 | connection_ptr new_connection_; 63 | 64 | /// The handler for all incoming requests. 65 | request_handler request_handler_; 66 | 67 | /// Log 68 | Log server_log_; 69 | }; 70 | 71 | } // namespace server3 72 | } // namespace http 73 | 74 | #endif // HTTP_SERVER3_SERVER_HPP 75 | -------------------------------------------------------------------------------- /lecture 3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kobe6672823/HPS/12e04af553887d1655aac850fc39759c4f3d0acd/lecture 3.pdf -------------------------------------------------------------------------------- /看pdf获得的一点小知识.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kobe6672823/HPS/12e04af553887d1655aac850fc39759c4f3d0acd/看pdf获得的一点小知识.docx -------------------------------------------------------------------------------- /看pdf获得的一点小知识.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kobe6672823/HPS/12e04af553887d1655aac850fc39759c4f3d0acd/看pdf获得的一点小知识.odt --------------------------------------------------------------------------------