|
分享一個(gè)簡(jiǎn)單地http服務(wù)器源代碼,適合于無系統(tǒng)的嵌入式平臺(tái)。
0.png (5.15 KB, 下載次數(shù): 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的參數(shù)列表,指向l_request_buffer中的地址 */
- uint16_t l_request_param_num; /* 解析后,Request的參數(shù)個(gè)數(shù) */
- 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; /* 實(shí)際接收到的正文長度 */
- uint16_t l_request_content_len_desired; /* 請(qǐng)求頭中指示的Request的正文長度,即正文應(yīng)收長度 */
- uint16_t l_cur_process_pos; /* 指在Request緩沖中,當(dāng)前處理到的位置 */
- /*****************************************************************************************************************************
- * 回調(diào)函數(shù),由驅(qū)動(dòng)循環(huán)調(diào)用,傳遞接收到的socket數(shù)據(jù)
- * 在本函數(shù)中,將socket傳遞的數(shù)據(jù)追加到http服務(wù)器的處理緩沖中,具體的協(xié)議處理則在http服務(wù)器的loop中進(jìn)行
- * 因?yàn)橐淮谓邮湛赡軣o法將Request的全部請(qǐng)求數(shù)據(jù)傳遞完成,所以需要先緩沖起來,湊成足夠大的request請(qǐng)求數(shù)據(jù),在loop中集中處理
- * 即使這樣,由于緩沖有限,所以當(dāng)POST數(shù)據(jù)超長時(shí),服務(wù)器仍會(huì)無法處理
- *****************************************************************************************************************************/
- 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");
- /* 把接收到的數(shù)據(jù)添加到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;
- }
- /*****************************************************************************************************************************
- * 獲取完整的一行
- * 返回值:該行的字符總數(shù),包括結(jié)尾的回車換行,為0表示未找到結(jié)尾的回車換行
- *****************************************************************************************************************************/
- 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的傳遞參數(shù)
- *****************************************************************************************************************************/
- 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 ) /* 判斷是否有&符號(hào) */
- {
- 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; /* 默認(rèn)沒有參數(shù) */
- for ( i = 0; i < url_len; i++ )
- {
- if ( data[i] == 0x3F ) /* 通過查找問號(hào),來判斷是否有參數(shù) */
- {
- 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;
- }
- /**********************************************************************
- * 服務(wù)器的出錯(cuò)響應(yīng)
- **********************************************************************/
- 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;
- //發(fā)送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;
- }
- /**********************************************************************
- * 服務(wù)器的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;
- /* 如果緩沖包達(dá)到最大處理長度,則直接返回錯(cuò)誤,關(guān)閉連接 */
- if ( l_request_length == HTTP_REQUEST_BUFF_SIZE )
- {
- /* 格式錯(cuò)誤,請(qǐng)求包數(shù)據(jù)超過處理上限 */
- http_respond_error(l_http_socket, 400);
- W5500_socket_TCP_close(l_http_socket);
- reset_request();
- return;
- }
- /* 判斷當(dāng)前是否正在接收正文 */
- if ( l_request_content_len_desired > 0 )
- {
- /* 正在接收正文,此時(shí)僅增加正文長度即可 */
- 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 )
- {
- /* 還沒達(dá)到預(yù)期的正文長度,結(jié)束本次循環(huán),待下次處理 */
- return;
- }
- else if ( l_request_content_len > l_request_content_len_desired )
- {
- /* 格式錯(cuò)誤,實(shí)際接收的正文長度已經(jīng)超過請(qǐng)求頭中的正文長度 */
- http_respond_error(l_http_socket, 400);
- W5500_socket_TCP_close(l_http_socket);
- reset_request();
- return;
- }
- else
- {
- /* 實(shí)際接收的正文長度與請(qǐng)求頭中的正文長度一致,則繼續(xù)處理 */
- 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和版本號(hào) */
- 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
- {
- /* 解析請(qǐng)求頭信息 */
- 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 ) /* 這是一個(gè)空行,默認(rèn)有消息正文 */
- {
- l_cur_process_pos += cur_request_line_len;
- /* 如果空行之后還有數(shù)據(jù),那就是正文 */
- 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
- {
- /* 沒有找到行,那說明已經(jīng)達(dá)到最末端 */
- l_cur_process_pos = l_request_length;
- }
- }
- if ( l_request_content_len > 0 )
- {
- if ( l_request_content_len_desired == 0 )
- {
- /* 格式錯(cuò)誤,請(qǐng)求頭未包含正文數(shù)據(jù)長度 */
- 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 )
- {
- /* 直接結(jié)束本次循環(huán),待下次處理 */
- return;
- }
- else if ( l_request_content_len > l_request_content_len_desired )
- {
- /* 格式錯(cuò)誤,實(shí)際接收的正文長度已經(jīng)超過請(qǐng)求頭中的正文長度 */
- http_respond_error(l_http_socket, 400);
- W5500_socket_TCP_close(l_http_socket);
- reset_request();
- return;
- }
- else
- {
- /* 實(shí)際接收的正文長度與請(qǐng)求頭中的正文長度一致,則繼續(xù)處理 */
- result = true;
- }
- }
- }
- else
- {
- if ( l_request_content_len_desired > 0 )
- {
- /* 格式錯(cuò)誤,請(qǐng)求頭中的正文長度 不為0,但接收的正文長度為0 */
- http_respond_error(l_http_socket, 400);
- W5500_socket_TCP_close(l_http_socket);
- reset_request();
- return;
- }
- else
- {
- /* 實(shí)際接收的正文長度與請(qǐng)求頭中的正文長度一致,則繼續(xù)處理 */
- result = true;
- }
- }
- }
- /* 進(jìn)行http響應(yīng),必須有請(qǐng)求數(shù)據(jù),并且正文接收處理完成 */
- if ( result && l_request_length > 0 )
- {
- /* 判斷方法、URL和版本號(hào)是否正確 */
- 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,獲取參數(shù) */
- l_request_param_num = parse_request_URL((uint8_t *)l_request_URL, &l_request_URI, l_request_param_list, HTTP_REQUEST_PARAM_MAX);
- /* 根據(jù)解析結(jié)果進(jìn)行處理 */
- if ( strcasecmp(l_request_method, "GET") == 0 )
- {
- result = true;
- }
- else if ( strcasecmp(l_request_method, "POST") == 0 )
- {
- /* 解析正文,獲取參數(shù) */
- 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 )
- {
- /* 沒有發(fā)現(xiàn)資源 */
- http_respond_error(l_http_socket, 501);
- }
- }
- else
- {
- /* 僅僅實(shí)現(xiàn)了GET和POST */
- http_respond_error(l_http_socket, 501);
- }
- }
- else
- {
- /* 不支持的版本 */
- http_respond_error(l_http_socket, 505);
- }
- }
- else
- {
- /* 格式錯(cuò)誤 */
- http_respond_error(l_http_socket, 400);
- }
- /* 傳輸完成后,必須要切斷連接 */
- W5500_socket_TCP_close(l_http_socket);
- reset_request();
- }
- }
- /**********************************************************************
- * 初始化,主程序調(diào)用
- **********************************************************************/
- 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;
- }
- }
復(fù)制代碼
所有資料51hei提供下載:
httpd.rar
(4.62 KB, 下載次數(shù): 8)
2019-10-9 17:58 上傳
點(diǎn)擊文件名下載附件
http服務(wù)器源代碼 下載積分: 黑幣 -5
|
評(píng)分
-
查看全部評(píng)分
|