// file : web/apache/request -*- C++ -*- // copyright : Copyright (c) 2014-2015 Code Synthesis Tools CC // license : MIT; see accompanying LICENSE file #ifndef WEB_APACHE_REQUEST #define WEB_APACHE_REQUEST #include #include #include #include #include #include #include // unique_ptr #include #include #include #include #include #include #include #include // move #include #include namespace web { namespace apache { class request: public web::request, public web::response, public write_state { friend class service; request (request_rec* rec) noexcept: rec_ (rec) {rec_->status = HTTP_OK;} // Flush of buffered content. // int flush (); // Get request body data stream. // virtual std::istream& content () { if (!in_) { std::unique_ptr in_buf ( new istreambuf (rec_, *this)); in_.reset (new std::istream (in_buf.get ())); in_buf_ = std::move (in_buf); in_->exceptions (std::ios::failbit | std::ios::badbit); // Save form data now otherwise will not be available to do later // when data read from stream. // form_data (); } return *in_; } // Get request parameters. // virtual const name_values& parameters () { if (!parameters_) { parameters_.reset (new name_values ()); try { parse_parameters (rec_->args); parse_parameters (form_data ()->c_str ()); } catch (const std::invalid_argument& ) { throw invalid_request (); } } return *parameters_; } // Get request cookies. // virtual const name_values& cookies (); // Get response status code. // status_code status () const noexcept {return rec_->status;} // Set response status code. // virtual void status (status_code status) { if (status != rec_->status) { // Setting status code in exception handler is a common usecase // where no sense to throw but still need to signal apache a // proper status code. // if (get_write_state () && !std::current_exception ()) { throw sequence_error ("::web::apache::request::status"); } rec_->status = status; buffer_ = true; out_.reset (); out_buf_.reset (); ap_set_content_type (rec_, nullptr); } } // Set response status code, content type and get body stream. // virtual std::ostream& content (status_code status, const std::string& type, bool buffer = true); // Add response cookie. // virtual void cookie (const char* name, const char* value, const std::chrono::seconds* max_age = 0, const char* path = 0, const char* domain = 0, bool secure = false); private: using string_ptr = std::unique_ptr; // Get application/x-www-form-urlencoded form data. // const string_ptr& form_data (); void parse_parameters (const char* args); static void mime_url_encode (const char* v, std::ostream& o); static std::string mime_url_decode (const char* b, const char* e, bool trim = false); bool get_write_state () const noexcept {return write_state_;} virtual void set_write_state () { if (!write_state_) { // Preparing to write a response read and discard request // body if any. // int r = ap_discard_request_body (rec_); if (r != OK) { throw invalid_request (r); } write_state_ = true; } } private: request_rec* rec_; bool buffer_ {true}; bool write_state_ {false}; std::unique_ptr out_buf_; std::unique_ptr out_; std::unique_ptr in_buf_; std::unique_ptr in_; std::unique_ptr parameters_; std::unique_ptr cookies_; string_ptr form_data_; }; } } #include #endif // WEB_APACHE_REQUEST