Use section linking to define httpd pages

This commit is contained in:
Jeremy Lakeman 2015-08-24 12:48:00 +09:30
parent dab244d92f
commit 84caf21969
9 changed files with 224 additions and 216 deletions

228
httpd.c
View File

@ -18,83 +18,44 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <sys/ioctl.h>
#include "serval.h"
#include "httpd.h"
#include "conf.h"
#include "overlay_address.h"
#include "overlay_interface.h"
#include "mem.h"
#include "net.h"
#include "server.h"
#include "conf.h"
#define RHIZOME_SERVER_MAX_LIVE_REQUESTS 32
static HTTP_HANDLER root_page;
static HTTP_HANDLER fav_icon_header;
static HTTP_HANDLER interface_page;
static HTTP_HANDLER neighbour_page;
static HTTP_HANDLER static_page;
HTTP_HANDLER restful_rhizome_bundlelist_json;
HTTP_HANDLER restful_rhizome_newsince;
HTTP_HANDLER restful_rhizome_insert;
HTTP_HANDLER restful_rhizome_append;
HTTP_HANDLER restful_rhizome_;
HTTP_HANDLER restful_meshms_;
HTTP_HANDLER restful_keyring_;
HTTP_HANDLER rhizome_status_page;
HTTP_HANDLER rhizome_file_page;
HTTP_HANDLER manifest_by_prefix_page;
HTTP_HANDLER rhizome_direct_import;
HTTP_HANDLER rhizome_direct_enquiry;
HTTP_HANDLER rhizome_direct_dispatch;
struct http_handler {
const char *path;
HTTP_HANDLER *parser;
};
struct http_handler paths[]={
{"/restful/rhizome/bundlelist.json", restful_rhizome_bundlelist_json},
{"/restful/rhizome/newsince/", restful_rhizome_newsince},
{"/restful/rhizome/insert", restful_rhizome_insert},
{"/restful/rhizome/append", restful_rhizome_append},
{"/restful/rhizome/", restful_rhizome_},
{"/restful/meshms/", restful_meshms_},
{"/restful/keyring/", restful_keyring_},
{"/rhizome/status", rhizome_status_page},
{"/rhizome/file/", rhizome_file_page},
{"/rhizome/import", rhizome_direct_import},
{"/rhizome/enquiry", rhizome_direct_enquiry},
{"/rhizome/manifestbyprefix/", manifest_by_prefix_page},
{"/rhizome/", rhizome_direct_dispatch},
{"/static/", static_page},
{"/interface/", interface_page},
{"/neighbour/", neighbour_page},
{"/favicon.ico", fav_icon_header},
{"/", root_page},
};
static int httpd_dispatch(struct http_request *hr)
{
httpd_request *r = (httpd_request *) hr;
INFOF("HTTP SERVER, %s %s", r->http.verb, r->http.path);
r->http.response.content_generator = NULL;
unsigned i;
for (i = 0; i < NELS(paths); ++i) {
const char *remainder;
if (str_startswith(r->http.path, paths[i].path, &remainder)){
int result = paths[i].parser(r, remainder);
if (result == -1 || (result >= 200 && result < 600))
return result;
if (result == 1)
return 0;
if (result)
return WHYF("dispatch function for %s returned invalid result %d", paths[i].path, result);
struct http_handler *handler, *parser=NULL;
const char *remainder=NULL;
size_t match_len=0;
for (handler = SECTION_START(httpd); handler < SECTION_END(httpd); ++handler) {
size_t path_len = strlen(handler->path);
if (parser && path_len < match_len)
continue;
const char *p;
if (str_startswith(r->http.path, handler->path, &p)){
match_len = path_len;
parser = handler;
remainder = p;
}
}
if (parser){
int result = parser->parser(r, remainder);
if (result == -1 || (result >= 200 && result < 600))
return result;
if (result == 1)
return 0;
if (result)
return WHYF("dispatch function for %s returned invalid result %d", parser->path, result);
}
return 404;
}
@ -544,142 +505,3 @@ int http_response_init_content_range(httpd_request *r, size_t resource_length)
}
return 0;
}
static int root_page(httpd_request *r, const char *remainder)
{
if (*remainder)
return 404;
if (r->http.verb != HTTP_VERB_GET)
return 405;
char temp[8192];
strbuf b = strbuf_local(temp, sizeof temp);
strbuf_sprintf(b, "<html><head><meta http-equiv=\"refresh\" content=\"5\" ></head><body>"
"<h1>Hello, I'm %s*</h1>",
alloca_tohex_sid_t_trunc(my_subscriber->sid, 16));
if (config.server.motd[0]) {
strbuf_puts(b, "<p>");
strbuf_html_escape(b, config.server.motd, strlen(config.server.motd));
strbuf_puts(b, "</p>");
}
strbuf_puts(b, "Interfaces;<br />");
int i;
for (i=0;i<OVERLAY_MAX_INTERFACES;i++){
if (overlay_interfaces[i].state==INTERFACE_STATE_UP)
strbuf_sprintf(b, "<a href=\"/interface/%d\">%d: %s, TX: %d, RX: %d</a><br />",
i, i, overlay_interfaces[i].name, overlay_interfaces[i].tx_count, overlay_interfaces[i].recv_count);
}
strbuf_puts(b, "Neighbours;<br />");
link_neighbour_short_status_html(b, "/neighbour");
if (is_rhizome_http_enabled()){
strbuf_puts(b, "<a href=\"/rhizome/status\">Rhizome Status</a><br />");
}
strbuf_puts(b, "</body></html>");
if (strbuf_overrun(b)) {
WHY("HTTP Root page buffer overrun");
return 500;
}
http_request_response_static(&r->http, 200, CONTENT_TYPE_HTML, temp, strbuf_len(b));
return 1;
}
static int fav_icon_header(httpd_request *r, const char *remainder)
{
if (*remainder)
return 404;
http_request_response_static(&r->http, 200, "image/vnd.microsoft.icon", (const char *)favicon_bytes, favicon_len);
return 1;
}
static int neighbour_page(httpd_request *r, const char *remainder)
{
if (r->http.verb != HTTP_VERB_GET)
return 405;
char buf[8*1024];
strbuf b = strbuf_local(buf, sizeof buf);
sid_t neighbour_sid;
if (str_to_sid_t(&neighbour_sid, remainder) == -1)
return 404;
struct subscriber *neighbour = find_subscriber(neighbour_sid.binary, sizeof(neighbour_sid.binary), 0);
if (!neighbour)
return 404;
strbuf_puts(b, "<html><head><meta http-equiv=\"refresh\" content=\"5\" ></head><body>");
link_neighbour_status_html(b, neighbour);
strbuf_puts(b, "</body></html>");
if (strbuf_overrun(b))
return -1;
http_request_response_static(&r->http, 200, CONTENT_TYPE_HTML, buf, strbuf_len(b));
return 1;
}
static int interface_page(httpd_request *r, const char *remainder)
{
if (r->http.verb != HTTP_VERB_GET)
return 405;
char buf[8*1024];
strbuf b=strbuf_local(buf, sizeof buf);
int index=atoi(remainder);
if (index<0 || index>=OVERLAY_MAX_INTERFACES)
return 404;
strbuf_puts(b, "<html><head><meta http-equiv=\"refresh\" content=\"5\" ></head><body>");
interface_state_html(b, &overlay_interfaces[index]);
strbuf_puts(b, "</body></html>");
if (strbuf_overrun(b))
return -1;
http_request_response_static(&r->http, 200, CONTENT_TYPE_HTML, buf, strbuf_len(b));
return 1;
}
static void finalise_union_close_file(httpd_request *r)
{
if (r->u.file.fd==-1)
return;
close(r->u.file.fd);
r->u.file.fd=-1;
}
static int static_file_generator(struct http_request *hr, unsigned char *buf, size_t bufsz, struct http_content_generator_result *result)
{
struct httpd_request *r=(struct httpd_request *)hr;
uint64_t remain = r->http.response.header.content_length + r->http.response.header.content_range_start - r->u.file.offset;
if (bufsz < remain)
remain = bufsz;
ssize_t bytes = read(r->u.file.fd, buf, remain);
if (bytes == -1)
return -1;
r->u.file.offset+=bytes;
result->generated = bytes;
return (r->u.file.offset >= r->http.response.header.content_length + r->http.response.header.content_range_start)?0:1;
}
static int static_page(httpd_request *r, const char *remainder)
{
if (r->http.verb != HTTP_VERB_GET)
return 405;
char path[PATH_MAX];
if (!*remainder)
remainder="index.html";
if (FORMF_SERVAL_ETC_PATH(path, "static/%s", remainder)==0)
return 500;
struct stat stat;
if (lstat(path, &stat))
return 404;
r->u.file.fd = open(path, O_RDONLY);
if (r->u.file.fd==-1)
return 404;
r->finalise_union=finalise_union_close_file;
// TODO find extension and set content type properly
http_response_init_content_range(r, stat.st_size);
if (r->http.response.header.content_range_start){
if (lseek64(r->u.file.fd, r->http.response.header.content_range_start, SEEK_SET)){
WARNF_perror("lseek(%s)", path);
return 500;
}
}
r->u.file.offset=r->http.response.header.content_range_start;
http_request_response_generated(&r->http, 200, CONTENT_TYPE_HTML, static_file_generator);
return 1;
}

14
httpd.h
View File

@ -219,6 +219,20 @@ int httpd_server_start(uint16_t port_low, uint16_t port_high);
typedef int HTTP_HANDLER(httpd_request *r, const char *remainder);
struct http_handler {
const char *path;
HTTP_HANDLER *parser;
};
DECLARE_SECTION(struct http_handler, httpd);
#define DECLARE_HANDLER(PATH, FUNC) \
static HTTP_HANDLER FUNC;\
static struct http_handler __##FUNC IN_SECTION(httpd) = {\
.path=PATH,\
.parser=FUNC\
}
int is_http_header_complete(const char *buf, size_t len, size_t read_since_last_call);
int authorize_restful(struct http_request *r);
int http_response_content_type(httpd_request *r, const char *what, const struct mime_content_type *ct);

View File

@ -27,9 +27,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define keyring_TOKEN_STRLEN (BASE64_ENCODED_LEN(sizeof(rhizome_bid_t) + sizeof(uint64_t)))
#define alloca_keyring_token(bid, offset) keyring_ token_to_str(alloca(keyring_TOKEN_STRLEN + 1), (bid), (offset))
DECLARE_HANDLER("/restful/keyring/", restful_keyring_);
static HTTP_HANDLER restful_keyring_identitylist_json;
int restful_keyring_(httpd_request *r, const char *remainder)
static int restful_keyring_(httpd_request *r, const char *remainder)
{
r->http.response.header.content_type = CONTENT_TYPE_JSON;
if (!is_rhizome_http_enabled())

View File

@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "httpd.h"
#include "strbuf_helpers.h"
DECLARE_HANDLER("/restful/meshms/", restful_meshms_);
static void on_rhizome_bundle_added(httpd_request *r, rhizome_manifest *m);
static void finalise_union_meshms_conversationlist(httpd_request *r)
@ -114,7 +116,7 @@ static HTTP_HANDLER restful_meshms_read_all_conversations;
static HTTP_HANDLER restful_meshms_read_all_messages;
static HTTP_HANDLER restful_meshms_read_to_offset;
int restful_meshms_(httpd_request *r, const char *remainder)
static int restful_meshms_(httpd_request *r, const char *remainder)
{
r->http.response.header.content_type = CONTENT_TYPE_JSON;
if (!is_rhizome_http_enabled())

View File

@ -31,6 +31,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "strbuf_helpers.h"
#include "socket.h"
DECLARE_HANDLER("/rhizome/import", rhizome_direct_import);
DECLARE_HANDLER("/rhizome/enquiry", rhizome_direct_enquiry);
DECLARE_HANDLER("/rhizome/", rhizome_direct_dispatch);
static int _form_temporary_file_path(struct __sourceloc __whence, httpd_request *r, char *pathbuf, size_t bufsiz, const char *field)
{
@ -357,7 +360,7 @@ static int rhizome_direct_process_mime_body(struct http_request *hr, char *buf,
return 0;
}
int rhizome_direct_import(httpd_request *r, const char *remainder)
static int rhizome_direct_import(httpd_request *r, const char *remainder)
{
if (*remainder)
return 404;
@ -374,7 +377,7 @@ int rhizome_direct_import(httpd_request *r, const char *remainder)
return 1;
}
int rhizome_direct_enquiry(httpd_request *r, const char *remainder)
static int rhizome_direct_enquiry(httpd_request *r, const char *remainder)
{
if (*remainder)
return 404;
@ -423,7 +426,7 @@ int rhizome_direct_addfile(httpd_request *r, const char *remainder)
return 1;
}
int rhizome_direct_dispatch(httpd_request *r, const char *UNUSED(remainder))
static int rhizome_direct_dispatch(httpd_request *r, const char *UNUSED(remainder))
{
if ( config.rhizome.api.addfile.uri_path[0]
&& strcmp(r->http.path, config.rhizome.api.addfile.uri_path) == 0

View File

@ -23,7 +23,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "str.h"
#include "strbuf.h"
int rhizome_file_page(httpd_request *r, const char *remainder)
DECLARE_HANDLER("/rhizome/status", rhizome_status_page);
DECLARE_HANDLER("/rhizome/file/", rhizome_file_page);
DECLARE_HANDLER("/rhizome/manifestbyprefix/", manifest_by_prefix_page);
static int rhizome_file_page(httpd_request *r, const char *remainder)
{
/* Stream the specified payload */
if (!is_rhizome_http_enabled())
@ -46,7 +50,7 @@ int rhizome_file_page(httpd_request *r, const char *remainder)
return 1;
}
int manifest_by_prefix_page(httpd_request *r, const char *remainder)
static int manifest_by_prefix_page(httpd_request *r, const char *remainder)
{
if (!is_rhizome_http_enabled())
return 403;
@ -70,7 +74,7 @@ int manifest_by_prefix_page(httpd_request *r, const char *remainder)
}
}
int rhizome_status_page(httpd_request *r, const char *remainder)
static int rhizome_status_page(httpd_request *r, const char *remainder)
{
if (!is_rhizome_http_enabled())
return 403;

View File

@ -22,6 +22,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "httpd.h"
#include "strbuf_helpers.h"
DECLARE_HANDLER("/restful/rhizome/bundlelist.json", restful_rhizome_bundlelist_json);
DECLARE_HANDLER("/restful/rhizome/newsince/", restful_rhizome_newsince);
DECLARE_HANDLER("/restful/rhizome/insert", restful_rhizome_insert);
DECLARE_HANDLER("/restful/rhizome/append", restful_rhizome_append);
DECLARE_HANDLER("/restful/rhizome/", restful_rhizome_);
static HTTP_RENDERER render_manifest_headers;
static void on_rhizome_bundle_added(httpd_request *r, rhizome_manifest *m);
@ -148,7 +154,7 @@ static int http_request_rhizome_response(struct httpd_request *r, uint16_t resul
static HTTP_CONTENT_GENERATOR restful_rhizome_bundlelist_json_content;
int restful_rhizome_bundlelist_json(httpd_request *r, const char *remainder)
static int restful_rhizome_bundlelist_json(httpd_request *r, const char *remainder)
{
r->http.response.header.content_type = CONTENT_TYPE_JSON;
r->http.render_extra_headers = render_manifest_headers;
@ -181,7 +187,7 @@ static int restful_rhizome_bundlelist_json_content(struct http_request *hr, unsi
return ret;
}
int restful_rhizome_newsince(httpd_request *r, const char *remainder)
static int restful_rhizome_newsince(httpd_request *r, const char *remainder)
{
r->http.response.header.content_type = CONTENT_TYPE_JSON;
if (!is_rhizome_http_enabled())
@ -327,7 +333,7 @@ static int insert_mime_part_end(struct http_request *);
static int insert_mime_part_header(struct http_request *, const struct mime_part_headers *);
static int insert_mime_part_body(struct http_request *, char *, size_t);
int restful_rhizome_insert(httpd_request *r, const char *remainder)
static int restful_rhizome_insert(httpd_request *r, const char *remainder)
{
r->http.response.header.content_type = CONTENT_TYPE_JSON;
r->http.render_extra_headers = render_manifest_headers;
@ -359,7 +365,7 @@ int restful_rhizome_insert(httpd_request *r, const char *remainder)
return 1;
}
int restful_rhizome_append(httpd_request *r, const char *remainder)
static int restful_rhizome_append(httpd_request *r, const char *remainder)
{
r->u.insert.appending = 1;
return restful_rhizome_insert(r, remainder);
@ -750,7 +756,7 @@ static HTTP_HANDLER restful_rhizome_bid_rhm;
static HTTP_HANDLER restful_rhizome_bid_raw_bin;
static HTTP_HANDLER restful_rhizome_bid_decrypted_bin;
int restful_rhizome_(httpd_request *r, const char *remainder)
static int restful_rhizome_(httpd_request *r, const char *remainder)
{
r->http.response.header.content_type = CONTENT_TYPE_JSON;
r->http.render_extra_headers = render_manifest_headers;

154
server_httpd.c Normal file
View File

@ -0,0 +1,154 @@
#include "serval.h"
#include "httpd.h"
#include "conf.h"
#include "overlay_address.h"
#include "overlay_interface.h"
#include "os.h"
DECLARE_HANDLER("/static/", static_page);
DECLARE_HANDLER("/interface/", interface_page);
DECLARE_HANDLER("/neighbour/", neighbour_page);
DECLARE_HANDLER("/favicon.ico", fav_icon_header);
DECLARE_HANDLER("/", root_page);
static int root_page(httpd_request *r, const char *remainder)
{
if (*remainder)
return 404;
if (r->http.verb != HTTP_VERB_GET)
return 405;
char temp[8192];
strbuf b = strbuf_local(temp, sizeof temp);
strbuf_sprintf(b, "<html><head><meta http-equiv=\"refresh\" content=\"5\" ></head><body>"
"<h1>Hello, I'm %s*</h1>",
alloca_tohex_sid_t_trunc(my_subscriber->sid, 16));
if (config.server.motd[0]) {
strbuf_puts(b, "<p>");
strbuf_html_escape(b, config.server.motd, strlen(config.server.motd));
strbuf_puts(b, "</p>");
}
strbuf_puts(b, "Interfaces;<br />");
int i;
for (i=0;i<OVERLAY_MAX_INTERFACES;i++){
if (overlay_interfaces[i].state==INTERFACE_STATE_UP)
strbuf_sprintf(b, "<a href=\"/interface/%d\">%d: %s, TX: %d, RX: %d</a><br />",
i, i, overlay_interfaces[i].name, overlay_interfaces[i].tx_count, overlay_interfaces[i].recv_count);
}
strbuf_puts(b, "Neighbours;<br />");
link_neighbour_short_status_html(b, "/neighbour");
if (is_rhizome_http_enabled()){
strbuf_puts(b, "<a href=\"/rhizome/status\">Rhizome Status</a><br />");
}
strbuf_puts(b, "</body></html>");
if (strbuf_overrun(b)) {
WHY("HTTP Root page buffer overrun");
return 500;
}
http_request_response_static(&r->http, 200, CONTENT_TYPE_HTML, temp, strbuf_len(b));
return 1;
}
static int fav_icon_header(httpd_request *r, const char *remainder)
{
if (*remainder)
return 404;
http_request_response_static(&r->http, 200, "image/vnd.microsoft.icon", (const char *)favicon_bytes, favicon_len);
return 1;
}
static int neighbour_page(httpd_request *r, const char *remainder)
{
if (r->http.verb != HTTP_VERB_GET)
return 405;
char buf[8*1024];
strbuf b = strbuf_local(buf, sizeof buf);
sid_t neighbour_sid;
if (str_to_sid_t(&neighbour_sid, remainder) == -1)
return 404;
struct subscriber *neighbour = find_subscriber(neighbour_sid.binary, sizeof(neighbour_sid.binary), 0);
if (!neighbour)
return 404;
strbuf_puts(b, "<html><head><meta http-equiv=\"refresh\" content=\"5\" ></head><body>");
link_neighbour_status_html(b, neighbour);
strbuf_puts(b, "</body></html>");
if (strbuf_overrun(b))
return -1;
http_request_response_static(&r->http, 200, CONTENT_TYPE_HTML, buf, strbuf_len(b));
return 1;
}
static int interface_page(httpd_request *r, const char *remainder)
{
if (r->http.verb != HTTP_VERB_GET)
return 405;
char buf[8*1024];
strbuf b=strbuf_local(buf, sizeof buf);
int index=atoi(remainder);
if (index<0 || index>=OVERLAY_MAX_INTERFACES)
return 404;
strbuf_puts(b, "<html><head><meta http-equiv=\"refresh\" content=\"5\" ></head><body>");
interface_state_html(b, &overlay_interfaces[index]);
strbuf_puts(b, "</body></html>");
if (strbuf_overrun(b))
return -1;
http_request_response_static(&r->http, 200, CONTENT_TYPE_HTML, buf, strbuf_len(b));
return 1;
}
static int static_file_generator(struct http_request *hr, unsigned char *buf, size_t bufsz, struct http_content_generator_result *result)
{
struct httpd_request *r=(struct httpd_request *)hr;
uint64_t remain = r->http.response.header.content_length + r->http.response.header.content_range_start - r->u.file.offset;
if (bufsz < remain)
remain = bufsz;
ssize_t bytes = read(r->u.file.fd, buf, remain);
if (bytes == -1)
return -1;
r->u.file.offset+=bytes;
result->generated = bytes;
return (r->u.file.offset >= r->http.response.header.content_length + r->http.response.header.content_range_start)?0:1;
}
static void finalise_union_close_file(httpd_request *r)
{
if (r->u.file.fd==-1)
return;
close(r->u.file.fd);
r->u.file.fd=-1;
}
static int static_page(httpd_request *r, const char *remainder)
{
if (r->http.verb != HTTP_VERB_GET)
return 405;
char path[PATH_MAX];
if (!*remainder)
remainder="index.html";
if (FORMF_SERVAL_ETC_PATH(path, "static/%s", remainder)==0)
return 500;
struct stat stat;
if (lstat(path, &stat))
return 404;
r->u.file.fd = open(path, O_RDONLY);
if (r->u.file.fd==-1)
return 404;
r->finalise_union=finalise_union_close_file;
// TODO find extension and set content type properly
http_response_init_content_range(r, stat.st_size);
if (r->http.response.header.content_range_start){
if (lseek64(r->u.file.fd, r->http.response.header.content_range_start, SEEK_SET)){
WARNF_perror("lseek(%s)", path);
return 500;
}
}
r->u.file.offset=r->http.response.header.content_range_start;
http_request_response_generated(&r->http, 200, CONTENT_TYPE_HTML, static_file_generator);
return 1;
}

View File

@ -97,6 +97,7 @@ SERVAL_DAEMON_SOURCES = \
rhizome_sync.c \
serval_packetvisualise.c \
server.c \
server_httpd.c \
vomp.c \
vomp_console.c \
fec-3.0.1/ccsds_tables.c \