/////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) // // See accompanying file COPYING.TXT file for licensing details. // /////////////////////////////////////////////////////////////////////////////// #ifndef CPPCMS_HTTP_CONTEXT_H #define CPPCMS_HTTP_CONTEXT_H #include #include #include #include #include #include #include #include namespace cppcms { class service; class application; class application_specific_pool; class cache_interface; class session_interface; namespace json { class value; } namespace impl { namespace cgi { class connection; } } /// /// \brief This namespace represent classes that are directly connected to handing HTTP requests and responses /// namespace http { class request; class response; class file; /// /// \brief context is a central class that holds all specific connection related information. /// It encapsulates CGI request and response, cache, session and locale information /// /// Instance of this class is created upon client requests, it provides access to all /// connection related interfaces. This class is unique per each applications hierarchy /// and destroyed when HTTP request/response is completed /// class CPPCMS_API context : public booster::noncopyable, public booster::enable_shared_from_this { public: /// \cond INTERNAL context(booster::shared_ptr conn); ~context(); impl::cgi::connection &connection(); void run(); /// \endcond /// /// Get an interface to HTTP request /// http::request &request(); /// /// Get an interface to HTTP response /// http::response &response(); /// /// Get global settings. Same as cppcms::service::settings /// json::value const &settings(); /// /// Get an interface to CppCMS Cache /// cache_interface &cache(); /// /// Get an interface to current session /// /// Note, when using asynchronous CppCMS applications, session data is not fetched /// and is not updated, because session access may be not cheap, So when using /// session_interface in asynchronous application make sure you call session_inerface::load /// member function /// session_interface &session(); /// /// Get current context locale /// std::locale locale(); /// /// Set locale explicitly. Note, it changes the locale of the response().out() stream as /// well /// void locale(std::locale const &new_locale); /// /// Set locale by name. Similar to locale(service().generator(name)). /// /// Note: it changes the locale of the response().out() stream as well /// void locale(std::string const &name); /// /// Get the central service instance /// cppcms::service &service(); /// /// Get current views skin name /// std::string skin(); /// /// Set current views skin name /// void skin(std::string const &name); typedef enum { operation_completed, ///< Asynchronous operation completed successfully operation_aborted ///< Asynchronous operation was canceled } completion_type; typedef booster::callback handler; /// /// Send all pending output data to the client and /// finalize the connection. Note, you can't use this /// object for communication any more. /// void complete_response(); /// /// Send all pending output data to the client and /// finalize the connection. Note, you can't use this /// object for communication any more. /// void async_complete_response(); /// /// Send all pending data to user, when operation is complete /// call handler \a h with status. /// /// Note: if the status is operation_aborted, you can't use /// this connection any more, the peer gone. /// void async_flush_output(handler const &h); /// /// Set handler for peer reset events. It is useful to cleanup /// connections that had timeout or just disconnected by user /// /// Notes: /// /// -# if async_complete_response was called, handler would not /// be called any more. /// -# If async_flush_output fails, this does not mean that /// this handler would be called as well, so you need to check both /// void async_on_peer_reset(booster::callback const &h); /// /// Submit the context to alternative pool - allows to transfer context from application to application, \a matched_url /// would be given to application::main for processing /// /// Note: /// /// - no output should be itransfered on this context /// - the context MUST be detached for existing application /// /// This function can be called from any thread /// /// \ver{v1_2} void submit_to_pool(booster::shared_ptr pool,std::string const &matched_url); /// /// Submit the context to alternative application - allows to transfer context from application to application, \a matched_url /// would be given to application::main for processing /// /// Note: /// /// - the app should be asynchronous /// - no output should be itransfered on this context /// - the context MUST be detached for existing application /// /// This function can be called from any thread /// /// \ver{v1_2} void submit_to_asynchronous_application(booster::intrusive_ptr app,std::string const &matched_url); private: struct holder { virtual ~holder() {} }; template struct specific_holder : public holder { specific_holder(T *ptr) : p(ptr) {} virtual ~specific_holder() {} booster::hold_ptr p; }; public: /// /// Get context specific value of type T binded to context. If none is stored or /// type mismatched NULL is returned /// /// \ver{v1_2} template T *get_specific() { specific_holder *sh=dynamic_cast *>(get_holder()); if(!sh) return 0; return sh->p.get(); } /// /// Reset context specific value of type T binded to context. Old value is deleted /// /// \ver{v1_2} template void reset_specific(T *ptr = 0) { if(ptr == 0) { set_holder(0); return; } specific_holder *sh=dynamic_cast *>(get_holder()); if(sh) { sh->p.reset(ptr); } else { specific_holder *sh = new specific_holder(ptr); set_holder(sh); } } /// /// Release context specific value binded to context. /// /// \ver{v1_2} template T *release_specific() { T *r = 0; specific_holder *sh=dynamic_cast *>(get_holder()); if(sh) { r = sh->p.release(); } set_holder(0); return r; } // CM-20230904 as usual hiding shtuff just complicates life. void make_error_message(std::exception const &e); private: void set_holder(holder *p); holder *get_holder(); friend class impl::cgi::connection; int on_content_progress(size_t n); int on_headers_ready(); int translate_exception(); void on_request_ready(bool error); void submit_to_pool_internal(booster::shared_ptr pool,std::string const &matched,bool now); static void dispatch(booster::shared_ptr const &pool,booster::shared_ptr const &self,std::string const &url); static void dispatch(booster::intrusive_ptr const &app,std::string const &url,bool syncronous); void try_restart(bool e); booster::shared_ptr self(); struct _data; booster::hold_ptr<_data> d; booster::shared_ptr conn_; }; } }; #endif