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.
 
 
 
 
 
 

203 lines
5.3 KiB

  1. #define CPPCMS_SOURCE
  2. #include "asio_config.h"
  3. #include "cgi_api.h"
  4. #include "cgi_acceptor.h"
  5. #include "asio_config.h"
  6. #include "service.h"
  7. #include "service_impl.h"
  8. #include "cppcms_error_category.h"
  9. #include <iostream>
  10. #include <stdlib.h>
  11. #include "config.h"
  12. #ifdef CPPCMS_USE_EXTERNAL_BOOST
  13. # include <boost/bind.hpp>
  14. #else // Internal Boost
  15. # include <cppcms_boost/bind.hpp>
  16. namespace boost = cppcms_boost;
  17. #endif
  18. namespace cppcms {
  19. namespace impl {
  20. namespace cgi {
  21. template<typename Proto,typename API> class socket_acceptor;
  22. template<typename Proto>
  23. class scgi : public connection {
  24. public:
  25. scgi(cppcms::service &srv) :
  26. connection(srv),
  27. start_(0),
  28. end_(0),
  29. socket_(srv.impl().get_io_service())
  30. {
  31. }
  32. ~scgi()
  33. {
  34. boost::system::error_code e;
  35. socket_.shutdown(boost::asio::basic_stream_socket<Proto>::shutdown_both,e);
  36. }
  37. virtual void async_read_headers(handler const &h)
  38. {
  39. buffer_.resize(16);
  40. boost::asio::async_read(
  41. socket_,
  42. boost::asio::buffer(buffer_),
  43. boost::bind(
  44. &scgi::on_first_read,
  45. self(),
  46. boost::asio::placeholders::error,
  47. boost::asio::placeholders::bytes_transferred,
  48. h));
  49. }
  50. void on_first_read(boost::system::error_code const &e,size_t n,handler const &h)
  51. {
  52. if(e) {
  53. h(e);
  54. return;
  55. }
  56. sep_=std::find(buffer_.begin(),buffer_.begin()+n,':') - buffer_.begin();
  57. if(sep_ >= 16) {
  58. h(boost::system::error_code(errc::protocol_violation,cppcms_category));
  59. return;
  60. }
  61. buffer_[sep_]=0;
  62. int len=atoi(&buffer_.front());
  63. if(len < 0 || 16384 < len) {
  64. h(boost::system::error_code(errc::protocol_violation,cppcms_category));
  65. return;
  66. }
  67. size_t size=n;
  68. buffer_.resize(sep_ + 2 + len); // len of number + ':' + content + ','
  69. if(buffer_.size() <= size) {
  70. // It can't be so short so
  71. h(boost::system::error_code(errc::protocol_violation,cppcms_category));
  72. return;
  73. }
  74. boost::asio::async_read(socket_,
  75. boost::asio::buffer(&buffer_[size],buffer_.size() - size),
  76. boost::bind( &scgi::on_headers_chunk_read,
  77. self(),
  78. boost::asio::placeholders::error,
  79. h));
  80. }
  81. void on_headers_chunk_read(boost::system::error_code const &e,handler const &h)
  82. {
  83. if(e) { h(e); return; }
  84. if(buffer_.back()!=',') {
  85. buffer_.back() = 0;
  86. // make sure it is NUL terminated
  87. h(boost::system::error_code(errc::protocol_violation,cppcms_category));
  88. return;
  89. }
  90. char const *p=&buffer_[sep_ + 1];
  91. while(p < &buffer_.back()) {
  92. std::string key=p;
  93. p+=key.size()+1;
  94. if(p>=&buffer_.back())
  95. break;
  96. std::string value=p;
  97. p+=value.size()+1;
  98. env_.insert(std::pair<std::string,std::string>(key,value));
  99. }
  100. buffer_.clear();
  101. h(boost::system::error_code());
  102. }
  103. // should be called only after headers are read
  104. virtual std::string getenv(std::string const &key)
  105. {
  106. std::map<std::string,std::string>::const_iterator p;
  107. p=env_.find(key);
  108. if(p==env_.end())
  109. return std::string();
  110. return p->second;
  111. }
  112. virtual std::map<std::string,std::string> const &getenv()
  113. {
  114. return env_;
  115. }
  116. virtual void async_read_some(void *p,size_t s,io_handler const &h)
  117. {
  118. socket_.async_read_some(boost::asio::buffer(p,s),h);
  119. }
  120. virtual void async_write_some(void const *p,size_t s,io_handler const &h)
  121. {
  122. socket_.async_write_some(boost::asio::buffer(p,s),h);
  123. }
  124. virtual size_t write_some(void const *buffer,size_t n)
  125. {
  126. return socket_.write_some(boost::asio::buffer(buffer,n));
  127. }
  128. virtual boost::asio::io_service &get_io_service()
  129. {
  130. return socket_.get_io_service();
  131. }
  132. virtual bool keep_alive()
  133. {
  134. return false;
  135. }
  136. virtual void async_write_eof(handler const &h)
  137. {
  138. boost::system::error_code e;
  139. socket_.shutdown(boost::asio::basic_stream_socket<Proto>::shutdown_send,e);
  140. socket_.get_io_service().post(boost::bind(h,boost::system::error_code()));
  141. }
  142. virtual void close()
  143. {
  144. boost::system::error_code e;
  145. socket_.shutdown(boost::asio::basic_stream_socket<Proto>::shutdown_receive,e);
  146. socket_.close(e);
  147. }
  148. virtual void async_read_eof(callback const &h)
  149. {
  150. static char a;
  151. socket_.async_read_some(boost::asio::buffer(&a,1),boost::bind(h));
  152. }
  153. private:
  154. size_t start_,end_,sep_;
  155. intrusive_ptr<scgi<Proto> > self()
  156. {
  157. return this;
  158. }
  159. friend class socket_acceptor<Proto,scgi<Proto> >;
  160. boost::asio::basic_stream_socket<Proto> socket_;
  161. std::vector<char> buffer_;
  162. std::map<std::string,std::string> env_;
  163. };
  164. typedef scgi<boost::asio::ip::tcp> tcp_socket_scgi;
  165. typedef tcp_socket_acceptor<tcp_socket_scgi> tcp_socket_scgi_acceptor;
  166. std::auto_ptr<acceptor> scgi_api_tcp_socket_factory(cppcms::service &srv,std::string ip,int port,int backlog)
  167. {
  168. std::auto_ptr<acceptor> a(new tcp_socket_scgi_acceptor(srv,ip,port,backlog));
  169. return a;
  170. }
  171. #if !defined(CPPCMS_WIN32)
  172. typedef scgi<boost::asio::local::stream_protocol> unix_socket_scgi;
  173. typedef unix_socket_acceptor<unix_socket_scgi> unix_socket_scgi_acceptor;
  174. std::auto_ptr<acceptor> scgi_api_unix_socket_factory(cppcms::service &srv,std::string socket,int backlog)
  175. {
  176. std::auto_ptr<acceptor> a(new unix_socket_scgi_acceptor(srv,socket,backlog));
  177. return a;
  178. }
  179. std::auto_ptr<acceptor> scgi_api_unix_socket_factory(cppcms::service &srv,int backlog)
  180. {
  181. std::auto_ptr<acceptor> a(new unix_socket_scgi_acceptor(srv,backlog));
  182. return a;
  183. }
  184. #endif
  185. } // cgi
  186. } // impl
  187. } // cppcms