aboutsummaryrefslogtreecommitdiff
path: root/web/server/apache/request.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'web/server/apache/request.hxx')
-rw-r--r--web/server/apache/request.hxx233
1 files changed, 233 insertions, 0 deletions
diff --git a/web/server/apache/request.hxx b/web/server/apache/request.hxx
new file mode 100644
index 0000000..bc105ec
--- /dev/null
+++ b/web/server/apache/request.hxx
@@ -0,0 +1,233 @@
+// 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