/////////////////////////////////////////////////////////////////////////////////// Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>//// See accompanying file COPYING.TXT file for licensing details./////////////////////////////////////////////////////////////////////////////////#define CPPCMS_SOURCE#include "cgi_api.h"#include "cgi_acceptor.h"#include <cppcms/service.h>#include "service_impl.h"#include "cppcms_error_category.h"#include <cppcms/json.h>#include <cppcms/cstdint.h>#include <stdlib.h>#include <string.h>#include <algorithm>#include <iostream>#include <stdio.h>#include <cppcms/config.h>#include <booster/aio/buffer.h>#include "binder.h"#include <utility>#include "cached_settings.h"#ifdef CPPCMS_WIN_NATIVE# ifndef NOMINMAX# define NOMINMAX# endif# include <winsock2.h>#else# include <arpa/inet.h>#endifnamespace io = booster::aio;namespace cppcms {namespace impl {namespace cgi {template<typename API,typename Factory> class socket_acceptor;class fastcgi : public connection {public:fastcgi(cppcms::service &srv) :connection(srv),socket_(srv.impl().get_io_service()),header_(),full_header_(),eof_(),eof_callback_(false){reset_all();int procs=srv.procs_no();if(procs < 1) procs=1;int threads=srv.threads_no();cuncurrency_hint_=srv.cached_settings().fastcgi.cuncurrency_hint;if(cuncurrency_hint_ < 0)cuncurrency_hint_ = procs*threads;}~fastcgi(){if(socket_.native()!=io::invalid_socket) {booster::system::error_code e;socket_.shutdown(io::stream_socket::shut_rdwr,e);}}virtual void async_read_headers(handler const &h){reset_all();async_read_record(mfunc_to_event_handler(&fastcgi::on_start_request,self(),h));}virtual void async_read_some(void *p,size_t s,io_handler const &h){if(read_length_ == content_length_) {socket_.get_io_service().post(h,booster::system::error_code(errc::protocol_violation,cppcms_category),0);return;}if(body_ptr_ < body_.size()) {size_t rest=body_.size() - body_ptr_;if(s > rest)s=rest;memcpy(p,&body_[body_ptr_],s);body_ptr_ += s;read_length_ += s;if(body_ptr_ == body_.size()) {body_ptr_ = 0;body_.clear();}if(read_length_ >= content_length_) {async_read_record(mfunc_to_event_handler(&fastcgi::on_read_stdin_eof_expected,self(),h,s));return;}socket_.get_io_service().post(h,booster::system::error_code(),s);return;}else {async_read_record(mfunc_to_event_handler(&fastcgi::on_some_input_recieved,self(),h,std::make_pair(p,s)));return;}}virtual void on_async_write_start(){}virtual void on_async_write_progress(bool){}private:void on_some_input_recieved(booster::system::error_code const &e,io_handler const &h,std::pair<void *,size_t> in){if(e) { h(e,0); return; }if( header_.type!=fcgi_stdin|| header_.request_id!=request_id_|| header_.content_length==0){h(booster::system::error_code(errc::protocol_violation,cppcms_category),0);return;}async_read_some(in.first,in.second,h);}void on_read_stdin_eof_expected(booster::system::error_code const &e,io_handler const &h,size_t s){if(e) { h(e,s); return; }if( header_.type!=fcgi_stdin|| header_.request_id!=request_id_|| header_.content_length!=0){h(booster::system::error_code(errc::protocol_violation,cppcms_category),s);return;}h(booster::system::error_code(),s);}public:virtual booster::aio::const_buffer format_output(booster::aio::const_buffer const &in,bool completed,booster::system::error_code &){booster::aio::const_buffer packet;booster::aio::const_buffer::entry const *chunks = in.get().first;//#define DEBUG_FASTCGI#ifdef DEBUG_FASTCGI{size_t n=in.get().second;printf("Format output of %d:\n",int(in.bytes_count()));for(size_t i=0;i<n;i++) {printf("[%.*s]",int(chunks[i].size),chunks[i].ptr);}if(completed) {printf("\nEOF\n");}else {printf("\n---\n");}}#endifsize_t reminder = in.bytes_count();size_t in_size = reminder;size_t chunk_consumed = 0;while(reminder > 0) {static const char pad[8]={0,0,0,0,0,0,0,0};static const size_t max_packet_len = 65535;size_t chunk = 0;int pad_len = 0;if(reminder > max_packet_len) {chunk = max_packet_len;if(in_size > max_packet_len && reminder == in_size) {// prepare only oncefull_header_.version = fcgi_version_1;full_header_.type=fcgi_stdout;full_header_.request_id=request_id_;full_header_.content_length = max_packet_len;full_header_.padding_length = pad_len = 1;full_header_.to_net();}else {pad_len = 1;}packet += io::buffer(&full_header_,sizeof(full_header_));}else {chunk = reminder;memset(&header_,0,sizeof(header_));header_.version=fcgi_version_1;header_.type=fcgi_stdout;header_.request_id=request_id_;header_.content_length = reminder;header_.padding_length =pad_len = (8 - (reminder % 8)) % 8;header_.to_net();packet += io::buffer(&header_,sizeof(header_));}reminder -= chunk;while(chunk > 0) {size_t next_size = chunks->size - chunk_consumed;if(next_size > chunk)next_size = chunk;packet += io::buffer(chunks->ptr + chunk_consumed, next_size);chunk_consumed += next_size;chunk -= next_size;if(chunk_consumed == chunks->size) {chunks++;chunk_consumed = 0;}}packet += io::buffer(pad,pad_len);}if(completed) {prepare_eof();packet += io::buffer(&eof_,sizeof(eof_));}#ifdef DEBUG_FASTCGIstd::pair<booster::aio::const_buffer::entry const *,size_t> cnk = packet.get();for(size_t i=0;i<cnk.second;i++) {std::cerr << "[ " << (void const *)(cnk.first[i].ptr) << " " << cnk.first[i].size << "]\n" << std::endl;}#endifreturn packet;}virtual booster::aio::stream_socket &socket() { return socket_; }virtual booster::aio::io_service &get_io_service(){return socket_.get_io_service();}virtual bool keep_alive(){bool ka_value = keep_alive_;reset_all();return ka_value;}void prepare_eof(){memset(&eof_,0,sizeof(eof_));for(unsigned i=0;i<2;i++) {eof_.headers_[i].version=fcgi_version_1;eof_.headers_[i].request_id=request_id_;}eof_.headers_[0].type=fcgi_stdout;eof_.headers_[1].type=fcgi_end_request;eof_.headers_[1].content_length=8;eof_.record_.protocol_status=fcgi_request_complete;eof_.headers_[0].to_net();eof_.headers_[1].to_net();eof_.record_.to_net();}virtual void do_eof(){if(eof_callback_)socket_.cancel();eof_callback_ = false;}struct io_handler_to_handler {callback h;io_handler_to_handler(callback const &c) : h(c) {}void operator()(booster::system::error_code const &,size_t){h();}};struct io_handler_to_event_handler {handler h;io_handler_to_event_handler(handler const &c) : h(c) {}void operator()(booster::system::error_code const &e,size_t){h(e);}};// This is not really correct because server may try// to multiplex or ask control... But meanwhile it is good enoughvirtual void async_read_eof(callback const &h){eof_callback_ = true;static char a;async_read_from_socket(&a,1,io_handler_to_handler(h));}private:////// defs////struct fcgi_header {unsigned char version;unsigned char type;uint16_t request_id;uint16_t content_length;unsigned char padding_length;unsigned char reserved;void to_host() {request_id = ntohs(request_id);content_length = ntohs(content_length);}void to_net() {request_id = htons(request_id);content_length = htons(content_length);}};enum {fcgi_header_len = 8,fcgi_version_1 = 1,fcgi_begin_request = 1,fcgi_abort_request = 2,fcgi_end_request = 3,fcgi_params = 4,fcgi_stdin = 5,fcgi_stdout = 6,fcgi_stderr = 7,fcgi_data = 8,fcgi_get_values = 9,fcgi_get_values_result =10,fcgi_unknown_type =11,fcgi_maxtype =11,fcgi_null_request_id = 0};struct fcgi_request_body {uint16_t role;unsigned char flags;unsigned char reserved [5];void to_host() { role = ntohs(role); }void to_net() { role = htons(role); }};struct fcgi_begin_request_record {fcgi_header header;fcgi_request_body body;void to_host() { header.to_host(); body.to_host(); }void to_net() { header.to_net(); body.to_net(); }};enum {fcgi_keep_conn = 1};enum {fcgi_responder = 1,fcgi_authorizer = 2,fcgi_filter = 3};struct fcgi_end_request_body {uint32_t app_status;unsigned char protocol_status;unsigned char reserved[3];void to_host() { app_status = ntohl(app_status); }void to_net() { app_status = htonl(app_status); }};struct fcgi_end_request_record {fcgi_header header;fcgi_end_request_body body;void to_host() { header.to_host(); body.to_host(); }void to_net() { header.to_net(); body.to_net(); }};enum {fcgi_request_complete = 0,fcgi_cant_mpx_conn = 1,fcgi_overloaded = 2,fcgi_unknown_role = 3};struct fcgi_unknown_type_body {unsigned char type;unsigned char reserved[7];};struct fcgi_unknown_type_record {fcgi_header header;fcgi_unknown_type_body body;void to_host() { header.to_host();}void to_net() { header.to_net(); }};union fcgi_record {fcgi_header header;fcgi_begin_request_record begin ;fcgi_end_request_record end;fcgi_unknown_type_record unknown;};////// end of defs////////void on_start_request(booster::system::error_code const &e,handler const &h){if(e) {h(e);return;}if(header_.version!=fcgi_version_1){h(booster::system::error_code(errc::protocol_violation,cppcms_category));return;}if(header_.type==fcgi_get_values) {header_.type = fcgi_get_values_result;std::vector<std::pair<std::string,std::string> > pairs;pairs.reserve(4);if(!parse_pairs(pairs)) {h(booster::system::error_code(errc::protocol_violation,cppcms_category));return;}body_.clear();std::locale l("C");std::ostringstream ss;ss.imbue(l);ss<<cuncurrency_hint_;for(unsigned i=0;i<pairs.size();i++) {std::string name=pairs[i].first;if(name=="FCGI_MAX_CONNS" || name=="FCGI_MAX_REQS")add_pair(name,ss.str());else if(name=="FCGI_MPXS_CONNS")add_pair(name,"0");}async_send_respnse(mfunc_to_event_handler(&fastcgi::on_params_response_sent,self(),h));}else if(header_.type!=fcgi_begin_request) {async_read_headers(h);return;}if(body_.size()!=sizeof(fcgi_request_body)) {h(booster::system::error_code(errc::protocol_violation,cppcms_category));return;}fcgi_request_body *body=reinterpret_cast<fcgi_request_body*>(&body_.front());body->to_host();keep_alive_=body->flags & fcgi_keep_conn;if(body->role!=fcgi_responder) {header_.type=fcgi_end_request;body_.assign(0,8);fcgi_end_request_body *body=reinterpret_cast<fcgi_end_request_body*>(&body_.front());body->protocol_status=fcgi_unknown_role;body->to_net();async_send_respnse(mfunc_to_event_handler(&fastcgi::on_params_response_sent,self(),h));return;}request_id_=header_.request_id;body_.clear();if(non_blocking_read_record()) {params_record_expected(booster::system::error_code(),h);}else {async_read_record(mfunc_to_event_handler(&fastcgi::params_record_expected,self(),h));}}uint32_t read_len(unsigned char const *&p,unsigned char const *e){if (p<e && *p < 0x80) {return *p++;}else if(e-p >= 4) {uint32_t B3=*p++;uint32_t B2=*p++;uint32_t B1=*p++;uint32_t B0=*p++;uint32_t len = ((B3 & 0x7fU) << 24) + (B2 << 16) + (B1 << 8) + B0;return len;}else {return 0xFFFFFFFFu;}}bool parse_pairs(){unsigned char const *p=reinterpret_cast<unsigned char const *>(&body_.front());unsigned char const *e=p + body_.size();while(p<e) {uint32_t nlen=read_len(p,e);uint32_t vlen=read_len(p,e);if(nlen == 0xFFFFFFFFu || vlen == 0xFFFFFFFFu)return false;char *name=0;if(uint32_t(e - p) >= nlen) { // don't chage order -- prevent integer overflowname = pool_.add(reinterpret_cast<char const *>(p),nlen);p+=nlen;}else {return false;}char *value = 0;if(uint32_t(e - p) >= vlen) { // don't chage order -- prevent integer overflowvalue = pool_.add(reinterpret_cast<char const *>(p),vlen);p+=vlen;}else {return false;}env_.add(name,value);}return true;}bool parse_pairs(std::vector<std::pair<std::string,std::string> > &container){unsigned char const *p=reinterpret_cast<unsigned char const *>(&body_.front());unsigned char const *e=p + body_.size();while(p<e) {uint32_t nlen=read_len(p,e);uint32_t vlen=read_len(p,e);if(nlen == 0xFFFFFFFFu || vlen == 0xFFFFFFFFu)return false;std::string name;if(uint32_t(e - p) >= nlen) { // don't chage order -- prevent integer overflowname.assign(reinterpret_cast<char const *>(p),nlen);p+=nlen;}else {return false;}std::string value;if(uint32_t(e - p) >= vlen) { // don't chage order -- prevent integer overflowvalue.assign(reinterpret_cast<char const *>(p),vlen);p+=vlen;}else {return false;}container.resize(container.size()+1);container.back().first.swap(name);container.back().second.swap(value);}return true;}void params_record_expected(booster::system::error_code const &e,handler const &h){if(e) {h(e);return;}for(;;){if(header_.type!=fcgi_params || header_.request_id!=request_id_)h(booster::system::error_code(errc::protocol_violation,cppcms_category));if(header_.content_length!=0) { // eofif(body_.size() < 16384) {if(non_blocking_read_record()) {continue;}else {async_read_record(mfunc_to_event_handler(&fastcgi::params_record_expected,self(),h));}}else {h(booster::system::error_code(errc::protocol_violation,cppcms_category));}return;}break;}parse_pairs();body_.clear();char const *s_length = env_.get("CONTENT_LENGTH");if(!s_length || *s_length == 0 || (content_length_ = atoll(s_length)) <=0)content_length_=0;if(content_length_==0) {if(non_blocking_read_record()) {stdin_eof_expected(booster::system::error_code(),h);}else {async_read_record(mfunc_to_event_handler(&fastcgi::stdin_eof_expected,self(),h));}return;}h(booster::system::error_code());}void stdin_eof_expected(booster::system::error_code const &e,handler const &h){if(e) { h(e); return; }if(header_.type!=fcgi_stdin || header_.content_length!=0) {h(booster::system::error_code(errc::protocol_violation,cppcms_category));return;}h(booster::system::error_code());}void on_params_response_sent(booster::system::error_code const &e,handler const &h){if(e) { h(e); return; }async_read_headers(h);}// this is internal function for short messagesvoid async_send_respnse(handler const &h){header_.content_length=body_.size();if(body_.size() % 8 != 0) {header_.padding_length=8 - (body_.size() % 8);body_.resize(body_.size() + header_.padding_length);}io::const_buffer packet =io::buffer(&header_,sizeof(header_))+ io::buffer(body_);header_.to_net();socket_.async_write(packet,io_handler_to_event_handler(h));}bool non_blocking_read_record(){fcgi_header hdr;if(!peek_bytes(&hdr,sizeof(hdr)))return false;hdr.to_host();size_t buffer_size = get_buffer_size();if(buffer_size < sizeof(hdr) + hdr.content_length + hdr.padding_length)return false;skip_bytes(sizeof(hdr));header_ = hdr;size_t cur_size=body_.size();size_t rec_size=header_.content_length+header_.padding_length;if(rec_size==0) {return true;}body_.resize(cur_size + rec_size);read_bytes(&body_[cur_size],rec_size);body_.resize(cur_size + header_.content_length);return true;}void async_read_record(handler const &h){async_read_from_socket(&header_,sizeof(header_),mfunc_to_io_handler(&fastcgi::on_header_read,self(),h));}struct on_header_read_binder : public booster::callable<void(booster::system::error_code const &,size_t)> {handler h;booster::shared_ptr<fastcgi> self;on_header_read_binder(handler const &_h,booster::shared_ptr<fastcgi> const &s) : h(_h),self(s){}virtual void operator()(booster::system::error_code const &e,size_t /*read*/){self->on_body_read(e,h);}};void on_header_read(booster::system::error_code const &e,size_t /*unused read*/,handler const &h){if(e) { h(e); return; }header_.to_host();size_t cur_size=body_.size();size_t rec_size=header_.content_length+header_.padding_length;if(rec_size==0) {h(booster::system::error_code());return;}body_.resize(cur_size + rec_size);std::auto_ptr<booster::callable<void(booster::system::error_code const &,size_t)> > cb;cb.reset(new on_header_read_binder(h,self()));async_read_from_socket(&body_[cur_size],rec_size,cb);}void on_body_read(booster::system::error_code const &e,handler const &h){if(e) { h(e); return; }body_.resize(body_.size() - header_.padding_length);h(booster::system::error_code());}void add_value(std::string const &value){if(value.size() <128) {body_.push_back(char(value.size()));}else {uint32_t size=value.size();size |= 0x80000000u;size=htonl(size);char *p=(char*)&size;body_.insert(body_.end(),p,p+sizeof(size));}}void add_pair(std::string const &name,std::string const &value){add_value(name);add_value(value);body_.insert(body_.end(),name.begin(),name.end());body_.insert(body_.end(),value.begin(),value.end());}booster::shared_ptr<fastcgi> self(){return booster::static_pointer_cast<fastcgi>(shared_from_this());}friend class socket_acceptor<fastcgi>;io::stream_socket socket_;fcgi_header header_;fcgi_header full_header_;std::vector<char> body_;long long read_length_;long long content_length_;unsigned body_ptr_;int request_id_;bool keep_alive_;int cuncurrency_hint_;struct eof_str {fcgi_header headers_[2];fcgi_end_request_body record_;} eof_;std::vector<char> cache_;size_t cache_start_,cache_end_;bool eof_callback_;void reset_all(){memset(&header_,0,sizeof(header_));body_.clear();read_length_=content_length_=0;body_ptr_=0;request_id_=0;keep_alive_=false;env_.clear();pool_.clear();memset(&eof_,0,sizeof(eof_));if(cache_.empty()) {cache_start_ = 0;cache_end_ = 0;}}bool peek_bytes(void *ptr,size_t n){if(cache_end_ - cache_start_ >= n) {memcpy(ptr,&cache_[cache_start_],n);return true;}return false;}size_t get_buffer_size(){return cache_end_ - cache_start_;}void skip_bytes(size_t n){assert(cache_end_ - cache_start_ >= n);cache_start_ +=n;}void read_bytes(void *ptr,size_t n){assert(cache_end_ - cache_start_ >=n);memcpy(ptr,&cache_[cache_start_],n);cache_start_+=n;}void async_read_from_socket(void *ptr,size_t n,booster::aio::io_handler const &cb){if(cache_end_ - cache_start_ >=n) {memcpy(ptr,&cache_[cache_start_],n);cache_start_+=n;socket_.get_io_service().post(cb,booster::system::error_code(),n);return;}if(cache_start_ == cache_end_) {cache_start_ = cache_end_ = 0;}else if(cache_start_!=0) {memmove(&cache_[0],&cache_[cache_start_],cache_end_ - cache_start_);cache_end_ = cache_end_ - cache_start_;cache_start_ = 0;}size_t min_size = std::max(n,size_t(16384));if(cache_.size() < n) {cache_.resize(min_size,0);}socket_.async_read_some(booster::aio::buffer(&cache_[cache_end_],cache_.size() - cache_end_),mfunc_to_io_handler(&fastcgi::on_some_read_from_socket,self(),cb,std::make_pair(ptr,n)));}void on_some_read_from_socket( booster::system::error_code const &e,size_t read_size,booster::callback<void(booster::system::error_code const &e,size_t read)> const &cb,std::pair<void *,size_t> inp){void *ptr = inp.first;size_t expected_read_size = inp.second;cache_end_ += read_size;if(e) {cb(e,0);return;}async_read_from_socket(ptr,expected_read_size,cb);}};std::auto_ptr<acceptor> fastcgi_api_tcp_socket_factory(cppcms::service &srv,std::string ip,int port,int backlog){std::auto_ptr<acceptor> a(new socket_acceptor<fastcgi>(srv,ip,port,backlog));return a;}#if !defined(CPPCMS_WIN32)std::auto_ptr<acceptor> fastcgi_api_unix_socket_factory(cppcms::service &srv,std::string socket,int backlog){std::auto_ptr<acceptor> a(new socket_acceptor<fastcgi>(srv,socket,backlog));return a;}std::auto_ptr<acceptor> fastcgi_api_unix_socket_factory(cppcms::service &srv,int backlog){std::auto_ptr<acceptor> a(new socket_acceptor<fastcgi>(srv,backlog));return a;}#endif} // cgi} // impl} // cppcms
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。