Problem writing a native HTTP server package
MagnificentPako opened this issue ยท comments
Because my native implementation wasn't yielding the results and consistency I need for my next project I tried to write a small package adding bindings for a C++ library. For some reason, it seems to mess up the arguments (namely host
and port
) leading to ``hostbeing completely empty and
port` being a random number.
Do you have any idea what I'm doing wrong?
https://github.com/MagnificentPako/emojicode/blob/emojicode-0.5/DefaultPackages/http/http.cpp
The code I tested it with is here:
https://github.com/MagnificentPako/emojicode/blob/emojicode-0.5/tests/http/simple.emojic
Here's what Valgrind told me:
https://gist.github.com/MagnificentPako/c18e5b8360e5392eeed5a5194828abe4
๐ ๐ host๐ก port๐ ๐ป 1
๐ ๐ ๐ป 2
You declared the initializer to take parameters, not serverRun
. By accessing variable(0)
etc. you're causing undefined behavior, thus a "random number".
Then you seem not to be initializing the Server
object. Unless the Server instance does not need to be initialized you should do something like
new (thread->thisObject()->val<Server>()) Server;
in the initializer.
Ohh, thanks for spotting that! I was searching for the problem everywhere but my header file.
However it seems like initializing the Server
in the initializer isn't enough; I'm still getting this
https://gist.github.com/MagnificentPako/e2750c6e0d19013b83f78eca6e5fbba8
Guess I'll actually have to learn C++ now ๐
I canโt really try it myself right now, but some suggestions:
- Try
*thread->thisObject()->val<Server>() = Server();
instead of thenew...
- Check that
prepareClass
is actually called for your class.
Thanks! I'm not entirely sure what I changed but now it seems to work!
This leads me to another problem though: I'm trying to use callables.
Do you have any idea how I can make the callable output to str
, then use the string in C++?
void serverRun(Emojicode::Thread *thread) {
const char *host = Emojicode::stringToCString(thread->variable(0).object);
Emojicode::EmojicodeInteger port = thread->variable(1).raw;
auto callable = thread->variable(2).object;
std::cout << host << "\n";
std::cout << port << "\n";
thread->thisObject()->val<Server>()->get(R"(.+)", [&](const Request& req, Response& res) {
Emojicode::Object* str = Emojicode::stringPool[0];
auto a = Emojicode::stringFromChar(req.path.c_str());
auto c = Emojicode::Value(a);
Emojicode::executeCallableExtern(callable,
&c,
sizeof(Emojicode::stringFromChar(req.path.c_str())),
thread,
str->val<Emojicode::String>()); // <--- THIS
res.set_content(Emojicode::stringToCString(str), "text/plain");
});
thread->thisObject()->val<Server>()->listen(host, port);
}
auto a = Emojicode::stringFromChar(req.path.c_str());
auto c = Emojicode::Value(a);
Value str;
Emojicode::executeCallableExtern(callable,
&c,
sizeof(Emojicode::stringFromChar(req.path.c_str())),
thread,
&str); // <--- THIS
res.set_content(Emojicode::stringToCString(str.object), "text/plain");
should work.
That said, have you read this?
stringFromChar
as well as stringToCString
are potentially garbage collector invoking. stringFromChar
allocates memory, if this allocation causes a GC cycle, callable
is no longer a valid pointer. You're code is relying on undefined behavior as of now.
Registering callables as callback with this get
method could get really complicated, as you somehow need to store the callable in a way that you can bring to the garbage collectors attention. One possible solution that pops into my head now: Let the objects of your class not store a Server
directly, but a wrapper structure (e.g. ServerWrapper
). Make ServerWrapper also store an array of callables and capture the index at which the callable was stored in the closure passed to get
. This list can be marked by the garbage collector by providing a custom mark function.
One last thing, you should probably deinitialize the Server instance before it is deallocated: http://www.emojicode.org/docs/guides/packageAPI.html#deinitialization
(I know it's complicated, but everything is getting better when 0.6 is released one day...)