Created
March 26, 2021 21:41
-
-
Save jkent/c937e9e371afe5d1b5b300433379779b to your computer and use it in GitHub Desktop.
modhttp.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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