F1CTL/Core/Src/http_server.c
2024-12-15 14:07:02 +08:00

197 lines
6.2 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "http_server.h"
// HTML页面模板
#include "html_files.h"
// 解析HTTP请求
static void parse_http_request(uint8_t* buffer, uint16_t length, http_request* req)
{
char* method = strtok((char*)buffer, " ");
char* uri = strtok(NULL, " ");
if(strcmp(method, "GET") == 0) {
req->method = HTTP_GET;
} else if(strcmp(method, "POST") == 0) {
req->method = HTTP_POST;
} else {
req->method = HTTP_UNKNOWN;
}
strncpy(req->uri, uri, MAX_URI_SIZE);
// 如果是POST请求查找请求体
if(req->method == HTTP_POST) {
char* body = strstr((char*)buffer, "\r\n\r\n");
if(body) {
body += 4;
req->body = (uint8_t*)body;
req->body_length = length - (body - (char*)buffer);
}
}
}
// 发送HTTP响应
static int send_all(uint8_t sn, const uint8_t* data, uint16_t length)
{
int total_sent = 0;
while (total_sent < length) {
int sent = send(sn, data + total_sent, length - total_sent);
if (sent <= 0) {
return -1; // 发送错误
}
total_sent += sent;
}
return total_sent;
}
static void send_chunked_response_header(uint8_t sn)
{
const char* header =
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n";
send_all(sn, (uint8_t*)header, strlen(header));
}
static void send_chunk(uint8_t sn, const char* data, uint16_t length)
{
char chunk_header[10];
sprintf(chunk_header, "%X\r\n", length);
send_all(sn, (uint8_t*)chunk_header, strlen(chunk_header));
send_all(sn, (uint8_t*)data, length);
send_all(sn, (uint8_t*)"\r\n", 2);
}
static void send_chunk_end(uint8_t sn)
{
send_all(sn, (uint8_t*)"0\r\n\r\n", 5);
}
#define CHUNK_SIZE 512
// 处理配置页面请求
static void handle_config_page(uint8_t sn)
{
char buffer[CHUNK_SIZE];
bool is_connected = (wizphy_getphylink() == PHY_LINK_ON);
char* link_status = is_connected ? "Connected" : "Disconnected";
char* status_class = is_connected ? "connected" : "disconnected";
// 先将完整的HTML内容格式化到一个临时缓冲区
char full_page[8192]; // 确保足够大
int total_len = sprintf(full_page, index_html,
gWIZNETINFO.mac[0], gWIZNETINFO.mac[1], gWIZNETINFO.mac[2],
gWIZNETINFO.mac[3], gWIZNETINFO.mac[4], gWIZNETINFO.mac[5],
gWIZNETINFO.ip[0], gWIZNETINFO.ip[1], gWIZNETINFO.ip[2], gWIZNETINFO.ip[3],
gWIZNETINFO.sn[0], gWIZNETINFO.sn[1], gWIZNETINFO.sn[2], gWIZNETINFO.sn[3],
gWIZNETINFO.gw[0], gWIZNETINFO.gw[1], gWIZNETINFO.gw[2], gWIZNETINFO.gw[3],
status_class, link_status);
// 发送响应头
send_chunked_response_header(sn);
// 分块发送内容
int sent = 0;
while (sent < total_len) {
int chunk_len = (total_len - sent) > CHUNK_SIZE ? CHUNK_SIZE : (total_len - sent);
memcpy(buffer, full_page + sent, chunk_len);
send_chunk(sn, buffer, chunk_len);
sent += chunk_len;
}
// 发送结束块
send_chunk_end(sn);
}
// 解析并更新网络配置
static void update_network_config(const char* body)
{
char mac[18], ip[16], subnet[16], gateway[16];
uint32_t mac_values[6], ip_values[4], subnet_values[4], gateway_values[4];
if(sscanf(body, "mac=%02X%%3A%02X%%3A%02X%%3A%02X%%3A%02X%%3A%02X&"
"ip=%d.%d.%d.%d&"
"subnet=%d.%d.%d.%d&"
"gateway=%d.%d.%d.%d",
&mac_values[0], &mac_values[1], &mac_values[2],
&mac_values[3], &mac_values[4], &mac_values[5],
&ip_values[0], &ip_values[1], &ip_values[2], &ip_values[3],
&subnet_values[0], &subnet_values[1], &subnet_values[2], &subnet_values[3],
&gateway_values[0], &gateway_values[1], &gateway_values[2], &gateway_values[3]) == 18)
{
// 更新MAC地址
for(int i = 0; i < 6; i++) {
gWIZNETINFO.mac[i] = (uint8_t)mac_values[i];
}
// 更新IP地址
for(int i = 0; i < 4; i++) {
gWIZNETINFO.ip[i] = (uint8_t)ip_values[i];
gWIZNETINFO.sn[i] = (uint8_t)subnet_values[i];
gWIZNETINFO.gw[i] = (uint8_t)gateway_values[i];
}
// 应用新的网络配置
wizchip_setnetinfo(&gWIZNETINFO);
}
}
void http_server_init(void)
{
// 创建服务器socket
socket(HTTP_SERVER_SOCKET, Sn_MR_TCP, HTTP_SERVER_PORT, 0);
listen(HTTP_SERVER_SOCKET);
}
void http_server_task(void)
{
uint8_t buffer[2048];
uint16_t size;
uint8_t status = getSn_SR(HTTP_SERVER_SOCKET);
switch(status)
{
case SOCK_LISTEN:
// 等待连接
break;
case SOCK_ESTABLISHED:
{
// 接收数据
if((size = getSn_RX_RSR(HTTP_SERVER_SOCKET)) > 0)
{
size = recv(HTTP_SERVER_SOCKET, buffer, sizeof(buffer));
if(size > 0)
{
http_request req;
parse_http_request(buffer, size, &req);
if(req.method == HTTP_GET) {
handle_config_page(HTTP_SERVER_SOCKET);
}
else if(req.method == HTTP_POST && strcmp(req.uri, "/config") == 0) {
update_network_config((char*)req.body);
// 重定向回配置页面
send_chunked_response_header(HTTP_SERVER_SOCKET);
send_chunk(HTTP_SERVER_SOCKET,
"<html><head><meta http-equiv='refresh' content='0;url=/'></head></html>",
strlen("<html><head><meta http-equiv='refresh' content='0;url=/'></head></html>"));
send_chunk_end(HTTP_SERVER_SOCKET);
}
}
}
break;
}
case SOCK_CLOSE_WAIT:
disconnect(HTTP_SERVER_SOCKET);
break;
case SOCK_CLOSED:
socket(HTTP_SERVER_SOCKET, Sn_MR_TCP, HTTP_SERVER_PORT, 0);
listen(HTTP_SERVER_SOCKET);
break;
}
}