ChipMaster's trial hacks on C++CMS starting with v1.2.1. Not sure I'll follow on with the v2 since it looks to be breaking and mostly frivolous.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

213 lines
4.1 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
  4. //
  5. // See accompanying file COPYING.TXT file for licensing details.
  6. //
  7. ///////////////////////////////////////////////////////////////////////////////
  8. #define CPPCMS_SOURCE
  9. #include <cppcms/http_file.h>
  10. #include <cppcms/urandom.h>
  11. #include <cppcms/cppcms_error.h>
  12. #include <booster/nowide/cstdio.h>
  13. #include <booster/nowide/fstream.h>
  14. #include <stdlib.h>
  15. #include <vector>
  16. #include "tohex.h"
  17. namespace cppcms {
  18. namespace http {
  19. struct file::impl_data {};
  20. std::string file::name() const
  21. {
  22. return name_;
  23. }
  24. std::string file::mime() const
  25. {
  26. return mime_;
  27. }
  28. std::string file::filename() const
  29. {
  30. return filename_;
  31. }
  32. long long file::size()
  33. {
  34. if(saved_in_file_) {
  35. std::streampos now=file_.tellp();
  36. file_.seekp(0,std::ios_base::end);
  37. long long size = file_.tellp();
  38. file_.seekp(now);
  39. return size;
  40. }
  41. else {
  42. return file_data_.tellp();
  43. }
  44. }
  45. std::istream &file::data()
  46. {
  47. if(saved_in_file_)
  48. return file_;
  49. else
  50. return file_data_;
  51. }
  52. std::ostream &file::write_data()
  53. {
  54. if(saved_in_file_) {
  55. return file_;
  56. }
  57. else {
  58. if(size() > static_cast<long long>(size_limit_)) {
  59. move_to_file();
  60. return file_;
  61. }
  62. else {
  63. return file_data_;
  64. }
  65. }
  66. }
  67. void file::copy_stream(std::istream &in,std::ostream &out)
  68. {
  69. std::vector<char> v(1024,0);
  70. while(!in.eof()) {
  71. in.read(&v.front(),1024);
  72. out.write(&v.front(),in.gcount());
  73. }
  74. }
  75. void file::save_to(std::string const &filename)
  76. {
  77. if(!saved_in_file_) {
  78. file_data_.clear();
  79. file_data_.seekg(0);
  80. save_by_copy(filename,file_data_);
  81. return;
  82. }
  83. file_.clear();
  84. file_.seekg(0);
  85. file_.sync();
  86. #ifdef CPPCMS_WIN32
  87. file_.close();
  88. /// we can't move opened file on windows as it would be locked
  89. if(booster::nowide::rename(tmp_file_name_.c_str(),filename.c_str())!=0) {
  90. file_.open(tmp_file_name_.c_str(),std::ios_base::binary | std::ios_base::in | std::ios_base::out);
  91. if(!file_) {
  92. throw cppcms_error("Failed to reopen file");
  93. }
  94. save_by_copy(filename,file_);
  95. file_.close();
  96. booster::nowide::remove(tmp_file_name_.c_str());
  97. }
  98. #else
  99. if(booster::nowide::rename(tmp_file_name_.c_str(),filename.c_str())!=0) {
  100. save_by_copy(filename,file_);
  101. booster::nowide::remove(tmp_file_name_.c_str());
  102. }
  103. file_.close();
  104. #endif
  105. removed_ = 1;
  106. }
  107. void file::save_by_copy(std::string const &file_name,std::istream &in)
  108. {
  109. booster::nowide::ofstream f(file_name.c_str(),std::ios_base::binary | std::ios_base::out);
  110. if(!f) {
  111. throw cppcms_error("Failed to save open file:"+file_name);
  112. }
  113. copy_stream(in,f);
  114. f << std::flush;
  115. f.close();
  116. }
  117. void file::set_memory_limit(size_t size)
  118. {
  119. size_limit_ = size;
  120. }
  121. void file::set_temporary_directory(std::string const &d)
  122. {
  123. temporary_dir_ = d;
  124. }
  125. void file::move_to_file()
  126. {
  127. std::string tmp_dir;
  128. if(temporary_dir_.empty()) {
  129. char const *tmp=getenv("TEMP");
  130. if(!tmp)
  131. tmp=getenv("TMP");
  132. if(!tmp)
  133. tmp="/tmp";
  134. tmp_dir=tmp;
  135. }
  136. else {
  137. tmp_dir = temporary_dir_;
  138. }
  139. tmp_file_name_ = tmp_dir + "/cppcms_uploads_";
  140. urandom_device rnd;
  141. char buf[16];
  142. char rand[33]={0};
  143. rnd.generate(buf,16);
  144. impl::tohex(buf,sizeof(buf),rand);
  145. tmp_file_name_.append(rand);
  146. tmp_file_name_+=".tmp";
  147. file_.open(tmp_file_name_.c_str(),
  148. std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::trunc);
  149. if(!file_)
  150. throw cppcms_error("Failed to create temporary file");
  151. file_data_.seekg(0);
  152. copy_stream(file_data_,file_);
  153. file_data_.str("");
  154. saved_in_file_ = 1;
  155. }
  156. file::file() :
  157. size_limit_(1024*128),
  158. saved_in_file_(0),
  159. removed_(0)
  160. {
  161. }
  162. file::~file()
  163. {
  164. if(saved_in_file_ && !removed_) {
  165. file_.close();
  166. if(!tmp_file_name_.empty()) {
  167. booster::nowide::remove(tmp_file_name_.c_str());
  168. }
  169. }
  170. }
  171. void file::filename(std::string const &v)
  172. {
  173. filename_=v;
  174. }
  175. void file::name(std::string const &v)
  176. {
  177. name_=v;
  178. }
  179. void file::mime(std::string const &v)
  180. {
  181. mime_=v;
  182. }
  183. } // http
  184. } // cppcms