Commit 555792de authored by Mathieu Stefani's avatar Mathieu Stefani

Added an ArrayBuf class that provides an array-based streambuf so that...

Added an ArrayBuf class that provides an array-based streambuf so that response content can now be directly serialized to a fixed-size char buffer with standard iostream interface
parent 11e79cb5
/* array_buf.h
Mathieu Stefani, 26 August 2015
An array backed streambuf
*/
#pragma once
#include <streambuf>
namespace Io {
enum class Init { Default, ZeroOut };
template<typename CharT>
class BasicOutArrayBuf : public std::basic_streambuf<CharT> {
public:
BasicOutArrayBuf(CharT* begin, CharT* end, Init init = Init::Default) {
if (init == Init::ZeroOut) {
std::fill(begin, end, CharT());
}
this->setp(begin, end);
}
template<size_t N>
BasicOutArrayBuf(char (&arr)[N], Init init = Init::Default) {
if (init == Init::ZeroOut) {
std::fill(arr, arr + N, CharT());
}
this->setp(arr, arr + N);
}
size_t len() const {
return this->pptr() - this->pbase();
}
};
typedef BasicOutArrayBuf<char> OutArrayBuf;
} // namespace IO
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "http.h" #include "http.h"
#include "net.h" #include "net.h"
#include "peer.h" #include "peer.h"
#include "array_buf.h"
using namespace std; using namespace std;
...@@ -22,6 +23,11 @@ static constexpr char CR = 0xD; ...@@ -22,6 +23,11 @@ static constexpr char CR = 0xD;
static constexpr char LF = 0xA; static constexpr char LF = 0xA;
static constexpr char CRLF[] = {CR, LF}; static constexpr char CRLF[] = {CR, LF};
template< class CharT, class Traits>
std::basic_ostream<CharT, Traits>& crlf(std::basic_ostream<CharT, Traits>& os) {
os.write(CRLF, 2);
}
static constexpr const char* ParserData = "__Parser"; static constexpr const char* ParserData = "__Parser";
namespace Private { namespace Private {
...@@ -331,31 +337,6 @@ namespace Private { ...@@ -331,31 +337,6 @@ namespace Private {
request.resource.clear(); request.resource.clear();
} }
ssize_t
Writer::writeRaw(const void* data, size_t len) {
buf = static_cast<char *>(memcpy(buf, data, len));
buf += len;
return 0;
}
ssize_t
Writer::writeString(const char* str) {
const size_t len = std::strlen(str);
return writeRaw(str, std::strlen(str));
}
ssize_t
Writer::writeHeader(const char* name, const char* value) {
writeString(name);
writeChar(':');
writeString(value);
writeRaw(CRLF, 2);
return 0;
}
} // namespace Private } // namespace Private
const char* methodString(Method method) const char* methodString(Method method)
...@@ -421,32 +402,26 @@ Response::writeTo(Tcp::Peer& peer) ...@@ -421,32 +402,26 @@ Response::writeTo(Tcp::Peer& peer)
int fd = peer.fd(); int fd = peer.fd();
char buffer[Const::MaxBuffer]; char buffer[Const::MaxBuffer];
std::memset(buffer, 0, Const::MaxBuffer); Io::OutArrayBuf obuf(buffer, Io::Init::ZeroOut);
Private::Writer fmt(buffer, sizeof buffer);
fmt.writeString("HTTP/1.1 "); std::ostream stream(&obuf);
fmt.writeInt(code_); stream << "HTTP/1.1 ";
fmt.writeChar(' '); stream << code_;
fmt.writeString(codeString(static_cast<Code>(code_))); stream << ' ';
fmt.writeRaw(CRLF, 2); stream << codeString(static_cast<Code>(code_));
stream << crlf;
for (const auto& header: headers.list()) { for (const auto& header: headers.list()) {
std::ostringstream oss; header->write(stream);
header->write(oss); stream << crlf;
std::string str = oss.str();
fmt.writeRaw(str.c_str(), str.size());
fmt.writeRaw(CRLF, 2);
} }
fmt.writeHeader("Content-Length", body.size()); stream << "Content-Length: " << body.size() << crlf;
stream << crlf;
fmt.writeRaw(CRLF, 2);
fmt.writeString(body.c_str());
const size_t len = fmt.cursor() - buffer; stream << body;
ssize_t bytes = send(fd, buffer, len, 0); ssize_t bytes = send(fd, buffer, obuf.len(), 0);
} }
void void
......
...@@ -293,47 +293,6 @@ namespace Private { ...@@ -293,47 +293,6 @@ namespace Private {
ssize_t contentLength; ssize_t contentLength;
}; };
struct Writer {
Writer(char* buffer, size_t len)
: buf(buffer)
, len(len)
{ }
ssize_t writeRaw(const void* data, size_t len);
ssize_t writeString(const char* str);
template<typename T>
typename std::enable_if<
std::is_integral<T>::value, ssize_t
>::type
writeInt(T value) {
auto str = std::to_string(value);
return writeRaw(str.c_str(), str.size());
}
ssize_t writeChar(char c) {
*buf++ = c;
return 0;
}
ssize_t writeHeader(const char* name, const char* value);
template<typename T>
typename std::enable_if<
std::is_arithmetic<T>::value, ssize_t
>::type
writeHeader(const char* name, T value) {
auto str = std::to_string(value);
return writeHeader(name, str.c_str());
}
char *cursor() const { return buf; }
private:
char* buf;
size_t len;
};
} }
class Handler : public Net::Tcp::Handler { class Handler : public Net::Tcp::Handler {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment