pion-net
4.0.9
|
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