标题:
一个简单的嵌入式平台httpd服务器源程序
[打印本页]
作者:
alwaysman
时间:
2019-10-9 17:59
标题:
一个简单的嵌入式平台httpd服务器源程序
分享一个简单地http服务器源代码,适合于无系统的嵌入式平台。
0.png
(5.15 KB, 下载次数: 63)
下载附件
2019-10-10 01:16 上传
源程序如下:
/*
* httpd.c
*
* Created on: 2019年09月01日
* Author: YAO Zhanhong
*/
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <udelay.h>
#include "SPI_W5500/SPI_W5500.h"
#include "html.h"
#include "httpd.h"
#include "httpd_htm.h"
SOCKET l_http_socket = W5500_SOCKET_INVALID;
uint8_t l_request_buffer[HTTP_REQUEST_BUFF_SIZE]; /* Request的缓冲 */
uint16_t l_request_length; /* Request的长度 */
char* l_request_param_list[HTTP_REQUEST_PARAM_MAX]; /* Request的参数列表,指向l_request_buffer中的地址 */
uint16_t l_request_param_num; /* 解析后,Request的参数个数 */
char* l_request_method; /* 解析后,Request的方法 */
char* l_request_URL; /* 解析后,Request的URL */
char* l_request_version; /* 解析后,Request的版本 */
char* l_request_URI; /* 解析后,Request的URI */
char* l_request_content; /* 解析后,Request的正文 */
uint16_t l_request_content_len; /* 实际接收到的正文长度 */
uint16_t l_request_content_len_desired; /* 请求头中指示的Request的正文长度,即正文应收长度 */
uint16_t l_cur_process_pos; /* 指在Request缓冲中,当前处理到的位置 */
/*****************************************************************************************************************************
* 回调函数,由驱动循环调用,传递接收到的socket数据
* 在本函数中,将socket传递的数据追加到http服务器的处理缓冲中,具体的协议处理则在http服务器的loop中进行
* 因为一次接收可能无法将Request的全部请求数据传递完成,所以需要先缓冲起来,凑成足够大的request请求数据,在loop中集中处理
* 即使这样,由于缓冲有限,所以当POST数据超长时,服务器仍会无法处理
*****************************************************************************************************************************/
void on_http_request(SOCKET s_client, uint8_t* data, uint16_t data_len)
{
if ( l_http_socket != s_client )
{
return;
}
if (data != NULL && data_len > 0 )
{
for ( int i = 0; i < data_len; i++ )
{
printf("%c", data[i]);
}
printf("\n");
/* 把接收到的数据添加到request缓冲 */
if ( l_request_length + data_len <= HTTP_REQUEST_BUFF_SIZE )
{
memcpy( l_request_buffer + l_request_length, data, data_len );
l_request_length += data_len;
}
else
{
memcpy( l_request_buffer + l_request_length, data, HTTP_REQUEST_BUFF_SIZE - l_request_length );
l_request_length = HTTP_REQUEST_BUFF_SIZE;
}
}
}
/*****************************************************************************************************************************
* 重置全部request接收变量
*****************************************************************************************************************************/
void reset_request()
{
memset(l_request_buffer, 0, HTTP_REQUEST_BUFF_SIZE);
l_request_length = 0;
for (uint16_t i = 0; i < HTTP_REQUEST_PARAM_MAX; i++ )
{
l_request_param_list[i] = NULL;
}
l_request_param_num = 0;
l_request_method = NULL;
l_request_URL = NULL;
l_request_version = NULL;
l_request_URI = NULL;
l_request_content = NULL;
l_request_content_len = 0;
l_request_content_len_desired = 0;
l_cur_process_pos = 0;
}
/*****************************************************************************************************************************
* 获取完整的一行
* 返回值:该行的字符总数,包括结尾的回车换行,为0表示未找到结尾的回车换行
*****************************************************************************************************************************/
uint16_t get_line(uint8_t* data, uint16_t data_len)
{
uint16_t ret_len = 0;
if ( data != NULL && data_len >= 2 )
{
for ( uint16_t i = 0; i < data_len - 1; i++ )
{
if ( data[i] == 0x0D && data[i+1] == 0x0A )
{
ret_len = i + 2;
break;
}
}
}
return ret_len;
}
/*****************************************************************************************************************************
* 解析Request的第一行,即:方法/URL/版本
*****************************************************************************************************************************/
void parse_request_first(uint8_t* data, uint16_t data_len, char** method, char** URL, char** version)
{
uint16_t cur_pos = 0;
*method = NULL;
*URL = NULL;
*version = NULL;
if ( data != NULL && data_len >= 2 )
{
*method = (char *)data;
for ( uint16_t i = cur_pos; i < data_len; i++ )
{
if ( data[i] == 0x20 )
{
data[i] = 0;
cur_pos = i + 1;
break;
}
}
*URL = (char *)(data + cur_pos);
for ( uint16_t i = cur_pos; i < data_len; i++ )
{
if ( data[i] == 0x20 )
{
data[i] = 0;
cur_pos = i + 1;
break;
}
}
*version = (char *)(data + cur_pos);
for ( uint16_t i = cur_pos; i < data_len; i++ )
{
if ( data[i] == 0x0D )
{
data[i] = 0;
break;
}
}
}
}
/*****************************************************************************************************************************
* 解析Request头信息
*****************************************************************************************************************************/
void parse_request_header(uint8_t* data, uint16_t data_len, char** item, char** value)
{
uint16_t cur_pos = 0;
*item = NULL;
*value = NULL;
if ( data != NULL && data_len >= 2 )
{
*item = (char *)data;
for ( uint16_t i = cur_pos; i < data_len; i++ )
{
if ( data[i] == 0x3A ) /* 寻找":" */
{
data[i] = 0;
cur_pos = i + 1;
break;
}
}
*value = (char *)(data + cur_pos);
for ( uint16_t i = cur_pos; i < data_len; i++ )
{
if ( data[i] == 0x0D )
{
data[i] = 0;
break;
}
}
}
}
/*****************************************************************************************************************************
* 解析Request的传递参数
*****************************************************************************************************************************/
uint16_t parse_request_parameter(uint8_t* data, uint16_t data_len, char** param_list, uint16_t param_max)
{
uint16_t i;
uint16_t param_num = 0;
uint16_t param_pos = 0;
for ( uint16_t i = 0; i < param_max; i++ )
{
param_list[i] = NULL;
}
if ( data != NULL && data_len >= 0 )
{
while ( param_pos < data_len )
{
if ( param_num >= param_max )
{
break;
}
param_list[param_num] = (char *)(data + param_pos);
for ( i = param_pos; i < data_len; i++ )
{
if ( data[i] == 0x26 ) /* 判断是否有&符号 */
{
data[i] = 0;
param_pos = i + 1;
param_num++;
break;
}
}
if ( i == data_len )
{
param_num++;
break;
}
}
}
return param_num;
}
/*****************************************************************************************************************************
* 解析Request的URL
*****************************************************************************************************************************/
uint16_t parse_request_URL(uint8_t* data, char** URI, char** param_list, uint16_t param_max)
{
uint16_t i;
uint16_t url_len = 0;
uint16_t param_num = 0;
uint16_t param_pos = 0;
for ( uint16_t i = 0; i < param_max; i++ )
{
param_list[i] = NULL;
}
if ( data != NULL )
{
url_len = (uint16_t)strlen(data);
}
if ( url_len > 0 )
{
*URI = (char *)data;
if( url_len > 1 )
{
param_pos = url_len; /* 默认没有参数 */
for ( i = 0; i < url_len; i++ )
{
if ( data[i] == 0x3F ) /* 通过查找问号,来判断是否有参数 */
{
data[i] = 0;
param_pos = i + 1;
break;
}
}
if ( param_pos < url_len )
{
param_num = parse_request_parameter( data + param_pos, url_len - param_pos, param_list, param_max );
}
}
}
return param_num;
}
/**********************************************************************
* 服务器的出错响应
**********************************************************************/
void http_respond_error(SOCKET s_client, uint16_t err_code)
{
char buf[128];
uint8_t* html_data = NULL;
uint16_t html_file_len = 0;
uint16_t html_send_pos = 0;
uint16_t cur_send_len = 0;
switch (err_code)
{
case 400:
sprintf(buf, "HTTP/1.0 400 Bad Request\r\n");
html_data = g_Respond_400;
html_file_len = sizeof(g_Respond_400);
break;
case 404:
sprintf(buf, "HTTP/1.0 404 Not Found\r\n");
html_data = g_Respond_404;
html_file_len = sizeof(g_Respond_404);
break;
case 501:
sprintf(buf, "HTTP/1.0 501 Method Not Implemented\r\n");
html_data = g_Respond_501;
html_file_len = sizeof(g_Respond_501);
break;
case 505:
sprintf(buf, "HTTP/1.0 505 Nonsupport http Version\r\n");
html_data = g_Respond_505;
html_file_len = sizeof(g_Respond_505);
break;
default:
sprintf(buf, "HTTP/1.0 %d ERROR\r\n", err_code);
}
W5500_send(s_client, buf, strlen(buf));
sprintf(buf, HTTP_SERVER_STRING);
W5500_send(s_client, buf, strlen(buf));
sprintf(buf, "Content-Type: text/html\r\n");
W5500_send(s_client, buf, strlen(buf));
sprintf(buf, "Content-Length: %d\r\n", html_file_len);
W5500_send(s_client, buf, strlen(buf));
sprintf(buf, "\r\n");
W5500_send(s_client, buf, strlen(buf));
if ( html_data != NULL && html_file_len > 0 )
{
while ( html_send_pos < html_file_len )
{
if ( html_send_pos + 500 < html_file_len )
{
cur_send_len = W5500_send(s_client, html_data + html_send_pos, 500);
}
else
{
cur_send_len = W5500_send(s_client, html_data + html_send_pos, html_file_len - html_send_pos );
}
if ( cur_send_len == 0 )
{
break;
}
html_send_pos += cur_send_len;
}
}
}
void server_respond(s_client)
{
char buf[1024];
uint16_t html_file_len = 0;
uint16_t html_send_pos = 0;
uint16_t cur_send_len = 0;
//发送HTTP头
sprintf(buf, "HTTP/1.0 200 OK\r\n");
W5500_send(s_client, buf, strlen(buf));
sprintf(buf, HTTP_SERVER_STRING);
W5500_send(s_client, buf, strlen(buf));
sprintf(buf, "Content-Type: text/html\r\n");
W5500_send(s_client, buf, strlen(buf));
sprintf(buf, "\r\n");
W5500_send(s_client, buf, strlen(buf));
/*
*
sprintf(buf, "<HTML><HEAD><TITLE>MESH Node Configuration Site</TITLE></HEAD>\r\n");
W5500_send(s_client, buf, strlen(buf));
sprintf(buf, "<BODY bgcolor=\"BLUE\">\r\n");
W5500_send(s_client, buf, strlen(buf));
sprintf(buf, "<form action=\"/config\" method=\"POST\">用户名:<input type=\"text\" name=\"test_name\"><br /><br />密 码:<input type=\"text\" name=\"test_pwd\"><br /><br /><input type=\"submit\"><form>\r\n");
W5500_send(s_client, buf, strlen(buf));
sprintf(buf, "</BODY></HTML>\r\n");
W5500_send(s_client, buf, strlen(buf));
* */
html_file_len = sizeof(g_HTML_index);
while ( html_send_pos < html_file_len )
{
if ( html_send_pos + 500 < html_file_len )
{
cur_send_len = W5500_send(s_client, g_HTML_index + html_send_pos, 500);
}
else
{
cur_send_len = W5500_send(s_client, g_HTML_index + html_send_pos, html_file_len - html_send_pos );
}
html_send_pos += cur_send_len;
}
}
bool http_process_request(SOCKET s_client, char* URI, char** param_list, uint16_t param_num )
{
bool result = false;
if ( strcasecmp(URI, "/") == 0 )
{
server_respond(s_client);
result = true;
}
else if ( strcasecmp(URI, "/config") == 0 )
{
//result = true;
}
return result;
}
/**********************************************************************
* 服务器的loop
**********************************************************************/
void HTTP_loop()
{
char* requeset_header_item = NULL;
char* requeset_header_item_value = NULL;
uint16_t cur_request_line_len = 0;
bool result = false;
/* 如果缓冲包达到最大处理长度,则直接返回错误,关闭连接 */
if ( l_request_length == HTTP_REQUEST_BUFF_SIZE )
{
/* 格式错误,请求包数据超过处理上限 */
http_respond_error(l_http_socket, 400);
W5500_socket_TCP_close(l_http_socket);
reset_request();
return;
}
/* 判断当前是否正在接收正文 */
if ( l_request_content_len_desired > 0 )
{
/* 正在接收正文,此时仅增加正文长度即可 */
l_request_content_len += l_request_length - l_cur_process_pos;
l_cur_process_pos = l_request_length;
if ( l_request_content_len < l_request_content_len_desired )
{
/* 还没达到预期的正文长度,结束本次循环,待下次处理 */
return;
}
else if ( l_request_content_len > l_request_content_len_desired )
{
/* 格式错误,实际接收的正文长度已经超过请求头中的正文长度 */
http_respond_error(l_http_socket, 400);
W5500_socket_TCP_close(l_http_socket);
reset_request();
return;
}
else
{
/* 实际接收的正文长度与请求头中的正文长度一致,则继续处理 */
result = true;
}
}
else
{
/* 把需要的信息全都解析出来 */
while ( l_cur_process_pos < l_request_length )
{
/* 提取一行,获得该行长度 */
cur_request_line_len = get_line( l_request_buffer + l_cur_process_pos, l_request_length - l_cur_process_pos );
if ( cur_request_line_len > 2 )
{
/* 如果是第一行,则解析方法、URL和版本号 */
if ( l_cur_process_pos == 0 )
{
parse_request_first(l_request_buffer, cur_request_line_len, &l_request_method, &l_request_URL, &l_request_version);
}
else
{
/* 解析请求头信息 */
parse_request_header( l_request_buffer + l_cur_process_pos, cur_request_line_len, &requeset_header_item, &requeset_header_item_value );
if( requeset_header_item != NULL && requeset_header_item_value != NULL )
{
/* 必须至少解析正文长度 */
if ( strcasecmp(requeset_header_item, "Content-Length") == 0 )
{
sscanf(requeset_header_item_value, "%hu", &l_request_content_len_desired);
}
}
}
l_cur_process_pos += cur_request_line_len;
}
else if ( cur_request_line_len == 2 ) /* 这是一个空行,默认有消息正文 */
{
l_cur_process_pos += cur_request_line_len;
/* 如果空行之后还有数据,那就是正文 */
if ( l_cur_process_pos < l_request_length )
{
l_request_content = (char *)(l_request_buffer + l_cur_process_pos );
l_request_content_len = l_request_length - l_cur_process_pos;
}
}
else
{
/* 没有找到行,那说明已经达到最末端 */
l_cur_process_pos = l_request_length;
}
}
if ( l_request_content_len > 0 )
{
if ( l_request_content_len_desired == 0 )
{
/* 格式错误,请求头未包含正文数据长度 */
http_respond_error(l_http_socket, 400);
W5500_socket_TCP_close(l_http_socket);
reset_request();
return;
}
else
{
if ( l_request_content_len < l_request_content_len_desired )
{
/* 直接结束本次循环,待下次处理 */
return;
}
else if ( l_request_content_len > l_request_content_len_desired )
{
/* 格式错误,实际接收的正文长度已经超过请求头中的正文长度 */
http_respond_error(l_http_socket, 400);
W5500_socket_TCP_close(l_http_socket);
reset_request();
return;
}
else
{
/* 实际接收的正文长度与请求头中的正文长度一致,则继续处理 */
result = true;
}
}
}
else
{
if ( l_request_content_len_desired > 0 )
{
/* 格式错误,请求头中的正文长度 不为0,但接收的正文长度为0 */
http_respond_error(l_http_socket, 400);
W5500_socket_TCP_close(l_http_socket);
reset_request();
return;
}
else
{
/* 实际接收的正文长度与请求头中的正文长度一致,则继续处理 */
result = true;
}
}
}
/* 进行http响应,必须有请求数据,并且正文接收处理完成 */
if ( result && l_request_length > 0 )
{
/* 判断方法、URL和版本号是否正确 */
if ( l_request_method != NULL && strlen(l_request_method) > 0 &&
l_request_URL != NULL && strlen(l_request_URL) > 0 &&
l_request_version != NULL && strlen(l_request_version) > 0 )
{
if ( strcasecmp(l_request_version, "HTTP/0.9") == 0 ||
strcasecmp(l_request_version, "HTTP/1.0") == 0 ||
strcasecmp(l_request_version, "HTTP/1.1") == 0 )
{
/* 解析URL,获取URI,获取参数 */
l_request_param_num = parse_request_URL((uint8_t *)l_request_URL, &l_request_URI, l_request_param_list, HTTP_REQUEST_PARAM_MAX);
/* 根据解析结果进行处理 */
if ( strcasecmp(l_request_method, "GET") == 0 )
{
result = true;
}
else if ( strcasecmp(l_request_method, "POST") == 0 )
{
/* 解析正文,获取参数 */
l_request_param_num = parse_request_parameter((uint8_t *)l_request_content, l_request_content_len, l_request_param_list, HTTP_REQUEST_PARAM_MAX);
result = true;
}
else
{
result = false;
}
/* 可以处理 */
if ( result )
{
result = http_process_request(l_http_socket, l_request_URI, l_request_param_list, l_request_param_num);
if ( !result )
{
/* 没有发现资源 */
http_respond_error(l_http_socket, 501);
}
}
else
{
/* 仅仅实现了GET和POST */
http_respond_error(l_http_socket, 501);
}
}
else
{
/* 不支持的版本 */
http_respond_error(l_http_socket, 505);
}
}
else
{
/* 格式错误 */
http_respond_error(l_http_socket, 400);
}
/* 传输完成后,必须要切断连接 */
W5500_socket_TCP_close(l_http_socket);
reset_request();
}
}
/**********************************************************************
* 初始化,主程序调用
**********************************************************************/
void HTTP_init(SOCKET s)
{
reset_request();
if ( W5500_socket_TCP_Server( s, HTTP_SERVER_PORT_DEFAULT, on_http_request ) )
{
W5500_socket_TCP_listen( s );
l_http_socket = s;
}
}
复制代码
所有资料51hei提供下载:
httpd.rar
(4.62 KB, 下载次数: 8)
2019-10-9 17:58 上传
点击文件名下载附件
http服务器源代码
下载积分: 黑币 -5
作者:
wofei1314
时间:
2019-10-17 11:44
谢谢分享~
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1