pion  5.0.6
services/FileService.hpp
00001 // ---------------------------------------------------------------------
00002 // pion:  a Boost C++ framework for building lightweight HTTP interfaces
00003 // ---------------------------------------------------------------------
00004 // Copyright (C) 2007-2014 Splunk Inc.  (https://github.com/splunk/pion)
00005 //
00006 // Distributed under the Boost Software License, Version 1.0.
00007 // See http://www.boost.org/LICENSE_1_0.txt
00008 //
00009 
00010 #ifndef __PION_FILESERVICE_HEADER__
00011 #define __PION_FILESERVICE_HEADER__
00012 
00013 #include <boost/shared_ptr.hpp>
00014 #include <boost/functional/hash.hpp>
00015 #include <boost/filesystem/path.hpp>
00016 #include <boost/thread/once.hpp>
00017 #include <boost/thread/mutex.hpp>
00018 #include <boost/shared_array.hpp>
00019 #include <pion/config.hpp>
00020 #include <pion/logger.hpp>
00021 #include <pion/hash_map.hpp>
00022 #include <pion/http/plugin_service.hpp>
00023 #include <pion/http/request.hpp>
00024 #include <pion/http/response_writer.hpp>
00025 #include <pion/http/server.hpp>
00026 #include <string>
00027 #include <map>
00028 
00029 
00030 namespace pion {        // begin namespace pion
00031 namespace plugins {     // begin namespace plugins
00032 
00033 
00037 class DiskFile {
00038 public:
00040     DiskFile(void)
00041         : m_file_size(0), m_last_modified(0) {}
00042 
00044     DiskFile(const boost::filesystem::path& path,
00045              char *content, unsigned long size,
00046              std::time_t modified, const std::string& mime)
00047         : m_file_path(path), m_file_content(content), m_file_size(size),
00048         m_last_modified(modified), m_mime_type(mime)
00049     {}
00050 
00052     DiskFile(const DiskFile& f)
00053         : m_file_path(f.m_file_path), m_file_content(f.m_file_content),
00054         m_file_size(f.m_file_size), m_last_modified(f.m_last_modified),
00055         m_last_modified_string(f.m_last_modified_string), m_mime_type(f.m_mime_type)
00056     {}
00057 
00059     void update(void);
00060 
00062     void read(void);
00063 
00069     bool checkUpdated(void);
00070 
00072     inline const boost::filesystem::path& getFilePath(void) const { return m_file_path; }
00073 
00075     inline char *getFileContent(void) { return m_file_content.get(); }
00076 
00078     inline bool hasFileContent(void) const { return static_cast<bool>(m_file_content); }
00079 
00081     inline unsigned long getFileSize(void) const { return m_file_size; }
00082 
00084     inline std::time_t getLastModified(void) const { return m_last_modified; }
00085 
00087     inline const std::string& getLastModifiedString(void) const { return m_last_modified_string; }
00088 
00090     inline const std::string& getMimeType(void) const { return m_mime_type; }
00091 
00093     inline void setFilePath(const boost::filesystem::path& p) { m_file_path = p; }
00094 
00096     inline void appendFilePath(const std::string& p) { m_file_path /= p; }
00097 
00099     inline void setMimeType(const std::string& t) { m_mime_type = t; }
00100 
00102     inline void resetFileContent(unsigned long n = 0) {
00103         if (n == 0) m_file_content.reset();
00104         else m_file_content.reset(new char[n]);
00105     }
00106 
00107 
00108 protected:
00109 
00111     boost::filesystem::path     m_file_path;
00112 
00114     boost::shared_array<char>   m_file_content;
00115 
00117     std::streamsize             m_file_size;
00118 
00120     std::time_t                 m_last_modified;
00121 
00123     std::string                 m_last_modified_string;
00124 
00126     std::string                 m_mime_type;
00127 };
00128 
00129 
00133 class DiskFileSender : 
00134     public boost::enable_shared_from_this<DiskFileSender>,
00135     private boost::noncopyable
00136 {
00137 public:
00146     static inline boost::shared_ptr<DiskFileSender>
00147         create(DiskFile& file,
00148                pion::http::request_ptr& http_request_ptr,
00149                pion::tcp::connection_ptr& tcp_conn,
00150                unsigned long max_chunk_size = 0) 
00151     {
00152         return boost::shared_ptr<DiskFileSender>(new DiskFileSender(file, http_request_ptr,
00153                                                                     tcp_conn, max_chunk_size));
00154     }
00155 
00157     virtual ~DiskFileSender() {}
00158 
00162     void send(void);
00163 
00165     inline void set_logger(logger log_ptr) { m_logger = log_ptr; }
00166 
00168     inline logger get_logger(void) { return m_logger; }
00169 
00170 
00171 protected:
00172 
00181     DiskFileSender(DiskFile& file,
00182                    pion::http::request_ptr& http_request_ptr,
00183                    pion::tcp::connection_ptr& tcp_conn,
00184                    unsigned long max_chunk_size);
00185 
00192     void handle_write(const boost::system::error_code& write_error,
00193                      std::size_t bytes_written);
00194 
00195 
00197     logger                              m_logger;
00198 
00199 
00200 private:
00201 
00203     DiskFile                                m_disk_file;
00204 
00206     pion::http::response_writer_ptr        m_writer;
00207 
00209     boost::filesystem::ifstream             m_file_stream;
00210 
00212     boost::shared_array<char>               m_content_buf;
00213 
00219     unsigned long                           m_max_chunk_size;
00220 
00222     unsigned long                           m_file_bytes_to_send;
00223 
00225     unsigned long                           m_bytes_sent;
00226 };
00227 
00229 typedef boost::shared_ptr<DiskFileSender>       DiskFileSenderPtr;
00230 
00231 
00235 class FileService :
00236     public pion::http::plugin_service
00237 {
00238 public:
00239 
00240     // default constructor and destructor
00241     FileService(void);
00242     virtual ~FileService() {}
00243 
00254     virtual void set_option(const std::string& name, const std::string& value);
00255 
00257     virtual void operator()(pion::http::request_ptr& http_request_ptr,
00258                             pion::tcp::connection_ptr& tcp_conn);
00259 
00261     virtual void start(void);
00262 
00264     virtual void stop(void);
00265 
00267     inline void set_logger(logger log_ptr) { m_logger = log_ptr; }
00268 
00270     inline logger get_logger(void) { return m_logger; }
00271 
00272 
00273 protected:
00274 
00276     typedef PION_HASH_MAP<std::string, DiskFile, PION_HASH_STRING >     CacheMap;
00277 
00279     typedef PION_HASH_MAP<std::string, std::string, PION_HASH_STRING >  MIMETypeMap;
00280 
00286     void scanDirectory(const boost::filesystem::path& dir_path);
00287 
00298     std::pair<CacheMap::iterator, bool>
00299         addCacheEntry(const std::string& relative_path,
00300                       const boost::filesystem::path& file_path,
00301                       const bool placeholder);
00302 
00309     static std::string findMIMEType(const std::string& file_name);
00310 
00311     void sendNotFoundResponse(pion::http::request_ptr& http_request_ptr,
00312                               pion::tcp::connection_ptr& tcp_conn);
00313 
00315     logger                  m_logger;
00316 
00317 
00318 private:
00319 
00321     static void createMIMETypes(void);
00322 
00323 
00325     static const std::string    DEFAULT_MIME_TYPE;
00326 
00328     static const unsigned int   DEFAULT_CACHE_SETTING;
00329 
00331     static const unsigned int   DEFAULT_SCAN_SETTING;
00332 
00334     static const unsigned long  DEFAULT_MAX_CACHE_SIZE;
00335 
00337     static const unsigned long  DEFAULT_MAX_CHUNK_SIZE;
00338 
00340     static boost::once_flag     m_mime_types_init_flag;
00341 
00343     static MIMETypeMap *        m_mime_types_ptr;
00344 
00345 
00347     boost::filesystem::path     m_directory;
00348 
00350     boost::filesystem::path     m_file;
00351 
00353     CacheMap                    m_cache_map;
00354 
00356     boost::mutex                m_cache_mutex;
00357 
00364     unsigned int                m_cache_setting;
00365 
00373     unsigned int                m_scan_setting;
00374 
00379     unsigned long               m_max_cache_size;
00380 
00386     unsigned long               m_max_chunk_size;
00387 
00391     bool                        m_writable;
00392 };
00393 
00394 
00395 }   // end namespace plugins
00396 }   // end namespace pion
00397 
00398 #endif