📄 filemodule.cpp
字号:
// determine the MIME type response_file.mime_type = findMIMEType( response_file.file_path.leaf() ); // get the file_size and last_modified timestamp response_file.update(); // just compare strings for simplicity (parsing this date format sucks!) if (response_file.last_modified_string == if_modified_since) { // no need to read the file; the modified times match! response_type = RESPONSE_NOT_MODIFIED; } else if (request->getMethod() == HTTPTypes::REQUEST_METHOD_HEAD) { response_type = RESPONSE_HEAD_OK; } else { response_type = RESPONSE_OK; // read the file (may throw exception) response_file.read(); if (m_cache_setting != 0) { // add new entry to the cache PION_LOG_DEBUG(m_logger, "Adding cache entry for request (" << getResource() << "): " << relative_path); boost::mutex::scoped_lock cache_lock(m_cache_mutex); m_cache_map.insert( std::make_pair(relative_path, response_file) ); } } } // prepare a response and set the Content-Type HTTPResponsePtr response(HTTPResponse::create()); response->setContentType(response_file.mime_type); // set Last-Modified header to enable client-side caching response->addHeader(HTTPTypes::HEADER_LAST_MODIFIED, response_file.last_modified_string); switch(response_type) { case RESPONSE_UNDEFINED: // this should never happen throw UndefinedResponseException(request->getResource()); break; case RESPONSE_NOT_MODIFIED: // set "Not Modified" response response->setResponseCode(HTTPTypes::RESPONSE_CODE_NOT_MODIFIED); response->setResponseMessage(HTTPTypes::RESPONSE_MESSAGE_NOT_MODIFIED); break; case RESPONSE_OK: // write the file's contents to the response stream if (response_file.file_size != 0) response->write(response_file.file_content.get(), response_file.file_size); // fall through to RESPONSE_HEAD_OK case RESPONSE_HEAD_OK: // set "OK" response (not really necessary since this is the default) response->setResponseCode(HTTPTypes::RESPONSE_CODE_OK); response->setResponseMessage(HTTPTypes::RESPONSE_MESSAGE_OK); break; } // send the response response->send(tcp_conn); return true;}void FileModule::start(void){ PION_LOG_DEBUG(m_logger, "Starting up resource (" << getResource() << ')'); // scan directory/file if scan setting != 0 if (m_scan_setting != 0) { // force caching if scan == (2 | 3) if (m_cache_setting == 0 && m_scan_setting > 1) m_cache_setting = 1; boost::mutex::scoped_lock cache_lock(m_cache_mutex); // add entry for file if one is defined if (! m_file.empty()) { // use empty relative_path for file option // use placeholder entry (do not pre-populate) if scan == 1 addCacheEntry("", m_file, m_scan_setting == 1); } // scan directory if one is defined if (! m_directory.empty()) scanDirectory(m_directory); }}void FileModule::stop(void){ PION_LOG_DEBUG(m_logger, "Shutting down resource (" << getResource() << ')'); // clear cached files (if started again, it will re-scan) boost::mutex::scoped_lock cache_lock(m_cache_mutex); m_cache_map.clear();}void FileModule::scanDirectory(const boost::filesystem::path& dir_path){ PION_LOG_DEBUG(m_logger, "Scanning directory (" << getResource() << "): " << dir_path.directory_string()); // iterate through items in the directory boost::filesystem::directory_iterator end_itr; for ( boost::filesystem::directory_iterator itr( dir_path ); itr != end_itr; ++itr ) { if ( boost::filesystem::is_directory(*itr) ) { // item is a sub-directory // recursively call scanDirectory() scanDirectory(*itr); } else { // item is a regular file // figure out relative path to the file std::string file_path_string( itr->path().file_string() ); std::string relative_path( file_path_string.substr(m_directory.directory_string().size() + 1) ); // add item to cache (use placeholder if scan == 1) addCacheEntry(relative_path, *itr, m_scan_setting == 1); } }}std::pair<FileModule::CacheMap::iterator, bool>FileModule::addCacheEntry(const std::string& relative_path, const boost::filesystem::path& file_path, const bool placeholder){ DiskFile cache_entry(file_path, NULL, 0, 0, findMIMEType(file_path.leaf())); if (! placeholder) { cache_entry.update(); try { cache_entry.read(); } catch (std::exception& e) { PION_LOG_ERROR(m_logger, "Unable to add file to cache: " << file_path.file_string()); return std::make_pair(m_cache_map.end(), false); } } std::pair<CacheMap::iterator, bool> add_entry_result = m_cache_map.insert( std::make_pair(relative_path, cache_entry) ); if (add_entry_result.second) { PION_LOG_DEBUG(m_logger, "Added file to cache: " << file_path.file_string()); } else { PION_LOG_ERROR(m_logger, "Unable to insert cache entry for file: " << file_path.file_string()); } return add_entry_result;}std::string FileModule::findMIMEType(const std::string& file_name) { // initialize m_mime_types if it hasn't been done already boost::call_once(FileModule::createMIMETypes, m_mime_types_init_flag); // determine the file's extension std::string extension(file_name.substr(file_name.find_last_of('.') + 1)); std::transform(extension.begin(), extension.end(), extension.begin(), tolower); // search for the matching mime type and return the result MIMETypeMap::iterator i = m_mime_types_ptr->find(extension); return (i == m_mime_types_ptr->end() ? DEFAULT_MIME_TYPE : i->second);}void FileModule::createMIMETypes(void) { // create the map static MIMETypeMap mime_types; // populate mime types mime_types["js"] = "text/javascript"; mime_types["txt"] = "text/plain"; mime_types["xml"] = "text/xml"; mime_types["css"] = "text/css"; mime_types["htm"] = "text/html"; mime_types["html"] = "text/html"; mime_types["xhtml"] = "text/html"; mime_types["gif"] = "image/gif"; mime_types["png"] = "image/png"; mime_types["jpg"] = "image/jpeg"; mime_types["jpeg"] = "image/jpeg"; // ... // set the static pointer m_mime_types_ptr = &mime_types;}// FileModule::DiskFile member functionsvoid FileModule::DiskFile::update(void){ // set file_size and last_modified file_size = boost::filesystem::file_size( file_path ); last_modified = boost::filesystem::last_write_time( file_path ); last_modified_string = HTTPTypes::get_date_string( last_modified );}void FileModule::DiskFile::read(void){ // re-allocate storage buffer for the file's content file_content.reset(new char[file_size]); // open the file for reading boost::filesystem::ifstream file_stream; file_stream.open(file_path, std::ios::in | std::ios::binary); // read the file into memory if (!file_stream.is_open() || !file_stream.read(file_content.get(), file_size)) throw FileModule::FileReadException(file_path.file_string());}bool FileModule::DiskFile::checkUpdated(void){ // get current values unsigned long cur_size = boost::filesystem::file_size( file_path ); time_t cur_modified = boost::filesystem::last_write_time( file_path ); // check if file has not been updated if (cur_modified == last_modified && cur_size == file_size) return false; // file has been updated // update file_size and last_modified timestamp file_size = cur_size; last_modified = cur_modified; last_modified_string = HTTPTypes::get_date_string( last_modified ); // read new contents read(); return true;}/// creates new FileModule objectsextern "C" FileModule *pion_create_FileModule(void){ return new FileModule();}/// destroys FileModule objectsextern "C" void pion_destroy_FileModule(FileModule *module_ptr){ delete module_ptr;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -