mirror of
https://github.com/matrix-construct/construct
synced 2024-12-01 19:22:53 +01:00
ircd::http: Update HTTP send-sides to write to stream_buffer.
This commit is contained in:
parent
8178d96f64
commit
51ebd9c346
5 changed files with 251 additions and 179 deletions
|
@ -254,20 +254,23 @@ struct ircd::http::request
|
||||||
struct head;
|
struct head;
|
||||||
struct content;
|
struct content;
|
||||||
|
|
||||||
using write_closure = std::function<void (const ilist<const_buffer> &)>;
|
|
||||||
using proffer = std::function<void (const head &)>;
|
using proffer = std::function<void (const head &)>;
|
||||||
using header = line::header;
|
using header = line::header;
|
||||||
|
|
||||||
request(const string_view &host = {},
|
// send
|
||||||
|
request(stream_buffer &,
|
||||||
|
const string_view &host,
|
||||||
const string_view &method = "GET",
|
const string_view &method = "GET",
|
||||||
const string_view &path = "/",
|
const string_view &path = "/",
|
||||||
const string_view &query = {},
|
const string_view &query = {},
|
||||||
const string_view &content = {},
|
const size_t &content_length = 0,
|
||||||
const write_closure & = nullptr,
|
const string_view &content_type = {},
|
||||||
const vector_view<const header> & = {});
|
const vector_view<const header> & = {},
|
||||||
|
const bool &termination = true);
|
||||||
|
|
||||||
|
// recv
|
||||||
request(parse::capstan &,
|
request(parse::capstan &,
|
||||||
content *const & = nullptr,
|
content *const &,
|
||||||
const proffer & = nullptr,
|
const proffer & = nullptr,
|
||||||
const headers::closure & = {});
|
const headers::closure & = {});
|
||||||
};
|
};
|
||||||
|
@ -315,13 +318,18 @@ struct ircd::http::response
|
||||||
using proffer = std::function<void (const head &)>;
|
using proffer = std::function<void (const head &)>;
|
||||||
using header = line::header;
|
using header = line::header;
|
||||||
|
|
||||||
response(const code &,
|
// send
|
||||||
const string_view &content,
|
response(stream_buffer &,
|
||||||
const write_closure &,
|
const code & = code::OK,
|
||||||
const vector_view<const header> & = {});
|
const size_t &content_length = 0,
|
||||||
|
const string_view &content_type = {},
|
||||||
|
const string_view &cache_control = {},
|
||||||
|
const vector_view<const header> & = {},
|
||||||
|
const bool &termination = true);
|
||||||
|
|
||||||
|
// recv
|
||||||
response(parse::capstan &,
|
response(parse::capstan &,
|
||||||
content *const & = nullptr,
|
content *const &,
|
||||||
const proffer & = nullptr,
|
const proffer & = nullptr,
|
||||||
const headers::closure & = {});
|
const headers::closure & = {});
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,7 @@ struct ircd::resource::request::object
|
||||||
|
|
||||||
struct ircd::resource::response
|
struct ircd::resource::response
|
||||||
{
|
{
|
||||||
response(client &, const string_view &str, const string_view &ct = "text/plain; charset=utf8", const http::code & = http::OK);
|
response(client &, const string_view &str, const string_view &content_type, const http::code & = http::OK);
|
||||||
response(client &, const json::object &str, const http::code & = http::OK);
|
response(client &, const json::object &str, const http::code & = http::OK);
|
||||||
response(client &, const json::array &str, const http::code & = http::OK);
|
response(client &, const json::array &str, const http::code & = http::OK);
|
||||||
response(client &, const json::members & = {}, const http::code & = http::OK);
|
response(client &, const json::members & = {}, const http::code & = http::OK);
|
||||||
|
|
315
ircd/http.cc
315
ircd/http.cc
|
@ -48,20 +48,25 @@ namespace ircd::http
|
||||||
template<class it, class top = unused_type> struct grammar;
|
template<class it, class top = unused_type> struct grammar;
|
||||||
struct parser extern const parser;
|
struct parser extern const parser;
|
||||||
|
|
||||||
size_t printed_size(const vector_view<const line::header> &headers);
|
|
||||||
size_t print(char *const &buf, const size_t &max, const vector_view<const line::header> &headers);
|
|
||||||
|
|
||||||
extern const std::unordered_map<ircd::http::code, ircd::string_view> reason;
|
extern const std::unordered_map<ircd::http::code, ircd::string_view> reason;
|
||||||
|
|
||||||
|
size_t serialized(const vector_view<const line::header> &headers);
|
||||||
|
void writeline(stream_buffer &, const stream_buffer::closure &);
|
||||||
|
void writeline(stream_buffer &);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_FUSION_ADAPT_STRUCT
|
BOOST_FUSION_ADAPT_STRUCT
|
||||||
(
|
(
|
||||||
ircd::http::line::request,
|
ircd::http::query,
|
||||||
( decltype(ircd::http::line::request::method), method )
|
( decltype(ircd::http::query::first), first )
|
||||||
( decltype(ircd::http::line::request::path), path )
|
( decltype(ircd::http::query::second), second )
|
||||||
( decltype(ircd::http::line::request::query), query )
|
)
|
||||||
( decltype(ircd::http::line::request::fragment), fragment )
|
|
||||||
( decltype(ircd::http::line::request::version), version )
|
BOOST_FUSION_ADAPT_STRUCT
|
||||||
|
(
|
||||||
|
ircd::http::line::header,
|
||||||
|
( decltype(ircd::http::line::header::first), first )
|
||||||
|
( decltype(ircd::http::line::header::second), second )
|
||||||
)
|
)
|
||||||
|
|
||||||
BOOST_FUSION_ADAPT_STRUCT
|
BOOST_FUSION_ADAPT_STRUCT
|
||||||
|
@ -74,16 +79,12 @@ BOOST_FUSION_ADAPT_STRUCT
|
||||||
|
|
||||||
BOOST_FUSION_ADAPT_STRUCT
|
BOOST_FUSION_ADAPT_STRUCT
|
||||||
(
|
(
|
||||||
ircd::http::line::header,
|
ircd::http::line::request,
|
||||||
( decltype(ircd::http::line::header::first), first )
|
( decltype(ircd::http::line::request::method), method )
|
||||||
( decltype(ircd::http::line::header::second), second )
|
( decltype(ircd::http::line::request::path), path )
|
||||||
)
|
( decltype(ircd::http::line::request::query), query )
|
||||||
|
( decltype(ircd::http::line::request::fragment), fragment )
|
||||||
BOOST_FUSION_ADAPT_STRUCT
|
( decltype(ircd::http::line::request::version), version )
|
||||||
(
|
|
||||||
ircd::http::query,
|
|
||||||
( decltype(ircd::http::query::first), first )
|
|
||||||
( decltype(ircd::http::query::second), second )
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const decltype(ircd::http::reason) ircd::http::reason
|
const decltype(ircd::http::reason) ircd::http::reason
|
||||||
|
@ -236,35 +237,6 @@ struct ircd::http::parser
|
||||||
}
|
}
|
||||||
const ircd::http::parser;
|
const ircd::http::parser;
|
||||||
|
|
||||||
size_t
|
|
||||||
ircd::http::print(char *const &buf,
|
|
||||||
const size_t &max,
|
|
||||||
const vector_view<const line::header> &headers)
|
|
||||||
{
|
|
||||||
size_t ret(0);
|
|
||||||
for(auto it(std::begin(headers)); it != std::end(headers); ++it)
|
|
||||||
{
|
|
||||||
ret += fmt::snprintf(buf + ret, max - ret, "%s: %s",
|
|
||||||
it->first,
|
|
||||||
it->second);
|
|
||||||
|
|
||||||
ret += snprintf(buf + ret, max - ret, "\r\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
ircd::http::printed_size(const vector_view<const line::header> &headers)
|
|
||||||
{
|
|
||||||
return std::accumulate(std::begin(headers), std::end(headers), size_t(1), []
|
|
||||||
(auto &ret, const auto &pair)
|
|
||||||
{
|
|
||||||
// key : SP value CRLF
|
|
||||||
return ret += pair.first.size() + 1 + 1 + pair.second.size() + 2;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ircd::http::request::request(parse::capstan &pc,
|
ircd::http::request::request(parse::capstan &pc,
|
||||||
content *const &c,
|
content *const &c,
|
||||||
const proffer &proffer,
|
const proffer &proffer,
|
||||||
|
@ -286,64 +258,77 @@ ircd::http::request::request(parse::capstan &pc,
|
||||||
*c = content{pc, h};
|
*c = content{pc, h};
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::http::request::request(const string_view &host,
|
/// Compose a request. This prints an HTTP head into the buffer. No real IO is
|
||||||
|
/// done here. After composing into the buffer, the user can then drive the
|
||||||
|
/// socket by sending the header and the content as specified.
|
||||||
|
///
|
||||||
|
/// If termination is false, no extra CRLF is printed to the buffer allowing
|
||||||
|
/// additional headers not specified to be appended later.
|
||||||
|
ircd::http::request::request(stream_buffer &out,
|
||||||
|
const string_view &host,
|
||||||
const string_view &method,
|
const string_view &method,
|
||||||
const string_view &path,
|
const string_view &path,
|
||||||
const string_view &query,
|
const string_view &query,
|
||||||
const string_view &content,
|
const size_t &content_length,
|
||||||
const write_closure &closure,
|
const string_view &content_type,
|
||||||
const vector_view<const header> &headers)
|
const vector_view<const header> &headers,
|
||||||
|
const bool &termination)
|
||||||
|
{
|
||||||
|
writeline(out, [&method, &path, &query](const mutable_buffer &out) -> size_t
|
||||||
{
|
{
|
||||||
assert(!method.empty());
|
|
||||||
assert(!path.empty());
|
assert(!path.empty());
|
||||||
|
assert(!method.empty());
|
||||||
static const auto &version
|
return fmt::sprintf
|
||||||
{
|
{
|
||||||
"HTTP/1.1"
|
out, "%s /%s%s%s HTTP/1.1",
|
||||||
};
|
method,
|
||||||
|
path,
|
||||||
char request_line[2048]; const auto request_line_len
|
|
||||||
{
|
|
||||||
snprintf(request_line, sizeof(request_line), "%s /%s%s%s %s\r\n",
|
|
||||||
method.c_str(),
|
|
||||||
path.c_str(),
|
|
||||||
query.empty()? "" : "?",
|
query.empty()? "" : "?",
|
||||||
query.empty()? "" : query.c_str(),
|
query.empty()? "" : query
|
||||||
version)
|
|
||||||
};
|
};
|
||||||
|
});
|
||||||
|
|
||||||
char host_line[128] {"Host: "}; const auto host_line_len
|
writeline(out, [&host](const mutable_buffer &out) -> size_t
|
||||||
{
|
{
|
||||||
6 + snprintf(host_line + 6, std::min(sizeof(host_line) - 6, host.size() + 3), "%s\r\n",
|
assert(!host.empty());
|
||||||
host.c_str())
|
return fmt::sprintf
|
||||||
};
|
|
||||||
|
|
||||||
char content_len[64]; const auto content_len_len
|
|
||||||
{
|
{
|
||||||
snprintf(content_len, sizeof(content_len), "Content-Length: %zu\r\n",
|
out, "Host: %s", host
|
||||||
content.size())
|
|
||||||
};
|
};
|
||||||
|
});
|
||||||
|
|
||||||
char user_headers[printed_size(headers) + 2]; auto user_headers_len
|
if(content_length)
|
||||||
|
writeline(out, [&content_type](const mutable_buffer &out) -> size_t
|
||||||
{
|
{
|
||||||
print(user_headers, sizeof(user_headers), headers)
|
return fmt::sprintf
|
||||||
};
|
|
||||||
|
|
||||||
assert(user_headers_len + 3 == sizeof(user_headers));
|
|
||||||
user_headers[user_headers_len++] = '\r';
|
|
||||||
user_headers[user_headers_len++] = '\n';
|
|
||||||
//user_headers[user_headers_len++] = '\0';
|
|
||||||
|
|
||||||
const ilist<const_buffer> vector
|
|
||||||
{
|
{
|
||||||
{ request_line, size_t(request_line_len) },
|
out, "Content-Type: %s", content_type?: "text/plain; charset=utf-8"
|
||||||
{ host_line, size_t(host_line_len) },
|
|
||||||
{ content_len, size_t(content_len_len) },
|
|
||||||
{ user_headers, size_t(user_headers_len) },
|
|
||||||
{ content.data(), content.size() },
|
|
||||||
};
|
};
|
||||||
|
});
|
||||||
|
|
||||||
closure(vector);
|
writeline(out, [&content_length](const mutable_buffer &out) -> size_t
|
||||||
|
{
|
||||||
|
return fmt::sprintf
|
||||||
|
{
|
||||||
|
out, "Content-Length: %zu", content_length
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
for(const auto &header : headers)
|
||||||
|
{
|
||||||
|
assert(!header.first.empty());
|
||||||
|
assert(!header.second.empty());
|
||||||
|
writeline(out, [&header](const mutable_buffer &out) -> size_t
|
||||||
|
{
|
||||||
|
return fmt::sprintf
|
||||||
|
{
|
||||||
|
out, "%s: %s", header.first, header.second
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(termination)
|
||||||
|
writeline(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::http::request::head::head(parse::capstan &pc,
|
ircd::http::request::head::head(parse::capstan &pc,
|
||||||
|
@ -394,84 +379,92 @@ ircd::http::response::response(parse::capstan &pc,
|
||||||
*c = content{pc, h};
|
*c = content{pc, h};
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::http::response::response(const code &code,
|
ircd::http::response::response(stream_buffer &out,
|
||||||
const string_view &content,
|
const code &code,
|
||||||
const write_closure &closure,
|
const size_t &content_length,
|
||||||
const vector_view<const header> &headers)
|
const string_view &content_type,
|
||||||
|
const string_view &cache_control,
|
||||||
|
const vector_view<const header> &headers,
|
||||||
|
const bool &termination)
|
||||||
{
|
{
|
||||||
char status_line[128]; const auto status_line_len
|
writeline(out, [&code](const mutable_buffer &out) -> size_t
|
||||||
{
|
{
|
||||||
snprintf(status_line, sizeof(status_line), "HTTP/1.1 %u %s\r\n",
|
return fmt::sprintf
|
||||||
uint(code),
|
{
|
||||||
status(code).data())
|
out, "HTTP/1.1 %u %s", uint(code), status(code)
|
||||||
};
|
};
|
||||||
|
});
|
||||||
|
|
||||||
char server_line[128]; const auto server_line_len
|
if(code >= 200 && code < 300)
|
||||||
|
writeline(out, [&code](const mutable_buffer &out) -> size_t
|
||||||
{
|
{
|
||||||
code >= 200 && code < 300?
|
return fmt::sprintf
|
||||||
snprintf(server_line, sizeof(server_line), "Server: %s (IRCd %s)\r\n",
|
{
|
||||||
BRANDING_NAME,
|
out, "Server: %s (IRCd %s)", BRANDING_NAME, BRANDING_VERSION
|
||||||
BRANDING_VERSION):
|
|
||||||
0
|
|
||||||
};
|
};
|
||||||
|
});
|
||||||
|
|
||||||
char date_line[128], date_buf[96]; const auto date_line_len
|
if(code < 400)
|
||||||
|
writeline(out, [](const mutable_buffer &out) -> size_t
|
||||||
{
|
{
|
||||||
code < 400?
|
char date_buf[96];
|
||||||
snprintf(data(date_line), size(date_line), "Date: %s\r\n",
|
return fmt::sprintf
|
||||||
timef(date_buf, ircd::localtime).c_str()):
|
{
|
||||||
0
|
out, "Date: %s", timef(date_buf, ircd::localtime)
|
||||||
};
|
};
|
||||||
|
});
|
||||||
|
|
||||||
char cache_line[64]; const auto cache_line_len
|
if((code >= 200 && code < 300) || (code >= 403 && code <= 405) || (code >= 300 && code < 400))
|
||||||
|
writeline(out, [&cache_control](const mutable_buffer &out) -> size_t
|
||||||
{
|
{
|
||||||
//TODO: real cache control subsystem
|
return fmt::sprintf
|
||||||
(code >= 200 && code < 300) || (code >= 403 && code <= 405) || (code >= 300 && code < 400)?
|
{
|
||||||
snprintf(cache_line, sizeof(cache_line), "Cache-Control: %s\r\n",
|
out, "Cache-Control: %s", cache_control?: "no-cache"
|
||||||
"no-cache"):
|
|
||||||
0
|
|
||||||
};
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const bool has_transfer_encoding
|
const bool has_transfer_encoding
|
||||||
{
|
{
|
||||||
std::any_of(std::begin(headers), std::end(headers), []
|
std::any_of(std::begin(headers), std::end(headers), []
|
||||||
(const auto &header)
|
(const auto &header)
|
||||||
{
|
{
|
||||||
return header == "Transfer-Encoding";
|
return iequals(header.first, "transfer-encoding"s);
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
char content_len[64]; const auto content_len_len
|
if((content_length && code != NO_CONTENT) || has_transfer_encoding)
|
||||||
|
writeline(out, [&content_type](const mutable_buffer &out) -> size_t
|
||||||
{
|
{
|
||||||
code != NO_CONTENT && !has_transfer_encoding?
|
return fmt::sprintf
|
||||||
snprintf(content_len, sizeof(content_len), "Content-Length: %zu\r\n",
|
|
||||||
content.size()):
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto user_headers_bufsize
|
|
||||||
{
|
{
|
||||||
printed_size(headers)
|
out, "Content-Type: %s", content_type?: "text/plain; charset=utf-8"
|
||||||
};
|
};
|
||||||
|
});
|
||||||
|
|
||||||
char user_headers[user_headers_bufsize]; const auto user_headers_len
|
if(code != NO_CONTENT && !has_transfer_encoding)
|
||||||
|
writeline(out, [&content_length](const mutable_buffer &out) -> size_t
|
||||||
{
|
{
|
||||||
print(user_headers, sizeof(user_headers), headers)
|
return fmt::sprintf
|
||||||
};
|
|
||||||
|
|
||||||
const ilist<const_buffer> iov
|
|
||||||
{
|
{
|
||||||
{ status_line, size_t(status_line_len) },
|
out, "Content-Length: %zu", content_length
|
||||||
{ server_line, size_t(server_line_len) },
|
|
||||||
{ date_line, size_t(date_line_len) },
|
|
||||||
{ cache_line, size_t(cache_line_len) },
|
|
||||||
{ user_headers, size_t(user_headers_len) },
|
|
||||||
{ content_len, size_t(content_len_len) },
|
|
||||||
{ "\r\n", 2 },
|
|
||||||
{ content.data(), content.size() },
|
|
||||||
};
|
};
|
||||||
|
});
|
||||||
|
|
||||||
closure(iov);
|
for(const auto &header : headers)
|
||||||
|
{
|
||||||
|
assert(!header.first.empty());
|
||||||
|
assert(!header.second.empty());
|
||||||
|
writeline(out, [&header](const mutable_buffer &out) -> size_t
|
||||||
|
{
|
||||||
|
return fmt::sprintf
|
||||||
|
{
|
||||||
|
out, "%s: %s", header.first, header.second
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(termination)
|
||||||
|
writeline(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::http::response::chunked::chunked(const code &code,
|
ircd::http::response::chunked::chunked(const code &code,
|
||||||
|
@ -491,10 +484,14 @@ ircd::http::response::chunked::chunked(const code &code,
|
||||||
|
|
||||||
std::copy(begin(user_headers), end(user_headers), headers + 1);
|
std::copy(begin(user_headers), end(user_headers), headers + 1);
|
||||||
|
|
||||||
|
//TODO: bitrot
|
||||||
|
assert(0);
|
||||||
|
/*
|
||||||
response
|
response
|
||||||
{
|
{
|
||||||
code, {}, closure, { headers, headers + num_headers }
|
code, {}, closure, { headers, headers + num_headers }
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::http::response::chunked::~chunked()
|
ircd::http::response::chunked::~chunked()
|
||||||
|
@ -849,13 +846,53 @@ ircd::http::parser::content_length(const string_view &str)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Close over the user's closure to append a newline.
|
||||||
|
void
|
||||||
|
ircd::http::writeline(stream_buffer &write,
|
||||||
|
const stream_buffer::closure &closure)
|
||||||
|
{
|
||||||
|
// A new stream_buffer is implicit constructed out of the mutable_buffer
|
||||||
|
// otherwise presented to this closure as its write window.
|
||||||
|
write([&closure](stream_buffer write)
|
||||||
|
{
|
||||||
|
const auto newline{[](const mutable_buffer &out)
|
||||||
|
{
|
||||||
|
return copy(out, "\r\n"_sv);
|
||||||
|
}};
|
||||||
|
|
||||||
|
write(closure);
|
||||||
|
write(newline);
|
||||||
|
return write.consumed();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ircd::http::writeline(stream_buffer &write)
|
||||||
|
{
|
||||||
|
writeline(write, [](const mutable_buffer &out)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
ircd::http::serialized(const vector_view<const line::header> &headers)
|
||||||
|
{
|
||||||
|
return std::accumulate(std::begin(headers), std::end(headers), size_t{0}, []
|
||||||
|
(auto &ret, const auto &pair)
|
||||||
|
{
|
||||||
|
// key : SP value CRLF
|
||||||
|
return ret += pair.first.size() + 1 + 1 + pair.second.size() + 2;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ircd::http::error::error(const enum code &code,
|
ircd::http::error::error(const enum code &code,
|
||||||
std::string content)
|
std::string content)
|
||||||
:ircd::error{generate_skip}
|
:ircd::error{generate_skip}
|
||||||
,code{code}
|
,code{code}
|
||||||
,content{std::move(content)}
|
,content{std::move(content)}
|
||||||
{
|
{
|
||||||
snprintf(buf, sizeof(buf), "%d %s", int(code), status(code).data());
|
snprintf(buf, sizeof(buf), "%d %s", int(code), status(code).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::http::code
|
ircd::http::code
|
||||||
|
|
25
ircd/m/io.cc
25
ircd/m/io.cc
|
@ -598,11 +598,10 @@ const
|
||||||
std::min(addl_headers.size(), size_t(64UL))
|
std::min(addl_headers.size(), size_t(64UL))
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t headers{2 + addl_headers_size};
|
size_t headers{1};
|
||||||
http::line::header header[headers + 1]
|
http::line::header header[headers + addl_headers_size]
|
||||||
{
|
{
|
||||||
{ "User-Agent", BRANDING_NAME " (IRCd " BRANDING_VERSION ")" },
|
{ "User-Agent", BRANDING_NAME " (IRCd " BRANDING_VERSION ")" },
|
||||||
{ "Content-Type", "application/json" },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for(size_t i(0); i < addl_headers_size; ++i)
|
for(size_t i(0); i < addl_headers_size; ++i)
|
||||||
|
@ -615,16 +614,32 @@ const
|
||||||
"Authorization", generate_authorization(x_matrix)
|
"Authorization", generate_authorization(x_matrix)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const auto content_type
|
||||||
|
{
|
||||||
|
"application/json; charset=utf-8"
|
||||||
|
};
|
||||||
|
|
||||||
|
const unique_buffer<mutable_buffer> head_buf{8192};
|
||||||
|
stream_buffer head{head_buf};
|
||||||
http::request
|
http::request
|
||||||
{
|
{
|
||||||
|
head,
|
||||||
destination,
|
destination,
|
||||||
method,
|
method,
|
||||||
path,
|
path,
|
||||||
query,
|
query,
|
||||||
content,
|
content.size(),
|
||||||
write_closure(server),
|
content_type,
|
||||||
{ header, headers }
|
{ header, headers }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ilist<const_buffer> vector
|
||||||
|
{
|
||||||
|
head.completed(),
|
||||||
|
content
|
||||||
|
};
|
||||||
|
|
||||||
|
write_closure(server)(vector);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ircd::m::name
|
namespace ircd::m::name
|
||||||
|
|
|
@ -496,7 +496,7 @@ ircd::resource::response::response(client &client,
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::resource::response::response(client &client,
|
ircd::resource::response::response(client &client,
|
||||||
const string_view &str,
|
const string_view &content,
|
||||||
const string_view &content_type,
|
const string_view &content_type,
|
||||||
const http::code &code)
|
const http::code &code)
|
||||||
{
|
{
|
||||||
|
@ -507,20 +507,32 @@ ircd::resource::response::response(client &client,
|
||||||
|
|
||||||
char rtime[64]; const auto rtime_len
|
char rtime[64]; const auto rtime_len
|
||||||
{
|
{
|
||||||
snprintf(rtime, sizeof(rtime), "%zdus",
|
snprintf(rtime, sizeof(rtime), "%zdus", request_time)
|
||||||
request_time)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
char head_buf[2048];
|
||||||
|
stream_buffer head{head_buf};
|
||||||
http::response
|
http::response
|
||||||
{
|
{
|
||||||
code, str, write_closure(client),
|
head,
|
||||||
|
code,
|
||||||
|
content.size(),
|
||||||
|
content_type,
|
||||||
|
string_view{}, // cache_control
|
||||||
{
|
{
|
||||||
{ "Content-Type", content_type },
|
|
||||||
{ "Access-Control-Allow-Origin", "*" }, //TODO: XXX
|
{ "Access-Control-Allow-Origin", "*" }, //TODO: XXX
|
||||||
{ "X-IRCd-Request-Timer", string_view{rtime, size_t(rtime_len)} }
|
{ "X-IRCd-Request-Timer", string_view{rtime, size_t(rtime_len)} }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ilist<const_buffer> vector
|
||||||
|
{
|
||||||
|
head.completed(),
|
||||||
|
content
|
||||||
|
};
|
||||||
|
|
||||||
|
write_closure(client)(vector);
|
||||||
|
|
||||||
log::debug("client[%s] HTTP %d %s in %ld$us; response in %ld$us (%s) content-length: %zu",
|
log::debug("client[%s] HTTP %d %s in %ld$us; response in %ld$us (%s) content-length: %zu",
|
||||||
string(remote(client)),
|
string(remote(client)),
|
||||||
int(code),
|
int(code),
|
||||||
|
@ -528,5 +540,5 @@ ircd::resource::response::response(client &client,
|
||||||
request_time,
|
request_time,
|
||||||
(client.request_timer.at<microseconds>().count() - request_time),
|
(client.request_timer.at<microseconds>().count() - request_time),
|
||||||
content_type,
|
content_type,
|
||||||
str.size());
|
content.size());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue