MODULE = Protocol::HTTP PACKAGE = Protocol::HTTP::Message
PROTOTYPES: DISABLE
BOOT {
Stash stash(__PACKAGE__);
xs::exp::create_constants(stash, {
{"STATE_HEADERS", (int)State::headers},
{"STATE_BODY", (int)State::body},
{"STATE_CHUNK", (int)State::chunk},
{"STATE_CHUNK_BODY", (int)State::chunk_body},
{"STATE_CHUNK_TRAILER", (int)State::chunk_trailer},
{"STATE_DONE", (int)State::done},
{"STATE_ERROR", (int)State::error}
});
xs::exp::autoexport(stash);
}
Hash Message::headers (Hash new_headers = Hash()) {
if (new_headers) {
set_headers(THIS, new_headers);
XSRETURN_UNDEF;
}
RETVAL = Hash::create(THIS->headers.size());
for (const auto& elem : THIS->headers.fields) {
auto len = elem.name.length();
auto key = (char*)alloca(sizeof(char)*len);
std::transform(elem.name.data(), elem.name.data() + len, key, ::tolower);
RETVAL.store(string_view(key, len), xs::out(elem.value));
}
}
string Message::header (string_view name, SV* val = nullptr) {
if (val) {
if (!sv_defined(val)) THIS->headers.remove(name);
else THIS->headers.set(string(name), xs::in<string>(val));
XSRETURN_UNDEF;
}
auto it = THIS->headers.find(name);
if (it == THIS->headers.fields.end()) XSRETURN_UNDEF;
RETVAL = it->value;
}
void Message::multiheader (string_view name, ...) {
if (items > 2) {
auto key = string(name);
for (auto i = 2; i < items; ++i) {
auto val = ST(i);
if (sv_defined(val)) THIS->headers.add(key, xs::in<string>(val));
}
XSRETURN_EMPTY;
}
for (auto& v : THIS->headers.get_multi(name)) {
mXPUSHs(xs::out(v).detach());
}
}
size_t Message::headers_size () {
RETVAL = THIS->headers.size();
}
Simple Message::body (SV* newval = nullptr) {
if (newval) {
THIS->body = xs::in<string>(newval);
XSRETURN_UNDEF;
}
RETVAL = strings_to_sv(THIS->body.parts);
}
int Message::http_version (SV* newval = nullptr) {
if (newval) {
THIS->http_version = SvIV(newval);
XSRETURN_UNDEF;
}
RETVAL = THIS->http_version;
}
bool Message::chunked (SV* newval = nullptr) {
if (newval) {
THIS->chunked = SvTRUE(newval);
XSRETURN_UNDEF;
}
RETVAL = THIS->chunked;
}
Simple Message::make_chunk(string s) {
RETVAL = strings_to_sv(THIS->make_chunk(s));
}
Simple Message::final_chunk(string s = {}) {
RETVAL = strings_to_sv(THIS->final_chunk(s));
}
void Message::compression () {
if (GIMME_V == G_ARRAY) {
mPUSHs(Simple((int)THIS->compression.type).detach());
mXPUSHs(Simple((int)THIS->compression.level).detach());
XSRETURN(2);
}
else {
dXSTARG;
PUSHi((int)THIS->compression.type);
}
}
void Message::compress (int method, int level = (int)Compression::Level::min) {
if (level < (int)Compression::Level::min || level > (int)Compression::Level::max) throw "bad compression level";
if (!is_valid_compression(method)) throw "bad compression";
THIS->compress((Compression::Type)method, (Compression::Level)level);
}
SV* CLONE_SKIP (...) {
XSRETURN_YES;
PERL_UNUSED_VAR(items);
}