HTTP server functionality is in there.

This commit is contained in:
2022-05-20 17:12:58 -04:00
parent cd3064eb05
commit ca271b8db1
9 changed files with 932 additions and 208 deletions

View File

@@ -458,6 +458,91 @@ void World::abort_all_http_requests(int status_code, std::string_view error) {
}
}
HttpServerResponse World::http_serve(const HttpParser &request) {
assert(stack_is_clear());
HttpServerResponse response;
// We're only supposed to be passed complete requests.
assert(request.complete());
// If the request is HTTP/1.1, then the response should be HTTP/1.1
response.set_http11(request.http11());
// If the incoming request has already been detected to be
// invalid by the HTTP parser, then just send the error
// message back to the client without involving lua at all.
if (request.errstatus()) {
response.fail(request.status(), request.error());
return response;
}
// Get the name of the desired function.
std::string_view fn = request.first_path_component("index");
if (!sv::is_lua_id(fn)) {
response.fail(404, util::ss("not a function name: ", fn));
return response;
}
lua_State *L = state();
LuaVar www, func, reqtab;
LuaStack LS(L, www, func, reqtab);
// Get the www class. If there's no such class,
// return a 503 Service Unavailable to the client.
eng::string err = LS.getclass(www, "www");
if (!err.empty()) {
response.fail(503, "class www doesn't exist");
LS.result();
return response;
}
// Get the closure. If there's no such closure,
// return a 404 Not Found to the client.
LS.rawget(func, www, fn);
if (!LS.isfunction(func)) {
response.fail(404, util::ss("no such function: www.", fn));
LS.result();
return response;
}
// Store the request into a lua table.
request.store(LS, reqtab);
// Call the function.
int oldtop = lua_gettop(L);
lua_pushvalue(L, func.index());
lua_pushvalue(L, reqtab.index());
Gui::store_global_pointer(L, nullptr);
open_lthread_state(0, 0, 0, false, false);
eng::string msg = traceback_pcall(L, 1, LUA_MULTRET);
close_lthread_state();
// If the call threw an error, return
// a 500 Internal Server Error to the client.
if (!msg.empty()) {
response.fail(500, msg);
LS.result();
return response;
}
// If the call didn't return a single table, return
// a 500 Internal Server Error to the client.
int newtop = lua_gettop(L);
if ((newtop != oldtop + 1) || (!lua_istable(L, newtop))) {
response.fail(500, util::ss("lua function www.", fn, " didn't return a table"));
LS.result();
return response;
}
// Try to convert the table into a response.
// If this results in an error, we don't have to do
// anything special, set_config will store the error.
response.set_config(LS, LuaSpecial(newtop));
response.set_defaults();
LS.result();
return response;
}
void World::run_unittests() {
assert(stack_is_clear());
source_db_.run_unittests();