// file : web/server/apache/request.hxx -*- C++ -*- // license : MIT; see accompanying LICENSE file #ifndef WEB_SERVER_APACHE_REQUEST_HXX #define WEB_SERVER_APACHE_REQUEST_HXX #include <httpd.h> // request_rec, HTTP_*, OK, M_POST #include <chrono> #include <memory> // unique_ptr #include <string> #include <vector> #include <istream> #include <ostream> #include <streambuf> #include <web/server/module.hxx> #include <web/server/apache/stream.hxx> namespace web { namespace apache { // The state of the request processing, reflecting an interaction with // Apache API (like reading/writing content function calls), with no // buffering taken into account. Any state different from the initial // suppose that some irrevocable interaction with Apache API have // happened, so request processing should be either completed, or // reported as failed. State values are ordered in a sense that the // higher value reflects the more advanced stage of processing, so the // request current state value may not decrease. // enum class request_state { // Denotes the initial stage of the request handling. At this stage // the request line and headers are already parsed by Apache. // initial, // Reading the request content. // reading, // Adding the response headers (cookies in particular). // headers, // Writing the response content. // writing }; // Extends istreambuf with read limit checking, caching, etc. (see the // implementation for details). // class istreambuf_cache; // Stream type for reading from Apache's bucket brigades. // class istream_buckets; class request: public web::request, public web::response, public stream_state { friend class service; // Can not be inline/default due to the member of // unique_ptr<istreambuf_cache> type. Note that istreambuf_cache type is // incomplete. // request (request_rec* rec) noexcept; ~request (); request_state state () const noexcept {return state_;} // Flush the buffered response content if present. The returned value // should be passed to Apache API on request handler exit. // int flush (); // Prepare for the request re-processing if possible (no unbuffered // read/write operations have been done). Throw sequence_error // otherwise. In particular, the preparation can include the response // content buffer cleanup, the request content buffer rewind. // void rewind (); // Get request path. // virtual const path_type& path (); // Get request body data stream. // virtual std::istream& content (std::size_t limit = 0, std::size_t buffer = 0); // Get request parameters. // virtual const name_values& parameters (std::size_t limit, bool url_only = false); // Get upload stream. // virtual std::istream& open_upload (std::size_t index); virtual std::istream& open_upload (const std::string& name); // Get request headers. // virtual const name_values& headers (); // 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); // 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 = nullptr, const char* path = nullptr, const char* domain = nullptr, bool secure = false, bool buffer = true); private: // On the first call cache the application/x-www-form-urlencoded or // multipart/form-data form data for the subsequent parameters parsing // and set the multipart flag accordingly. Don't cache if the request is // in the reading or later state. Return true if the cache contains the // form data. // // Note that the function doesn't change the content buffering (see // content() function for details) nor rewind the content stream after // reading. // bool form_data (std::size_t limit); // Used to also parse application/x-www-form-urlencoded POST body. // void parse_url_parameters (const char* args); void parse_multipart_parameters (const std::vector<char>& body); // Return a list of the upload input streams. Throw sequence_error if // the parameters() function was not called yet. Throw invalid_argument // if the request doesn't contain multipart form data. // using uploads_type = std::vector<std::unique_ptr<istream_buckets>>; uploads_type& uploads () const; // Advance the request processing state. Noop if new state is equal to // the current one. Throw sequence_error if the new state is less then // the current one. Can throw invalid_request if HTTP request is // malformed. // void state (request_state); // stream_state members implementation. // virtual void set_read_state () {state (request_state::reading);} virtual void set_write_state () {state (request_state::writing);} private: request_rec* rec_; request_state state_ = request_state::initial; path_type path_; std::unique_ptr<name_values> parameters_; bool url_only_parameters_; // Meaningless if parameters_ is NULL; // Uploaded file streams. If not NULL, is parallel to the parameters // list. // std::unique_ptr<uploads_type> uploads_; std::unique_ptr<name_values> headers_; std::unique_ptr<name_values> cookies_; // Form data cache. Is empty if the body doesn't contain the form data. // std::unique_ptr<std::vector<char>> form_data_; bool form_multipart_; // Meaningless if form_data_ is NULL or empty; std::unique_ptr<istreambuf_cache> in_buf_; std::unique_ptr<std::istream> in_; std::unique_ptr<std::streambuf> out_buf_; std::unique_ptr<std::ostream> out_; }; } } #include <web/server/apache/request.ixx> #endif // WEB_SERVER_APACHE_REQUEST_HXX