HTTP stuff now uses keyword parser.
This commit is contained in:
@@ -734,50 +734,55 @@ void HttpClientRequest::set_defaults() {
|
||||
}
|
||||
}
|
||||
|
||||
void HttpClientRequest::set_config(LuaStack &LS0, LuaSlot tab) {
|
||||
LuaVar key, val;
|
||||
LuaStack LS(LS0.state(), key, val);
|
||||
LS.set(key, LuaNil);
|
||||
while (LS.next(tab, key, val)) {
|
||||
eng::string kstr;
|
||||
if (LS.isstring(key)) kstr = LS.ckstring(key);
|
||||
if (kstr == "method") {
|
||||
set_method(LS, val);
|
||||
} else if (kstr == "host") {
|
||||
set_host(LS, val);
|
||||
} else if (kstr == "port") {
|
||||
set_port(LS, val);
|
||||
} else if (kstr == "path") {
|
||||
set_path(LS, val);
|
||||
} else if (kstr == "params") {
|
||||
set_params(LS, val);
|
||||
} else if (kstr == "url") {
|
||||
set_url(LS, val);
|
||||
} else if (kstr == "verifycertificate") {
|
||||
set_verify_certificate(LS, val);
|
||||
} else if (kstr == "mimetype") {
|
||||
set_mime_type(LS, val);
|
||||
} else if (kstr == "content") {
|
||||
set_content(LS, val);
|
||||
} else if (kstr == "html") {
|
||||
set_content(LS, val);
|
||||
set_mime_type("text/html");
|
||||
} else if (kstr == "text") {
|
||||
set_content(LS, val);
|
||||
set_mime_type("text/plain");
|
||||
} else if (kstr == "json") {
|
||||
set_content(LS, val);
|
||||
set_mime_type("application/json");
|
||||
} else if (kstr == "bytes") {
|
||||
set_content(LS, val);
|
||||
set_mime_type("application/octet-stream");
|
||||
} else if (kstr == "jsonvalue") {
|
||||
set_jsonvalue(LS, val);
|
||||
} else if (kstr == "") {
|
||||
check_fail(util::ss("configuration parameter names must be strings."));
|
||||
} else {
|
||||
check_fail(util::ss("unrecognized request configuration parameter: ", kstr));
|
||||
}
|
||||
void HttpClientRequest::configure(LuaKeywordParser &kp) {
|
||||
LuaVar val;
|
||||
LuaStack LS(kp.state(), val);
|
||||
if (kp.parse(val, "method")) {
|
||||
set_method(LS, val);
|
||||
}
|
||||
if (kp.parse(val, "host")) {
|
||||
set_host(LS, val);
|
||||
}
|
||||
if (kp.parse(val, "port")) {
|
||||
set_port(LS, val);
|
||||
}
|
||||
if (kp.parse(val, "path")) {
|
||||
set_path(LS, val);
|
||||
}
|
||||
if (kp.parse(val, "params")) {
|
||||
set_params(LS, val);
|
||||
}
|
||||
if (kp.parse(val, "url")) {
|
||||
set_url(LS, val);
|
||||
}
|
||||
if (kp.parse(val, "verifycertificate")) {
|
||||
set_verify_certificate(LS, val);
|
||||
}
|
||||
if (kp.parse(val, "mimetype")) {
|
||||
set_mime_type(LS, val);
|
||||
}
|
||||
if (kp.parse(val, "content")) {
|
||||
set_content(LS, val);
|
||||
}
|
||||
if (kp.parse(val, "html")) {
|
||||
set_content(LS, val);
|
||||
set_mime_type("text/html");
|
||||
}
|
||||
|
||||
if (kp.parse(val, "text")) {
|
||||
set_content(LS, val);
|
||||
set_mime_type("text/plain");
|
||||
}
|
||||
if (kp.parse(val, "json")) {
|
||||
set_content(LS, val);
|
||||
set_mime_type("application/json");
|
||||
}
|
||||
if (kp.parse(val, "bytes")) {
|
||||
set_content(LS, val);
|
||||
set_mime_type("application/octet-stream");
|
||||
}
|
||||
if (kp.parse(val, "jsonvalue")) {
|
||||
set_jsonvalue(LS, val);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1025,40 +1030,39 @@ void HttpServerResponse::set_jsonvalue(LuaStack &LS, LuaSlot val) {
|
||||
set_mime_type("application/json");
|
||||
}
|
||||
|
||||
void HttpServerResponse::set_config(LuaStack &LS0, LuaSlot tab) {
|
||||
LuaVar key, val;
|
||||
LuaStack LS(LS0.state(), key, val);
|
||||
LS.set(key, LuaNil);
|
||||
while (LS.next(tab, key, val)) {
|
||||
eng::string kstr;
|
||||
if (LS.isstring(key)) kstr = LS.ckstring(key);
|
||||
if (kstr == "status") {
|
||||
set_status(LS, val);
|
||||
} else if (kstr == "maxage") {
|
||||
set_max_age(LS, val);
|
||||
} else if (kstr == "mimetype") {
|
||||
set_mime_type(LS, val);
|
||||
} else if (kstr == "content") {
|
||||
set_content(LS, val);
|
||||
} else if (kstr == "html") {
|
||||
set_content(LS, val);
|
||||
set_mime_type("text/html");
|
||||
} else if (kstr == "text") {
|
||||
set_content(LS, val);
|
||||
set_mime_type("text/plain");
|
||||
} else if (kstr == "json") {
|
||||
set_content(LS, val);
|
||||
set_mime_type("application/json");
|
||||
} else if (kstr == "bytes") {
|
||||
set_content(LS, val);
|
||||
set_mime_type("application/octet-stream");
|
||||
} else if (kstr == "jsonvalue") {
|
||||
set_jsonvalue(LS, val);
|
||||
} else if (kstr == "") {
|
||||
check_fail(util::ss("response configuration parameters must be strings."));
|
||||
} else {
|
||||
check_fail(util::ss("unrecognized response configuration parameter: ", kstr));
|
||||
}
|
||||
void HttpServerResponse::configure(LuaKeywordParser &kp) {
|
||||
LuaVar val;
|
||||
LuaStack LS(kp.state(), val);
|
||||
if (kp.parse(val, "status")) {
|
||||
set_status(LS, val);
|
||||
}
|
||||
if (kp.parse(val, "maxage")) {
|
||||
set_max_age(LS, val);
|
||||
}
|
||||
if (kp.parse(val, "mimetype")) {
|
||||
set_mime_type(LS, val);
|
||||
}
|
||||
if (kp.parse(val, "content")) {
|
||||
set_content(LS, val);
|
||||
}
|
||||
if (kp.parse(val, "html")) {
|
||||
set_content(LS, val);
|
||||
set_mime_type("text/html");
|
||||
}
|
||||
if (kp.parse(val, "text")) {
|
||||
set_content(LS, val);
|
||||
set_mime_type("text/plain");
|
||||
}
|
||||
if (kp.parse(val, "json")) {
|
||||
set_content(LS, val);
|
||||
set_mime_type("application/json");
|
||||
}
|
||||
if (kp.parse(val, "bytes")) {
|
||||
set_content(LS, val);
|
||||
set_mime_type("application/octet-stream");
|
||||
}
|
||||
if (kp.parse(val, "jsonvalue")) {
|
||||
set_jsonvalue(LS, val);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1712,8 +1716,10 @@ LuaDefine(http_clientrequest, "request",
|
||||
LuaArg tab;
|
||||
LuaRet str;
|
||||
LuaStack LS(L, tab, str);
|
||||
LuaKeywordParser kp(LS, tab);
|
||||
HttpClientRequest req;
|
||||
req.set_config(LS, tab);
|
||||
req.configure(kp);
|
||||
kp.final_check_throw();
|
||||
req.set_defaults();
|
||||
eng::string error = req.check();
|
||||
if (!error.empty()) {
|
||||
@@ -1882,8 +1888,10 @@ LuaDefine(http_serverresponse, "response",
|
||||
LuaArg tab;
|
||||
LuaRet str;
|
||||
LuaStack LS(L, tab, str);
|
||||
LuaKeywordParser kp(LS, tab);
|
||||
HttpServerResponse resp;
|
||||
resp.set_config(LS, tab);
|
||||
resp.configure(kp);
|
||||
kp.final_check_throw();
|
||||
resp.set_defaults();
|
||||
LS.set(str, resp.debug_string());
|
||||
return LS.result();
|
||||
@@ -1915,4 +1923,4 @@ LuaDefine(http_statuscode, "(statusstring)", "Convert a string to a 3-digit stat
|
||||
LS.set(code, status_code_from_string(sstr));
|
||||
int iresult = LS.result();
|
||||
return iresult;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,8 +104,9 @@ public:
|
||||
void set_defaults();
|
||||
|
||||
// Populate request-related fields from a Lua table.
|
||||
void set_config(LuaStack &LS0, LuaSlot tab);
|
||||
|
||||
// Doesn't throw errors, instead, returns errors via check().
|
||||
void configure(LuaKeywordParser &kp);
|
||||
|
||||
// Get or Set the request IDs.
|
||||
//
|
||||
// This class does not use these fields, it just stores
|
||||
@@ -208,8 +209,9 @@ public:
|
||||
void set_defaults();
|
||||
|
||||
// Populate request-related fields from a Lua table.
|
||||
// Doesn't throw errors, instead, returns them via check()
|
||||
//
|
||||
void set_config(LuaStack &LS0, LuaSlot tab);
|
||||
void configure(LuaKeywordParser &kp);
|
||||
|
||||
// Set the keep_alive flag.
|
||||
//
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <climits>
|
||||
#include "wrap-string.hpp"
|
||||
#include "wrap-set.hpp"
|
||||
#include "wrap-sstream.hpp"
|
||||
|
||||
LuaSpecial LuaRegistry(LUA_REGISTRYINDEX);
|
||||
LuaNilMarker LuaNil;
|
||||
@@ -468,8 +469,10 @@ void LuaStack::setvisited(LuaSlot tab, bool visited) const {
|
||||
LuaKeywordParser::LuaKeywordParser(lua_State *L, int slot) {
|
||||
L_ = L;
|
||||
slot_ = slot;
|
||||
if (!lua_istable(L_, slot_)) {
|
||||
luaL_error(L_, "expected an argument which is a table full of keywords");
|
||||
not_table_ = !lua_istable(L_, slot_);
|
||||
if (not_table_) {
|
||||
lua_newtable(L_);
|
||||
lua_replace(L_, slot_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,20 +488,32 @@ bool LuaKeywordParser::parse(LuaSlot out, const char *kw) {
|
||||
}
|
||||
};
|
||||
|
||||
void LuaKeywordParser::check_unparsed_keywords() {
|
||||
eng::string LuaKeywordParser::final_check() {
|
||||
if (not_table_) {
|
||||
return "expected a keyword table";
|
||||
}
|
||||
if (lua_nkeys(L_, slot_) != int(parsed_.size())) {
|
||||
lua_pushnil(L_);
|
||||
while (lua_next(L_, slot_) != 0) {
|
||||
lua_pop(L_, 1); // Don't need the value.
|
||||
if (!lua_isstring(L_, -1)) {
|
||||
luaL_error(L_, "keyword table contains non-string key");
|
||||
return "keyword table contains non-string key";
|
||||
}
|
||||
const char *kw = lua_tostring(L_, -1);
|
||||
if (parsed_.find(kw) == parsed_.end()) {
|
||||
luaL_error(L_, "keyword %s not known", kw);
|
||||
eng::ostringstream oss;
|
||||
oss << "keyword " << kw << " not known";
|
||||
return oss.str();
|
||||
}
|
||||
}
|
||||
assert(false && "should never get here in check_unparsed_keywords");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void LuaKeywordParser::final_check_throw() {
|
||||
eng::string err = final_check();
|
||||
if (!err.empty()) {
|
||||
luaL_error(L_, "%s", err.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,14 +531,15 @@ class LuaKeywordParser {
|
||||
};
|
||||
};
|
||||
private:
|
||||
bool not_table_;
|
||||
lua_State *L_;
|
||||
int slot_;
|
||||
eng::set<const char *, cmp_char> parsed_;
|
||||
|
||||
void init(const lua_State *L, int slot);
|
||||
public:
|
||||
// The constructor will throw a lua error if the
|
||||
// slot is not a table.
|
||||
// If the slot is not a table, sets the not_table
|
||||
// flag and creates a dummy table in the slot.
|
||||
LuaKeywordParser(lua_State *L, int slot);
|
||||
LuaKeywordParser(const LuaStack &LS, LuaSlot slot) : LuaKeywordParser(LS.state(), slot.index()) {}
|
||||
|
||||
@@ -546,9 +547,12 @@ public:
|
||||
// Return true if the value is non-nil.
|
||||
bool parse(LuaSlot slot, const char *kw);
|
||||
|
||||
// Check if there are any keywords in the table that
|
||||
// were never parsed. If so, throw an error.
|
||||
void check_unparsed_keywords();
|
||||
// Check if there were any errors. If so, return an
|
||||
// error message.
|
||||
eng::string final_check();
|
||||
|
||||
// Check if there are any errors. If so, throw a lua error.
|
||||
void final_check_throw();
|
||||
|
||||
// Fetch the state pointer.
|
||||
lua_State *state() const { return L_; }
|
||||
|
||||
@@ -64,7 +64,7 @@ LuaDefine(tangible_animate, "tan,configtable",
|
||||
int64_t id = w->alloc_id_predictable();
|
||||
AnimStep step;
|
||||
step.configure(kp, tan->anim_queue_.back());
|
||||
kp.check_unparsed_keywords();
|
||||
kp.final_check_throw();
|
||||
if (step.action() == "") {
|
||||
luaL_error(L, "animation action must be specified");
|
||||
}
|
||||
@@ -152,7 +152,7 @@ LuaDefine(tangible_build, "config",
|
||||
// Parse the initial animation step.
|
||||
AnimStep initstep, blank;
|
||||
initstep.configure(kp, blank);
|
||||
kp.check_unparsed_keywords();
|
||||
kp.final_check_throw();
|
||||
if (!initstep.has_xyz()) {
|
||||
luaL_error(L, "You must specify (X,Y,Z) for new tangible");
|
||||
}
|
||||
@@ -368,7 +368,7 @@ LuaDefine(tangible_find, "config",
|
||||
LuaKeywordParser kw(LS, config);
|
||||
PlaneScan scan;
|
||||
scan.configure(kw);
|
||||
kw.check_unparsed_keywords();
|
||||
kw.final_check_throw();
|
||||
|
||||
// When the configure routine sees the 'near' flag, it stores the tangible
|
||||
// ID, but not the center and plane, because doing so would require it to
|
||||
@@ -761,12 +761,14 @@ int lfn_http_request(lua_State *L, const char *method) {
|
||||
LuaArg request;
|
||||
LuaRet response;
|
||||
LuaStack LS(L, request, response);
|
||||
LuaKeywordParser kp(LS, request);
|
||||
HttpClientRequest req;
|
||||
|
||||
// Parse the request and make sure it's valid.
|
||||
// If not, immediately pass a '400 bad request' back to lua.
|
||||
req.set_method(method);
|
||||
req.set_config(LS, request);
|
||||
req.configure(kp);
|
||||
kp.final_check_throw();
|
||||
req.set_defaults();
|
||||
eng::string error = req.check();
|
||||
if (!error.empty()) {
|
||||
|
||||
@@ -533,10 +533,13 @@ HttpServerResponse World::http_serve(const HttpParser &request) {
|
||||
}
|
||||
|
||||
// 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));
|
||||
LuaKeywordParser kp(LS, LuaSpecial(newtop));
|
||||
response.configure(kp);
|
||||
response.set_defaults();
|
||||
eng::string kperr = kp.final_check();
|
||||
if (!kperr.empty()) {
|
||||
response.fail(500, kperr);
|
||||
}
|
||||
LS.result();
|
||||
return response;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user