|
- #define CPPCMS_SOURCE
- #include "asio_config.h"
- #include "cgi_api.h"
- #include "cgi_acceptor.h"
- #include "asio_config.h"
- #include "service.h"
- #include "service_impl.h"
- #include "cppcms_error_category.h"
- #include <iostream>
- #include <stdlib.h>
- #include "config.h"
- #ifdef CPPCMS_USE_EXTERNAL_BOOST
- # include <boost/bind.hpp>
- #else // Internal Boost
- # include <cppcms_boost/bind.hpp>
- namespace boost = cppcms_boost;
- #endif
-
- namespace cppcms {
- namespace impl {
- namespace cgi {
- template<typename Proto,typename API> class socket_acceptor;
- template<typename Proto>
- class scgi : public connection {
- public:
- scgi(cppcms::service &srv) :
- connection(srv),
- start_(0),
- end_(0),
- socket_(srv.impl().get_io_service())
- {
- }
- ~scgi()
- {
- boost::system::error_code e;
- socket_.shutdown(boost::asio::basic_stream_socket<Proto>::shutdown_both,e);
- }
- virtual void async_read_headers(handler const &h)
- {
- buffer_.resize(16);
- boost::asio::async_read(
- socket_,
- boost::asio::buffer(buffer_),
- boost::bind(
- &scgi::on_first_read,
- self(),
- boost::asio::placeholders::error,
- boost::asio::placeholders::bytes_transferred,
- h));
-
- }
-
- void on_first_read(boost::system::error_code const &e,size_t n,handler const &h)
- {
- if(e) {
- h(e);
- return;
- }
- sep_=std::find(buffer_.begin(),buffer_.begin()+n,':') - buffer_.begin();
- if(sep_ >= 16) {
- h(boost::system::error_code(errc::protocol_violation,cppcms_category));
- return;
- }
- buffer_[sep_]=0;
- int len=atoi(&buffer_.front());
- if(len < 0 || 16384 < len) {
- h(boost::system::error_code(errc::protocol_violation,cppcms_category));
- return;
- }
- size_t size=n;
- buffer_.resize(sep_ + 2 + len); // len of number + ':' + content + ','
- if(buffer_.size() <= size) {
- // It can't be so short so
- h(boost::system::error_code(errc::protocol_violation,cppcms_category));
- return;
- }
- boost::asio::async_read(socket_,
- boost::asio::buffer(&buffer_[size],buffer_.size() - size),
- boost::bind( &scgi::on_headers_chunk_read,
- self(),
- boost::asio::placeholders::error,
- h));
- }
- void on_headers_chunk_read(boost::system::error_code const &e,handler const &h)
- {
- if(e) { h(e); return; }
- if(buffer_.back()!=',') {
- buffer_.back() = 0;
- // make sure it is NUL terminated
- h(boost::system::error_code(errc::protocol_violation,cppcms_category));
- return;
- }
-
- char const *p=&buffer_[sep_ + 1];
- while(p < &buffer_.back()) {
- std::string key=p;
- p+=key.size()+1;
- if(p>=&buffer_.back())
- break;
- std::string value=p;
- p+=value.size()+1;
- env_.insert(std::pair<std::string,std::string>(key,value));
- }
- buffer_.clear();
-
- h(boost::system::error_code());
- }
-
- // should be called only after headers are read
- virtual std::string getenv(std::string const &key)
- {
- std::map<std::string,std::string>::const_iterator p;
- p=env_.find(key);
- if(p==env_.end())
- return std::string();
- return p->second;
- }
- virtual std::map<std::string,std::string> const &getenv()
- {
- return env_;
- }
- virtual void async_read_some(void *p,size_t s,io_handler const &h)
- {
- socket_.async_read_some(boost::asio::buffer(p,s),h);
- }
- virtual void async_write_some(void const *p,size_t s,io_handler const &h)
- {
- socket_.async_write_some(boost::asio::buffer(p,s),h);
- }
- virtual size_t write_some(void const *buffer,size_t n)
- {
- return socket_.write_some(boost::asio::buffer(buffer,n));
- }
- virtual boost::asio::io_service &get_io_service()
- {
- return socket_.get_io_service();
- }
- virtual bool keep_alive()
- {
- return false;
- }
-
- virtual void async_write_eof(handler const &h)
- {
- boost::system::error_code e;
- socket_.shutdown(boost::asio::basic_stream_socket<Proto>::shutdown_send,e);
- socket_.get_io_service().post(boost::bind(h,boost::system::error_code()));
- }
-
- virtual void close()
- {
- boost::system::error_code e;
- socket_.shutdown(boost::asio::basic_stream_socket<Proto>::shutdown_receive,e);
- socket_.close(e);
- }
-
- virtual void async_read_eof(callback const &h)
- {
- static char a;
- socket_.async_read_some(boost::asio::buffer(&a,1),boost::bind(h));
- }
-
- private:
- size_t start_,end_,sep_;
- intrusive_ptr<scgi<Proto> > self()
- {
- return this;
- }
- friend class socket_acceptor<Proto,scgi<Proto> >;
- boost::asio::basic_stream_socket<Proto> socket_;
- std::vector<char> buffer_;
- std::map<std::string,std::string> env_;
- };
-
- typedef scgi<boost::asio::ip::tcp> tcp_socket_scgi;
- typedef tcp_socket_acceptor<tcp_socket_scgi> tcp_socket_scgi_acceptor;
- std::auto_ptr<acceptor> scgi_api_tcp_socket_factory(cppcms::service &srv,std::string ip,int port,int backlog)
- {
- std::auto_ptr<acceptor> a(new tcp_socket_scgi_acceptor(srv,ip,port,backlog));
- return a;
- }
- #if !defined(CPPCMS_WIN32)
- typedef scgi<boost::asio::local::stream_protocol> unix_socket_scgi;
- typedef unix_socket_acceptor<unix_socket_scgi> unix_socket_scgi_acceptor;
- std::auto_ptr<acceptor> scgi_api_unix_socket_factory(cppcms::service &srv,std::string socket,int backlog)
- {
- std::auto_ptr<acceptor> a(new unix_socket_scgi_acceptor(srv,socket,backlog));
- return a;
- }
- std::auto_ptr<acceptor> scgi_api_unix_socket_factory(cppcms::service &srv,int backlog)
- {
- std::auto_ptr<acceptor> a(new unix_socket_scgi_acceptor(srv,backlog));
- return a;
- }
- #endif
-
-
- } // cgi
- } // impl
- } // cppcms
-
|