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.
 
 
 
 
 
 

770 lines
19 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. //#define DEBUG_HTTP_PARSER
  10. #include "cgi_api.h"
  11. #include "cgi_acceptor.h"
  12. #include <cppcms/service.h>
  13. #include "service_impl.h"
  14. #include "cppcms_error_category.h"
  15. #include <cppcms/json.h>
  16. #include "http_parser.h"
  17. #include <cppcms/config.h>
  18. #include <cppcms/util.h>
  19. #include <string.h>
  20. #include <iostream>
  21. #include <list>
  22. #include <sstream>
  23. #include <algorithm>
  24. #include <cppcms_boost/bind.hpp>
  25. #include <stdio.h>
  26. namespace boost = cppcms_boost;
  27. // for testing only
  28. //#define CPPCMS_NO_SO_SNDTIMO
  29. #if defined(__sun)
  30. # ifndef CPPCMS_NO_SO_SNDTIMO
  31. # define CPPCMS_NO_SO_SNDTIMO
  32. # endif
  33. #endif
  34. #ifdef CPPCMS_NO_SO_SNDTIMO
  35. #include <poll.h>
  36. #include <errno.h>
  37. #endif
  38. #include <booster/aio/buffer.h>
  39. #include <booster/aio/deadline_timer.h>
  40. #include <booster/aio/aio_category.h>
  41. #include <booster/log.h>
  42. #include "cached_settings.h"
  43. #include "format_number.h"
  44. #include "string_map.h"
  45. #include "send_timeout.h"
  46. #include "rewrite.h"
  47. namespace io = booster::aio;
  48. namespace cppcms {
  49. namespace impl {
  50. namespace cgi {
  51. class http;
  52. class http_watchdog : public booster::enable_shared_from_this<http_watchdog> {
  53. public:
  54. typedef booster::shared_ptr<http> http_ptr;
  55. typedef booster::weak_ptr<http> weak_http_ptr;
  56. http_watchdog(booster::aio::io_service &srv) :
  57. timer_(srv)
  58. {
  59. }
  60. void check(booster::system::error_code const &e=booster::system::error_code());
  61. void add(weak_http_ptr p)
  62. {
  63. connections_.insert(p);
  64. }
  65. void remove(weak_http_ptr p)
  66. {
  67. connections_.erase(p);
  68. }
  69. private:
  70. typedef std::set<weak_http_ptr> connections_type;
  71. connections_type connections_;
  72. booster::aio::deadline_timer timer_;
  73. };
  74. class http_creator {
  75. public:
  76. http_creator() {} // for concept
  77. http_creator(booster::aio::io_service &srv,json::value const &settings,std::string const &ip="0.0.0.0",int port = 8080) :
  78. ip_(ip),port_(port),watchdog_(new http_watchdog(srv))
  79. {
  80. if(settings.find("http.rewrite").type()==json::is_array) {
  81. rewrite_.reset(new url_rewriter(settings.find("http.rewrite").array()));
  82. }
  83. watchdog_->check();
  84. }
  85. http *operator()(cppcms::service &srv) const;
  86. private:
  87. std::string ip_;
  88. int port_;
  89. booster::shared_ptr<http_watchdog> watchdog_;
  90. booster::shared_ptr<url_rewriter> rewrite_;
  91. };
  92. namespace {
  93. char non_const_empty_string[1]={0};
  94. }
  95. class http : public connection {
  96. public:
  97. http( cppcms::service &srv,
  98. std::string const &ip,
  99. int port,
  100. booster::shared_ptr<http_watchdog> wd,
  101. booster::shared_ptr<url_rewriter> rw
  102. )
  103. :
  104. connection(srv),
  105. socket_(srv.impl().get_io_service()),
  106. input_body_ptr_(0),
  107. input_parser_(input_body_,input_body_ptr_),
  108. output_pbase_(0),
  109. output_pptr_(0),
  110. output_epptr_(0),
  111. output_parser_(output_pbase_,output_pptr_,output_epptr_),
  112. request_method_(non_const_empty_string),
  113. request_uri_(non_const_empty_string),
  114. headers_done_(false),
  115. first_header_observerd_(false),
  116. total_read_(0),
  117. time_to_die_(0),
  118. timeout_(0),
  119. sync_option_is_set_(false),
  120. in_watchdog_(false),
  121. watchdog_(wd),
  122. rewrite_(rw),
  123. eof_callback_(false)
  124. {
  125. env_.add("SERVER_SOFTWARE",CPPCMS_PACKAGE_NAME "/" CPPCMS_PACKAGE_VERSION);
  126. env_.add("SERVER_NAME",pool_.add(ip));
  127. char *sport = pool_.alloc(10);
  128. format_number(port,sport,10);
  129. env_.add("SERVER_PORT",sport);
  130. env_.add("GATEWAY_INTERFACE","CGI/1.0");
  131. env_.add("SERVER_PROTOCOL","HTTP/1.0");
  132. timeout_ = srv.cached_settings().http.timeout;
  133. }
  134. ~http()
  135. {
  136. if(socket_.native()!=io::invalid_socket) {
  137. booster::system::error_code e;
  138. socket_.shutdown(io::stream_socket::shut_rdwr,e);
  139. }
  140. }
  141. void update_time()
  142. {
  143. time_to_die_ = time(0) + timeout_;
  144. }
  145. void log_timeout()
  146. {
  147. char const *uri = request_uri_;
  148. if(!uri || *uri==0)
  149. uri = "unknown";
  150. BOOSTER_INFO("cppcms_http") << "Timeout on connection for URI: " << uri << " from " << cgetenv("REMOTE_ADDR");
  151. }
  152. void die()
  153. {
  154. log_timeout();
  155. close();
  156. }
  157. void async_die()
  158. {
  159. socket_.cancel();
  160. die();
  161. }
  162. time_t time_to_die()
  163. {
  164. return time_to_die_;
  165. }
  166. void async_read_some_headers(handler const &h)
  167. {
  168. socket_.on_readable(boost::bind(&http::some_headers_data_read,self(),_1,h));
  169. update_time();
  170. }
  171. virtual void async_read_headers(handler const &h)
  172. {
  173. update_time();
  174. add_to_watchdog();
  175. async_read_some_headers(h);
  176. }
  177. void some_headers_data_read(booster::system::error_code const &er,handler const &h)
  178. {
  179. if(er) { h(er); return; }
  180. booster::system::error_code e;
  181. size_t n = socket_.bytes_readable(e);
  182. if(e) { h(e); return ; }
  183. if(n > 16384)
  184. n=16384;
  185. if(input_body_.capacity() < n) {
  186. input_body_.reserve(n);
  187. }
  188. input_body_.resize(input_body_.capacity(),0);
  189. input_body_ptr_=0;
  190. n = socket_.read_some(booster::aio::buffer(input_body_),e);
  191. total_read_+=n;
  192. if(total_read_ > 16384) {
  193. h(booster::system::error_code(errc::protocol_violation,cppcms_category));
  194. return;
  195. }
  196. input_body_.resize(n);
  197. for(;;) {
  198. using ::cppcms::http::impl::parser;
  199. switch(input_parser_.step()) {
  200. case parser::more_data:
  201. // Assuming body_ptr == body.size()
  202. async_read_some_headers(h);
  203. return;
  204. case parser::got_header:
  205. if(!first_header_observerd_) {
  206. first_header_observerd_=true;
  207. char const *header_begin = input_parser_.header_.c_str();
  208. char const *header_end = header_begin + input_parser_.header_.size();
  209. char const *query=header_end;
  210. char const *rmethod=std::find( header_begin,
  211. header_end,
  212. ' ');
  213. if(rmethod!=header_end)
  214. query=std::find(rmethod+1,header_end,' ');
  215. if(query!=header_end) {
  216. request_method_ = pool_.add(header_begin,rmethod);
  217. request_uri_ = pool_.add(rmethod+1,query);
  218. first_header_observerd_=true;
  219. BOOSTER_INFO("cppcms_http") << request_method_ <<" " << request_uri_;
  220. }
  221. else {
  222. h(booster::system::error_code(errc::protocol_violation,cppcms_category));
  223. return;
  224. }
  225. }
  226. else { // Any other header
  227. char const *name = "";
  228. char const *value = "";
  229. if(!parse_single_header(input_parser_.header_,name,value)) {
  230. h(booster::system::error_code(errc::protocol_violation,cppcms_category));
  231. return;
  232. }
  233. if(strcmp(name,"CONTENT_LENGTH")==0 || strcmp(name,"CONTENT_TYPE")==0)
  234. env_.add(name,value);
  235. else {
  236. char *updated_name =pool_.alloc(strlen(name) + 5 + 1);
  237. strcpy(updated_name,"HTTP_");
  238. strcat(updated_name,name);
  239. env_.add(updated_name,value);
  240. }
  241. }
  242. break;
  243. case parser::end_of_headers:
  244. process_request(h);
  245. return;
  246. case parser::error_observerd:
  247. h(booster::system::error_code(errc::protocol_violation,cppcms_category));
  248. return;
  249. }
  250. }
  251. }
  252. virtual void async_read_some(void *p,size_t s,io_handler const &h)
  253. {
  254. update_time();
  255. if(input_body_ptr_==input_body_.size()) {
  256. input_body_.clear();
  257. input_body_ptr_=0;
  258. }
  259. if(!input_body_.empty()) {
  260. if(input_body_.size() - input_body_ptr_ < s) {
  261. s=input_body_.size() - input_body_ptr_;
  262. }
  263. memcpy(p,&input_body_[input_body_ptr_],s);
  264. input_body_ptr_+=s;
  265. if(input_body_ptr_==input_body_.size()) {
  266. input_body_.clear();
  267. input_body_ptr_=0;
  268. }
  269. socket_.get_io_service().post(boost::bind(h,booster::system::error_code(),s));
  270. return;
  271. }
  272. if(input_body_.capacity()!=0) {
  273. std::vector<char> v;
  274. input_body_.swap(v);
  275. }
  276. socket_.async_read_some(io::buffer(p,s),h);
  277. }
  278. virtual void do_eof()
  279. {
  280. if(eof_callback_)
  281. socket_.cancel();
  282. eof_callback_ = false;
  283. booster::system::error_code e;
  284. socket_.shutdown(io::stream_socket::shut_wr,e);
  285. socket_.close(e);
  286. }
  287. #ifndef CPPCMS_NO_SO_SNDTIMO
  288. size_t timed_write_some(booster::aio::const_buffer const &buf,booster::system::error_code &e)
  289. {
  290. set_sync_options(e);
  291. if(e) return 0;
  292. booster::ptime start = booster::ptime::now();
  293. size_t n = socket_.write_some(buf,e);
  294. booster::ptime end = booster::ptime::now();
  295. // it may actually return with success but return small
  296. // a small buffer
  297. if(booster::ptime::to_number(end - start) >= timeout_ - 0.1) {
  298. e=booster::system::error_code(errc::protocol_violation,cppcms_category);
  299. die();
  300. return n;
  301. }
  302. if(e && (io::basic_socket::would_block(e)
  303. #ifdef CPPCMS_WIN32
  304. || e.value() == 10060 // WSAETIMEDOUT - do not want to include windows.h
  305. #endif
  306. )
  307. ) {
  308. // handle timeout with SO_SNDTIMEO
  309. // that responds with EAGIAN or EWOULDBLOCK
  310. die();
  311. }
  312. return n;
  313. }
  314. #else
  315. size_t timed_write_some(booster::aio::const_buffer const &buf,booster::system::error_code &e)
  316. {
  317. booster::ptime start = booster::ptime::now();
  318. pollfd pfd=pollfd();
  319. pfd.fd = socket_.native();
  320. pfd.events = POLLOUT;
  321. pfd.revents = 0;
  322. int msec = timeout_ * 1000;
  323. int r = 0;
  324. while((r=poll(&pfd,1,msec))<0 && errno==EINTR) {
  325. msec -= booster::ptime::milliseconds(booster::ptime::now() - start);
  326. if(msec <= 0) {
  327. r = 0;
  328. break;
  329. }
  330. }
  331. if(r < 0) {
  332. e=booster::system::error_code(errno,booster::system::system_category);
  333. return 0;
  334. }
  335. if(pfd.revents & POLLOUT)
  336. return socket_.write_some(buf,e);
  337. e=booster::system::error_code(errc::protocol_violation,cppcms_category);
  338. return 0;
  339. }
  340. #endif
  341. bool write_to_socket(booster::aio::const_buffer const &bufin,booster::system::error_code &e)
  342. {
  343. booster::aio::const_buffer buf = bufin;
  344. size_t total = 0;
  345. while(!buf.empty()) {
  346. size_t n = timed_write_some(buf,e);
  347. total += n;
  348. buf += n;
  349. if(e) {
  350. close();
  351. break;
  352. }
  353. }
  354. return total == bufin.bytes_count();
  355. }
  356. void set_sync_options(booster::system::error_code &e)
  357. {
  358. if(!sync_option_is_set_) {
  359. socket_.set_non_blocking_if_needed(false,e);
  360. if(e)
  361. return;
  362. cppcms::impl::set_send_timeout(socket_,timeout_,e);
  363. if(e)
  364. return;
  365. sync_option_is_set_ = true;
  366. }
  367. }
  368. virtual booster::aio::io_service &get_io_service()
  369. {
  370. return socket_.get_io_service();
  371. }
  372. virtual bool keep_alive()
  373. {
  374. return false;
  375. }
  376. void close()
  377. {
  378. booster::system::error_code e;
  379. socket_.shutdown(io::stream_socket::shut_rdwr,e);
  380. socket_.close(e);
  381. }
  382. virtual void async_read_eof(callback const &h)
  383. {
  384. watchdog_->add(self());
  385. static char a;
  386. socket_.async_read_some(io::buffer(&a,1),boost::bind(h));
  387. }
  388. void on_async_write_start()
  389. {
  390. update_time();
  391. watchdog_->add(self());
  392. }
  393. void on_async_write_progress(bool completed)
  394. {
  395. update_time();
  396. if(completed)
  397. watchdog_->remove(self());
  398. }
  399. virtual booster::aio::stream_socket &socket() { return socket_; }
  400. virtual booster::aio::const_buffer format_output(booster::aio::const_buffer const &in,bool /*completed*/,booster::system::error_code &e)
  401. {
  402. update_time();
  403. add_to_watchdog();
  404. if(headers_done_)
  405. return in;
  406. booster::aio::const_buffer packet;
  407. std::pair<booster::aio::const_buffer::entry const *,size_t> tmp = in.get();
  408. booster::aio::const_buffer::entry const *entry = tmp.first;
  409. size_t parts = tmp.second;
  410. output_pbase_=output_pptr_=output_epptr_=0;
  411. bool r=false;
  412. while(parts > 0) {
  413. output_pbase_=static_cast<char const *>(entry->ptr);
  414. output_pptr_ = output_pbase_;
  415. output_epptr_ = output_pbase_ + entry->size;
  416. r =process_output_headers(e);
  417. parts--;
  418. entry++;
  419. if(r) {
  420. if(!e)
  421. headers_done_ = true;
  422. break;
  423. }
  424. }
  425. if(e)
  426. return packet;
  427. if(!r) {
  428. tmp = in.get();
  429. entry = tmp.first;
  430. parts = tmp.second;
  431. output_body_.reserve(output_body_.size() + in.bytes_count());
  432. while(parts > 0) {
  433. output_body_.insert(output_body_.end(),entry->ptr,entry->ptr+entry->size);
  434. parts--;
  435. entry++;
  436. }
  437. return packet;
  438. }
  439. packet+= booster::aio::buffer(response_line_);
  440. if(!output_body_.empty())
  441. packet+= booster::aio::buffer(output_body_);
  442. packet+= in;
  443. return packet;
  444. }
  445. private:
  446. bool process_output_headers(booster::system::error_code &e)
  447. {
  448. static char const *addon =
  449. "Server: CppCMS-Embedded/" CPPCMS_PACKAGE_VERSION "\r\n"
  450. "Connection: close\r\n";
  451. using cppcms::http::impl::parser;
  452. for(;;) {
  453. switch(output_parser_.step()) {
  454. case parser::more_data:
  455. return false;
  456. case parser::got_header:
  457. {
  458. char const *name="";
  459. char const *value="";
  460. if(!parse_single_header(output_parser_.header_,name,value)) {
  461. e=booster::system::error_code(errc::protocol_violation,cppcms_category);
  462. return true;
  463. }
  464. if(strcmp(name,"STATUS")==0) {
  465. response_line_ = "HTTP/1.0 ";
  466. response_line_ +=value;
  467. response_line_ +="\r\n";
  468. response_line_.append(addon);
  469. return true;
  470. }
  471. }
  472. break;
  473. case parser::end_of_headers:
  474. response_line_ = "HTTP/1.0 200 Ok\r\n";
  475. response_line_.append(addon);
  476. return true;
  477. case parser::error_observerd:
  478. e=booster::system::error_code(errc::protocol_violation,cppcms_category);
  479. return true;
  480. }
  481. }
  482. }
  483. void process_request(handler const &h)
  484. {
  485. if( strcmp(request_method_,"GET")!=0
  486. && strcmp(request_method_,"POST")!=0
  487. && strcmp(request_method_,"HEAD")!=0
  488. && strcmp(request_method_,"PUT")!=0
  489. && strcmp(request_method_,"DELETE")!=0
  490. && strcmp(request_method_,"OPTIONS")!=0
  491. )
  492. {
  493. error_response("HTTP/1.0 501 Not Implemented\r\n\r\n",h);
  494. return;
  495. }
  496. env_.add("REQUEST_METHOD",request_method_);
  497. if(rewrite_)
  498. request_uri_ = rewrite_->rewrite(request_uri_,pool_);
  499. char const *remote_addr=0;
  500. if(service().cached_settings().http.proxy.behind==true) {
  501. std::vector<std::string> const &variables =
  502. service().cached_settings().http.proxy.remote_addr_cgi_variables;
  503. for(unsigned i=0;remote_addr == 0 && i<variables.size();i++) {
  504. remote_addr = env_.get(variables[i].c_str());
  505. }
  506. }
  507. if(!remote_addr) {
  508. booster::system::error_code e;
  509. remote_addr=pool_.add(socket_.remote_endpoint(e).ip());
  510. if(e) {
  511. close();
  512. h(e);
  513. return;
  514. }
  515. }
  516. env_.add("REMOTE_HOST",remote_addr);
  517. env_.add("REMOTE_ADDR",remote_addr);
  518. if(request_uri_[0]!='/') {
  519. error_response("HTTP/1.0 400 Bad Request\r\n\r\n",h);
  520. return;
  521. }
  522. char *path=non_const_empty_string;
  523. char *query = strchr(request_uri_,'?');
  524. if(query == 0) {
  525. path=request_uri_;
  526. }
  527. else {
  528. path=pool_.add(request_uri_,query - request_uri_);
  529. env_.add("QUERY_STRING",query + 1);
  530. }
  531. std::vector<std::string> const &script_names =
  532. service().cached_settings().http.script_names;
  533. size_t path_size = strlen(path);
  534. for(unsigned i=0;i<script_names.size();i++) {
  535. std::string const &name=script_names[i];
  536. size_t name_size = name.size();
  537. if(path_size >= name_size && memcmp(path,name.c_str(),name_size) == 0
  538. && (path_size == name_size || path[name_size]=='/'))
  539. {
  540. env_.add("SCRIPT_NAME",pool_.add(name));
  541. path = path + name_size;
  542. break;
  543. }
  544. }
  545. env_.add("PATH_INFO",pool_.add(util::urldecode(path,path+strlen(path))));
  546. update_time();
  547. h(booster::system::error_code());
  548. }
  549. void on_async_read_complete()
  550. {
  551. remove_from_watchdog();
  552. }
  553. void error_response(char const *message,handler const &h)
  554. {
  555. socket_.async_write(io::buffer(message,strlen(message)),
  556. boost::bind(&http::on_error_response_written,self(),_1,h));
  557. }
  558. void on_error_response_written(booster::system::error_code const &e,handler const &h)
  559. {
  560. if(e) {
  561. h(e);
  562. return;
  563. }
  564. close();
  565. h(booster::system::error_code(errc::protocol_violation,cppcms_category));
  566. }
  567. bool parse_single_header(std::string const &header,char const *&o_name,char const *&o_value)
  568. {
  569. char const *p=header.c_str();
  570. char const *e=p + header.size();
  571. char const *name_end = p;
  572. p=cppcms::http::protocol::skip_ws(p,e);
  573. name_end=cppcms::http::protocol::tocken(p,e);
  574. if(name_end==p)
  575. return false;
  576. size_t name_size = name_end - p;
  577. char *name = pool_.alloc(name_size + 1);
  578. *std::copy(p,name_end,name) = 0;
  579. p=name_end;
  580. p=cppcms::http::protocol::skip_ws(p,e);
  581. if(p==e || *p!=':')
  582. return false;
  583. ++p;
  584. p=cppcms::http::protocol::skip_ws(p,e);
  585. char *value = pool_.alloc(e-p+1);
  586. *std::copy(p,e,value) = 0;
  587. for(unsigned i=0;i<name_size;i++) {
  588. if(name[i] == '-')
  589. name[i]='_';
  590. else if('a' <= name[i] && name[i] <='z')
  591. name[i]=name[i]-'a' + 'A';
  592. }
  593. o_name = name;
  594. o_value = value;
  595. return true;
  596. }
  597. booster::shared_ptr<http> self()
  598. {
  599. return booster::static_pointer_cast<http>(shared_from_this());
  600. }
  601. friend class socket_acceptor<http,http_creator>;
  602. booster::aio::stream_socket socket_;
  603. std::vector<char> input_body_;
  604. unsigned input_body_ptr_;
  605. ::cppcms::http::impl::parser input_parser_;
  606. std::vector<char> output_body_;
  607. char const *output_pbase_;
  608. char const *output_pptr_;
  609. char const *output_epptr_;
  610. ::cppcms::http::impl::parser output_parser_;
  611. std::string response_line_;
  612. char *request_method_;
  613. char *request_uri_;
  614. bool headers_done_;
  615. bool first_header_observerd_;
  616. unsigned total_read_;
  617. time_t time_to_die_;
  618. int timeout_;
  619. bool sync_option_is_set_;
  620. bool in_watchdog_;
  621. void add_to_watchdog()
  622. {
  623. if(!in_watchdog_) {
  624. watchdog_->add(self());
  625. in_watchdog_ = true;
  626. }
  627. }
  628. void remove_from_watchdog()
  629. {
  630. if(in_watchdog_) {
  631. watchdog_->remove(self());
  632. in_watchdog_ = false;
  633. }
  634. }
  635. booster::shared_ptr<http_watchdog> watchdog_;
  636. booster::shared_ptr<url_rewriter> rewrite_;
  637. bool eof_callback_;
  638. };
  639. void http_watchdog::check(booster::system::error_code const &e)
  640. {
  641. if(e)
  642. return;
  643. std::list<http_ptr> kill;
  644. time_t now = time(0);
  645. for(connections_type::iterator p=connections_.begin(),e=connections_.end();p!=e;) {
  646. booster::shared_ptr<http> ptr = p->lock();
  647. if(!ptr) {
  648. connections_type::iterator tmp = p;
  649. ++p;
  650. connections_.erase(tmp);
  651. }
  652. else {
  653. if(ptr->time_to_die() < now) {
  654. kill.push_back(ptr);
  655. connections_type::iterator tmp = p;
  656. ++p;
  657. connections_.erase(tmp);
  658. }
  659. else {
  660. ++p;
  661. }
  662. }
  663. }
  664. for(std::list<http_ptr>::iterator p=kill.begin();p!=kill.end();++p) {
  665. (*p)->async_die();
  666. }
  667. timer_.expires_from_now(booster::ptime(1));
  668. timer_.async_wait(boost::bind(&http_watchdog::check,shared_from_this(),_1));
  669. }
  670. http *http_creator::operator()(cppcms::service &srv) const
  671. {
  672. return new http(srv,ip_,port_,watchdog_,rewrite_);
  673. }
  674. std::auto_ptr<acceptor> http_api_factory(cppcms::service &srv,std::string ip,int port,int backlog)
  675. {
  676. typedef socket_acceptor<http,http_creator> acceptor_type;
  677. std::auto_ptr<acceptor_type> acc(new acceptor_type(srv,ip,port,backlog));
  678. acc->factory(http_creator(srv.get_io_service(),srv.settings(),ip,port));
  679. std::auto_ptr<acceptor> a(acc);
  680. return a;
  681. }
  682. } // cgi
  683. } // impl
  684. } // cppcms