aboutsummaryrefslogtreecommitdiff
path: root/web/apache/stream
diff options
context:
space:
mode:
Diffstat (limited to 'web/apache/stream')
-rw-r--r--web/apache/stream87
1 files changed, 48 insertions, 39 deletions
diff --git a/web/apache/stream b/web/apache/stream
index eb62b85..5f76347 100644
--- a/web/apache/stream
+++ b/web/apache/stream
@@ -5,28 +5,44 @@
#ifndef WEB_APACHE_STREAM
#define WEB_APACHE_STREAM
-#include <streambuf>
-#include <ios> // streamsize
-#include <algorithm> // min(), max()
-#include <cstring> // memmove()
-#include <memory> // unique_ptr
-
#include <httpd/httpd.h>
#include <httpd/http_protocol.h>
+#include <ios> // streamsize
+#include <memory> // unique_ptr
+#include <cstring> // memmove()
+#include <streambuf>
+#include <algorithm> // min(), max()
+
#include <web/module>
namespace web
{
namespace apache
{
- class ostreambuf : public std::streambuf
+ // Object of a class implementing this interface is intended for
+ // keeping the state of writing response to the client.
+ //
+ struct write_state
{
- public:
- ostreambuf (request_rec* rec) : rec_ (rec) {}
+ // Called by ostreambuf methods when some content to be written to the
+ // client.
+ //
+ virtual void
+ set_write_state () = 0;
+
+ // Called to check if any data have already been written to the client.
+ // Such checks required for some operations which are impossible to
+ // execute after response is partially written.
+ //
+ virtual bool
+ get_write_state () const noexcept = 0;
+ };
- bool
- write_flag () const noexcept {return write_;}
+ class ostreambuf: public std::streambuf
+ {
+ public:
+ ostreambuf (request_rec* rec, write_state& ws): rec_ (rec), ws_ (ws) {}
private:
virtual int_type
@@ -34,7 +50,7 @@ namespace web
{
if (c != traits_type::eof ())
{
- flag_write ();
+ ws_.set_write_state ();
char chr = c;
@@ -51,7 +67,7 @@ namespace web
virtual std::streamsize
xsputn (const char* s, std::streamsize num)
{
- flag_write ();
+ ws_.set_write_state ();
if (ap_rwrite (s, num, rec_) < 0)
{
@@ -64,7 +80,7 @@ namespace web
virtual int
sync ()
{
- if(ap_rflush (rec_) < 0)
+ if (ap_rflush (rec_) < 0)
{
throw invalid_request (HTTP_REQUEST_TIME_OUT);
}
@@ -72,40 +88,30 @@ namespace web
return 0;
}
- void
- flag_write () noexcept
- {
- if (!write_)
- {
- // 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_ = true;
- }
- }
-
private:
request_rec* rec_;
- bool write_ {false};
+ write_state& ws_;
};
- class istreambuf : public std::streambuf
+ class istreambuf: public std::streambuf
{
public:
- istreambuf (request_rec* rec, size_t bufsize = 1024, size_t putback = 1)
+ istreambuf (request_rec* rec,
+ write_state& ws,
+ size_t bufsize = 1024,
+ size_t putback = 1)
: rec_ (rec),
+ ws_ (ws),
bufsize_ (std::max (bufsize, (size_t)1)),
putback_ (std::min (putback, bufsize_ - 1)),
buf_ (new char[bufsize_])
{
+ if (ws_.get_write_state ())
+ {
+ throw sequence_error ("::web::apache::istreambuf::istreambuf");
+ }
+
char* p = buf_.get () + putback_;
setg (p, p, p);
@@ -121,6 +127,11 @@ namespace web
virtual int_type
underflow ()
{
+ if (ws_.get_write_state ())
+ {
+ throw sequence_error ("::web::apache::istreambuf::underflow");
+ }
+
if (gptr () < egptr ())
return traits_type::to_int_type (*gptr ());
@@ -144,15 +155,13 @@ namespace web
return traits_type::to_int_type (*gptr ());
}
- bool error () const noexcept {return error_;}
-
private:
request_rec* rec_;
+ write_state& ws_;
size_t bufsize_;
size_t putback_;
std::unique_ptr<char[]> buf_;
- bool error_ {false};
};
}