Commit 76bcf0b0 authored by Raptor Engineering Development Team's avatar Raptor Engineering Development Team
Browse files

Add initial version of the Kestrel Web service

Framework now in place for further expansion
parent 76938bb4
No related merge requests found
......@@ -5,6 +5,7 @@ SET(FPGA_BUILD_DIR "${CMAKE_CURRENT_SOURCE_DIR}/bootrom/fpga/release"
"Path to the FPGA build folder from the litex-boards repo: <litex-boards-repo>/litex_boards/targets/build/versa_ecp5")
SET(KESTREL_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/kestrel)
SET(CIVETWEB_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/civetweb)
SET(EMBEDDED_FILE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/embeddedfiles)
cmake_minimum_required(VERSION 3.13.1)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
......@@ -35,4 +36,27 @@ target_sources(app PRIVATE
${KESTREL_SOURCE_DIR}/src/webservice.c
${KESTREL_SOURCE_DIR}/src/direct_uart.c
${CIVETWEB_SOURCE_DIR}/src/libc_extensions.c
${CIVETWEB_SOURCE_DIR}/src/raptor_extensions.c
)
SET(embedded_file_sources
${EMBEDDED_FILE_SOURCE_DIR}/index.html
${EMBEDDED_FILE_SOURCE_DIR}/header.inc
${EMBEDDED_FILE_SOURCE_DIR}/footer.inc
${EMBEDDED_FILE_SOURCE_DIR}/style.css
${EMBEDDED_FILE_SOURCE_DIR}/raptor_logo.jpg
${EMBEDDED_FILE_SOURCE_DIR}/kestrel_avatar_small.png
)
SET(embedded_file_sources_list "")
foreach(file ${embedded_file_sources})
string(APPEND embedded_file_sources_list ${file} "\;")
endforeach()
SET(static_file_header ${KESTREL_SOURCE_DIR}/src/static_files.h)
add_custom_target(
static_files ALL
COMMAND COMMAND ${CMAKE_COMMAND} -D KESTREL_SOURCE_DIR="${KESTREL_SOURCE_DIR}" -D embedded_file_sources="${embedded_file_sources_list}" -P ${CMAKE_CURRENT_SOURCE_DIR}/generate_static_files.cmake
DEPENDS ${embedded_file_sources}
COMMENT "Generating C header file from static files"
)
\ No newline at end of file
# Copyright 2020 Sivachandran Paramasivam
# Licensed under the terms of the MIT license
include(CMakeParseArguments)
# Function to wrap a given string into multiple lines at the given column position.
# Parameters:
# VARIABLE - The name of the CMake variable holding the string.
# AT_COLUMN - The column position at which string will be wrapped.
function(WRAP_STRING)
set(oneValueArgs VARIABLE AT_COLUMN)
cmake_parse_arguments(WRAP_STRING "${options}" "${oneValueArgs}" "" ${ARGN})
string(LENGTH ${${WRAP_STRING_VARIABLE}} stringLength)
math(EXPR offset "0")
while(stringLength GREATER 0)
if(stringLength GREATER ${WRAP_STRING_AT_COLUMN})
math(EXPR length "${WRAP_STRING_AT_COLUMN}")
else()
math(EXPR length "${stringLength}")
endif()
string(SUBSTRING ${${WRAP_STRING_VARIABLE}} ${offset} ${length} line)
set(lines "${lines}\n${line}")
math(EXPR stringLength "${stringLength} - ${length}")
math(EXPR offset "${offset} + ${length}")
endwhile()
set(${WRAP_STRING_VARIABLE} "${lines}" PARENT_SCOPE)
endfunction()
# Function to embed contents of a file as byte array in C/C++ header file(.h). The header file
# will contain a byte array and integer variable holding the size of the array.
# Parameters
# SOURCE_FILE - The path of source file whose contents will be embedded in the header file.
# VARIABLE_NAME - The name of the variable for the byte array. The string "_SIZE" will be append
# to this name and will be used a variable name for size variable.
# HEADER_FILE - The path of header file.
# APPEND - If specified appends to the header file instead of overwriting it
# NULL_TERMINATE - If specified a null byte(zero) will be append to the byte array. This will be
# useful if the source file is a text file and we want to use the file contents
# as string. But the size variable holds size of the byte array without this
# null byte.
# Usage:
# bin2h(SOURCE_FILE "Logo.png" HEADER_FILE "Logo.h" VARIABLE_NAME "LOGO_PNG")
function(BIN2H)
set(options APPEND NULL_TERMINATE)
set(oneValueArgs SOURCE_FILE VARIABLE_NAME HEADER_FILE)
cmake_parse_arguments(BIN2H "${options}" "${oneValueArgs}" "" ${ARGN})
# reads source file contents as hex string
file(READ ${BIN2H_SOURCE_FILE} hexString HEX)
string(LENGTH ${hexString} hexStringLength)
# appends null byte if asked
if(BIN2H_NULL_TERMINATE)
set(hexString "${hexString}00")
endif()
# wraps the hex string into multiple lines at column 32(i.e. 16 bytes per line)
wrap_string(VARIABLE hexString AT_COLUMN 32)
math(EXPR arraySize "${hexStringLength} / 2")
# adds '0x' prefix and comma suffix before and after every byte respectively
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " arrayValues ${hexString})
# removes trailing comma
string(REGEX REPLACE ", $" "" arrayValues ${arrayValues})
# converts the variable name into proper C identifier
string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
string(TOLOWER "embedded_file_${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
# declares byte array and the length variables
set(arrayDefinition "const unsigned char ${BIN2H_VARIABLE_NAME}[] = { ${arrayValues} };")
set(arraySizeDefinition "const size_t ${BIN2H_VARIABLE_NAME}_SIZE = ${arraySize};")
set(declarations "${arrayDefinition}\n\n${arraySizeDefinition}\n\n")
if(BIN2H_APPEND)
file(APPEND ${BIN2H_HEADER_FILE} "${declarations}")
else()
file(WRITE ${BIN2H_HEADER_FILE} "${declarations}")
endif()
endfunction()
\ No newline at end of file
bootrom @ 5573c718
Subproject commit 399db4c68f98c326d07e2e842980ae8741bfd5a4
Subproject commit 5573c7184997d0d3e18b8df87c0ee9e1fbfed3cf
// © 2021 Raptor Engineering, LLC
//
// Released under the terms of the GPL v3
// See the LICENSE file for full details
#ifndef _RAPTOR_EXTENSIONS
#define _RAPTOR_EXTENSIONS
void civetweb_send_file_data(struct mg_connection *conn, const uint8_t* data, int64_t len);
void civetweb_send_file(struct mg_connection *conn, const char* content_type, const uint8_t* data, size_t length);
#endif // _RAPTOR_EXTENSIONS
\ No newline at end of file
/*
* Copyright (c) 2019 Antmicro Ltd
* Copyright (c) 2021 Raptor Engineering, LLC <sales@raptorengineering.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
......@@ -30,6 +31,9 @@ size_t strftime(char *dst, size_t dst_size,
{
FN_MISSING();
// Prevent garbage from being transmitted
memset(dst, 0, dst_size);
return 0;
}
......
/* Copyright (c) 2013-2021 the Civetweb developers
* Copyright (c) 2004-2013 Sergey Lyubka
* Copyright (c) 2021 Raptor Engineering, LLC <sales@raptorengineering.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdint.h>
#include <zephyr.h>
#include <posix/pthread.h>
#include "libc_extensions.h"
#include "civetweb.h"
/* General purpose buffer size. */
#if !defined(MG_BUF_LEN) /* in bytes */
#define MG_BUF_LEN (1024 * 8)
#endif
/* Return null terminated string of given maximum length.
* Report errors if length is exceeded. */
static void
mg_vsnprintf(const struct mg_connection *conn,
int *truncated,
char *buf,
size_t buflen,
const char *fmt,
va_list ap)
{
int n, ok;
if (buflen == 0) {
if (truncated) {
*truncated = 1;
}
return;
}
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-nonliteral"
/* Using fmt as a non-literal is intended here, since it is mostly called
* indirectly by mg_snprintf */
#endif
n = (int)vsnprintf(buf, buflen, fmt, ap);
ok = (n >= 0) && ((size_t)n < buflen);
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
if (ok) {
if (truncated) {
*truncated = 0;
}
} else {
if (truncated) {
*truncated = 1;
}
n = (int)buflen - 1;
}
buf[n] = '\0';
}
static void
mg_snprintf(const struct mg_connection *conn,
int *truncated,
char *buf,
size_t buflen,
const char *fmt,
...)
{
va_list ap;
va_start(ap, fmt);
mg_vsnprintf(conn, truncated, buf, buflen, fmt, ap);
va_end(ap);
}
static void
mg_strlcpy(char *dst, const char *src, size_t n)
{
for (; *src != '\0' && n > 1; n--) {
*dst++ = *src++;
}
*dst = '\0';
}
/* Convert time_t to a string. According to RFC2616, Sec 14.18, this must be
* included in all responses other than 100, 101, 5xx. */
static void
gmt_time_string(char *buf, size_t buf_len, time_t *t)
{
#if !defined(REENTRANT_TIME)
struct tm *tm;
tm = ((t != NULL) ? gmtime(t) : NULL);
if (tm != NULL) {
#else
struct tm _tm;
struct tm *tm = &_tm;
if (t != NULL) {
gmtime_r(t, tm);
#endif
strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", tm);
} else {
mg_strlcpy(buf, "Thu, 01 Jan 1970 00:00:00 GMT", buf_len);
buf[buf_len - 1] = '\0';
}
}
static int parse_range_header(const char *header, int64_t *a, int64_t *b)
{
return sscanf(header, "bytes=%lld-%lld", a, b);
}
void civetweb_send_file_data(struct mg_connection *conn, const uint8_t* data, int64_t len)
{
char buf[MG_BUF_LEN];
int to_read, num_written;
if (!data || !conn) {
return;
}
while (len > 0) {
/* Calculate how much to read from the file in the buffer */
to_read = sizeof(buf);
if ((int64_t)to_read > len) {
to_read = (int)len;
}
/* Send read bytes to the client, exit the loop on error */
if ((num_written = mg_write(conn, data, (size_t)to_read))
!= to_read) {
break;
}
data += num_written;
/* Both read and were successful, adjust counters */
len -= num_written;
}
}
void civetweb_send_file(struct mg_connection *conn, const char* content_type, const uint8_t* data, size_t length)
{
char lm[64], etag[64];
char range[128]; /* large enough, so there will be no overflow */
const char *range_hdr;
int64_t cl, r1, r2;
int n, truncated;
const char *encoding = 0;
const char *origin_hdr;
const char *cors_orig_cfg;
const char *cors1, *cors2;
int status_code;
int is_head_request;
// FIXME
// Set to some future date for images to avoid constant reloads from the overtaxed Kestrel web server...
uint64_t last_modified = 0;
cl = (int64_t)length;
status_code = 200;
range[0] = '\0';
/* Check if there is a range header */
range_hdr = mg_get_header(conn, "Range");
/* If "Range" request was made: parse header, send only selected part
* of the file. */
r1 = r2 = 0;
if ((range_hdr != NULL)
&& ((n = parse_range_header(range_hdr, &r1, &r2)) > 0) && (r1 >= 0)
&& (r2 >= 0)) {
status_code = 206;
cl = (n == 2) ? (((r2 > cl) ? cl : r2) - r1 + 1) : (cl - r1);
mg_snprintf(conn,
NULL, /* range buffer is big enough */
range,
sizeof(range),
"bytes "
"%lld-%lld/%lld",
r1,
r1 + cl - 1,
length);
}
/* Standard CORS header */
origin_hdr = mg_get_header(conn, "Origin");
cors1 = "Access-Control-Allow-Origin";
cors2 = cors_orig_cfg;
/* Prepare Etag, and Last-Modified headers. */
gmt_time_string(lm, sizeof(lm), &last_modified);
mg_snprintf(NULL,
NULL, /* All calls to construct_etag use 64 byte buffer */
etag,
sizeof(etag),
"\"%lx.%lld\"",
(unsigned long)last_modified,
length);
/* Create 2xx (200, 206) response */
mg_response_header_start(conn, status_code);
mg_response_header_add(conn, "Cache-Control", "600", -1);
//send_additional_header(conn);
mg_response_header_add(conn,
"Content-Type",
content_type,
(int)strlen(content_type));
if (cors1[0] != 0) {
mg_response_header_add(conn, cors1, cors2, -1);
}
mg_response_header_add(conn, "Last-Modified", lm, -1);
mg_response_header_add(conn, "Etag", etag, -1);
/* Without on-the-fly compression, we know the content-length
* and we can use ranges (with on-the-fly compression we cannot).
* So we send these response headers only in this case. */
char len[32];
int trunc = 0;
mg_snprintf(conn, &trunc, len, sizeof(len), "%lld", cl);
if (!trunc) {
mg_response_header_add(conn, "Content-Length", len, -1);
}
mg_response_header_add(conn, "Accept-Ranges", "bytes", -1);
if (encoding) {
mg_response_header_add(conn, "Content-Encoding", encoding, -1);
}
if (range[0] != 0) {
mg_response_header_add(conn, "Content-Range", range, -1);
}
/* Send all headers */
mg_response_header_send(conn);
if (!is_head_request) {
civetweb_send_file_data(conn, data + r1, cl);
}
}
\ No newline at end of file
</div>
<div class="footer">
<table width=100%>
<tr>
<td width=100% align=center>
<table class="footer_text">
<tr>
<td rowspan=2>
<a href="https://www.raptorengineering.com"><img src="raptor_logo.jpg" height="30" border="0"></a>
</td>
<td>
Kestrel brought to you by <a href="https://www.raptorengineering.com">Raptor Engineering</a>
</td>
</tr>
<tr>
<td>
Get the <a href="https://gitlab.raptorengineering.com/kestrel-collaboration">source code</a> and collaborate on our GitLab server today!
</td>
</tr>
</table>
</td>
</tr>
</table>
</div>
</body>
</html>
<body>
<img src="kestrel_avatar_small.png" height="100" border="0" style="float:left; position:absolute; top: 0px; z-index: 10;">
<div class="sidebar_nav">
<a href="/info">Info</a>
<a href="/firmwareupload$">Firmware</a>
</div>
<div class="header">
Kestrel SoftBMC
</div>
<div class="main">
<h3>Welcome to the Kestrel web management portal!</h3>
Available actions:
<ul>
<li><a href=/info>System information</a></li>
<li><a href=/firmwareupload>Firmware upload</a></li>
</ul>
embeddedfiles/kestrel_avatar_small.png

34.7 KB

embeddedfiles/raptor_logo.jpg

15.6 KB

include(${KESTREL_SOURCE_DIR}/../bin2hex.cmake)
SET(static_file_header ${KESTREL_SOURCE_DIR}/src/static_files.h)
file(WRITE ${static_file_header} "// © 2021 Raptor Engineering, LLC\n//\n// Released under the terms of the GPL v3\n// See the LICENSE file for full details\n\n#ifndef _STATIC_FILES\n#define _STATIC_FILES\n\n")
foreach(file ${embedded_file_sources})
get_filename_component(variableName ${file} NAME)
bin2h(SOURCE_FILE ${file} HEADER_FILE ${static_file_header} VARIABLE_NAME ${variableName} APPEND NULL_TERMINATE)
file(APPEND ${static_file_header} "\n")
endforeach()
file(APPEND ${static_file_header} "\n\n#endif // _STATIC_FILES\n")
\ No newline at end of file
......@@ -37,6 +37,7 @@ struct firmware_buffer_region {
uint8_t *buffer_address;
unsigned long long buffer_length;
uintptr_t current_write_offset;
unsigned long long valid_bytes;
uint8_t locked;
uint8_t overflow;
};
......
/*
* Copyright (c) 2019 Antmicro Ltd
* Copyright (c) 2021 Raptor Engineering, LLC <sales@raptorengineering.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
......@@ -13,6 +14,9 @@
#define WITH_ZEPHYR 1
#include "kestrel.h"
#include "raptor_extensions.h"
#include "static_files.h"
#define HTTP_PORT 8080
#define HTTPS_PORT 4443
......@@ -21,8 +25,52 @@
/* Use samllest possible value of 1024 (see the line 18619 of civetweb.c) */
#define MAX_REQUEST_SIZE_BYTES 1024
#define STANDARD_HEADER(title) \
"<head>" \
"<link rel=\"stylesheet\" href=\"style.css\"><meta charset=\"UTF-8\">" \
"<title>" title "</title>" \
"</head>"
#define SEND_STANDARD_TITLE_HEADER(conn, title) \
civetweb_send_file_data(conn, STANDARD_HEADER(title), sizeof(STANDARD_HEADER(title)));
#define SEND_STANDARD_HEADER(conn, title) \
SEND_STANDARD_TITLE_HEADER(conn, title) \
civetweb_send_file_data(conn, embedded_file_header_inc, sizeof(embedded_file_header_inc)-1);
#define SEND_STANDARD_FOOTER(conn) \
civetweb_send_file_data(conn, embedded_file_footer_inc, sizeof(embedded_file_footer_inc)-1);
#define KESTREL_WEBSERVICE_DEFINE_FILE_HANDLER(name, type) \
static int static_file_##name##_handler(struct mg_connection *conn, void *cbdata) \
{ \
civetweb_send_file(conn, type, embedded_file_##name, sizeof(embedded_file_##name)-1); \
return 200; \
}
#define KESTREL_WEBSERVICE_DEFINE_PAGE_HANDLER(name, type, title) \
static int static_file_##name##_handler(struct mg_connection *conn, void *cbdata) \
{ \
mg_printf(conn, \
"HTTP/1.1 200 OK\r\n" \
"Content-Type: text/html\r\n" \
"Connection: close\r\n\r\n"); \
SEND_STANDARD_HEADER(conn, title) \
civetweb_send_file_data(conn, embedded_file_##name, sizeof(embedded_file_##name)-1); \
SEND_STANDARD_FOOTER(conn) \
return 200; \
}
#define KESTREL_WEBSERVICE_REGISTER_FILE_HANDLER(name, path) \
mg_set_request_handler(ctx, path, static_file_##name##_handler, (void *)0);
K_THREAD_STACK_DEFINE(civetweb_stack, CIVETWEB_MAIN_THREAD_STACK_SIZE);
KESTREL_WEBSERVICE_DEFINE_PAGE_HANDLER(index_html, "text/html", "Kestrel SoftBMC")
KESTREL_WEBSERVICE_DEFINE_FILE_HANDLER(style_css, "text/css")
KESTREL_WEBSERVICE_DEFINE_FILE_HANDLER(raptor_logo_jpg, "image/jpeg")
KESTREL_WEBSERVICE_DEFINE_FILE_HANDLER(kestrel_avatar_small_png, "image/png")
struct civetweb_info {
const char *version;
const char *os;
......@@ -48,21 +96,6 @@ void send_ok(struct mg_connection *conn)
"Connection: close\r\n\r\n");
}
int hello_world_handler(struct mg_connection *conn, void *cbdata)
{
send_ok(conn);
mg_printf(conn, "<html><body>");
mg_printf(conn, "<h3>Hello World from Zephyr!</h3>");
mg_printf(conn, "See also:\n");
mg_printf(conn, "<ul>\n");
mg_printf(conn, "<li><a href=/info>system info</a></li>\n");
mg_printf(conn, "<li><a href=/firmwareupload>firmware upload</a></li>\n");
mg_printf(conn, "</ul>\n");
mg_printf(conn, "</body></html>\n");
return 200;
}
int system_info_handler(struct mg_connection *conn, void *cbdata)
{
static const struct json_obj_descr descr[] = {
......@@ -90,18 +123,17 @@ int system_info_handler(struct mg_connection *conn, void *cbdata)
return 500;
}
SEND_STANDARD_HEADER(conn, "Kestrel Information")
mg_printf(conn, "<html><body>");
mg_printf(conn, "<h3>Server info</h3>");
mg_printf(conn, "<h3>BMC information</h3>");
mg_printf(conn, "<ul>\n");
mg_printf(conn, "<li>host os - %s</li>\n", info.os);
mg_printf(conn, "<li>server - civetweb %s</li>\n", info.version);
mg_printf(conn, "<li>compiler - %s</li>\n", info.compiler);
mg_printf(conn, "<li>board - %s</li>\n", CONFIG_BOARD);
mg_printf(conn, "<li>BMC OS - %s</li>\n", info.os);
mg_printf(conn, "<li>Server - civetweb %s</li>\n", info.version);
mg_printf(conn, "<li>Compiler - %s</li>\n", info.compiler);
mg_printf(conn, "<li>Board - %s</li>\n", CONFIG_BOARD);
mg_printf(conn, "</ul>\n");
mg_printf(conn, "</body></html>\n");
SEND_STANDARD_FOOTER(conn);
return 200;
}
......@@ -112,18 +144,18 @@ int firmware_upload_form_handler(struct mg_connection *conn, void *cbdata)
"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
"close\r\n\r\n");
mg_printf(conn, "<!DOCTYPE html>\n");
mg_printf(conn, "<html>\n<head>\n");
mg_printf(conn, "<meta charset=\"UTF-8\">\n");
mg_printf(conn, "<title>File upload</title>\n");
mg_printf(conn, "</head>\n<body>\n");
SEND_STANDARD_HEADER(conn, "Firmware Upload")
mg_printf(conn, "<h3>Firmware Upload</h3>");
mg_printf(conn,
"<form action=\"%s\" method=\"POST\" "
"enctype=\"multipart/form-data\">\n",
(const char *)cbdata);
mg_printf(conn, "<input type=\"file\" name=\"firmwarefile\" multiple>\n");
mg_printf(conn, "<input type=\"submit\" value=\"Submit\">\n");
mg_printf(conn, "</form>\n</body>\n</html>\n");
mg_printf(conn, "</form>\n");
SEND_STANDARD_FOOTER(conn);
return 200;
}
......@@ -154,6 +186,7 @@ int fw_data_received(const char *key, const char *value, size_t valuelen, void *
}
memcpy(fw_data->buffer_address + fw_data->current_write_offset, value, valuelen);
fw_data->current_write_offset += valuelen;
fw_data->valid_bytes = fw_data->current_write_offset;
return 0;
}
......@@ -172,29 +205,36 @@ int firmware_upload_handler(struct mg_connection *conn, void *cbdata)
* mg_handle_form_request. */
(void)req_info;
mg_printf(conn,
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n\r\n");
main_firmware_buffer.locked = 1;
main_firmware_buffer.overflow = 0;
main_firmware_buffer.current_write_offset = 0;
main_firmware_buffer.valid_bytes = 0;
/* Call the form handler */
mg_printf(conn, "File(s) uploaded:");
ret = mg_handle_form_request(conn, &fdh);
main_firmware_buffer.locked = 0;
mg_printf(conn, "\r\n%i files\r\n", ret);
mg_printf(conn, "\r\n%ld bytes\r\n", main_firmware_buffer.current_write_offset);
mg_printf(conn,
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n\r\n");
SEND_STANDARD_HEADER(conn, "Firmware Uploaded")
mg_printf(conn, "<h3>Firmware Uploaded</h3>");
mg_printf(conn, "<p>");
mg_printf(conn, "File(s) uploaded:<br>");
mg_printf(conn, "%i files<br>", ret);
mg_printf(conn, "%lld bytes<br>", main_firmware_buffer.valid_bytes);
if (main_firmware_buffer.overflow) {
mg_printf(conn, "\r\nWARNING: Data was discarded due to buffer overflow!r\n");
mg_printf(conn, "<p>WARNING: Data was discarded due to buffer overflow!");
SEND_STANDARD_FOOTER(conn);
return 500;
}
SEND_STANDARD_FOOTER(conn);
return 200;
}
......@@ -223,11 +263,19 @@ void *main_pthread(void *arg)
return 0;
}
mg_set_request_handler(ctx, "/$", hello_world_handler, (void *)0);
// Static pages
KESTREL_WEBSERVICE_REGISTER_FILE_HANDLER(index_html, "/$")
KESTREL_WEBSERVICE_REGISTER_FILE_HANDLER(style_css, "/style.css$")
// Static files
KESTREL_WEBSERVICE_REGISTER_FILE_HANDLER(raptor_logo_jpg, "/raptor_logo.jpg$")
KESTREL_WEBSERVICE_REGISTER_FILE_HANDLER(kestrel_avatar_small_png, "/kestrel_avatar_small.png$")
// Dynamic pages
mg_set_request_handler(ctx, "/info$", system_info_handler, (void *)0);
mg_set_request_handler(ctx, "/firmwareupload", firmware_upload_form_handler, (void *)"/firmwareupload.callback");
mg_set_request_handler(ctx, "/firmwareupload.callback", firmware_upload_handler, (void *)0);
mg_set_request_handler(ctx, "/firmwareupload$", firmware_upload_form_handler, (void *)"/firmwareupload.callback");
mg_set_request_handler(ctx, "/firmwareupload.callback$", firmware_upload_handler, (void *)0);
return 0;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment