add webserver components, some webserver fices and improvements in templating, add real time history chart
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// Created on 2018/10/17 by Ondrej Hruska <ondra@ondrovo.com>
|
||||
//
|
||||
|
||||
#ifndef FBNODE_EMBEDDED_FILES_H
|
||||
#define FBNODE_EMBEDDED_FILES_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <esp_err.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct embedded_file_info {
|
||||
const uint8_t * start;
|
||||
const uint8_t * end;
|
||||
const char * name;
|
||||
const char * mime;
|
||||
};
|
||||
|
||||
enum file_access_level {
|
||||
/** Public = file accessed by a wildcard route */
|
||||
FILE_ACCESS_PUBLIC = 0,
|
||||
/** Protected = file included in a template or explicitly specified in a route */
|
||||
FILE_ACCESS_PROTECTED = 1,
|
||||
/** Files protected against read-out */
|
||||
FILE_ACCESS_PRIVATE = 2,
|
||||
};
|
||||
|
||||
extern const struct embedded_file_info EMBEDDED_FILE_LOOKUP[];
|
||||
extern const size_t EMBEDDED_FILE_LOOKUP_LEN;
|
||||
|
||||
/**
|
||||
* Find an embedded file by its name.
|
||||
*
|
||||
* This function is weak. It crawls the EMBEDDED_FILE_LOOKUP table and checks for exact match, also
|
||||
* testing with www_get_static_file_access_check if the access is allowed.
|
||||
*
|
||||
* @param name - file name
|
||||
* @param access - access level (public - wildcard fallthrough, protected - files for the server, loaded explicitly)
|
||||
* @param[out] file - the file struct is stored here if found, unchanged if not found.
|
||||
* @return status code
|
||||
*/
|
||||
esp_err_t www_get_static_file(const char *name, enum file_access_level access, const struct embedded_file_info **file);
|
||||
|
||||
/**
|
||||
* Check file access permission (if using the default www_get_static_file implementation).
|
||||
*
|
||||
* This function is weak. The default implementation returns always true.
|
||||
*/
|
||||
bool www_get_static_file_access_check(const struct embedded_file_info *file, enum file_access_level access);
|
||||
|
||||
#endif //FBNODE_EMBEDDED_FILES_H
|
||||
@@ -0,0 +1,227 @@
|
||||
//
|
||||
// This module implements token substitution in files served by the server.
|
||||
//
|
||||
// Tokens are in the form {token}, or {escape:token}, where escape can be:
|
||||
// - h ... html escape (plain text in a html file, attribute value)
|
||||
// - j ... js escape (for use in JS strings)
|
||||
//
|
||||
// When no escape is specified, the token substitution is written verbatim into the response.
|
||||
//
|
||||
// var foo = "{j:foo}";
|
||||
// <input value="{h:old_value}">
|
||||
// {generated-html-goes-here}
|
||||
//
|
||||
// Token can be made optional by adding '?' at the end (this can't be used for includes).
|
||||
// Such token then simply becomes empty string when not substituted, as opposed to being included in the page verbatim.
|
||||
//
|
||||
// <input value="{h:old_value?}">
|
||||
//
|
||||
// token names can contain alnum, dash, period and underscore, and are case sensitive.
|
||||
//
|
||||
//
|
||||
// It is further possible to include a static file with optional key-value replacements. These serve as defaults.
|
||||
//
|
||||
// {@_subfile.html}
|
||||
// {@_subfile.html|key=value lalala}
|
||||
// {@_subfile.html|key=value lalala|other=value}
|
||||
//
|
||||
// File inclusion can be nested, and the files can use replacement tokens as specified by the include statement
|
||||
//
|
||||
// Created on 2019/01/24 by Ondrej Hruska <ondra@ondrovo.com>
|
||||
//
|
||||
|
||||
#ifndef FBNODE_TOKEN_SUBS_H
|
||||
#define FBNODE_TOKEN_SUBS_H
|
||||
|
||||
#include "embedded_files.h"
|
||||
#include <rom/queue.h>
|
||||
#include <esp_err.h>
|
||||
#include <esp_http_server.h>
|
||||
|
||||
/** Max length of a token buffer (must suffice for all included filenames) */
|
||||
#define MAX_TOKEN_LEN 32
|
||||
|
||||
/** Max length of a key-value substitution when using tpl_kv_replacer;
|
||||
* This is also used internally for in-line replacements in file imports. */
|
||||
#define TPL_KV_KEY_LEN 24
|
||||
/** Max length of a substituion in tpl_kv_replacer */
|
||||
#define TPL_KV_SUBST_LEN 64
|
||||
|
||||
/**
|
||||
* Escape type - argument for httpd_resp_send_chunk_escaped()
|
||||
*/
|
||||
typedef enum {
|
||||
TPL_ESCAPE_NONE = 0,
|
||||
TPL_ESCAPE_HTML,
|
||||
TPL_ESCAPE_JS,
|
||||
} tpl_escape_t;
|
||||
|
||||
enum {
|
||||
HTOPT_NONE = 0,
|
||||
HTOPT_NO_HEADERS = 1 << 0,
|
||||
HTOPT_NO_CLOSE = 1 << 1,
|
||||
HTOPT_INCLUDE = HTOPT_NO_HEADERS|HTOPT_NO_CLOSE,
|
||||
};
|
||||
|
||||
/**
|
||||
* Send string using a given escaping scheme
|
||||
*
|
||||
* @param r
|
||||
* @param buf - buf to send
|
||||
* @param len - buf len, or HTTPD_RESP_USE_STRLEN
|
||||
* @param escape - escaping type
|
||||
* @return success
|
||||
*/
|
||||
esp_err_t httpd_resp_send_chunk_escaped(httpd_req_t *r, const char *buf, ssize_t len, tpl_escape_t escape);
|
||||
|
||||
/**
|
||||
* Template substitution callback. Data shall be sent using httpd_resp_send_chunk_escaped().
|
||||
*
|
||||
* @param[in,out] context - user-defined page state data
|
||||
* @param[in] token - replacement token
|
||||
* @return ESP_OK if the token was substituted, ESP_ERR_NOT_FOUND if it is unknown, other errors on e.g. send failure
|
||||
*/
|
||||
typedef esp_err_t (*template_subst_t)(httpd_req_t *r, void *context, const char *token, tpl_escape_t escape);
|
||||
|
||||
/**
|
||||
* Send a template file as a response. The content type from the file struct will be used.
|
||||
*
|
||||
* Use HTOPT_INCLUDE when used to embed a file inside a template.
|
||||
*
|
||||
* @param r - request
|
||||
* @param file_index - file index in EMBEDDED_FILE_LOOKUP
|
||||
* @param replacer - substitution callback, can be NULL if only includes are to be processed
|
||||
* @param context - arbitrary context, will be passed to the replacer function; can be NULL
|
||||
* @param opts - flag options (HTOPT_*)
|
||||
*/
|
||||
esp_err_t httpd_send_template_file(httpd_req_t *r, int file_index, template_subst_t replacer, void *context, uint32_t opts);
|
||||
|
||||
/**
|
||||
* Same as httpd_send_template_file, but using an `embedded_file_info` struct.
|
||||
*/
|
||||
esp_err_t httpd_send_template_file_struct(httpd_req_t *r, const struct embedded_file_info *file, template_subst_t replacer, void *context, uint32_t opts);
|
||||
|
||||
/**
|
||||
* Process and send a string template.
|
||||
* The content-type header should be set beforehand, if different from the default (text/html).
|
||||
*
|
||||
* Use HTOPT_INCLUDE when used to embed a file inside a template.
|
||||
*
|
||||
* @param r - request
|
||||
* @param template - template string (does not have to be terminated by a null byte)
|
||||
* @param template_len - length of the template string; -1 to use strlen()
|
||||
* @param replacer - substitution callback, can be NULL if only includes are to be processed
|
||||
* @param context - arbitrary context, will be passed to the replacer function; can be NULL
|
||||
* @param opts - flag options (HTOPT_*)
|
||||
*/
|
||||
esp_err_t httpd_send_template(httpd_req_t *r, const char *template, ssize_t template_len, template_subst_t replacer, void *context, uint32_t opts);
|
||||
|
||||
/**
|
||||
* Send a static file. This can be used to just send a file, or to embed a static template as a token substitution.
|
||||
*
|
||||
* Use HTOPT_INCLUDE when used to embed a file inside a template.
|
||||
*
|
||||
* Note: use httpd_resp_send_chunk_escaped() or httpd_resp_send_chunk() to send a plain string.
|
||||
*
|
||||
* @param r - request
|
||||
* @param file_index - file index in EMBEDDED_FILE_LOOKUP
|
||||
* @param escape - escape option
|
||||
* @param opts - flag options (HTOPT_*)
|
||||
* @return
|
||||
*/
|
||||
esp_err_t httpd_send_static_file(httpd_req_t *r, int file_index, tpl_escape_t escape, uint32_t opts);
|
||||
|
||||
/**
|
||||
* Same as httpd_send_template_file, but using an `embedded_file_info` struct.
|
||||
*/
|
||||
esp_err_t httpd_send_static_file_struct(httpd_req_t *r, const struct embedded_file_info *file, tpl_escape_t escape, uint32_t opts);
|
||||
|
||||
struct tpl_kv_entry {
|
||||
char key[TPL_KV_KEY_LEN]; // copied here
|
||||
char subst[TPL_KV_SUBST_LEN]; // copied here
|
||||
char *subst_heap;
|
||||
SLIST_ENTRY(tpl_kv_entry) link;
|
||||
};
|
||||
|
||||
SLIST_HEAD(tpl_kv_list, tpl_kv_entry);
|
||||
|
||||
/**
|
||||
* key-value replacer that works with a dynamically allocated SLIST.
|
||||
*
|
||||
* @param r - request
|
||||
* @param context - context - must be a pointer to `struct tpl_kv_list`
|
||||
* @param token - token to replace
|
||||
* @param escape - escape option
|
||||
* @return OK/not found/other
|
||||
*/
|
||||
esp_err_t tpl_kv_replacer(httpd_req_t *r, void *context, const char *token, tpl_escape_t escape);
|
||||
|
||||
/**
|
||||
* Add a pair into the substitutions list
|
||||
*
|
||||
* @param head - list head
|
||||
* @param key - key, copied
|
||||
* @param subst - value, copied
|
||||
* @return success (fails if malloc failed)
|
||||
*/
|
||||
esp_err_t tpl_kv_add(struct tpl_kv_list *head, const char *key, const char *subst);
|
||||
|
||||
/**
|
||||
* Add a heap-allocated string to the replacer.
|
||||
*
|
||||
* @param head - list head
|
||||
* @param key - key, copied
|
||||
* @param subst - value, copied
|
||||
* @return success (fails if malloc failed)
|
||||
*/
|
||||
esp_err_t tpl_kv_add_heapstr(struct tpl_kv_list *head, const char *key, char *subst);
|
||||
|
||||
/**
|
||||
* Convenience function that converts an IP address to string and adds it as a substitution
|
||||
*
|
||||
* @param head - list head
|
||||
* @param key - key, copied
|
||||
* @param ip4h - host order ipv4 address
|
||||
* @return success
|
||||
*/
|
||||
esp_err_t tpl_kv_add_ipv4str(struct tpl_kv_list *head, const char *key, uint32_t ip4h);
|
||||
|
||||
/** add int as a substitution; key is copied */
|
||||
esp_err_t tpl_kv_add_int(struct tpl_kv_list *head, const char *key, int32_t num);
|
||||
|
||||
/** add long as a substitution; key is copied */
|
||||
esp_err_t tpl_kv_add_long(struct tpl_kv_list *head, const char *key, int64_t num);
|
||||
|
||||
/** add printf-formatted value; key is copied */
|
||||
esp_err_t tpl_kv_sprintf(struct tpl_kv_list *head, const char *key, const char *format, ...)
|
||||
__attribute__((format(printf,3,4)));
|
||||
|
||||
/**
|
||||
* Init a substitutions list (on the stack)
|
||||
*
|
||||
* @return the list
|
||||
*/
|
||||
static inline struct tpl_kv_list tpl_kv_init(void)
|
||||
{
|
||||
return (struct tpl_kv_list) {.slh_first = NULL};
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the list (head is left alone because it was allocated on the stack)
|
||||
* @param head
|
||||
*/
|
||||
void tpl_kv_free(struct tpl_kv_list *head);
|
||||
|
||||
/**
|
||||
* Send the map as an ASCII table separated by Record Separator (30) and Unit Separator (31).
|
||||
* Content type is set to application/octet-stream.
|
||||
*
|
||||
* key 31 value 30
|
||||
* key 31 value 30
|
||||
* key 31 value
|
||||
*
|
||||
* @param req
|
||||
*/
|
||||
esp_err_t tpl_kv_send_as_ascii_map(httpd_req_t *req, struct tpl_kv_list *head);
|
||||
|
||||
#endif //FBNODE_TOKEN_SUBS_H
|
||||
Reference in New Issue
Block a user