Air quality sensor
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

216 lines
7.3 KiB

//
// 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 <sys/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
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);
/**
* 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