HTTP server functionality is in there.
This commit is contained in:
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user