This repository has been archived on 2023-07-17. You can view files and clone it, but cannot push or open issues or pull requests.
bl_mcu_sdk/examples/emac/lwip_http_server/http_server.c

342 lines
10 KiB
C

/**
* @file http_server.c
* @brief
*
* Copyright (c) 2021 Bouffalolab team
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
*/
#include "bflb_platform.h"
#include "lwip/api.h"
#include "lwip/arch.h"
#include "lwip/opt.h"
// #include "lwip/inet.h"
// #include "lwip/netif.h"
#include "lwip/tcpbase.h"
#include "lwip/tcp.h"
#include "lwip/apps/fs.h"
#include "lwip/apps/httpd.h"
#include "FreeRTOS.h"
#include "task.h"
#include "http_server.h"
const HtmlServerRouter_TypeDef httpRouter[] = {
{ "/", "/index.html" },
{ "/favicon.ico", "/asset/favicon.ico" },
{ "/js/main.js", "/js/main.js" },
{ "/css/style.css", "/css/style.css" },
{ "/css/asset/off.png", "/asset/off.png" },
{ "/asset/off.png", "/asset/off.png" },
{ "/css/asset/on.png", "/asset/on.png" },
{ "/asset/on.png", "/asset/on.png" },
{ "/asset/ok.json", "/asset/ok.json" },
{ "*", "/404.html" }
};
SemaphoreHandle_t console_lock = NULL;
sys_sem_t s_x_btn_semaphore = NULL;
char button_clicked_flag = false;
static struct netconn *http_active_conn = NULL;
static StackType_t http_server_stack[512];
static StaticTask_t http_server_handle;
void send_file(const char *path)
{
struct fs_file file;
err_t error = ERR_OK;
error = fs_open(&file, path);
if (error == ERR_OK) {
netconn_write(http_active_conn, (const unsigned char *)(file.data), (size_t)file.len, NETCONN_NOCOPY);
} else {
OS_MSG("[ERROR] send file read failed, path: %s, error code: %d\r\n", path, error);
}
fs_close(&file);
}
err_t try_send_file(const char *path)
{
struct fs_file file;
err_t error = ERR_OK;
error = fs_open(&file, path);
if (error == ERR_OK) {
netconn_write(http_active_conn, (const unsigned char *)(file.data), (size_t)file.len, NETCONN_NOCOPY);
} else {
OS_MSG("[ERROR] try send file read failed, path: %s, error code: %d\r\n", path, error);
}
fs_close(&file);
return error;
}
void serch_send_file(const char *url)
{
static uint16_t router_length = sizeof(httpRouter) / sizeof(HtmlRequestMethod_TypeDef);
uint16_t i = 0;
for (i = 0; i < router_length; i++) {
if (!strcmp(url, httpRouter[i].url)) {
send_file(httpRouter[i].path);
break;
}
}
/* send 404 */
if (i >= router_length) {
OS_MSG("[WARNING] Not found path %s, sended 404 page.\r\n", url);
send_file(httpRouter[router_length - 1].path);
}
}
void http_post_btn_process(const char *url, const char *body)
{
if (strstr(body, "true") == NULL) {
button_clicked_flag = false;
} else {
button_clicked_flag = true;
}
xSemaphoreGive(s_x_btn_semaphore);
}
void process_http_get(const char *url, const char *body)
{
serch_send_file(url);
}
void process_http_post(const char *url, const char *body)
{
if (!strcmp(url, "/button_clicked")) {
http_post_btn_process(url, body);
serch_send_file("/asset/ok.json");
}
}
void process_http_request(const char *requset, uint16_t length)
{
char *mem = NULL;
char *str = NULL;
char *body = NULL;
char *url = NULL;
mem = malloc(length);
memset(mem, 0, length);
str = mem;
body = mem;
memcpy(str, requset, sizeof(char) * length);
HtmlRequestMethod_TypeDef method = HTTP_UNKNOWN;
/* get http request method */
if (str != NULL) {
str = strtok(str, " ");
if (!strcmp(str, "GET")) {
method = HTTP_GET;
OS_MSG("[LOG] Methon: GET\r\n");
} else if (!strcmp(str, "POST")) {
method = HTTP_POST;
OS_MSG("[LOG] Methon: POST\r\n");
} else {
method = HTTP_UNKNOWN;
OS_MSG("[LOG] Methon: UNKNOWN\r\n");
}
}
/* get url */
if (str != NULL) {
str = strtok(NULL, " ");
if (str != NULL) {
url = malloc(strlen(str) + 1);
memset(url, 0, strlen(str) + 1);
strcpy(url, str);
OS_MSG("[LOG] URL: %s\r\n", url);
}
}
memcpy(body, requset, sizeof(char) * length);
/* process http requset */
switch (method) {
case HTTP_GET:
process_http_get(url, body);
break;
case HTTP_POST:
process_http_post(url, body);
break;
default:
break;
}
free(url);
free(mem);
}
void http_server_process(struct netconn *conn)
{
struct netbuf *inbuf;
char *buf;
uint16_t buflen;
if (netconn_recv(conn, &inbuf) == ERR_OK) {
if (netconn_err(conn) == ERR_OK) {
netbuf_data(inbuf, (void **)&buf, &buflen);
process_http_request(buf, buflen);
}
netconn_close(conn);
netbuf_delete(inbuf);
}
}
void http_server_thread(void *arg)
{
// httpd_init();
struct netconn *conn, *newconn;
LWIP_UNUSED_ARG(arg);
/* create a new tcp connection handle */
conn = netconn_new(NETCONN_TCP);
if (conn != NULL) {
/* bind to port 80 HTTP whit default IP addr */
if (netconn_bind(conn, IP4_ADDR_ANY, HTTP_SERVER_PORT) == ERR_OK) {
/* start listening port */
netconn_listen(conn);
OS_MSG("http server listen :%d", HTTP_SERVER_PORT);
while (1) {
if (netconn_accept(conn, &newconn) == ERR_OK) {
if (newconn == NULL) {
OS_MSG("[ERROR]");
}
http_active_conn = newconn;
http_server_process(newconn);
http_active_conn = NULL;
netconn_delete(newconn);
}
}
}
}
}
void http_server_init(void)
{
// sys_thread_new("http_server", http_server_thread, NULL, 512, 2);
xTaskCreateStatic((void *)http_server_thread, (char *)"http_server", sizeof(http_server_stack) / 4, NULL, osPriorityAboveNormal, http_server_stack, &http_server_handle);
}
#if LWIP_NETCONN
#ifndef HTTPD_DEBUG
#define HTTPD_DEBUG LWIP_DBG_OFF
#endif
static const char http_html_hdr[] = "HTTP/1.1 200 OK\r\nContent-type: text/html\r\n\r\n";
static const char http_index_html[] = "<html><head><title>Congrats!</title></head><body><h1>Welcome to our lwIP HTTP server!</h1><p>This is a small test page, served by httpserver-netconn.</body></html>";
/** Serve one HTTP connection accepted in the http thread */
static void http_server_netconn_serve(struct netconn *conn)
{
struct netbuf *inbuf;
char *buf;
u16_t buflen;
err_t err;
/* Read the data from the port, blocking if nothing yet there.
We assume the request (the part we care about) is in one netbuf */
err = netconn_recv(conn, &inbuf);
if (err == ERR_OK) {
netbuf_data(inbuf, (void **)&buf, &buflen);
/* Is this an HTTP GET command? (only check the first 5 chars, since
there are other formats for GET, and we're keeping it very simple )*/
if (buflen >= 5 &&
buf[0] == 'G' &&
buf[1] == 'E' &&
buf[2] == 'T' &&
buf[3] == ' ' &&
buf[4] == '/') {
/* Send the HTML header
* subtract 1 from the size, since we dont send the \0 in the string
* NETCONN_NOCOPY: our data is const static, so no need to copy it
*/
err = netconn_write(conn, http_html_hdr, sizeof(http_html_hdr) - 1, NETCONN_COPY);
OS_MSG("netconn write!conn:0x%x err:%d\r\n", conn, err);
/* Send our HTML page */
err = netconn_write(conn, http_index_html, sizeof(http_index_html) - 1, NETCONN_NOCOPY);
OS_MSG("netconn write!conn:0x%x err:%d\r\n", conn, err);
}
}
/* Close the connection (server closes in HTTP) */
netconn_close(conn);
/* Delete the buffer (netconn_recv gives us ownership,
so we have to make sure to deallocate the buffer) */
netbuf_delete(inbuf);
}
/** The main function, never returns! */
static void http_server_netconn_thread(void *arg)
{
struct netconn *conn, *newconn;
err_t err;
LWIP_UNUSED_ARG(arg);
/* Create a new TCP connection handle */
/* Bind to port 80 (HTTP) with default IP address */
conn = netconn_new(NETCONN_TCP);
netconn_bind(conn, IP_ADDR_ANY, 80);
LWIP_ERROR("http_server: invalid conn", (conn != NULL), return;);
/* Put the connection into LISTEN state */
netconn_listen(conn);
OS_MSG("http server listen port: 80\r\n");
do {
err = netconn_accept(conn, &newconn);
if (err == ERR_OK) {
http_server_netconn_serve(newconn);
netconn_delete(newconn);
}
} while (err == ERR_OK);
LWIP_DEBUGF(HTTPD_DEBUG, ("http_server_netconn_thread: netconn_accept received error %d, shutting down", err));
netconn_close(conn);
netconn_delete(conn);
}
/** Initialize the HTTP server (start its thread) */
void http_server_netconn_init(void)
{
sys_thread_new("http_server_netconn", http_server_netconn_thread, NULL, DEFAULT_THREAD_STACKSIZE, osPriorityAboveNormal);
}
#endif /* LWIP_NETCONN*/