00001
00002
00003
00004
00005
00006
00007
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 {
00031 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
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 }
00460 }
00461
00462 #endif