aboutsummaryrefslogtreecommitdiff
path: root/web/apache/request.ixx
diff options
context:
space:
mode:
Diffstat (limited to 'web/apache/request.ixx')
-rw-r--r--web/apache/request.ixx218
1 files changed, 218 insertions, 0 deletions
diff --git a/web/apache/request.ixx b/web/apache/request.ixx
new file mode 100644
index 0000000..a427fd4
--- /dev/null
+++ b/web/apache/request.ixx
@@ -0,0 +1,218 @@
+// file : web/apache/request.ixx -*- C++ -*-
+// copyright : Copyright (c) 2014-2015 Code Synthesis Tools CC
+// license : MIT; see accompanying LICENSE file
+
+#include <iomanip>
+#include <sstream>
+#include <cstring>
+#include <cstdlib>
+
+#include <strings.h> // strcasecmp()
+
+namespace web
+{
+ namespace apache
+ {
+ inline int request::
+ flush ()
+ {
+ if (buffer_ && out_buf_)
+ {
+ set_content_type ();
+
+ auto b = dynamic_cast<std::stringbuf*> (out_buf_.get ());
+ assert(b);
+
+ std::string s (b->str ());
+
+ if (!s.empty ())
+ {
+ // Before writing response read and discard request body if any.
+ //
+ int r = ap_discard_request_body (rec_);
+
+ if (r == OK)
+ {
+ if (status_ == HTTP_OK)
+ {
+ if (ap_rwrite (s.c_str (), s.length (), rec_) < 0)
+ {
+ status_ = HTTP_REQUEST_TIME_OUT;
+ }
+ }
+ else
+ {
+ ap_custom_response (rec_, status_, s.c_str ());
+ }
+ }
+ else
+ status_ = r;
+ }
+
+ out_.reset ();
+ out_buf_.reset ();
+ }
+
+ return status_ == HTTP_OK ? OK : status_;
+ }
+
+ inline const request::string_ptr& request::
+ form_data ()
+ {
+ if (!form_data_)
+ {
+ form_data_.reset (new std::string ());
+ const char *ct = apr_table_get (rec_->headers_in, "Content-Type");
+
+ if (ct && !strncasecmp ("application/x-www-form-urlencoded", ct, 33))
+ {
+ std::istream& istr (data ());
+ std::getline (istr, *form_data_);
+
+ // Make request data still be available.
+ //
+
+ std::unique_ptr<std::streambuf> in_buf (
+ new std::stringbuf (*form_data_));
+
+ in_.reset (new std::istream (in_buf.get ()));
+ in_buf_ = std::move (in_buf);
+ in_->exceptions (std::ios::failbit | std::ios::badbit);
+ }
+ }
+
+ return form_data_;
+ }
+
+ inline void request::
+ parse_parameters (const char* args)
+ {
+ for (auto n (args); n != 0; )
+ {
+ const char* v = strchr (n, '=');
+ const char* e = strchr (n, '&');
+
+ if (e && e < v)
+ v = 0;
+
+ std::string name (v
+ ? mime_url_decode (n, v) :
+ (e
+ ? mime_url_decode (n, e)
+ : mime_url_decode (n, n + std::strlen (n))));
+
+ std::string value;
+
+ if (v++)
+ {
+ value = e
+ ? mime_url_decode (v, e)
+ : mime_url_decode (v, v + std::strlen (v));
+ }
+
+ if (!name.empty () || !value.empty ())
+ parameters_->emplace_back (std::move (name), std::move (value));
+
+ n = e ? e + 1 : 0;
+ }
+ }
+
+ inline void request::
+ mime_url_encode (const char* v, std::ostream& o)
+ {
+ char f = o.fill ();
+ std::ios_base::fmtflags g = o.flags ();
+ o << std::hex << std::uppercase << std::right << std::setfill ('0');
+ char c;
+
+ while ((c = *v++) != '\0')
+ {
+ if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9'))
+ {
+ o << c;
+ }
+ else
+ switch (c)
+ {
+ case ' ': o << '+'; break;
+ case '.':
+ case '_':
+ case '-':
+ case '~': o << c; break;
+ default: o << "%" << std::setw (2) << (unsigned short)c;
+ }
+ }
+
+ o.flags (g);
+ o.fill (f);
+ }
+
+ inline std::string request::
+ mime_url_decode (const char* b, const char* e, bool trim)
+ {
+ if (trim)
+ {
+ b += std::strspn (b, " ");
+
+ if (b >= e)
+ return std::string();
+
+ while (*--e == ' ');
+ ++e;
+ }
+
+ std::string value;
+ value.reserve (e - b);
+
+ char bf[3];
+ bf[2] = '\0';
+
+ while (b != e)
+ {
+ char c = *b++;
+
+ switch (c)
+ {
+ case '+':
+ {
+ value.append (" ");
+ break;
+ }
+ case '%':
+ {
+ if (*b == '\0' || b[1] == '\0')
+ {
+ throw std::invalid_argument (
+ "::web::apache::request::mime_url_decode short");
+ }
+
+ *bf = *b;
+ bf[1] = b[1];
+
+ char* ebf = 0;
+ size_t vl = std::strtoul (bf, &ebf, 16);
+
+ if (*ebf != '\0')
+ {
+ throw std::invalid_argument (
+ "::web::apache::request::mime_url_decode wrong");
+ }
+
+ value.append (1, (char)vl);
+ b += 2;
+ break;
+ }
+ default:
+ {
+ value.append (1, c);
+ break;
+ }
+ }
+ }
+
+ return value;
+ }
+
+ }
+}