Files
TAIXIN/sdk/lib/net/http/http.c

1821 lines
51 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 <csi_config.h>
// #include <test_kernel_config.h>
#include "csi_kernel.h"
#include "lwip/netif.h"
#include "lwip/inet.h"
#include "lwip/sockets.h"
#include "netif/ethernetif.h"
#include "typesdef.h"
#include "osal/mutex.h"
#include "lib/net/eloop/eloop.h"
#include "event.h"
#include "sys_config.h"
#include "lwip/tcpip.h"
#include "osal/sleep.h"
#include "dev/csi/hgdvp.h"
#include "list.h"
#include "dev.h"
#include "devid.h"
#include "osal/irq.h"
#include "osal/string.h"
#include "dev/jpg/hgjpg.h"
#include "jpgdef.h"
#include "lib/video/dvp/jpeg/jpg.h"
#include "osal/msgqueue.h"
#include "basic_include.h"
#include "cjson/cJSON.h"
#include "http.h"
#include "netif/ethernet.h"
#include "lwip/def.h"
#include "lwip/stats.h"
#include "lwip/etharp.h"
#include "lwip/ip.h"
#include "lwip/snmp.h"
#include "syscfg.h"
#include "fs/fatfs/osal_file.h"
#include "app/video_app/file_thumb.h"
#include "video_app_h264_msi.h"
#include "audio_media_ctrl/audio_code_ctrl.h"
#include "audio_msi/audio_adc.h"
#define addWeb(web, url, type,reponse,queue) { url,type,reponse,queue }
// 结构体申请空间函数
#ifdef MORE_SRAM
#define STREAM_LIBC_MALLOC os_malloc_psram
#define STREAM_LIBC_FREE os_free_psram
#define STREAM_LIBC_ZALLOC os_zalloc_psram
#else
#define STREAM_LIBC_MALLOC os_malloc
#define STREAM_LIBC_FREE os_free
#define STREAM_LIBC_ZALLOC os_zalloc
#endif
extern struct msi *h264_msi_init();
extern struct msi *mp4_encode_msi_init(const char *mp4_msi_name,uint16_t filter_type);
extern struct msi *jpg_thumb_msi_init(const char *msi_name, uint16_t filter);
void free_http_head(struct httpresp *resp);
typedef char *ERR_STR;
#define WEBURLNUM 5
const char *const http404 = "<html><body><p>URL is err</p></body></html>";
const char webstr_ret[][100] = {
{"<html>\r\n"},
{"<head>\r\n"},
{" <meta http-equiv=\"refresh\" content=\"0; url=/web\" />\r\n"},
{"</head>\r\n"},
{"<body>\r\n"},
{"</body>\r\n"},
{"</html>\r\n"},
};
const char webstr[][200] = {
{"<!DOCTYPE html>\r\n"},
{"<html lang=\"zh\">\r\n"},
{"<head>\r\n"},
{" <meta charset=\"UTF-8\">\r\n"},
{" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n"},
{" <title>EAGLE 功能选择</title>\r\n"},
{" <style>\r\n"},
{" body { \r\n"},
{" font-family: Arial, sans-serif;\r\n"},
{" margin: 0;\r\n"},
{" background-color: #e0f7fa; /* 浅蓝色背景 */\r\n"},
{"}\r\n"},
{"\r\n"},
{"/* 包含整个内容的大矩形容器 */\r\n"},
{".container-wrapper {\r\n"},
{" display: flex;\r\n"},
{" justify-content: center;\r\n"},
{" align-items: center;\r\n"},
{" min-height: 100vh;\r\n"},
{" padding: 20px;\r\n"},
{"}\r\n"},
{"\r\n"},
{"/* 页面主要内容容器 */\r\n"},
{".container {\r\n"},
{" display: flex;\r\n"},
{" flex-direction: column;\r\n"},
{" align-items: center;\r\n"},
{" padding: 20px;\r\n"},
{" background-color: #ffffff; /* 白色背景 */\r\n"},
{" border-radius: 20px; /* 圆角效果 */\r\n"},
{" box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 轻微阴影 */\r\n"},
{" width: 100%;\r\n"},
{" max-width: 800px; /* 最大宽度 */\r\n"},
{"}\r\n"},
{"\r\n"},
{"/* 顶部标题样式 */\r\n"},
{".header-title {\r\n"},
{" font-size: 28px; /* 大字体大小 */\r\n"},
{" font-weight: bold;\r\n"},
{" color: #000; /* 黑色字体 */\r\n"},
{" margin-bottom: 10px; /* 与内容间距 */\r\n"},
{"}\r\n"},
{"\r\n"},
{"/* 标题区域的样式 */\r\n"},
{".title-box {\r\n"},
{" display: flex;\r\n"},
{" align-items: center;\r\n"},
{" justify-content: center;\r\n"},
{" background-color: #ffffff; /* 白色背景 */\r\n"},
{" padding: 0px;\r\n"},
{" font-size: 16px; /* 与按钮一致 */\r\n"},
{" color: #0000CD; /* 按钮字体颜色 */\r\n"},
{" margin-bottom: 1px; /* 调整底部间距 */\r\n"},
{"}\r\n"},
{"/* 按钮容器的样式 */\r\n"},
{".button-box {\r\n"},
{" border: 2px solid #f0f0f0; /* 边框颜色为灰白色,边框宽度为 2px */\r\n"},
{" border-radius: 10px; /* 边框圆角半径设置为 10px */\r\n"},
{" padding: 10px; /* 内边距设置为 10px */\r\n"},
{" background-color: #ffffff; /* 白色背景 */\r\n"},
{" box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 轻微阴影 */\r\n"},
{" margin-top: 20px; /* 顶部外边距设置为 20px */\r\n"},
{" margin-bottom: 20px; /* 底部外边距设置为 20px */\r\n"},
{" width: 100%; /* 宽度设置为 100% */\r\n"},
{" max-width: 800px; /* 最大宽度设置为 800px */\r\n"},
{"}\r\n"},
{"\r\n"},
{"/* 按钮行的样式 */\r\n"},
{".button-row {\r\n"},
{" display: flex; /* 使用 Flexbox 布局 */\r\n"},
{" flex-wrap: wrap; /* 允许子元素换行 */\r\n"},
{" justify-content: center; /* 子元素在主轴方向居中对齐 */\r\n"},
{" margin: 0 -5px; /* 调整按钮行的左右间距 */\r\n"},
{"}\r\n"},
{"\r\n"},
{"/* 按钮的基本样式 */\r\n"},
{".button { \r\n"},
{" padding: 10px 20px; /* 内边距上下设置为 10px左右设置为 20px */\r\n"},
{" margin: 5px; /* 按钮之间的间距设置为 5px */\r\n"},
{" font-size: 16px; /* 字体大小设置为 16px */\r\n"},
{" cursor: pointer; /* 鼠标悬停时显示为手型 */\r\n"},
{" border: none; /* 去除按钮的边框 */\r\n"},
{" background-color: #f0f0f0; /* 背景颜色设置为灰色 */\r\n"},
{" color: #007bff; /* 按钮字体颜色设置为蓝色 */\r\n"},
{" border-radius: 10px; /* 边框圆角半径设置为 10px */\r\n"},
{" transition: background-color 0.3s, transform 0.2s; /* 设置背景颜色和变换的过渡效果 */\r\n"},
{" flex: 1 1 23%; /* 设置按钮的灵活性,基础宽度占容器的 23% */\r\n"},
{" box-sizing: border-box; /* 确保内边距和边框包含在元素宽度的计算中 */\r\n"},
{"}\r\n"},
{"\r\n"},
{"/* 鼠标悬停时按钮的样式 */\r\n"},
{".button:hover { \r\n"},
{" background-color: #b0b0b0; /* 悬停时按钮的背景颜色变为浅灰色 */\r\n"},
{" transform: scale(1.05); /* 鼠标悬停时按钮略微放大 */\r\n"},
{"}\r\n"},
{"\r\n"},
{"/* 底部小号字体标题样式 */\r\n"},
{".footer-title {\r\n"},
{" font-size: 14px; /* 小号字体 */\r\n"},
{" color: #000; /* 黑色字体 */\r\n"},
{" margin-top: 20px; /* 顶部间距 */\r\n"},
{" text-align: center; /* 居中对齐 */\r\n"},
{"}\r\n"},
{"\r\n"},
{"/* 媒体查询:在屏幕宽度小于 600px 时应用以下样式 */\r\n"},
{"@media (max-width: 600px) {\r\n"},
{" .button {\r\n"},
{" font-size: 14px; /* 减少按钮的字体大小 */\r\n"},
{" padding: 8px 16px; /* 减少按钮的内边距 */\r\n"},
{" flex: 1 1 22%; /* 调整按钮的宽度占比,以适应较小的屏幕 */\r\n"},
{" }\r\n"},
{" .button-row {\r\n"},
{" margin: 0 -3px; /* 调整按钮行的左右间距,以适应较小的屏幕 */\r\n"},
{" }\r\n"},
{"}\r\n"},
{"\r\n"},
{" </style>\r\n"},
{"</head>\r\n"},
{"<body>\r\n"},
{" <div class=\"container-wrapper\">\r\n"},
{" <div class=\"container\">\r\n"},
{" <!-- 顶部大标题 -->\r\n"},
{" <div class=\"header-title\">TaiXin V0.0.1</div>\r\n"},
{" \r\n"},
{" <!-- 功能选择部分 -->\r\n"},
{" <header class=\"title-box\">MODULE styels</header>\r\n"},
{" <div class=\"button-box\">\r\n"},
{" <div class=\"button-row\">\r\n"},
{" <button class=\"button\" onclick=\"location.href='/button?btn=1'\" aria-label=\"选择功能 1 绿色\">w264</button>\r\n"},
{" <button class=\"button\" onclick=\"location.href='/button?btn=2'\" aria-label=\"选择功能 2 红色\">reserve1</button>\r\n"},
{" <button class=\"button\" onclick=\"location.href='/button?btn=3'\" aria-label=\"选择功能 3 蓝色\">reserve2</button>\r\n"},
{" <button class=\"button\" onclick=\"location.href='/button?btn=4'\" aria-label=\"选择功能 4 白色\">reserve3</button>\r\n"},
{" </div>\r\n"},
{" <div class=\"button-row\">\r\n"},
{" <button class=\"button\" onclick=\"location.href='/button?btn=5'\" aria-label=\"选择功能 5\">reserve4</button>\r\n"},
{" <button class=\"button\" onclick=\"location.href='/button?btn=6'\" aria-label=\"选择功能 6\">reserve5</button>\r\n"},
{" <button class=\"button\" onclick=\"location.href='/button?btn=7'\" aria-label=\"选择功能 7\">reserve6</button>\r\n"},
{" <button class=\"button\" onclick=\"location.href='/button?btn=8'\" aria-label=\"选择功能 8\">reserve7</button>\r\n"},
{" </div>\r\n"},
{" </div>\r\n"},
{"\r\n"},
// {" <!-- 车标部分 -->\r\n"},
// {" <header class=\"title-box\">Logo</header>\r\n"},
// {" <div class=\"button-box\">\r\n"},
// {" <div class=\"button-row\">\r\n"},
// {" <button class=\"button\" onclick=\"location.href='/button_logo?btn=9'\" aria-label=\"选择车标 1\">BMW</button>\r\n"},
// {" <button class=\"button\" onclick=\"location.href='/button_logo?btn=10'\" aria-label=\"选择车标 2\">Benz</button>\r\n"},
// {" </div>\r\n"},
// {" </div>\r\n"},
// {"\r\n"},
// {" <!-- 自定义部分 -->\r\n"},
// {" <header class=\"title-box\">Customize</header>\r\n"},
// {" <div class=\"button-box\">\r\n"},
// {" <div class=\"button-row\">\r\n"},
// {" <button class=\"button\" onclick=\"location.href='/button?btn=11'\" aria-label=\"选择自定义 1\">GIF</button>\r\n"},
// {" <button class=\"button\" onclick=\"location.href='/button?btn=12'\" aria-label=\"选择自定义 2\">IMAGE</button>\r\n"},
// {" </div>\r\n"},
// {" </div>\r\n"},
// {" \r\n"},
{" <!-- 底部小号字体标题 -->\r\n"},
{" <div class=\"footer-title\">If it does not display, please refresh or reset</div>\r\n"},
{" <div class=\"footer-title\">Just for test demo</div>\r\n"},
{" </div>\r\n"},
{" </div>\r\n"},
{"</body>\r\n"},
{"</html>\r\n"},
{"\r\n"},
};
//static struct url getweb;
//static struct url postweb;
static struct settingJson postSetting;
#ifndef INVALID_SOCKET
#define INVALID_SOCKET ~0
#endif
// http回应的一些字段
struct httpIndex const httpIndex = {.Type = "Content-Type", .Length = "Content-Length", .Disposition = "Content-Disposition", .Connection = "Connection",.Accept_Range = "Accept-Ranges"};
#define ISSOCKHANDLE(x) (x != INVALID_SOCKET)
int osal_set_tcp_nodelay(SOCK_HDL fd, int o)
{
uint8_t opt = o;
return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, sizeof opt);
}
int osal_set_reuseaddr(SOCK_HDL fd, int o)
{
uint8_t opt = o;
return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof opt);
}
void osal_socket_close(SOCK_HDL fd)
{
if (ISSOCKHANDLE(fd))
{
closesocket(fd);
}
else
_os_printf("socket close fail\n");
}
void http_reponse_web(struct httpClient *httpClient);
void http_reponse_ret(struct httpClient *httpClient);
static struct url getweb[] =
{
addWeb(web, "", 1, http_send_error, NULL),
addWeb(web, "web", 1, http_reponse_web, NULL),
};
// 初始化
void initJson(struct settingJson *json)
{
json->key = NULL;
json->type = 0;
json->reponse = NULL;
json->next = NULL;
}
// 添加json方法
void addJson(struct settingJson *json, char *key, char type, jsonReponse reponse)
{
struct settingJson *mjson = json;
struct settingJson *add = STREAM_LIBC_MALLOC(sizeof(struct settingJson));
while (mjson->next)
{
mjson = mjson->next;
}
add->next = NULL;
add->type = type;
add->key = STREAM_LIBC_MALLOC(strlen(key) + 1);
memcpy(add->key, key, strlen(key) + 1);
add->reponse = reponse;
mjson->next = add;
}
// 配置json拥有的方法
void default_json(struct settingJson *json)
{
addJson(json, "timer", cJSON_Number, NULL);
}
// 执行json中的函数
void executeJson(struct settingJson *json, cJSON *cJSON)
{
struct settingJson *Njson = json;
while (1)
{
if (!Njson)
{
break;
}
if (Njson->type == cJSON->type && !strcmp(Njson->key, cJSON->string))
{
_os_printf("found json:%s->type:%d\r\n", Njson->key, Njson->type);
if (Njson->reponse)
{
Njson->reponse(Njson, cJSON);
}
else
{
_os_printf("json->reponse is NULL!\r\n");
}
break;
}
Njson = Njson->next;
}
}
#if 0
static void initWeb(struct url *web)
{
web->url = NULL;
web->type = 1;
web->reponse = http_reponse_web;//http_send_error; // http_reponse_web;//http_send_error;
web->queue = NULL;
web->next = NULL;
}
// web方法添加
void addWeb(struct url *web, const char *url, char type, http_reponse reponse, http_queue queue)
{
_os_printf("url:%s\r\n", url);
struct url *addweb = web;
struct url *add = STREAM_LIBC_MALLOC(sizeof(struct url));
while (addweb->next)
{
addweb = addweb->next;
//_os_printf("test:%d\turl:%s\r\n",addweb->type,addweb->url);
}
add->next = NULL;
add->type = type;
add->queue = queue;
add->reponse = reponse;
add->url = url;
addweb->next = add;
}
#endif
void http_reponse_button1(struct httpClient *httpClient)
{
http_reponse_ret(httpClient);
}
// get方法的一些配置
void default_getweb(struct url *web)
{
//addWeb(web, "button?btn=1", 1, http_reponse_button1, NULL);
}
// post方法的一些配置
void default_postweb(struct url *web)
{
//addWeb(web, "test", 1, http_post_Test, NULL);
}
// 初始化并申请空间给httpClient
struct httpClient *initHttpClient()
{
struct httpClient *httpClient = STREAM_LIBC_MALLOC(sizeof(struct httpClient));
if (!httpClient)
{
return NULL;
}
httpClient->fdClient = 0;
httpClient->httpserver = NULL;
// httpClient->http_request = NULL;
httpClient->web = NULL;
httpClient->pattern = NULL;
return httpClient;
}
// http缩略图需要的的缩略图有特定格式因此需要自己拍的格式才会读到正确
int http_thumb(void *fp)
{
uint32_t thumbLocate;
int thumbsize;
uint8_t buf[8];
int start = osal_ftell(fp);
osal_fread(buf, 1, 2, fp);
if (buf[0] != 0xff || buf[1] != 0xd8)
{
_os_printf("not photo!!!\r\n");
osal_fseek(fp, start);
return -1;
}
osal_fseek(fp, start + 20);
osal_fread(buf, 1, 8, fp);
//_os_printf("%x\t%x\t%x\t%x\r\n",buf[0],buf[1],buf[2],buf[3]);
if (buf[0] == 0xff && buf[1] == 0xe1 && buf[2] == 0x00 && buf[3] == 0x06)
{
memcpy(&thumbLocate, &buf[4], 4);
osal_fseek(fp, start + thumbLocate);
thumbsize = osal_fsize(fp) - thumbLocate;
_os_printf("thumbLocate:%d\r\n", thumbLocate);
return thumbsize;
}
else
{
_os_printf("%x\t%x\t%x\t%x\r\n", buf[0], buf[1], buf[2], buf[3]);
_os_printf("not our photo!!!\r\n");
osal_fseek(fp, start);
return -2;
}
}
// 寻找AVI缩略图的位置,返回相对本帧图片的缩略图位置,并且偏移到对应位置,最后直接读取缩略图大小即可
int http_avi_thumb_Locate(void *fp)
{
int thumbLocate;
uint8_t buf[8];
// 该帧的起始位置
int start = osal_ftell(fp);
osal_fread(buf, 1, 2, fp);
if (buf[0] != 0xff || buf[1] != 0xd8)
{
_os_printf("not photo!!!\r\n");
// uartPrintfBuf(buf, 2);
// osal_fseek(fp,start);
osal_fclose(fp);
return -1;
}
osal_fseek(fp, start + 20);
osal_fread(buf, 1, 8, fp);
//_os_printf("%x\t%x\t%x\t%x\r\n",buf[0],buf[1],buf[2],buf[3]);
if (buf[0] == 0xff && buf[1] == 0xe1 && buf[2] == 0x00 && buf[3] == 0x06)
{
memcpy(&thumbLocate, &buf[4], 4);
osal_fseek(fp, start + thumbLocate);
_os_printf("thumbLocate:%d\r\n", thumbLocate);
return thumbLocate;
}
else
{
_os_printf("%x\t%x\t%x\t%x\r\n", buf[0], buf[1], buf[2], buf[3]);
_os_printf("not our photo!!!\r\n");
osal_fseek(fp, start);
return -2;
}
}
// 读取一行,以\r\n代表回车主要用于http请求字段
static uint8_t readline(char *buf, uint32_t *len)
{
uint32_t lineLen = 0;
// uartPrintfBuf(buf,4);
if (*buf == 0 || *buf == '\0')
{
return 2; // 结束,代表该字符串没有任何数据
}
if (*buf == '\r' && *(buf + 1) == '\n')
{
return 3; // http头部分结束,空一行
}
while (1)
{
if (*buf == 0)
{
return 1; // 无检测到换行符
}
else
{
if (*buf == '\r' && *(buf + 1) == '\n')
{
*len = lineLen + 2;
return 0; // 检测到换行符号
}
buf++;
lineLen++;
}
}
}
// 这是对GET请求字段的判断因为与其他字段不同所以单独判断
void parseGet(char *recBuf, struct httpEntry *http)
{
uint8_t len = 0;
char *src = recBuf;
while (*recBuf != ' ' && *recBuf)
{
len++;
recBuf++;
}
char *method = STREAM_LIBC_MALLOC(len + 1);
memcpy(method, src, len);
*(method + len) = '\0';
recBuf++;
src = recBuf;
len = 0;
while (*recBuf != ' ' && *recBuf)
{
len++;
recBuf++;
}
char *url = STREAM_LIBC_MALLOC(len + 1);
memcpy(url, src, len);
*(url + len) = '\0';
http->key = method;
http->value = url;
http->next = NULL;
_os_printf("url:%s\r\n", url);
}
// 解析某一段字符串是否为http请求的字段
// 格式: key: value
// 这段解析根据chrome浏览器的格式所以是针对性的可能不适合其他地方例如冒号后面有一个空格程序中直接跳过而不是对空格判断
void parseRequest(char *recBuf, uint8_t buflen, struct httpEntry *http)
{
uint8_t len = 0;
char *src = recBuf;
struct httpEntry *httpNext = STREAM_LIBC_MALLOC(sizeof(struct httpEntry));
while (http->next)
{
http = http->next;
}
http->next = httpNext;
while (*recBuf != ':' && *recBuf)
{
if (len >= buflen)
{
break;
}
len++;
recBuf++;
}
char *index = STREAM_LIBC_MALLOC(len + 1);
memcpy(index, src, len);
*(index + len) = '\0';
recBuf += 2;
len += 3;
src = recBuf;
char *value;
// 如果非正常情况下会导致buflen(一行数据的长度)也没有找到":",应该是错误的
// 未经过验证
if (buflen >= len)
{
value = STREAM_LIBC_MALLOC(buflen - len + 1);
memcpy(value, src, buflen - len);
*(value + buflen - len) = '\0';
}
else
{
value = STREAM_LIBC_MALLOC(1);
*value = '\0';
}
httpNext->key = index;
httpNext->value = value;
httpNext->next = NULL;
}
// post内容
void postContent(char *recBuf, uint8_t buflen, struct httpEntry *http)
{
struct httpEntry *httpNext = STREAM_LIBC_MALLOC(sizeof(struct httpEntry));
while (http->next)
{
http = http->next;
}
http->next = httpNext;
char *index = STREAM_LIBC_MALLOC(8);
char *value = STREAM_LIBC_MALLOC(buflen + 1);
memcpy(index, "Content", 7);
*(index + 7) = '\0';
memcpy(value, recBuf, buflen);
*(value + buflen) = '\0';
httpNext->key = index;
httpNext->value = value;
httpNext->next = NULL;
}
// 保存http请求头的信息
void http_request_msg(char *recBuf, struct httpEntry *http_request)
{
uint8_t times = 0;
uint8_t result = 0;
uint32_t len;
char *startBuf = recBuf;
while (1)
{
result = readline(recBuf, &len);
if (result != 0)
{
//_os_printf("result:%d\r\n",result);
if (result == 3) // 检测到有空的一行,\r\n 2字节
{
recBuf += 2; // 偏移2字节去掉空行
uint16_t contentLen = strlen(startBuf) - (recBuf - startBuf);
_os_printf("contentLen:%d\r\n", contentLen);
if (contentLen) // 代表空行后面还有内容,很有可能是post过来的内容
{
postContent(recBuf, contentLen, http_request);
}
}
break;
}
// 添加一个保存key与value的链表
times++;
if (times == 1)
{
// 第一次时解析http的get的头部,格式与后面数据不一样
parseGet(recBuf, http_request);
}
else
{
parseRequest(recBuf, len, http_request);
}
recBuf += len;
}
}
// 释放http请求头的空间
void free_request(struct httpEntry *http)
{
struct httpEntry *next = http;
struct httpEntry *current;
while (1)
{
if (next->next)
{
current = next;
next = next->next;
STREAM_LIBC_FREE(current->key);
STREAM_LIBC_FREE(current->value);
STREAM_LIBC_FREE(current);
}
else
{
if (next->value)
{
STREAM_LIBC_FREE(next->value);
}
if (next->key)
{
STREAM_LIBC_FREE(next->key);
}
STREAM_LIBC_FREE(next);
break;
}
}
}
// 打印接收到的请求字段现在按使用的是GET字段其他都没有进行判断
void print_request(struct httpEntry *http)
{
struct httpEntry *next = http;
while (1)
{
_os_printf("%s:%s\r\n", next->key, next->value);
if (next->next)
{
next = next->next;
}
else
{
break;
}
}
}
// 返回 NULL代表没有匹配成功 url:返回匹配成功的地址
// 地址的匹配
// 可能要修改web的遍历方式这样增加的时候可以改动小一点
// 暂时主要识别GET /test HTTP/1.1这部分字段
struct url *parsePath(struct httpEntry *http, struct url *gweb, struct url *pweb)
{
struct url *parseWeb;
if (!strcmp(http->key, "GET"))
{
_os_printf("\r\nenter GET!\r\n\r\n key:%s value:%s len:%d pattern:%s\r\n", http->key, http->value, sizeof(http->value), http->pattern);
if (http->value[0] != '/')
{
_os_printf("\r\nnot GET request!!!\r\n\r\n");
return NULL;
}
// 第一个保留为404页面
// 循环寻找web的get方法
parseWeb = gweb;
while (parseWeb && parseWeb->url)
{
// 完全匹配
if (parseWeb->type == 1)
{
if (!strcmp(&http->value[1], parseWeb->url))
{
_os_printf("parseWeb return:%x\r\n", parseWeb);
return parseWeb;
}
}
// 前部分匹配
else if (parseWeb->type == 2)
{
uint8_t len;
len = strlen(parseWeb->url);
char *pattern = STREAM_LIBC_MALLOC(len + 1);
memcpy(pattern, &http->value[1], len);
*(pattern + len) = '\0';
if (!strcmp(pattern, parseWeb->url))
{
http->pattern = &http->value[1 + len];
STREAM_LIBC_FREE(pattern);
return parseWeb;
}
STREAM_LIBC_FREE(pattern);
}
else
{
_os_printf("no parsePath!\r\n");
return NULL;
}
parseWeb++;
}
}
else if (!strcmp(http->key, "POST"))
{
_os_printf("enter POST!\r\n");
if (http->value[0] != '/')
{
_os_printf("not POST request!!!\r\n");
return NULL;
}
// 第一个保留为404页面
// 循环寻找web的get方法
parseWeb = pweb;
while (parseWeb && parseWeb->url)
{
//_os_printf("web%d url:%s\tvalue:%s\r\n",i,web[i].url,&http->value[1]);
// 完全匹配
if (parseWeb->type == 1)
{
if (!strcmp(&http->value[1], parseWeb->url))
{
_os_printf("parsePath1 correct:%s!!!\r\n", &http->value[1]);
return parseWeb;
}
}
// 前部分匹配
else if (parseWeb->type == 2)
{
uint8_t len;
len = strlen(parseWeb->url);
char *pattern = STREAM_LIBC_MALLOC(len + 1);
memcpy(pattern, &http->value[1], len);
*(pattern + len) = '\0';
//_os_printf("pattern:%s\r\n",pattern);
if (!strcmp(pattern, parseWeb->url))
{
http->pattern = &http->value[1 + len];
_os_printf("parsePath2 correct:%s!!!\r\n", http->pattern);
STREAM_LIBC_FREE(pattern);
return parseWeb;
}
STREAM_LIBC_FREE(pattern);
}
else
{
_os_printf("no this parseWeb type:%d!\r\n", parseWeb->type);
_os_printf("parseWeb:%X\r\n", parseWeb);
return NULL;
}
parseWeb++;
}
}
//_os_printf("not correct path!!!\r\n");
// 没有匹配的返回第一个都是null,没有太多实际作用
return NULL;
}
const uint8_t reponse2[] = "Hello!!!";
// 释放httpClient的资源包括socket和结构体其他需要释放的空间
void closeRes(struct httpClient *httpClient)
{
if(httpClient == NULL)
return;
if (httpClient->pattern)
{
_os_printf("pattern:%s\r\n", httpClient->pattern);
STREAM_LIBC_FREE(httpClient->pattern);
}
if (httpClient->http_request)
{
free_request(httpClient->http_request);
}
//检查是否发送完成
uint32_t start_time = os_jiffies();
while(!socket_done(httpClient->fdClient))
{
if(os_jiffies() - start_time > 1000)
{
break;
}
os_sleep_ms(10);
}
os_printf("done:%d\n",socket_done(httpClient->fdClient));
osal_socket_close(httpClient->fdClient);
}
// 释放httpClient的资源包括socket和结构体其他需要释放的空间
void closeKeepRes(struct httpClient *httpClient)
{
if (httpClient->pattern)
{
STREAM_LIBC_FREE(httpClient->pattern);
}
if (httpClient->http_request)
{
free_request(httpClient->http_request);
}
}
// 创建http头部和响应码
struct httpresp *http_create_reply(int code, char *reply)
{
uint32_t len;
struct httpresp *resp;
resp = STREAM_LIBC_MALLOC(sizeof(struct httpresp));
if (!resp)
{
return NULL;
}
resp->headbuf = STREAM_LIBC_MALLOC(1024);
resp->msgMaxLen = 1024;
resp->msgLen = 0;
resp->stat = 0;
len = sprintf(resp->headbuf, "HTTP/1.0 %d %s\r\n", code, reply);
resp->msgLen += len;
return resp;
}
// 头部添加
void http_add_header(struct httpresp *resp, const char *name, char *value)
{
if (resp->stat || !resp || !resp->headbuf)
{
_os_printf("http_add_header err!\r\n");
return;
}
//uint32_t len;
uint32_t headLen;
headLen = strlen(name) + strlen(value) + 4; // 包括4字节的: \r\n)
if (headLen + resp->msgLen > resp->msgMaxLen)
{
resp->stat = 1;
return;
}
sprintf(resp->headbuf + resp->msgLen, "%s: %s\r\n", name, value);
resp->msgLen += headLen;
}
// http头部发送,name应该是contentLen字段
// 头部的最后信息应该是内容的长度
int http_header_send(struct httpresp *resp, const char *name, uint32_t len, int fd)
{
int res;
char contentLen[10];
sprintf(contentLen, "%d\r\n", len);
http_add_header(resp, name, contentLen);
if (resp->stat || !resp || !resp->headbuf)
{
free_http_head(resp);
_os_printf("http header err!\r\n");
return -2;
}
res = send(fd, resp->headbuf, strlen(resp->headbuf), 0);
free_http_head(resp);
return res;
}
// 404返回
void http_send_error(struct httpClient *httpClient)
{
struct httpresp *head;
int fd = httpClient->fdClient;
head = http_create_reply(404, "Not Found");
http_add_header(head, httpIndex.Connection, "close");
http_add_header(head, httpIndex.Type, "text/html");
http_header_send(head, httpIndex.Length, strlen(http404), fd);
send(fd, http404, strlen(http404), 0);
closeRes(httpClient);
}
#define HTTPREADLEN 1460 + 0x10
// 文件内容发送传递的fp已经偏移好位置
int http_file_send(void *fp, int fd)
{
uint32_t len;
uint32_t total_len = 0;
int res = 0;
char *fileContent = STREAM_LIBC_MALLOC(HTTPREADLEN);
char *buf = (char*)(((uint32_t)fileContent + 0x10) & (~0x0f));
os_printf("content:%X\r\n", fileContent);
_os_printf("buf:%X\r\n", buf);
while (1)
{
len = osal_fread(buf, 1, HTTPREADLEN - 0x10, fp);
total_len += len;
//_os_printf("http file send:%d\r\n",len);
if (len == 0)
{
osal_fclose(fp);
// int iRecvLen = recv( fd, fileContent, 1023, 0);
STREAM_LIBC_FREE(fileContent);
os_printf("total_len:%d\r\n", total_len);
//_os_printf("http_file_send iRecvLen:%d\r\n",iRecvLen);
return res;
}
res = send(fd, buf, len, 0);
if (res == -1)
{
_os_printf("socket err!\r\n");
osal_fclose(fp);
STREAM_LIBC_FREE(fileContent);
return res;
}
}
}
int http_send(void *fp, int fd, uint32_t size)
{
uint32_t readlen = HTTPREADLEN - 0x10;
int len;
int res;
// 为了16byte对齐,所以要增加0x10
char *fileContent = STREAM_LIBC_MALLOC(HTTPREADLEN);
if (!fileContent)
{
// Todo:申请空间不足
return 1;
}
// 进行16byte对齐
char *buf =(char*)( ((uint32_t)fileContent + 0x10) & (~0x0f));
while (1)
{
if (size < readlen)
{
readlen = size;
}
len = osal_fread(buf, 1, readlen, fp);
if (len == 0)
{
res = 3;
break;
}
res = send(fd, buf, len, 0);
if (res < 0)
{
_os_printf("http_send err:%d!\r\n", res);
res = 2;
break;
}
size -= len;
if (size == 0)
{
res = 0;
break;
}
}
osal_fclose(fp);
STREAM_LIBC_FREE(fileContent);
return res;
}
// 释放http头部回应的空间
void free_http_head(struct httpresp *resp)
{
if (resp)
{
if (resp->headbuf)
{
STREAM_LIBC_FREE(resp->headbuf);
}
STREAM_LIBC_FREE(resp);
}
}
// static void http_reponse()
// 测试下载文件
void http_reponse_File(struct httpClient *httpClient)
{
int fd = httpClient->fdClient;
void *fp;
int res;
_os_printf("Line:%d\tfunc:%s\n", __LINE__, __FUNCTION__); // portMAX_DELAY
fp = osal_fopen("1:/AVI/AVI1.AVI", "rb");
if (fp == NULL)
{
goto FileFail;
}
struct httpresp *head;
head = http_create_reply(200, "OK");
http_add_header(head, httpIndex.Type, "application/force-download");
http_add_header(head, httpIndex.Connection, "close");
http_add_header(head, httpIndex.Disposition, "attachment; filename=AVI1.AVI");
res = http_header_send(head, httpIndex.Length, osal_fsize(fp), fd);
if (res < 0)
{
goto HeadSendErr;
}
// 文件发送
res = http_file_send(fp, fd);
if (res == -1)
{
goto SocketErr;
}
// 正常结束
goto ReleaseRes;
HeadSendErr:
_os_printf("HeadSenderr:%d!\r\n", res);
osal_fclose(fp);
goto ReleaseRes;
FileFail:
_os_printf("open file fail!\r\n");
goto ReleaseRes;
#if 0
FileNameErr:
_os_printf("file path err!!!\r\n");
goto ReleaseRes;
#endif
SocketErr:
_os_printf("socket err!!!\r\n");
goto ReleaseRes;
ReleaseRes:
closeRes(httpClient);
return;
}
// photo文件夹的原图查看
void new_http_reponse_OJpg(struct httpClient *httpClient)
{
char path[30];
void *fp;
int fd = httpClient->fdClient;
int res;
_os_printf("%s\r\n", __FUNCTION__);
_os_printf("fileName:%s\r\n", httpClient->pattern);
#if 1
sprintf(path, "%s%s", "1:/", httpClient->pattern);
_os_printf("path:%s\r\n", path);
fp = osal_fopen(path, "rb");
if (fp == NULL)
{
goto FileFail;
}
_os_printf("Line:%d\tfunc:%s\n", __LINE__, __FUNCTION__); // portMAX_DELAY
// 头发送
struct httpresp *head;
head = http_create_reply(200, "OK");
http_add_header(head, httpIndex.Type, "image/jpeg");
http_add_header(head, httpIndex.Connection, "close");
res = http_header_send(head, httpIndex.Length, osal_fsize(fp), fd);
if (res < 0)
{
goto HeadSendErr;
}
// 文件发送
res = http_file_send(fp, fd);
if (res == -1)
{
goto SocketErr;
}
#endif
// 正常结束
goto ReleaseRes;
HeadSendErr:
_os_printf("HeadSenderr:%d!\r\n", res);
osal_fclose(fp);
goto ReleaseRes;
FileFail:
_os_printf("open file fail!\r\n");
goto ReleaseRes;
#if 0
FileNameErr:
_os_printf("file path err!!!\r\n");
goto ReleaseRes;
#endif
SocketErr:
_os_printf("socket err!!!\r\n");
goto ReleaseRes;
ReleaseRes:
closeRes(httpClient);
return;
}
// photo中的缩略图查看
void new_http_reponse_TJpg(struct httpClient *httpClient)
{
char path[30];
void *fp;
int thumbsize;
int fd = httpClient->fdClient;
sprintf(path, "%s%s", "1:/", httpClient->pattern);
_os_printf("path:%s\r\n", path);
fp = osal_fopen(path, "rb");
if (fp == NULL)
{
goto FileFail;
}
thumbsize = http_thumb(fp);
if (thumbsize < 0)
{
goto ThumbFail;
}
// http头配置与发送
struct httpresp *head;
int res;
head = http_create_reply(200, "OK");
http_add_header(head, httpIndex.Type, "image/jpeg");
http_add_header(head, httpIndex.Connection, "close");
res = http_header_send(head, httpIndex.Length, thumbsize, fd);
if (res < 0)
{
_os_printf("socket err!\r\n");
goto HeadSendErr;
}
// 文件发送
res = http_file_send(fp, fd);
if (res == -1)
{
goto SocketErr;
}
// 正常结束
goto ReleaseRes;
HeadSendErr:
osal_fclose(fp);
_os_printf("HeadSenderr:%d!\r\n", res);
goto ReleaseRes;
FileFail:
_os_printf("open file fail!\r\n");
goto ReleaseRes;
#if 0
FileNameErr:
_os_printf("file path err!!!\r\n");
goto ReleaseRes;
#endif
SocketErr:
_os_printf("socket err!!!\r\n");
goto ReleaseRes;
ThumbFail:
_os_printf("http_thumb err!!!\r\n");
goto ReleaseRes;
ReleaseRes:
closeRes(httpClient);
return;
}
// photo中的缩略图查看
void http_reponse_TJpg(struct httpClient *httpClient)
{
char path[30];
void *fp;
int thumbsize;
int fd = httpClient->fdClient;
// 图片文件缩略图的一些判断
if (strlen(httpClient->pattern) > 12)
{
goto FileNameErr;
}
_os_printf("fileName:%s\r\n", httpClient->pattern);
sprintf(path, "%s%s", "1:/DCIM/", httpClient->pattern);
fp = osal_fopen(path, "rb");
if (fp == NULL)
{
goto FileFail;
}
thumbsize = http_thumb(fp);
if (thumbsize < 0)
{
goto ThumbFail;
}
// http头配置与发送
struct httpresp *head;
int res;
head = http_create_reply(200, "OK");
http_add_header(head, httpIndex.Type, "image/jpeg");
http_add_header(head, httpIndex.Connection, "close");
res = http_header_send(head, httpIndex.Length, thumbsize, fd);
if (res < 0)
{
_os_printf("socket err!\r\n");
goto HeadSendErr;
}
// 文件发送
res = http_file_send(fp, fd);
if (res == -1)
{
goto SocketErr;
}
// 正常结束
goto ReleaseRes;
HeadSendErr:
osal_fclose(fp);
_os_printf("HeadSenderr:%d!\r\n", res);
goto ReleaseRes;
FileFail:
_os_printf("open file fail!\r\n");
goto ReleaseRes;
FileNameErr:
_os_printf("file path err!!!\r\n");
goto ReleaseRes;
SocketErr:
_os_printf("socket err!!!\r\n");
goto ReleaseRes;
ThumbFail:
_os_printf("http_thumb err!!!\r\n");
goto ReleaseRes;
ReleaseRes:
closeRes(httpClient);
return;
}
// 测试http的post方法
void http_post_Test(struct httpClient *httpClient)
{
struct httpresp *head;
// char *http_reponse = STREAM_LIBC_MALLOC(1024);
int fd = httpClient->fdClient;
head = http_create_reply(200, "OK");
http_add_header(head, httpIndex.Type, "application/json");
http_add_header(head, httpIndex.Connection, "close");
cJSON *json;
char *out = NULL;
struct httpEntry *postContent = httpClient->http_request;
struct httpEntry *postContentLen = NULL;
// 读取post的内容和长度
while (1)
{
if (!postContent)
{
break;
}
if (!strcmp(postContent->key, "Content"))
{
break;
}
if (!strcmp(postContent->key, "Content-Length"))
{
postContentLen = postContent;
}
postContent = postContent->next;
}
if (postContent)
{
json = cJSON_Parse(postContent->value); // 获取整个大的句柄
int i = 0;
for (i = 0; i < cJSON_GetArraySize(json); i++)
{
cJSON *item = cJSON_GetArrayItem(json, i);
executeJson(&postSetting, item);
/*
if(cJSON_String == item->type)
{
_os_printf("%s->%s\r\n",item->string,item->valuestring);
}
*/
}
// out=cJSON_Print(json); //这个是可以输出的。为获取的整个json的值
out = cJSON_PrintUnformatted(json);
cJSON_Delete(json);
if (postContentLen)
{
_os_printf("%s->%s\r\n", postContentLen->key, postContentLen->value);
}
}
// 如果接收不完整,则会在这里重新去尝试接收,前提已经接收到所有的头部,否则可能还是会出错,尚未做处理
else
{
_os_printf("rec continue\r\n");
if (postContentLen)
{
_os_printf("%s->%s\r\n", postContentLen->key, postContentLen->value);
char *recBuf = STREAM_LIBC_MALLOC(1024);
int iRecvLen = recv(fd, recBuf, 1024, 0);
recBuf[iRecvLen] = 0;
_os_printf("rec again len:%d\r\n", strlen(recBuf));
json = cJSON_Parse(recBuf); // 获取整个大的句柄
int i = 0;
for (i = 0; i < cJSON_GetArraySize(json); i++)
{
cJSON *item = cJSON_GetArrayItem(json, i);
executeJson(&postSetting, item);
}
out = cJSON_PrintUnformatted(json);
cJSON_Delete(json);
STREAM_LIBC_FREE(recBuf);
_os_printf("rec again finish!\r\n");
}
}
if (out)
{
http_header_send(head, httpIndex.Length, strlen(out), fd);
send(fd, out, strlen(out), 0);
}
STREAM_LIBC_FREE(out);
// STREAM_LIBC_FREE(http_reponse);
closeRes(httpClient);
}
// 测试http显示hello
extern unsigned char webdata[6788];
uint8 read_flash_file_list(char *list);
void http_reponse_ret(struct httpClient *httpClient)
{
uint32_t sendlen = 0;
uint32_t itk = 0;
uint32_t len_str = 0;
uint32_t len;
uint32_t str_offset;
struct httpresp *head;
uint8_t *list_table = (uint8_t*)os_malloc(3*1024);
if(!list_table)
{
return;
}
// char *http_reponse = STREAM_LIBC_MALLOC(1024);
int fd = httpClient->fdClient;
_os_printf("%s %d\r\n", __func__, __LINE__);
head = http_create_reply(200, "OK");
http_add_header(head, httpIndex.Type, "text/html");
http_add_header(head, httpIndex.Connection, "close");
// sprintf(http_reponse, "%s", "Hello!!!");
memset(list_table, 0, 3 * 1024);
// read_flash_file_list(list_table);
//_os_printf("list_table:%s\r\n",list_table);
// http_header_send(head, httpIndex.Length, strlen(list_table),fd);
len_str = sizeof(webstr_ret);
_os_printf("len_str:%d\r\n", len_str);
len_str = len_str / 100;
for (itk = 0; itk < len_str; itk++)
{
sendlen += strlen(webstr_ret[itk]); // strlen(webstr);
}
http_header_send(head, httpIndex.Length, sendlen, fd);
str_offset = 0;
while (sendlen)
{
if (sendlen > 1024)
{
len = 0;
while (len < 1024)
{
memcpy(list_table + len, webstr_ret[str_offset], strlen(webstr_ret[str_offset]));
len += strlen(webstr_ret[str_offset]);
str_offset++;
}
send(fd, list_table, len, 0);
sendlen = sendlen - len;
}
else
{
len = 0;
for (itk = str_offset; itk < len_str; itk++)
{
memcpy(list_table + len, webstr_ret[itk], strlen(webstr_ret[itk]));
len += strlen(webstr_ret[itk]);
}
send(fd, list_table, len, 0);
sendlen = 0;
}
}
// STREAM_LIBC_FREE(http_reponse);
closeRes(httpClient);
// user_action(MSG_ID_TAKE_PHOTO); //模拟测试按键拍照的效果
if(list_table)
{
os_free(list_table);
}
}
void http_reponse_web(struct httpClient *httpClient)
{
uint32_t sendlen = 0;
//uint32_t offset = 0;
uint32_t itk = 0;
uint32_t len_str = 0;
uint32_t len;
uint32_t str_offset;
struct httpresp *head;
uint8_t *list_table = (uint8_t*)os_malloc(3*1024);
if(!list_table)
{
return;
}
// char *http_reponse = STREAM_LIBC_MALLOC(1024);
int fd = httpClient->fdClient;
_os_printf("%s %d\r\n", __func__, __LINE__);
head = http_create_reply(200, "OK");
http_add_header(head, httpIndex.Type, "text/html");
http_add_header(head, httpIndex.Connection, "close");
// sprintf(http_reponse, "%s", "Hello!!!");
memset(list_table, 0, 3 * 1024);
// read_flash_file_list(list_table);
//_os_printf("list_table:%s\r\n",list_table);
// http_header_send(head, httpIndex.Length, strlen(list_table),fd);
len_str = sizeof(webstr);
_os_printf("len_str :%d\r\n", len_str);
len_str = len_str / 200;
for (itk = 0; itk < len_str; itk++)
{
sendlen += strlen(webstr[itk]); // strlen(webstr);
}
http_header_send(head, httpIndex.Length, sendlen, fd);
str_offset = 0;
while (sendlen)
{
if (sendlen > 1024)
{
len = 0;
while (len < 1024)
{
memcpy(list_table + len, webstr[str_offset], strlen(webstr[str_offset]));
len += strlen(webstr[str_offset]);
str_offset++;
}
send(fd, list_table, len, 0);
sendlen = sendlen - len;
}
else
{
len = 0;
for (itk = str_offset; itk < len_str; itk++)
{
// _os_printf("web :%d ",itk);
memcpy(list_table + len, webstr[itk], strlen(webstr[itk]));
len += strlen(webstr[itk]);
}
// _os_printf("len_tab:%d\r\n",len);
send(fd, list_table, len, 0);
sendlen = 0;
}
}
// STREAM_LIBC_FREE(http_reponse);
closeRes(httpClient);
// user_action(MSG_ID_TAKE_PHOTO); //模拟测试按键拍照的效果
if(list_table)
{
os_free(list_table);
}
}
static void thread_rec_pool_queue(struct httpserver *httpserver)
{
int32 ret;
struct httpClient *httpClient_pool;
while (1)
{
httpClient_pool = (struct httpClient *)os_msgq_get2(&httpserver->thread_pool_queue,-1,&ret);
if(httpClient_pool && ret == 0)
{
_os_printf("%s %d httpserver->thread_pool_queue:%x\r\n", __FUNCTION__, ret, httpserver->thread_pool_queue);
http_thread_pool(httpClient_pool, getweb, NULL);
STREAM_LIBC_FREE(httpClient_pool);
httpClient_pool = NULL;
}
}
}
// 发送有个队列消息
static uint8_t httpqueue_thread_send_pool(struct httpClient *httpClient)
{
long res;
res = os_msgq_put(&httpClient->httpserver->thread_pool_queue, (uint32_t)httpClient,-1);
_os_printf("QueueSend finish:%d!!!\r\n", res);
if (res != 0)
{
STREAM_LIBC_FREE(httpClient);
_os_printf("QueueSend fail!\r\n");
}
return 0;
}
// 监听到socket就进入http_thread进行处理
void http_thread_pool(struct httpClient *httpClient, struct url *gweb, struct url *pweb)
{
// static uint32_t requestTimes = 0;
char *recBuf;
struct url *web;
int fd = httpClient->fdClient;
struct httpEntry *http_request = STREAM_LIBC_MALLOC(sizeof(struct httpEntry));
http_request->next = NULL;
http_request->key = NULL;
http_request->value = NULL;
http_request->pattern = NULL;
recBuf = STREAM_LIBC_MALLOC(1024);
//_os_printf("fd:%d http_request:%08x recBuf:%08x\r\n",fd,http_request,recBuf);
while (1)
{
int iRecvLen = recv(fd, recBuf, 1023, 0);
_os_printf("iRecvLen:%d\r\n", iRecvLen);
if (iRecvLen > 0)
{
recBuf[iRecvLen] = 0;
http_request_msg(recBuf, http_request);
// 这里只是判断了GET方法其他字段都没有去判断
web = parsePath(http_request, gweb, pweb);
httpClient->http_request = http_request;
if (web && (web->reponse || web->queue))
{
// if(web->url)
//{
// _os_printf("web->url:%s\r\n",web->url);
// }
// else
//{
// _os_printf("no found web\r\n");
// }
// 如果部分匹配,则将后面的内容复制出来
if (http_request->pattern)
{
_os_printf("request->pattern:%s\r\n", http_request->pattern);
httpClient->pattern = STREAM_LIBC_MALLOC(strlen(http_request->pattern) + 1);
memcpy(httpClient->pattern, http_request->pattern, strlen(http_request->pattern) + 1);
}
httpClient->web = web;
// httpClient->http_request = http_request;
if (web->queue)
{
web->queue(httpClient);
}
else
{
web->reponse(httpClient);
}
}
// 增加404错误以及一些提示
// 不应该出现在这里
else
{
http_send_error(httpClient);
_os_printf("shouldn't appear here!\r\n");
}
break;
}
else if (iRecvLen == 0)
{
osal_socket_close(fd);
_os_printf("RecErr:iRecvLen:%d\t%d\r\n", iRecvLen, fd);
STREAM_LIBC_FREE(http_request);
break;
}
else
{
_os_printf("RecErr:iRecvLen:%d\t%d\r\n", iRecvLen, fd);
osal_socket_close(fd);
STREAM_LIBC_FREE(http_request);
break;
}
}
STREAM_LIBC_FREE(recBuf);
return;
}
// 客户端
// 创建http 的GET请求
struct httpresp *http_create_GET(char *url)
{
uint32_t len;
struct httpresp *resp;
resp = STREAM_LIBC_MALLOC(sizeof(struct httpresp));
if (!resp)
{
return NULL;
}
resp->headbuf = STREAM_LIBC_MALLOC(1024);
resp->msgMaxLen = 1024;
resp->msgLen = 0;
resp->stat = 0;
len = sprintf(resp->headbuf, "GET /%s HTTP/1.1\r\n", url);
resp->msgLen += len;
return resp;
}
int http_GET_header_send(struct httpresp *resp, int fd)
{
int res;
if (resp->stat || !resp || !resp->headbuf)
{
free_http_head(resp);
_os_printf("http header err!\r\n");
return -2;
}
res = send(fd, resp->headbuf, strlen(resp->headbuf), 0);
free_http_head(resp);
return res;
}
/********************* Initial ********************/
static void do_accept(void *ei, void *d)
{
SOCK_HDL fd;
unsigned int i;
struct sockaddr_in addr;
struct httpClient *httpClient = initHttpClient();
if (!httpClient)
{
return;
}
struct httpserver *httpserver = (struct httpserver *)d;
_os_printf("httpserver fd:%d\r\n", httpserver->fdServer);
i = sizeof(addr);
if ((fd = accept(httpserver->fdServer, (struct sockaddr *)&addr, &i)) < 0)
{
return;
}
_os_printf("accepted connection from %s:%d\r\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
#if 0
if (osal_set_tcp_nodelay(fd, 1) < 0)
{
// osal_socket_strerr(strerr1, socket_errno);
// p_info("error setting TCP_NODELAY on socket: %s", strerr1);
}
#endif
_os_printf("create new thread fd:%d\r\n", fd);
httpClient->fdClient = fd;
httpClient->httpserver = httpserver;
httpClient->time = os_jiffies();
httpClient->pattern = NULL;
httpClient->http_request = NULL;
#if 1
int nNetTimeout = 1000; // 1秒
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&nNetTimeout, sizeof(int)) < 0)
{
_os_printf("111111error setsockopt TCP connection\r\n");
}
#endif
httpqueue_thread_send_pool(httpClient);
// osal_thread_create(http_thread, httpClient, 15, 0, 4096, "http_thread");
}
static int http_listen(int port)
{
struct sockaddr_in addr;
SOCK_HDL fd;
//ERR_STR strerr;
//k_task_handle_t queue1;
//k_task_handle_t queue2;
struct httpserver *httpserver = STREAM_LIBC_MALLOC(sizeof(struct httpserver));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = 0;
addr.sin_port = htons(port);
if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
return -1;
}
if (osal_set_reuseaddr(fd, 1) < 0) {}
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
// osal_socket_strerr(strerr, socket_errno);
// p_err("unable to bind to tcp socket: %s\r\n", strerr);
close(fd);
return -1;
}
if (listen(fd, 8) < 0)
{
// osal_socket_strerr(strerr, socket_errno);
// p_err("error when attempting to listen on tcp socket: %s\r\n", strerr);
close(fd);
return -1;
}
httpserver->fdServer = fd;
os_msgq_init(&httpserver->thread_pool_queue,32);
os_task_create("queue1", (os_task_func_t)thread_rec_pool_queue, httpserver, OS_TASK_PRIORITY_NORMAL, 0, NULL, 2048);
//initWeb(&getweb);
//default_getweb(&getweb);
eloop_add_fd(fd, EVENT_READ, EVENT_F_ENABLED, do_accept, (void *)httpserver);
_os_printf("listening on http port %s:%d\r\n", inet_ntoa(addr.sin_addr), port);
return 0;
}
/********************* GLOBAL CONFIGURATION DIRECTIVES ********************/
int config_http(int port)
{
if (port <= 0 || port > 65535)
{
_os_printf("invalid listen port %d", port);
return -1;
}
return http_listen(port);
}