net/services/FileService.hpp

00001 // ------------------------------------------------------------------
00002 // pion-net: a C++ framework for building lightweight HTTP interfaces
00003 // ------------------------------------------------------------------
00004 // Copyright (C) 2007-2008 Atomic Labs, Inc.  (http://www.atomiclabs.com)
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/PionLogger.hpp>
00020 #include <pion/PionException.hpp>
00021 #include <pion/PionHashMap.hpp>
00022 #include <pion/net/WebService.hpp>
00023 #include <pion/net/HTTPRequest.hpp>
00024 #include <pion/net/HTTPResponseWriter.hpp>
00025 #include <pion/net/HTTPServer.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 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::net::HTTPRequestPtr& request,
00149                pion::net::TCPConnectionPtr& tcp_conn,
00150                unsigned long max_chunk_size = 0) 
00151     {
00152         return boost::shared_ptr<DiskFileSender>(new DiskFileSender(file, request,
00153                                                                     tcp_conn, max_chunk_size));
00154     }
00155 
00157     virtual ~DiskFileSender() {}
00158 
00162     void send(void);
00163 
00165     inline void setLogger(PionLogger log_ptr) { m_logger = log_ptr; }
00166 
00168     inline PionLogger getLogger(void) { return m_logger; }
00169 
00170 
00171 protected:
00172 
00181     DiskFileSender(DiskFile& file,
00182                    pion::net::HTTPRequestPtr& request,
00183                    pion::net::TCPConnectionPtr& tcp_conn,
00184                    unsigned long max_chunk_size);
00185 
00192     void handleWrite(const boost::system::error_code& write_error,
00193                      std::size_t bytes_written);
00194 
00195 
00197     PionLogger                              m_logger;
00198 
00199 
00200 private:
00201 
00203     DiskFile                                m_disk_file;
00204 
00206     pion::net::HTTPResponseWriterPtr        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::net::WebService
00237 {
00238 public:
00239 
00241     class DirectoryNotFoundException : public PionException {
00242     public:
00243         DirectoryNotFoundException(const std::string& dir)
00244             : PionException("FileService directory not found: ", dir) {}
00245     };
00246 
00248     class NotADirectoryException : public PionException {
00249     public:
00250         NotADirectoryException(const std::string& dir)
00251             : PionException("FileService option is not a directory: ", dir) {}
00252     };
00253 
00255     class FileNotFoundException : public PionException {
00256     public:
00257         FileNotFoundException(const std::string& file)
00258             : PionException("FileService file not found: ", file) {}
00259     };
00260 
00262     class NotAFileException : public PionException {
00263     public:
00264         NotAFileException(const std::string& file)
00265             : PionException("FileService option is not a file: ", file) {}
00266     };
00267 
00269     class InvalidCacheException : public PionException {
00270     public:
00271         InvalidCacheException(const std::string& value)
00272             : PionException("FileService invalid value for cache option: ", value) {}
00273     };
00274 
00276     class InvalidScanException : public PionException {
00277     public:
00278         InvalidScanException(const std::string& value)
00279             : PionException("FileService invalid value for scan option: ", value) {}
00280     };
00281 
00283     class InvalidOptionValueException : public PionException {
00284     public:
00285         InvalidOptionValueException(const std::string& option, const std::string& value)
00286             : PionException("FileService invalid value for " + option + " option: ", value) {}
00287     };
00288 
00290     class FileReadException : public PionException {
00291     public:
00292         FileReadException(const std::string& value)
00293             : PionException("FileService unable to read file: ", value) {}
00294     };
00295 
00297     class UndefinedResponseException : public PionException {
00298     public:
00299         UndefinedResponseException(const std::string& value)
00300             : PionException("FileService has an undefined response: ", value) {}
00301     };
00302 
00303 
00304     // default constructor and destructor
00305     FileService(void);
00306     virtual ~FileService() {}
00307 
00318     virtual void setOption(const std::string& name, const std::string& value);
00319 
00321     virtual void operator()(pion::net::HTTPRequestPtr& request,
00322                             pion::net::TCPConnectionPtr& tcp_conn);
00323 
00325     virtual void start(void);
00326 
00328     virtual void stop(void);
00329 
00331     inline void setLogger(PionLogger log_ptr) { m_logger = log_ptr; }
00332 
00334     inline PionLogger getLogger(void) { return m_logger; }
00335 
00336 
00337 protected:
00338 
00340     typedef PION_HASH_MAP<std::string, DiskFile, PION_HASH_STRING >     CacheMap;
00341 
00343     typedef PION_HASH_MAP<std::string, std::string, PION_HASH_STRING >  MIMETypeMap;
00344 
00350     void scanDirectory(const boost::filesystem::path& dir_path);
00351 
00362     std::pair<CacheMap::iterator, bool>
00363         addCacheEntry(const std::string& relative_path,
00364                       const boost::filesystem::path& file_path,
00365                       const bool placeholder);
00366 
00373     static std::string findMIMEType(const std::string& file_name);
00374 
00375     void sendNotFoundResponse(pion::net::HTTPRequestPtr& http_request,
00376                               pion::net::TCPConnectionPtr& tcp_conn);
00377 
00379     PionLogger                  m_logger;
00380 
00381 
00382 private:
00383 
00385     static void createMIMETypes(void);
00386 
00387 
00389     static const std::string    DEFAULT_MIME_TYPE;
00390 
00392     static const unsigned int   DEFAULT_CACHE_SETTING;
00393 
00395     static const unsigned int   DEFAULT_SCAN_SETTING;
00396 
00398     static const unsigned long  DEFAULT_MAX_CACHE_SIZE;
00399 
00401     static const unsigned long  DEFAULT_MAX_CHUNK_SIZE;
00402 
00404     static boost::once_flag     m_mime_types_init_flag;
00405 
00407     static MIMETypeMap *        m_mime_types_ptr;
00408 
00409 
00411     boost::filesystem::path     m_directory;
00412 
00414     boost::filesystem::path     m_file;
00415 
00417     CacheMap                    m_cache_map;
00418 
00420     boost::mutex                m_cache_mutex;
00421 
00428     unsigned int                m_cache_setting;
00429 
00437     unsigned int                m_scan_setting;
00438 
00443     unsigned long               m_max_cache_size;
00444 
00450     unsigned long               m_max_chunk_size;
00451 
00455     bool                        m_writable;
00456 };
00457 
00458 
00459 }   // end namespace plugins
00460 }   // end namespace pion
00461 
00462 #endif

Generated on Fri Apr 30 14:48:53 2010 for pion-net by  doxygen 1.4.7