Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ListTalk/classes/Thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ LT__BEGIN_DECLS

LT_DECLARE_CLASS(LT_Thread);

typedef LT_Value (*LT_Thread_Callback)(void* context);

LT_Thread* LT_Thread_basicNew(LT_Thread_Callback callback,
void* context,
char* name);
LT_Thread* LT_Thread_new(LT_Value callable, char* name);
LT_Thread* LT_Thread_current(void);

Expand Down
75 changes: 75 additions & 0 deletions ListTalk/networking/HTTP.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/* SPDX-License-Identifier: MIT */
#ifndef H__ListTalk__networking__HTTP__
#define H__ListTalk__networking__HTTP__

#include <ListTalk/classes/Dictionary.h>
#include <ListTalk/classes/String.h>
#include <ListTalk/networking/Socket.h>

LT__BEGIN_DECLS

LT_DECLARE_CLASS(LT_HTTPRequest);
LT_DECLARE_CLASS(LT_HTTPResponse);
LT_DECLARE_CLASS(LT_HTTPStreamingResponse);
LT_DECLARE_CLASS(LT_HTTPServer);

/* Header names are stored in lower case, making lookup case insensitive. */
LT_String* LT_HTTP_header_name(const char* bytes, size_t length);
int LT_HTTP_parse_header(LT_Dictionary* headers,
const uint8_t* bytes,
size_t length);

LT_HTTPRequest* LT_HTTPRequest_read(LT_TCPSocket* socket);
LT_String* LT_HTTPRequest_method(LT_HTTPRequest* request);
LT_String* LT_HTTPRequest_target(LT_HTTPRequest* request);
LT_String* LT_HTTPRequest_version(LT_HTTPRequest* request);
LT_ImmutableDictionary* LT_HTTPRequest_headers(LT_HTTPRequest* request);
LT_Value LT_HTTPRequest_header(LT_HTTPRequest* request, LT_String* name);
LT_ByteVector* LT_HTTPRequest_read_body(LT_HTTPRequest* request);
void LT_HTTPRequest_respond(LT_HTTPRequest* request,
unsigned status,
LT_Dictionary* headers,
const void* body,
size_t body_length);
void LT_HTTPRequest_respond_with(LT_HTTPRequest* request, LT_Value result);
void LT_HTTPRequest_close(LT_HTTPRequest* request);

LT_HTTPResponse* LT_HTTPResponse_new(unsigned status,
LT_Dictionary* headers,
LT_Value body);
unsigned LT_HTTPResponse_status(LT_HTTPResponse* response);
LT_ImmutableDictionary* LT_HTTPResponse_headers(LT_HTTPResponse* response);
LT_Value LT_HTTPResponse_body(LT_HTTPResponse* response);

void LT_HTTPStreamingResponse_set_status(LT_HTTPStreamingResponse* response,
unsigned status);
void LT_HTTPStreamingResponse_set_content_type(
LT_HTTPStreamingResponse* response,
LT_String* content_type
);
void LT_HTTPStreamingResponse_header_at_put(
LT_HTTPStreamingResponse* response,
LT_String* name,
LT_String* value
);
void LT_HTTPStreamingResponse_write(LT_HTTPStreamingResponse* response,
LT_Value data);
void LT_HTTPStreamingResponse_send_data(LT_HTTPStreamingResponse* response,
LT_Value data);
void LT_HTTPStreamingResponse_send_event_data(
LT_HTTPStreamingResponse* response,
LT_String* event,
LT_Value data
);
void LT_HTTPStreamingResponse_send_event_with_fields(
LT_HTTPStreamingResponse* response,
LT_Value fields
);

LT_HTTPServer* LT_HTTPServer_new(const char* host, uint16_t port, int backlog);
LT_HTTPRequest* LT_HTTPServer_accept(LT_HTTPServer* server);
LT_Value LT_HTTPServer_handle(LT_HTTPServer* server, LT_Value handler);
void LT_HTTPServer_close(LT_HTTPServer* server);

LT__END_DECLS
#endif
22 changes: 22 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ networking_lib = library(
[
'src/networking/Socket.c',
'src/networking/IPSocket.c',
'src/networking/HTTP.c',
'src/networking/SocketBuffer.c',
'src/networking/UnixSocket.c',
],
Expand Down Expand Up @@ -359,6 +360,17 @@ socket_module = shared_module(
install_dir : listtalk_native_module_dir
)

httpd_module = shared_module(
'httpd',
'src/modules/httpd.c',
name_prefix : '',
name_suffix : 'ltm',
link_with : [vm_lib, networking_lib],
dependencies : listtalk_deps,
install : true,
install_dir : listtalk_native_module_dir
)

if md4c_dep.found() and md4c_html_dep.found()
markdown_config = configuration_data()
markdown_config.set10(
Expand Down Expand Up @@ -595,6 +607,16 @@ test(
depends : [socket_module]
)

test(
'eval_httpd',
listtalk_exe,
args : [
'-L', meson.current_build_dir(),
meson.current_source_dir() / 'tests' / 'eval-httpd.lt'
],
depends : [httpd_module]
)

if md4c_dep.found() and md4c_html_dep.found()
test(
'eval_markdown',
Expand Down
44 changes: 39 additions & 5 deletions src/classes/Thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ struct LT_Thread_s {
LT_MutexWord state_lock;
LT_CondWord state_cond;
LT_ThreadState* thread_state;
LT_Value callable;
LT_Thread_Callback callback;
void* context;
LT_Value result;
char* name;
bool finished : 1;
Expand Down Expand Up @@ -307,7 +308,7 @@ static void* thread_main(void* opaque){

state->current_thread = thread;
set_current_native_thread_name(thread->name);
result = LT_apply(thread->callable, LT_NIL, LT_NIL, LT_NIL, NULL);
result = thread->callback(thread->context);

LT_MutexWord_lock(&thread->state_lock);
thread->result = result;
Expand All @@ -318,14 +319,20 @@ static void* thread_main(void* opaque){
return NULL;
}

LT_Thread* LT_Thread_new(LT_Value callable, char* name){
LT_Thread* LT_Thread_basicNew(LT_Thread_Callback callback,
void* context,
char* name){
LT_Thread* thread = LT_Class_ALLOC(LT_Thread);
int errnum;

if (callback == NULL){
LT_error("Thread callback must not be NULL");
}
LT_MutexWord_init(&thread->state_lock);
LT_CondWord_init(&thread->state_cond);
thread->thread_state = NULL;
thread->callable = callable;
thread->callback = callback;
thread->context = context;
thread->result = LT_NIL;
thread->name = name != NULL ? LT_strdup(name) : NULL;
thread->finished = 0;
Expand All @@ -342,6 +349,32 @@ LT_Thread* LT_Thread_new(LT_Value callable, char* name){
return thread;
}

struct ThreadCallableContext {
LT_Value callable;
};

static LT_Value apply_thread_callable(void* opaque){
struct ThreadCallableContext* context = opaque;

return LT_apply(
context->callable,
LT_NIL, LT_NIL, LT_NIL, NULL
);
}

LT_Thread* LT_Thread_new(LT_Value callable, char* name){
struct ThreadCallableContext* context = GC_NEW(
struct ThreadCallableContext
);

context->callable = callable;
return LT_Thread_basicNew(
apply_thread_callable,
context,
name
);
}


LT_Thread* LT_Thread_current(void){
LT_ThreadState* state = LT_thread_state();
Expand All @@ -352,7 +385,8 @@ LT_Thread* LT_Thread_current(void){
LT_MutexWord_init(&state->current_thread->state_lock);
LT_CondWord_init(&state->current_thread->state_cond);
state->current_thread->thread_state = state;
state->current_thread->callable = LT_NIL;
state->current_thread->callback = NULL;
state->current_thread->context = NULL;
state->current_thread->result = LT_NIL;
state->current_thread->name = NULL;
state->current_thread->finished = 1;
Expand Down
21 changes: 21 additions & 0 deletions src/modules/httpd.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* SPDX-License-Identifier: MIT */
#include <ListTalk/ListTalk.h>
#include <ListTalk/networking/HTTP.h>

void ListTalk_httpd_load(LT_Environment* environment){
LT_Package* package = LT_Package_new("ListTalk:HTTPD");

#define BIND_CLASS(name, class_name) \
LT_Environment_bind( \
environment, \
LT_Symbol_new_in(package, name), \
LT_STATIC_CLASS(class_name), \
LT_ENV_BINDING_FLAG_CONSTANT \
)
BIND_CLASS("Server", LT_HTTPServer);
BIND_CLASS("Request", LT_HTTPRequest);
BIND_CLASS("Response", LT_HTTPResponse);
BIND_CLASS("StreamingResponse", LT_HTTPStreamingResponse);
#undef BIND_CLASS
LT_loader_provide(environment, "httpd");
}
Loading