分享一个简单地http服务器源代码,适合于无系统的嵌入式平台。
源程序如下:
- /*
- * 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)
|