pion-net  4.0.9
FileService.hpp
1 // ------------------------------------------------------------------
2 // pion-net: a C++ framework for building lightweight HTTP interfaces
3 // ------------------------------------------------------------------
4 // Copyright (C) 2007-2008 Atomic Labs, Inc. (http://www.atomiclabs.com)
5 //
6 // Distributed under the Boost Software License, Version 1.0.
7 // See http://www.boost.org/LICENSE_1_0.txt
8 //
9 
10 #ifndef __PION_FILESERVICE_HEADER__
11 #define __PION_FILESERVICE_HEADER__
12 
13 #include <boost/shared_ptr.hpp>
14 #include <boost/functional/hash.hpp>
15 #include <boost/filesystem/path.hpp>
16 #include <boost/thread/once.hpp>
17 #include <boost/thread/mutex.hpp>
18 #include <boost/shared_array.hpp>
19 #include <pion/PionLogger.hpp>
20 #include <pion/PionException.hpp>
21 #include <pion/PionHashMap.hpp>
22 #include <pion/net/WebService.hpp>
23 #include <pion/net/HTTPRequest.hpp>
24 #include <pion/net/HTTPResponseWriter.hpp>
25 #include <pion/net/HTTPServer.hpp>
26 #include <string>
27 #include <map>
28 
29 
30 namespace pion { // begin namespace pion
31 namespace plugins { // begin namespace plugins
32 
33 
37 class DiskFile {
38 public:
40  DiskFile(void)
41  : m_file_size(0), m_last_modified(0) {}
42 
44  DiskFile(const boost::filesystem::path& path,
45  char *content, unsigned long size,
46  std::time_t modified, const std::string& mime)
47  : m_file_path(path), m_file_content(content), m_file_size(size),
48  m_last_modified(modified), m_mime_type(mime)
49  {}
50 
52  DiskFile(const DiskFile& f)
56  {}
57 
59  void update(void);
60 
62  void read(void);
63 
69  bool checkUpdated(void);
70 
72  inline const boost::filesystem::path& getFilePath(void) const { return m_file_path; }
73 
75  inline char *getFileContent(void) { return m_file_content.get(); }
76 
78  inline bool hasFileContent(void) const { return m_file_content; }
79 
81  inline unsigned long getFileSize(void) const { return m_file_size; }
82 
84  inline std::time_t getLastModified(void) const { return m_last_modified; }
85 
87  inline const std::string& getLastModifiedString(void) const { return m_last_modified_string; }
88 
90  inline const std::string& getMimeType(void) const { return m_mime_type; }
91 
93  inline void setFilePath(const boost::filesystem::path& p) { m_file_path = p; }
94 
96  inline void appendFilePath(const std::string& p) { m_file_path /= p; }
97 
99  inline void setMimeType(const std::string& t) { m_mime_type = t; }
100 
102  inline void resetFileContent(unsigned long n = 0) {
103  if (n == 0) m_file_content.reset();
104  else m_file_content.reset(new char[n]);
105  }
106 
107 
108 protected:
109 
111  boost::filesystem::path m_file_path;
112 
114  boost::shared_array<char> m_file_content;
115 
117  std::streamsize m_file_size;
118 
120  std::time_t m_last_modified;
121 
124 
126  std::string m_mime_type;
127 };
128 
129 
134  public boost::enable_shared_from_this<DiskFileSender>,
135  private boost::noncopyable
136 {
137 public:
146  static inline boost::shared_ptr<DiskFileSender>
148  pion::net::HTTPRequestPtr& request,
149  pion::net::TCPConnectionPtr& tcp_conn,
150  unsigned long max_chunk_size = 0)
151  {
152  return boost::shared_ptr<DiskFileSender>(new DiskFileSender(file, request,
153  tcp_conn, max_chunk_size));
154  }
155 
157  virtual ~DiskFileSender() {}
158 
162  void send(void);
163 
165  inline void setLogger(PionLogger log_ptr) { m_logger = log_ptr; }
166 
168  inline PionLogger getLogger(void) { return m_logger; }
169 
170 
171 protected:
172 
181  DiskFileSender(DiskFile& file,
182  pion::net::HTTPRequestPtr& request,
183  pion::net::TCPConnectionPtr& tcp_conn,
184  unsigned long max_chunk_size);
185 
192  void handleWrite(const boost::system::error_code& write_error,
193  std::size_t bytes_written);
194 
195 
198 
199 
200 private:
201 
203  DiskFile m_disk_file;
204 
206  pion::net::HTTPResponseWriterPtr m_writer;
207 
209  boost::filesystem::ifstream m_file_stream;
210 
212  boost::shared_array<char> m_content_buf;
213 
219  unsigned long m_max_chunk_size;
220 
222  unsigned long m_file_bytes_to_send;
223 
225  unsigned long m_bytes_sent;
226 };
227 
229 typedef boost::shared_ptr<DiskFileSender> DiskFileSenderPtr;
230 
231 
235 class FileService :
236  public pion::net::WebService
237 {
238 public:
239 
242  public:
243  DirectoryNotFoundException(const std::string& dir)
244  : PionException("FileService directory not found: ", dir) {}
245  };
246 
249  public:
250  NotADirectoryException(const std::string& dir)
251  : PionException("FileService option is not a directory: ", dir) {}
252  };
253 
256  public:
257  FileNotFoundException(const std::string& file)
258  : PionException("FileService file not found: ", file) {}
259  };
260 
263  public:
264  NotAFileException(const std::string& file)
265  : PionException("FileService option is not a file: ", file) {}
266  };
267 
270  public:
271  InvalidCacheException(const std::string& value)
272  : PionException("FileService invalid value for cache option: ", value) {}
273  };
274 
277  public:
278  InvalidScanException(const std::string& value)
279  : PionException("FileService invalid value for scan option: ", value) {}
280  };
281 
284  public:
285  InvalidOptionValueException(const std::string& option, const std::string& value)
286  : PionException("FileService invalid value for " + option + " option: ", value) {}
287  };
288 
291  public:
292  FileReadException(const std::string& value)
293  : PionException("FileService unable to read file: ", value) {}
294  };
295 
298  public:
299  UndefinedResponseException(const std::string& value)
300  : PionException("FileService has an undefined response: ", value) {}
301  };
302 
303 
304  // default constructor and destructor
305  FileService(void);
306  virtual ~FileService() {}
307 
318  virtual void setOption(const std::string& name, const std::string& value);
319 
321  virtual void operator()(pion::net::HTTPRequestPtr& request,
322  pion::net::TCPConnectionPtr& tcp_conn);
323 
325  virtual void start(void);
326 
328  virtual void stop(void);
329 
331  inline void setLogger(PionLogger log_ptr) { m_logger = log_ptr; }
332 
334  inline PionLogger getLogger(void) { return m_logger; }
335 
336 
337 protected:
338 
340  typedef PION_HASH_MAP<std::string, DiskFile, PION_HASH_STRING > CacheMap;
341 
343  typedef PION_HASH_MAP<std::string, std::string, PION_HASH_STRING > MIMETypeMap;
344 
350  void scanDirectory(const boost::filesystem::path& dir_path);
351 
362  std::pair<CacheMap::iterator, bool>
363  addCacheEntry(const std::string& relative_path,
364  const boost::filesystem::path& file_path,
365  const bool placeholder);
366 
373  static std::string findMIMEType(const std::string& file_name);
374 
375  void sendNotFoundResponse(pion::net::HTTPRequestPtr& http_request,
376  pion::net::TCPConnectionPtr& tcp_conn);
377 
380 
381 
382 private:
383 
385  static void createMIMETypes(void);
386 
387 
389  static const std::string DEFAULT_MIME_TYPE;
390 
392  static const unsigned int DEFAULT_CACHE_SETTING;
393 
395  static const unsigned int DEFAULT_SCAN_SETTING;
396 
398  static const unsigned long DEFAULT_MAX_CACHE_SIZE;
399 
401  static const unsigned long DEFAULT_MAX_CHUNK_SIZE;
402 
404  static boost::once_flag m_mime_types_init_flag;
405 
407  static MIMETypeMap * m_mime_types_ptr;
408 
409 
411  boost::filesystem::path m_directory;
412 
414  boost::filesystem::path m_file;
415 
417  CacheMap m_cache_map;
418 
420  boost::mutex m_cache_mutex;
421 
428  unsigned int m_cache_setting;
429 
437  unsigned int m_scan_setting;
438 
443  unsigned long m_max_cache_size;
444 
450  unsigned long m_max_chunk_size;
451 
455  bool m_writable;
456 };
457 
458 
459 } // end namespace plugins
460 } // end namespace pion
461 
462 #endif