Skip to content

Instantly share code, notes, and snippets.

@jkent
Created March 26, 2021 21:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jkent/c937e9e371afe5d1b5b300433379779b to your computer and use it in GitHub Desktop.
Save jkent/c937e9e371afe5d1b5b300433379779b to your computer and use it in GitHub Desktop.
modhttp.c
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Copyright 2021 Jeff Kent <jeff@jkent.net> */
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
#include "py/runtime.h"
#include "libesphttpd/httpd.h"
#include "libesphttpd/port.h"
/****************
* Object Types
****************/
STATIC const mp_obj_type_t mp_server_type;
STATIC const mp_obj_type_t mp_routes_type;
STATIC const mp_obj_type_t mp_route_handler_type;
STATIC const mp_obj_type_t mp_route_type;
STATIC const mp_obj_type_t mp_c_fun_type;
STATIC const mp_obj_type_t mp_conn_type;
typedef struct _mp_obj_server_t {
mp_obj_base_t base;
ehttpd_inst_t *inst;
mp_obj_t *routes;
} mp_obj_server_t;
typedef struct _mp_obj_routes_t {
mp_obj_base_t base;
ehttpd_inst_t *inst;
} mp_obj_routes_t;
typedef struct _mp_obj_routes_it_t {
mp_obj_base_t base;
mp_fun_1_t iternext;
ehttpd_route_t *route;
} mp_obj_routes_it_t;
typedef struct _mp_obj_route_t {
mp_obj_base_t base;
ehttpd_route_t *route;
} mp_obj_route_t;
typedef struct _mp_c_func_obj_t {
mp_obj_base_t base;
void *p;
} mp_c_func_obj_t;
typedef struct _mp_obj_conn_t {
mp_obj_base_t base;
ehttpd_conn_t *conn;
} mp_obj_conn_t;
typedef struct _mp_obj_handler_t {
mp_obj_base_t base;
mp_fun_2_t fun;
mp_obj_conn_t *conn;
mp_obj_dict_t *dict;
ehttpd_status_t status;
xSemaphoreHandle event;
} mp_obj_route_handler_t;
/**********
* Server
**********/
STATIC mp_obj_t mp_server_make_new(const mp_obj_type_t *type_in,
size_t n_args, size_t n_kw, const mp_obj_t *args)
{
#if defined(EHTTPD_TLS_MBEDTLS) || defined(EHTTPD_TLS_OPENSSL)
mp_arg_check_num(n_args, n_kw, 0, 3, true);
#else
mp_arg_check_num(n_args, n_kw, 0, 3, false);
#endif
mp_obj_server_t *self = m_new_obj_with_finaliser(mp_obj_server_t);
self->base.type = type_in;
self->inst = NULL;
const char *addr = "0.0.0.0:80";
size_t conn_max = 2;
ehttpd_flags_t flags = EHTTPD_FLAG_NONE;
if (n_args > 0) {
if (mp_obj_is_true(args[0])) {
flags |= EHTTPD_FLAG_TLS;
}
if (n_args > 1) {
addr = mp_obj_str_get_str(args[1]);
if (n_args > 2) {
conn_max = mp_obj_get_int(args[2]);
}
}
}
self->inst = ehttpd_init(addr, NULL, conn_max, flags);
if (self->inst == NULL) {
mp_raise_msg(&mp_type_MemoryError,
MP_ERROR_TEXT("could not initialize http server"));
}
#if defined(EHTTPD_TLS_MBEDTLS) || defined(EHTTPD_TLS_OPENSSL)
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_cert, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_key, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
};
mp_arg_val_t kargs[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, args + 1, &kw_args,
MP_ARRAY_SIZE(allowed_args), allowed_args, kargs);
if (kargs[ARG_cert].u_obj != MP_OBJ_NULL &&
kargs[ARG_key].u_obj != MP_OBJ_NULL) {
size_t cert_len;
const char *cert_data = mp_obj_str_get_data(kargs[ARG_cert].u_obj,
&cert_len);
size_t key_len;
const char *key_data = mp_obj_str_get_data(kargs[ARG_key].u_obj,
&key_len);
ehttpd_set_cert_and_key(self->inst, cert_data, cert_len,
key_data, key_len);
}
#endif
if (!ehttpd_start(self->inst)) {
return mp_const_none;
}
mp_obj_t server = MP_OBJ_FROM_PTR(self);
self->routes = mp_routes_type.make_new(&mp_routes_type, 1, 0, &server);
self->inst->user = server;
return server;
}
STATIC void mp_server_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest)
{
mp_obj_server_t *self = MP_OBJ_TO_PTR(self_in);
if (dest[0] == MP_OBJ_NULL) {
/* load */
if (attr == MP_QSTR_routes) {
dest[0] = self->routes;
return;
}
const mp_obj_type_t *type = mp_obj_get_type(self);
mp_map_elem_t *elem = mp_map_lookup(&type->locals_dict->map,
MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
if (elem != NULL) {
mp_convert_member_lookup(self, type, elem->value, dest);
}
} else if (dest[0] == MP_OBJ_SENTINEL && dest[1] != MP_OBJ_NULL) {
/* store */
if (attr == MP_QSTR_routes) {
return;
}
mp_raise_msg(&mp_type_AttributeError,
MP_ERROR_TEXT("can't set attribute"));
} else {
/* delete */
mp_raise_msg(&mp_type_AttributeError,
MP_ERROR_TEXT("can't delete attribute"));
}
}
#if defined(EHTTPD_TLS_MBEDTLS) || defined(EHTTPD_TLS_OPENSSL)
STATIC mp_obj_t mp_server_set_client_validation(mp_obj_t self_in,
mp_obj_t enable)
{
mp_obj_server_t *self = MP_OBJ_TO_PTR(self_in);
ehttpd_set_client_validation(self->inst, mp_obj_is_true(enable));
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(mp_server_set_client_validation_obj,
mp_server_set_client_validation);
STATIC mp_obj_t mp_server_add_client_cert(mp_obj_t self_in, mp_obj_t cert)
{
mp_obj_server_t *self = MP_OBJ_TO_PTR(self_in);
size_t cert_len;
const char *cert_data = mp_obj_str_get_data(cert, &cert_len);
ehttpd_add_client_cert(self->inst, cert_data, cert_len);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(mp_server_add_client_cert_obj,
mp_server_add_client_cert);
#endif
STATIC mp_obj_t mp_server_shutdown(mp_obj_t self_in)
{
mp_obj_server_t *self = MP_OBJ_TO_PTR(self_in);
ehttpd_shutdown(self->inst);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_server_shutdown_obj,
mp_server_shutdown);
STATIC const mp_rom_map_elem_t mp_server_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_server_shutdown_obj) },
{ MP_ROM_QSTR(MP_QSTR_shutdown),
MP_ROM_PTR(&mp_server_shutdown_obj) },
#if defined(EHTTPD_TLS_MBEDTLS) || defined(EHTTPD_TLS_OPENSSL)
{ MP_ROM_QSTR(MP_QSTR_set_client_validation),
MP_ROM_PTR(&mp_server_set_client_validation_obj) },
{ MP_ROM_QSTR(MP_QSTR_add_client_cert),
MP_ROM_PTR(&mp_server_add_client_cert_obj) },
#endif
};
STATIC MP_DEFINE_CONST_DICT(mp_server_locals_dict,
mp_server_locals_dict_table);
STATIC const mp_obj_type_t mp_server_type = {
{ &mp_type_type },
.name = MP_QSTR_server,
.make_new = mp_server_make_new,
.attr = mp_server_attr,
.locals_dict = (mp_obj_t)&mp_server_locals_dict,
};
/**********
* Routes
**********/
STATIC ehttpd_status_t route_handler(ehttpd_conn_t *conn);
STATIC void mp_routes_print(const mp_print_t *print, mp_obj_t self_in,
mp_print_kind_t kind)
{
mp_obj_iter_buf_t iter_buf;
mp_obj_t item, iterable = mp_getiter(self_in, &iter_buf);
bool first = true;
mp_print_str(print, "[");
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
if (!first) {
mp_print_str(print, ", ");
}
first = false;
mp_obj_print_helper(print, item, kind);
}
mp_print_str(print, "]");
}
STATIC mp_obj_t mp_routes_make_new(const mp_obj_type_t *type_in,
size_t n_args, size_t n_kw, const mp_obj_t *args)
{
mp_arg_check_num(n_args, n_kw, 1, 1, false);
mp_obj_server_t *server = MP_OBJ_TO_PTR(args[0]);
mp_obj_routes_t *self = m_new_obj_with_finaliser(mp_obj_routes_t);
self->base.type = type_in;
self->inst = server->inst;
return MP_OBJ_FROM_PTR(self);
}
STATIC mp_obj_t mp_routes_unary_op(mp_unary_op_t op, mp_obj_t self_in)
{
mp_obj_routes_t *self = MP_OBJ_TO_PTR(self_in);
switch (op) {
case MP_UNARY_OP_BOOL:
return mp_obj_new_bool(self->inst->route_head != NULL);
case MP_UNARY_OP_LEN: {
int count = 0;
mp_obj_iter_buf_t iter_buf;
mp_obj_t item, iterable = mp_getiter(self, &iter_buf);
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
count++;
}
return MP_OBJ_NEW_SMALL_INT(count);
}
default:
return MP_OBJ_NULL;
}
}
STATIC mp_obj_t mp_routes_iternext(mp_obj_t self_in) {
mp_obj_routes_it_t *self = MP_OBJ_TO_PTR(self_in);
if (self->route == NULL) {
return MP_OBJ_STOP_ITERATION;
}
mp_obj_route_t *obj = mp_route_type.make_new(&mp_route_type, 1, 0,
&self_in);
self->route = self->route->next;
return obj;
}
STATIC mp_obj_t mp_routes_getiter(mp_obj_t self_in,
mp_obj_iter_buf_t *iter_buf)
{
mp_obj_routes_t *self = MP_OBJ_TO_PTR(self_in);
mp_obj_routes_it_t *iter = (mp_obj_routes_it_t*)iter_buf;
iter->base.type = &mp_type_polymorph_iter;
iter->iternext = mp_routes_iternext;
iter->route = self->inst->route_head;
return MP_OBJ_FROM_PTR(iter);
}
STATIC mp_obj_t mp_routes_insert_head(mp_obj_t self_in, mp_obj_t path_in,
mp_obj_t fun_in)
{
mp_obj_routes_t *self = MP_OBJ_TO_PTR(self_in);
const char *path = mp_obj_str_get_str(path_in);
ehttpd_route_t *route = ehttpd_route_insert_head(self->inst, path);
route->handler = route_handler;
route->arg = fun_in;
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_3(mp_routes_insert_head_obj,
mp_routes_insert_head);
STATIC mp_obj_t mp_routes_insert_tail(mp_obj_t self_in, mp_obj_t path_in,
mp_obj_t fun_in)
{
mp_obj_routes_t *self = MP_OBJ_TO_PTR(self_in);
const char *path = mp_obj_str_get_str(path_in);
ehttpd_route_t *route = ehttpd_route_insert_tail(self->inst, path);
route->handler = route_handler;
route->arg = fun_in;
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_3(mp_routes_insert_tail_obj,
mp_routes_insert_tail);
STATIC mp_obj_t mp_routes_insert_after(size_t n_args, const mp_obj_t *args)
{
mp_obj_routes_t *self = MP_OBJ_TO_PTR(args[0]);
const char *path = mp_obj_str_get_str(args[2]);
ehttpd_route_t *route = ehttpd_route_insert_after(self->inst, args[1],
path);
route->handler = route_handler;
route->arg = args[3];
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_routes_insert_after_obj, 4, 4,
mp_routes_insert_after);
STATIC mp_obj_t mp_routes_remove(mp_obj_t self_in, mp_obj_t route_in)
{
mp_obj_routes_t *self = MP_OBJ_TO_PTR(self_in);
ehttpd_route_remove(self->inst, route_in);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(mp_routes_remove_obj, mp_routes_remove);
STATIC mp_obj_t mp_routes_remove_head(mp_obj_t self_in)
{
mp_obj_routes_t *self = MP_OBJ_TO_PTR(self_in);
ehttpd_route_remove_head(self->inst);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_routes_remove_head_obj, mp_routes_remove_head);
STATIC const mp_rom_map_elem_t mp_routes_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_insert_head),
MP_ROM_PTR(&mp_routes_insert_head_obj) },
{ MP_ROM_QSTR(MP_QSTR_insert_tail),
MP_ROM_PTR(&mp_routes_insert_tail_obj) },
{ MP_ROM_QSTR(MP_QSTR_insert_after),
MP_ROM_PTR(&mp_routes_insert_after_obj) },
{ MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_routes_remove_obj) },
{ MP_ROM_QSTR(MP_QSTR_remove_head),
MP_ROM_PTR(&mp_routes_remove_head_obj) },
};
STATIC MP_DEFINE_CONST_DICT(mp_routes_locals_dict,
mp_routes_locals_dict_table);
STATIC const mp_obj_type_t mp_routes_type = {
{ &mp_type_type },
.name = MP_QSTR_routes,
.print = mp_routes_print,
.make_new = mp_routes_make_new,
.unary_op = mp_routes_unary_op,
.getiter = mp_routes_getiter,
.locals_dict = (mp_obj_t)&mp_routes_locals_dict,
};
/*********
* Route
*********/
STATIC void mp_route_print(const mp_print_t *print, mp_obj_t self_in,
mp_print_kind_t kind)
{
mp_obj_route_t *self = MP_OBJ_TO_PTR(self_in);
if (MICROPY_PY_UJSON && kind == PRINT_JSON) {
mp_print_str(print, "['");
} else {
mp_print_str(print, "('");
kind = PRINT_REPR;
}
mp_print_str(print, self->route->path);
mp_print_str(print, "', ");
if (self->route->handler == route_handler) {
mp_obj_print_helper(print, self->route->arg, kind);
} else {
mp_obj_t obj =
mp_obj_new_int_from_uint((uintptr_t)self->route->handler);
mp_obj_t handler = mp_c_fun_type.make_new(&mp_c_fun_type,
1, 0, &obj);
mp_obj_print_helper(print, handler, kind);
}
if (MICROPY_PY_UJSON && kind == PRINT_JSON) {
mp_print_str(print, "]");
} else {
mp_print_str(print, ")");
}
}
STATIC mp_obj_t mp_route_make_new(const mp_obj_type_t *type_in,
size_t n_args, size_t n_kw, const mp_obj_t *args)
{
mp_arg_check_num(n_args, n_kw, 1, 1, false);
mp_obj_routes_it_t *it = MP_OBJ_TO_PTR(args[0]);
mp_obj_route_t *self = m_new_obj_with_finaliser(mp_obj_route_t);
self->base.type = type_in;
self->route = it->route;
return MP_OBJ_FROM_PTR(self);
}
STATIC const mp_obj_type_t mp_route_type = {
{ &mp_type_type },
.name = MP_QSTR_route,
.print = mp_route_print,
.make_new = mp_route_make_new,
};
/**************
* C Function
**************/
STATIC void mp_c_func_print(const mp_print_t *print, mp_obj_t self_in,
mp_print_kind_t kind)
{
(void)kind;
mp_c_func_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "<c function at %p>", self->p);
}
STATIC mp_obj_t mp_c_func_make_new(const mp_obj_type_t *type_in,
size_t n_args, size_t n_kw, const mp_obj_t *args)
{
mp_arg_check_num(n_args, n_kw, 1, 1, false);
mp_c_func_obj_t *self = m_new_obj_with_finaliser(mp_c_func_obj_t);
self->base.type = type_in;
self->p = (void *)mp_obj_int_get_uint_checked(args[0]);
return MP_OBJ_FROM_PTR(self);
}
STATIC const mp_obj_type_t mp_c_fun_type = {
{ &mp_type_type },
.name = MP_QSTR_c_function,
.print = mp_c_func_print,
.make_new = mp_c_func_make_new,
};
/**************
* Connection
**************/
STATIC mp_obj_t mp_conn_get_header(mp_obj_t self_in, mp_obj_t name_in)
{
mp_obj_conn_t *self = MP_OBJ_TO_PTR(self_in);
const char *key = mp_obj_str_get_str(name_in);
const char *value = ehttpd_get_header(self->conn, key);
if (value == NULL) {
return mp_const_none;
}
return mp_obj_new_str(value, strlen(value));
}
MP_DEFINE_CONST_FUN_OBJ_2(mp_conn_get_header_obj, mp_conn_get_header);
STATIC mp_obj_t mp_conn_set_chunked(mp_obj_t self_in, mp_obj_t enable_in)
{
mp_obj_conn_t *self = MP_OBJ_TO_PTR(self_in);
ehttpd_set_chunked_encoding(self->conn, mp_obj_is_true(enable_in));
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(mp_conn_set_chunked_obj, mp_conn_set_chunked);
STATIC mp_obj_t mp_conn_set_close(mp_obj_t self_in, mp_obj_t close_in)
{
mp_obj_conn_t *self = MP_OBJ_TO_PTR(self_in);
ehttpd_set_close(self->conn, mp_obj_is_true(close_in));
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(mp_conn_set_close_obj, mp_conn_set_close);
STATIC mp_obj_t mp_conn_start_response(mp_obj_t self_in, mp_obj_t code_in)
{
mp_obj_conn_t *self = MP_OBJ_TO_PTR(self_in);
mp_uint_t code = mp_obj_get_int(code_in);
ehttpd_start_response(self->conn, code);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(mp_conn_start_response_obj, mp_conn_start_response);
STATIC mp_obj_t mp_conn_enqueue_header(mp_obj_t self_in, mp_obj_t name_in,
mp_obj_t value_in)
{
mp_obj_conn_t *self = MP_OBJ_TO_PTR(self_in);
const char *name = mp_obj_str_get_str(name_in);
const char *value = mp_obj_str_get_str(value_in);
ehttpd_header(self->conn, name, value);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_3(mp_conn_enqueue_header_obj, mp_conn_enqueue_header);
STATIC mp_obj_t mp_conn_end_headers(mp_obj_t self_in)
{
mp_obj_conn_t *self = MP_OBJ_TO_PTR(self_in);
ehttpd_end_headers(self->conn);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_conn_end_headers_obj, mp_conn_end_headers);
STATIC mp_obj_t mp_conn_enqueue_cache_headers(mp_obj_t self_in,
mp_obj_t mime_in)
{
mp_obj_conn_t *self = MP_OBJ_TO_PTR(self_in);
const char *mime = mp_obj_str_get_str(mime_in);
ehttpd_add_cache_header(self->conn, mime);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(mp_conn_enqueue_cache_headers_obj,
mp_conn_enqueue_cache_headers);
STATIC mp_obj_t mp_conn_prepare(mp_obj_t self_in, mp_obj_t buf_in)
{
mp_obj_conn_t *self = MP_OBJ_TO_PTR(self_in);
size_t len;
const char *buf = mp_obj_str_get_data(buf_in, &len);
ssize_t ret = ehttpd_prepare(self->conn, (void **)&buf, len);
if (ret < 0) {
return mp_const_none;
}
return mp_obj_new_int_from_uint(ret);
}
MP_DEFINE_CONST_FUN_OBJ_2(mp_conn_prepare_obj, mp_conn_prepare);
STATIC mp_obj_t mp_conn_enqueue(mp_obj_t self_in, mp_obj_t buf_in)
{
mp_obj_conn_t *self = MP_OBJ_TO_PTR(self_in);
size_t len;
const char *buf = mp_obj_str_get_data(buf_in, &len);
return mp_obj_new_bool(ehttpd_enqueue(self->conn, buf, len));
}
MP_DEFINE_CONST_FUN_OBJ_2(mp_conn_enqueue_obj, mp_conn_enqueue);
STATIC mp_obj_t mp_conn_flush(mp_obj_t self_in)
{
mp_obj_conn_t *self = MP_OBJ_TO_PTR(self_in);
ehttpd_flush(self->conn);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_conn_flush_obj, mp_conn_flush);
STATIC mp_obj_t mp_conn_is_ssl(mp_obj_t self_in)
{
mp_obj_conn_t *self = MP_OBJ_TO_PTR(self_in);
return mp_obj_new_bool(ehttpd_is_ssl(self->conn));
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_conn_is_ssl_obj, mp_conn_is_ssl);
STATIC mp_obj_t mp_conn_send(mp_obj_t self_in, mp_obj_t buf_in)
{
mp_obj_conn_t *self = MP_OBJ_TO_PTR(self_in);
size_t len;
const char *buf = mp_obj_str_get_data(buf_in, &len);
ssize_t ret = ehttpd_send(self->conn, (void *)buf, len);
if (ret < 0) {
return mp_const_none;
}
return mp_obj_new_int_from_uint(ret);
}
MP_DEFINE_CONST_FUN_OBJ_2(mp_conn_send_obj, mp_conn_send);
STATIC mp_obj_t mp_conn_disconnect(mp_obj_t self_in)
{
mp_obj_conn_t *self = MP_OBJ_TO_PTR(self_in);
mp_conn_disconnect(self->conn);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_conn_disconnect_obj, mp_conn_disconnect);
STATIC const mp_rom_map_elem_t mp_conn_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_get_header), MP_ROM_PTR(&mp_conn_get_header) },
{ MP_ROM_QSTR(MP_QSTR_set_chunked),
MP_ROM_PTR(&mp_conn_set_chunked) },
{ MP_ROM_QSTR(MP_QSTR_set_close), MP_ROM_PTR(&mp_conn_set_close) },
{ MP_ROM_QSTR(MP_QSTR_start_response),
MP_ROM_PTR(&mp_conn_start_response) },
{ MP_ROM_QSTR(MP_QSTR_enqueue_header),
MP_ROM_PTR(&mp_conn_enqueue_header) },
{ MP_ROM_QSTR(MP_QSTR_end_headers), MP_ROM_PTR(&mp_conn_end_headers) },
{ MP_ROM_QSTR(MP_QSTR_enqueue_cache_headers),
MP_ROM_PTR(&mp_conn_enqueue_cache_headers) },
{ MP_ROM_QSTR(MP_QSTR_prepare), MP_ROM_PTR(&mp_conn_prepare) },
{ MP_ROM_QSTR(MP_QSTR_enqueue), MP_ROM_PTR(&mp_conn_enqueue) },
{ MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_conn_flush) },
{ MP_ROM_QSTR(MP_QSTR_is_ssl), MP_ROM_PTR(&mp_conn_is_ssl) },
{ MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&mp_conn_send) },
{ MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&mp_conn_disconnect) },
};
STATIC MP_DEFINE_CONST_DICT(mp_conn_locals_dict,
mp_conn_locals_dict_table);
STATIC const mp_obj_type_t mp_conn_type = {
{ &mp_type_type },
.name = MP_QSTR_conn,
.locals_dict = (mp_obj_t)&mp_conn_locals_dict,
};
/*****************
* Route Handler
*****************/
STATIC mp_obj_t mp_route_handler(mp_obj_t arg)
{
mp_obj_route_handler_t *handler = MP_OBJ_TO_PTR(arg);
mp_obj_t status_obj = mp_call_function_1_protected(handler->fun,
handler->conn);//, MP_OBJ_FROM_PTR(handler->dict));
handler->status = mp_obj_get_int(status_obj);
xSemaphoreGive(handler->event);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_route_handler_obj, mp_route_handler);
STATIC ehttpd_status_t route_handler(ehttpd_conn_t *conn)
{
mp_obj_route_handler_t *handler = conn->user;
if (handler == NULL) {
handler = m_new_obj(mp_obj_route_handler_t);
handler->base.type = &mp_route_handler_type;
vSemaphoreCreateBinary(handler->event);
xSemaphoreTake(handler->event, portMAX_DELAY);
handler->conn = m_new_obj(mp_obj_conn_t);
handler->conn->base.type = &mp_conn_type;
handler->conn->conn = conn;
handler->fun = conn->route->arg;
handler->dict = mp_obj_new_dict(0);
conn->user = handler;
} else {
mp_obj_dict_store(handler->dict, MP_OBJ_NEW_QSTR(MP_QSTR_more),
mp_const_true);
}
mp_sched_schedule((mp_obj_t)&mp_route_handler_obj, handler);
xSemaphoreTake(handler->event, portMAX_DELAY);
ehttpd_status_t status = handler->status;
if (status != EHTTPD_STATUS_MORE) {
vSemaphoreDelete(handler->event);
free(handler);
}
return status;
}
STATIC const mp_obj_type_t mp_route_handler_type = {
{ &mp_type_type },
.name = MP_QSTR_handler,
};
/***********
* Globals
***********/
STATIC const mp_rom_map_elem_t mp_module_httpd_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_http) },
{ MP_ROM_QSTR(MP_QSTR_server), MP_ROM_PTR(&mp_server_type) },
/* http methods */
{ MP_ROM_QSTR(MP_QSTR_METHOD_DELETE), MP_ROM_INT(EHTTPD_METHOD_DELETE) },
{ MP_ROM_QSTR(MP_QSTR_METHOD_GET), MP_ROM_INT(EHTTPD_METHOD_GET) },
{ MP_ROM_QSTR(MP_QSTR_METHOD_OPTIONS), MP_ROM_INT(EHTTPD_METHOD_OPTIONS) },
{ MP_ROM_QSTR(MP_QSTR_METHOD_PATCH), MP_ROM_INT(EHTTPD_METHOD_PATCH) },
{ MP_ROM_QSTR(MP_QSTR_METHOD_POST), MP_ROM_INT(EHTTPD_METHOD_POST) },
{ MP_ROM_QSTR(MP_QSTR_METHOD_PUT), MP_ROM_INT(EHTTPD_METHOD_PUT) },
/* handler return codes */
{ MP_ROM_QSTR(MP_QSTR_STATUS_AUTHENTICATED), MP_ROM_INT(EHTTPD_STATUS_AUTHENTICATED) },
{ MP_ROM_QSTR(MP_QSTR_STATUS_DONE), MP_ROM_INT(EHTTPD_STATUS_DONE) },
{ MP_ROM_QSTR(MP_QSTR_STATUS_FOUND), MP_ROM_INT(EHTTPD_STATUS_FOUND) },
{ MP_ROM_QSTR(MP_QSTR_STATUS_MORE), MP_ROM_INT(EHTTPD_STATUS_MORE) },
{ MP_ROM_QSTR(MP_QSTR_STATUS_NOTFOUND), MP_ROM_INT(EHTTPD_STATUS_NOTFOUND) },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_http_globals,
mp_module_httpd_globals_table);
const mp_obj_module_t mp_module_http = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&mp_module_http_globals,
};
MP_REGISTER_MODULE(MP_QSTR_http, mp_module_http, MODULE_HTTP_ENABLED);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment