Merge branch 'master' into readme-en

master
朱天龙 (Armink) 4 years ago committed by GitHub
commit ee7794e983
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -59,7 +59,9 @@ To use the WebClient software package, you need to select it in the RT-Thread pa
RT-Thread online packages RT-Thread online packages
IoT-internet of things ---> IoT-internet of things --->
[*] WebClient: A HTTP/HTTPS Client for RT-Thread [*] WebClient: A HTTP/HTTPS Client for RT-Thread
[ ] Enable debug log output
[ ] Enable webclient GET/POST samples [ ] Enable webclient GET/POST samples
[ ] Enable file download feature support
Select TLS mode (Not support) ---> Select TLS mode (Not support) --->
(x) Not support (x) Not support
() SAL TLS support () SAL TLS support
@ -68,13 +70,10 @@ RT-Thread online packages
``` ```
**Enable webclient GET/POST samples**: add sample code; **Enable webclient GET/POST samples**: add sample code;
**Select TLS mode**: Configure to enable HTTPS support and select the supported mode; **Select TLS mode**: Configure to enable HTTPS support and select the supported mode;
- **Not support**: Does not support TLS function; - **Not support**: Does not support TLS function;
- **SAL TLS support**: Configure the TLS function support in the SAL component, and abstract the TLS operation in the SAL component. Users also need to **manually configure the type of TLS software package used** (currently only supports the MbedTLS package); - **SAL TLS support**: Configure the TLS function support in the SAL component, and abstract the TLS operation in the SAL component. Users also need to **manually configure the type of TLS software package used** (currently only supports the MbedTLS package);
- **MbedTLS support**: configure MbedTLS function support; - **MbedTLS support**: configure MbedTLS function support;
**Version**: Configure the software package version. **Version**: Configure the software package version.
After the configuration is complete, let the RT-Thread package manager automatically update, or use the pkgs --update command to update the package to the BSP. After the configuration is complete, let the RT-Thread package manager automatically update, or use the pkgs --update command to update the package to the BSP.
@ -90,10 +89,10 @@ After the configuration is complete, let the RT-Thread package manager automatic
## 4. Matters needing attention ## 4. Matters needing attention
- When the WebClient software package connects to the HTTPS server, you need to enable the TLS function support in WebClient. - When the WebClient software package connects to the HTTPS server, you need to enable the TLS function support in WebClient.
- After the WebClient software package version update (`V1.0.0 -> the current latest version V2.0.0`), the function interface and usage process in the software package have changed. If the previous interface is used in the developer code, the latest version interface can be adapted , Or select the `V1.0.0` version in the version number configuration, the specific modification method can refer to the software package [migration guide](docs/migration-guide.md). - After the WebClient software package version update (`V1.0.0 -> the current latest version V2.0.0`), the function interface and usage process in the software package have changed. If the previous interface is used in the developer code, the latest version interface can be adapted , Or select the `V1.0.0` version in the version number configuration, the specific modification method can refer to the software package [migration guide](docs/migration-guide.md).
## 5. Contact & Thanks ## 5. Contact & Thanks
- Maintenance: RT-Thread development team - Maintenance: RT-Thread development team

@ -3,7 +3,10 @@ from building import *
cwd = GetCurrentDir() cwd = GetCurrentDir()
path = [cwd + '/inc'] path = [cwd + '/inc']
src = Glob('src/*.c') src = Glob('src/webclient.c')
if GetDepend(['WEBCLIENT_USING_FILE_DOWMLOAD']):
src += Glob('src/webclient_file.c')
if GetDepend(['WEBCLIENT_USING_SAMPLES']): if GetDepend(['WEBCLIENT_USING_SAMPLES']):
src += Glob('samples/*.c') src += Glob('samples/*.c')

@ -66,7 +66,7 @@ int webclient_get_position(struct webclient_session *session, const char *URI, i
## 发送 POST 请求 ## 发送 POST 请求
```c ```c
int webclient_post(struct webclient_session *session, const char *URI, const char *post_data); int webclient_post(struct webclient_session *session, const char *URI, const void *post_data, size_t data_len);
``` ```
发送 HTTP POST 请求命令,上传数据到 HTTP 服务器。 发送 HTTP POST 请求命令,上传数据到 HTTP 服务器。
@ -76,6 +76,7 @@ int webclient_post(struct webclient_session *session, const char *URI, const cha
|session | 当前连接会话结构体指针 | |session | 当前连接会话结构体指针 |
|URI | 连接的 HTTP 服务器地址 | |URI | 连接的 HTTP 服务器地址 |
|post_data | 需要上传的数据地址 | |post_data | 需要上传的数据地址 |
|data_len | 需要上传数据的长度 |
| **返回** | **描述** | | **返回** | **描述** |
|`>0` | HTTP 响应状态码 | |`>0` | HTTP 响应状态码 |
|<0 | | |<0 | |
@ -83,7 +84,7 @@ int webclient_post(struct webclient_session *session, const char *URI, const cha
## 发送数据 ## 发送数据
```c ```c
int webclient_write(struct webclient_session *session, const unsigned char *buffer, size_t size); int webclient_write(struct webclient_session *session, const void *buffer, size_t size);
``` ```
发送数据到连接的服务器。 发送数据到连接的服务器。
@ -101,7 +102,7 @@ int webclient_write(struct webclient_session *session, const unsigned char *buff
## 接收数据 ## 接收数据
```c ```c
int webclient_read(struct webclient_session *session, unsigned char *buffer, size_t size); int webclient_read(struct webclient_session *session, void *buffer, size_t size);
``` ```
从连接的服务器接收数据。 从连接的服务器接收数据。
@ -169,7 +170,7 @@ const char *webclient_header_fields_get(struct webclient_session *session, const
## 接收响应数据到指定地址 ## 接收响应数据到指定地址
```c ```c
int webclient_response(struct webclient_session *session, unsigned char **response); int webclient_response(struct webclient_session *session, void **response, size_t *resp_len);
``` ```
该函数用于发送 GET 或 POST 请求之后, 可以接收响应数据到指定地址。 该函数用于发送 GET 或 POST 请求之后, 可以接收响应数据到指定地址。
@ -178,6 +179,7 @@ int webclient_response(struct webclient_session *session, unsigned char **respon
|:------------------|:-----------------------------------| |:------------------|:-----------------------------------|
|session | 当前连接会话结构体指针 | |session | 当前连接会话结构体指针 |
|response | 存放接收数据的字符串地址 | |response | 存放接收数据的字符串地址 |
|resp_len | 接收数据的长度的指针 |
| **返回** | **描述** | | **返回** | **描述** |
| `>0` | 成功接收数据的长度 | | `>0` | 成功接收数据的长度 |
| <=0 | 接收数据失败 | | <=0 | 接收数据失败 |
@ -185,7 +187,7 @@ int webclient_response(struct webclient_session *session, unsigned char **respon
## 发送 GET/POST 请求并接收响应数据 ## 发送 GET/POST 请求并接收响应数据
```c ```c
int webclient_request(const char *URI, const char *header, const char *post_data, unsigned char **response); int webclient_request(const char *URI, const char *header, const void *post_data, size_t data_len, void **response, size_t *resp_len);
``` ```
| 参数 | 描述 | | 参数 | 描述 |
@ -197,11 +199,30 @@ int webclient_request(const char *URI, const char *header, const char *post_data
|post_data | 发送到服务器的数据 | |post_data | 发送到服务器的数据 |
| | = NULL该发送请求为 GET 请求 | | | = NULL该发送请求为 GET 请求 |
| | != NULL该发送请求为 POST 请求 | | | != NULL该发送请求为 POST 请求 |
| data_len | 发送数据的长度 |
|response | 存放接收数据的字符串地址 | |response | 存放接收数据的字符串地址 |
|resp_len | 接收数据长度的指针 |
| **返回** | **描述** | | **返回** | **描述** |
| `>0` | 成功接收数据的长度 | | `>0` | 成功接收数据的长度 |
| <=0 | 接收数据失败 | | <=0 | 接收数据失败 |
## 拼接请求头部数据
```c
int webclient_request_header_add(char **request_header, const char *fmt, ...);
```
该函数适用于 webclient_request 函数发送请求之前,头部数据的拼接和添加。
| 参数 | 描述 |
|:------------------|:-----------------------------------|
|request_header | 请求头部数据缓冲区地址 |
|fmt | 添加字段数据的表达式 |
|... | 添加的字段数据,为可变参数 |
| **返回** | **描述** |
| `>0` | 成功添加的字段数据的长度 |
| <=0 | 头部数据添加失败或内存不足 |
## 获取 HTTP 响应状态码 ## 获取 HTTP 响应状态码

@ -1,8 +1,10 @@
# 迁移指南 # 迁移指南
## 1、V1.0.0 -> V2.0.0 版本改动
本节主要介绍 WebClient 软件包版本升级之后(`V1.0.0` -> 最近版本 `V2.0.0`),软件包的改动和适配最新版本的方式。 本节主要介绍 WebClient 软件包版本升级之后(`V1.0.0` -> 最近版本 `V2.0.0`),软件包的改动和适配最新版本的方式。
## 函数改动 ### 函数改动
1. 添加 `webclient_session_create()` 创建客户端结构体函数 1. 添加 `webclient_session_create()` 创建客户端结构体函数
@ -29,9 +31,9 @@
- 添加获取当前响应状态码函数(`webclient_resp_status_get` - 添加获取当前响应状态码函数(`webclient_resp_status_get`
- 添加获取当前响应 Content-Length 数据函数(`webclient_content_length_get`)。 - 添加获取当前响应 Content-Length 数据函数(`webclient_content_length_get`)。
## 流程改动 ### 流程改动
### GET 请求流程改动 #### GET 请求流程改动
下面以发送自定义头部数据的 GET 请求方式为例,介绍新版本软件包中 GET 流程改动。 下面以发送自定义头部数据的 GET 请求方式为例,介绍新版本软件包中 GET 流程改动。
@ -93,7 +95,7 @@ while(1)
webclient_close(session); webclient_close(session);
``` ```
### POST 请求流程改动 #### POST 请求流程改动
下面以发送自定义头部数据的 POST 请求方式为例,介绍新版本软件包中的 POST 流程改动。 下面以发送自定义头部数据的 POST 请求方式为例,介绍新版本软件包中的 POST 流程改动。
@ -143,9 +145,36 @@ session = webclient_session_create(1024)
webclient_header_fields_add(session, "Content-Length: %s", post_data_sz); webclient_header_fields_add(session, "Content-Length: %s", post_data_sz);
webclient_post(session, URI, post_data); webclient_post(session, URI, post_data, rt_strlen(post_data));
webclient_close(session); webclient_close(session);
``` ```
上述介绍 WebClient 常用 GET/POST 请求方法改动,更多流程介绍请查看软件包 [使用指南](user-guide.md)。 上述介绍 WebClient 常用 GET/POST 请求方法改动,更多流程介绍请查看软件包 [使用指南](user-guide.md)。
## 2、V2.1.0 -> V2.2.0 版本改动
V2.2.0 版本主要改动部分为函数接口参数定义,目的是为了适配非字符串格式数据的读写,其他函数的使用流程未产生明显改动。
### 函数改动
- `webclient_post` 函数参数改动
该函数入参 `const char *post_data` 修改为 `const void *post_data`,并添加`size_t data_len` 参数,用于确定需要发送的数据长度。
- `webclient_read` 函数参数改动
该函数入参 `unsigned char *buffer` 修改为 `void *buffer`,用于适配非字符串数据接收。
- `webclient_write` 函数参数改动
该函数入参 `const unsigned char *buffer` 修改为 `const void *buffer`,用于适配非字符串数据发送。
- `webclient_response` 函数参数改动
该函数入参 `unsigned char **response` 修改为 `void **response`,并且添加参数 `size_t *resp_len`,用于获取接收数据长度信息,适配非字符串数据接收。
- `webclient_request` 函数参数改动
该函数入参 `const char *post_data` 修改为 `const void *post_data`,入参 `unsigned char **response` 修改为 `void **response`,并且添加入参 `size_t data_len``size_t *resp_len`,用于适配非字符串数据接收和发送。

@ -23,8 +23,10 @@ WebClient 软件包提供两个 HTTP Client 示例程序, 分别用于演示软
RT-Thread online packages RT-Thread online packages
IoT - internet of things ---> IoT - internet of things --->
[*] WebClient: A HTTP/HTTPS Client for RT-Thread [*] WebClient: A HTTP/HTTPS Client for RT-Thread
[ ] Enable support tls protocol [ ] Enable debug log output
[*] Enable webclient GET/POST samples # 开启 WebClient 测试例程 [*] Enable webclient GET/POST samples # 开启 WebClient 测试例程
[ ] Enable file download feature support
Select TLS mode (Not support) --->
Version (latest) ---> # 开启使用最新版本软件包 Version (latest) ---> # 开启使用最新版本软件包
``` ```
@ -50,17 +52,22 @@ GET 请求示例流程:
GET 请求示例使用方式有如下两种: GET 请求示例使用方式有如下两种:
- 在 MSH 中使用命令 `web_get_test` 执行 GET 请求示例程序,可以获取并打印显示默认网址下载的文件信息,如下图 LOG 显示: - 在 MSH 中使用命令 `web_get_test` 执行 GET 请求示例程序,可以获取并打印显示默认网址下载的文件信息;在 MSH 中使用命令 `web_get_test -s` 执行 POST 请求示例程序使用简化接口webclient_request 接口)发送 GET请求适用于简短数据的收发。如下图 LOG 显示:
```c ```c
msh />web_get_test msh />web_get_test
webclient GET request response data : webclient get response data:
RT-Thread is an open source IoT operating system from China, which has strong scalability: from a tiny kernel running on a tiny core, for example ARM Cortex-M0, or Cortex-M3/4/7, to a rich feature system running on MIPS32, ARM Cortex-A8, ARM Cortex-A9 DualCore etc.
msh />web_get_test -s
webclient send get request by simplify request interface.
webclient get response data:
RT-Thread is an open source IoT operating system from China, which has strong scalability: from a tiny kernel running on a tiny core, for example ARM Cortex-M0, or Cortex-M3/4/7, to a rich feature system running on MIPS32, ARM Cortex-A8, ARM Cortex-A9 DualCore etc. RT-Thread is an open source IoT operating system from China, which has strong scalability: from a tiny kernel running on a tiny core, for example ARM Cortex-M0, or Cortex-M3/4/7, to a rich feature system running on MIPS32, ARM Cortex-A8, ARM Cortex-A9 DualCore etc.
msh /> msh />
``` ```
- 在 MSH 中使用命令 `web_get_test [URI]` 格式命令执行 GET 请求示例程序,其中 URI 为用户自定义的支持 GET 请求的地址。 - 在 MSH 中使用命令 `web_get_test [URI]` `web_get_test -s [URI]` 格式命令执行 GET 请求示例程序,其中 URI 为用户自定义的支持 GET 请求的地址。
### POST 请求示例 ### POST 请求示例
@ -75,13 +82,18 @@ POST 请求示例流程如下:
POST 请求示例使用方式有如下两种: POST 请求示例使用方式有如下两种:
- 在 MSH 中使用命令 `web_post_test` 执行 POST 请求示例程序,可以获取并打印显示响应数据(默认 POST 请求的地址是类似于回显的地址,会返回上传的数据),如下图 LOG 显示: - 在 MSH 中使用命令 `web_post_test` 执行 POST 请求示例程序,可以获取并打印显示响应数据(默认 POST 请求的地址是类似于回显的地址,会返回上传的数据);在 MSH 中使用命令 `web_post_test -s` 执行 POST 请求示例程序使用简化接口webclient_request 接口)发送 POST 请求,适用于简短数据的收发。如下图 LOG 显示:
```c ```c
msh />web_post_test msh />web_post_test
webclient POST request response data : webclient post response data :
RT-Thread is an open source IoT operating system from China!
msh />
msh />web_post_test -s
webclient send post request by simplify request interface.
webclient post response data:
RT-Thread is an open source IoT operating system from China! RT-Thread is an open source IoT operating system from China!
msh /> msh />
``` ```
- 在 MSH 中使用命令 `web_post_test [URI]` 格式命令执行 POST 请求示例程序,其中 URI 为用户自定义的支持 POST 请求的地址。 - 在 MSH 中使用命令 `web_post_test [URI]` 或者 `web_post_test -s [URI]` 格式命令执行 POST 请求示例程序,其中 URI 为用户自定义的支持 POST 请求的地址。

@ -14,6 +14,7 @@
RT-Thread online packages RT-Thread online packages
IoT - internet of things ---> IoT - internet of things --->
[*] WebClient: A HTTP/HTTPS Client for RT-Thread [*] WebClient: A HTTP/HTTPS Client for RT-Thread
[ ] Enable debug log output
[ ] Enable webclient GET/POST samples [ ] Enable webclient GET/POST samples
Select TLS mode (Not support) ---> Select TLS mode (Not support) --->
(x) Not support (x) Not support
@ -22,6 +23,8 @@ RT-Thread online packages
Version (latest) ---> Version (latest) --->
``` ```
**Enable debug log output**:开启调试日志显示,可以用于查看请求和响应的头部数据信息;
**Enable webclient GET/POST samples** :添加示例代码; **Enable webclient GET/POST samples** :添加示例代码;
**Select TLS mode** :配置开启 HTTPS 支持,选择支持的模式; **Select TLS mode** :配置开启 HTTPS 支持,选择支持的模式;
@ -135,7 +138,7 @@ if ((resp_status = webclient_get(session, URI)) != 200)
4 **接收响应的数据** 4 **接收响应的数据**
发送 GET/POST 请求之后,可以使用 `webclient_read` 函数接收响应的实际数据。因为响应的实际数据可能比较长,所以往往我们需要循环接收响应数据,指导数据接收完毕。 发送 GET/POST 请求之后,可以使用 `webclient_read` 函数接收响应的实际数据。因为响应的实际数据可能比较长,所以往往我们需要循环接收响应数据,直到数据接收完毕。
如下所示为循环接收并打印响应数据方式: 如下所示为循环接收并打印响应数据方式:
@ -253,6 +256,7 @@ webclient_close(session)
```c ```c
struct webclient_session *session = NULL; struct webclient_session *session = NULL;
size_t length = 0;
char *result; char *result;
session = webclient_create(1024); session = webclient_create(1024);
@ -262,7 +266,7 @@ if(webclient_get(session, URI) != 200)
LOG_E("error!"); LOG_E("error!");
} }
webclient_response(session, &result); webclient_response(session, &result, &length);
web_free(result); web_free(result);
webclient_close(session); webclient_close(session);
@ -273,9 +277,13 @@ webclient_close(session);
多用于接收数据长度较小,且头部信息已经拼接给出的 GET 请求。 多用于接收数据长度较小,且头部信息已经拼接给出的 GET 请求。
```c ```c
char *result; size_t length = 0;
char *result, *header = RT_NULL;
webclient_request(URI, header, NULL, &result); /* 拼接自定义头部数据 */
webclient_request_header_add(&header, "User-Agent: RT-Thread HTTP Agent\r\n");
webclient_request(URI, header, NULL, 0, &result, &length);
web_free(result); web_free(result);
``` ```
@ -296,7 +304,7 @@ webclient_header_fields_add(session, "Content-Length: %d\r\n", post_data_sz);
webclient_header_fields_add(session, "Content-Type: application/octet-stream\r\n"); webclient_header_fields_add(session, "Content-Type: application/octet-stream\r\n");
/* 分段数据上传 webclient_post 第三个传输上传数据为 NULL改为下面循环上传数据*/ /* 分段数据上传 webclient_post 第三个传输上传数据为 NULL改为下面循环上传数据*/
if( webclient_post(session, URI, NULL) != 200) if( webclient_post(session, URI, NULL, 0) != 200)
{ {
LOG_E("error!"); LOG_E("error!");
} }
@ -328,7 +336,7 @@ session = webclient_create(1024);
webclient_header_fields_add(session, "Content-Length: %d\r\n", strlen(post_data)); webclient_header_fields_add(session, "Content-Length: %d\r\n", strlen(post_data));
webclient_header_fields_add(session, "Content-Type: application/octet-stream\r\n"); webclient_header_fields_add(session, "Content-Type: application/octet-stream\r\n");
if(webclient_post(session, URI, post_data) != 200); if(webclient_post(session, URI, post_data, rt_strlen(post_data)) != 200);
{ {
LOG_E("error!"); LOG_E("error!");
} }
@ -341,8 +349,13 @@ webclient_close(session);
```c ```c
char *post_data = "abcdefg"; char *post_data = "abcdefg";
char *header = RT_NULL;
/* 拼接自定义头部数据 */
webclient_request_header_add(&header, "Content-Length: %d\r\n", strlen(post_data));
webclient_request_header_add(&header, "Content-Type: application/octet-stream\r\n");
webclient_request(URI, NULL, post_data, NULL); webclient_request(URI, header, post_data, rt_strlen(post_data), NULL, NULL);
``` ```
## 常见问题 ## 常见问题
@ -355,7 +368,7 @@ webclient_request(URI, NULL, post_data, NULL);
- 原因:使用 HTTPS 地址但是没有开启 HTTPS 支持。 - 原因:使用 HTTPS 地址但是没有开启 HTTPS 支持。
- 解决方法:在 WebClient 软件包 menuconfig 配置选项中开启 `Enable support tls protocol` 选项支持 - 解决方法:在 WebClient 软件包 menuconfig 配置选项中 选择 `Select TLS mode` 选项为 `MbedTLS support` 或者 `SAL TLS support`
### 头部数据长度超出 ### 头部数据长度超出

@ -47,8 +47,8 @@ extern "C" {
#define web_strdup rt_strdup #define web_strdup rt_strdup
#endif #endif
#define WEBCLIENT_SW_VERSION "2.0.1" #define WEBCLIENT_SW_VERSION "2.2.0"
#define WEBCLIENT_SW_VERSION_NUM 0x20001 #define WEBCLIENT_SW_VERSION_NUM 0x20200
#define WEBCLIENT_HEADER_BUFSZ 4096 #define WEBCLIENT_HEADER_BUFSZ 4096
#define WEBCLIENT_RESPONSE_BUFSZ 4096 #define WEBCLIENT_RESPONSE_BUFSZ 4096
@ -110,7 +110,7 @@ int webclient_get(struct webclient_session *session, const char *URI);
int webclient_get_position(struct webclient_session *session, const char *URI, int position); int webclient_get_position(struct webclient_session *session, const char *URI, int position);
/* send HTTP POST request */ /* send HTTP POST request */
int webclient_post(struct webclient_session *session, const char *URI, const char *post_data); int webclient_post(struct webclient_session *session, const char *URI, const void *post_data, size_t data_len);
/* close and release wenclient session */ /* close and release wenclient session */
int webclient_close(struct webclient_session *session); int webclient_close(struct webclient_session *session);
@ -118,16 +118,17 @@ int webclient_close(struct webclient_session *session);
int webclient_set_timeout(struct webclient_session *session, int millisecond); int webclient_set_timeout(struct webclient_session *session, int millisecond);
/* send or receive data from server */ /* send or receive data from server */
int webclient_read(struct webclient_session *session, unsigned char *buffer, size_t size); int webclient_read(struct webclient_session *session, void *buffer, size_t size);
int webclient_write(struct webclient_session *session, const unsigned char *buffer, size_t size); int webclient_write(struct webclient_session *session, const void *buffer, size_t size);
/* webclient GET/POST header buffer operate by the header fields */ /* webclient GET/POST header buffer operate by the header fields */
int webclient_header_fields_add(struct webclient_session *session, const char *fmt, ...); int webclient_header_fields_add(struct webclient_session *session, const char *fmt, ...);
const char *webclient_header_fields_get(struct webclient_session *session, const char *fields); const char *webclient_header_fields_get(struct webclient_session *session, const char *fields);
/* send HTTP POST/GET request, and get response data */ /* send HTTP POST/GET request, and get response data */
int webclient_response(struct webclient_session *session, unsigned char **response); int webclient_response(struct webclient_session *session, void **response, size_t *resp_len);
int webclient_request(const char *URI, const char *header, const char *post_data, unsigned char **response); int webclient_request(const char *URI, const char *header, const void *post_data, size_t data_len, void **response, size_t *resp_len);
int webclient_request_header_add(char **request_header, const char *fmt, ...);
int webclient_resp_status_get(struct webclient_session *session); int webclient_resp_status_get(struct webclient_session *session);
int webclient_content_length_get(struct webclient_session *session); int webclient_content_length_get(struct webclient_session *session);

@ -16,40 +16,16 @@
#define GET_LOCAL_URI "http://www.rt-thread.com/service/rt-thread.txt" #define GET_LOCAL_URI "http://www.rt-thread.com/service/rt-thread.txt"
int webclient_get_test(int argc, char **argv) /* send HTTP GET request by common request interface, it used to receive longer data */
static int webclient_get_comm(const char *uri)
{ {
struct webclient_session* session = RT_NULL; struct webclient_session* session = RT_NULL;
unsigned char *buffer = RT_NULL; unsigned char *buffer = RT_NULL;
char *URI = RT_NULL;
int index, ret = 0; int index, ret = 0;
int bytes_read, resp_status; int bytes_read, resp_status;
int content_length = -1; int content_length = -1;
if (argc == 1) buffer = (unsigned char *) web_malloc(GET_RESP_BUFSZ);
{
URI = web_strdup(GET_LOCAL_URI);
if(URI == RT_NULL)
{
rt_kprintf("no memory for create URI buffer.\n");
return -1;
}
}
else if (argc == 2)
{
URI = web_strdup(argv[1]);
if(URI == RT_NULL)
{
rt_kprintf("no memory for create URI buffer.\n");
return -1;
}
}
else
{
rt_kprintf("webclient_get_test [URI] - webclient GET request test.\n");
return -1;
}
buffer = (unsigned char *) web_malloc(GET_HEADER_BUFSZ);
if (buffer == RT_NULL) if (buffer == RT_NULL)
{ {
rt_kprintf("no memory for receive buffer.\n"); rt_kprintf("no memory for receive buffer.\n");
@ -67,14 +43,14 @@ int webclient_get_test(int argc, char **argv)
} }
/* send GET request by default header */ /* send GET request by default header */
if ((resp_status = webclient_get(session, URI)) != 200) if ((resp_status = webclient_get(session, uri)) != 200)
{ {
rt_kprintf("webclient GET request failed, response(%d) error.\n", resp_status); rt_kprintf("webclient GET request failed, response(%d) error.\n", resp_status);
ret = -RT_ERROR; ret = -RT_ERROR;
goto __exit; goto __exit;
} }
rt_kprintf("webclient GET request response data :\n"); rt_kprintf("webclient get response data: \n");
content_length = webclient_content_length_get(session); content_length = webclient_content_length_get(session);
if (content_length < 0) if (content_length < 0)
@ -82,7 +58,7 @@ int webclient_get_test(int argc, char **argv)
rt_kprintf("webclient GET request type is chunked.\n"); rt_kprintf("webclient GET request type is chunked.\n");
do do
{ {
bytes_read = webclient_read(session, buffer, GET_RESP_BUFSZ); bytes_read = webclient_read(session, (void *)buffer, GET_RESP_BUFSZ);
if (bytes_read <= 0) if (bytes_read <= 0)
{ {
break; break;
@ -102,7 +78,7 @@ int webclient_get_test(int argc, char **argv)
do do
{ {
bytes_read = webclient_read(session, buffer, bytes_read = webclient_read(session, (void *)buffer,
content_length - content_pos > GET_RESP_BUFSZ ? content_length - content_pos > GET_RESP_BUFSZ ?
GET_RESP_BUFSZ : content_length - content_pos); GET_RESP_BUFSZ : content_length - content_pos);
if (bytes_read <= 0) if (bytes_read <= 0)
@ -132,15 +108,105 @@ __exit:
web_free(buffer); web_free(buffer);
} }
if (URI) return ret;
}
/* send HTTP GET request by simplify request interface, it used to received shorter data */
static int webclient_get_smpl(const char *uri)
{
char *response = RT_NULL;
size_t resp_len = 0;
int index;
if (webclient_request(uri, RT_NULL, RT_NULL, 0, (void **)&response, &resp_len) < 0)
{ {
web_free(URI); rt_kprintf("webclient send get request failed.");
return -RT_ERROR;
} }
return ret; rt_kprintf("webclient send get request by simplify request interface.\n");
rt_kprintf("webclient get response data: \n");
for (index = 0; index < rt_strlen(response); index++)
{
rt_kprintf("%c", response[index]);
}
rt_kprintf("\n");
if (response)
{
web_free(response);
}
return 0;
}
int webclient_get_test(int argc, char **argv)
{
char *uri = RT_NULL;
if (argc == 1)
{
uri = web_strdup(GET_LOCAL_URI);
if(uri == RT_NULL)
{
rt_kprintf("no memory for create get request uri buffer.\n");
return -RT_ENOMEM;
}
webclient_get_comm(uri);
}
else if (argc == 2)
{
if (rt_strcmp(argv[1], "-s") == 0)
{
uri = web_strdup(GET_LOCAL_URI);
if(uri == RT_NULL)
{
rt_kprintf("no memory for create get request uri buffer.\n");
return -RT_ENOMEM;
}
webclient_get_smpl(uri);
}
else
{
uri = web_strdup(argv[1]);
if(uri == RT_NULL)
{
rt_kprintf("no memory for create get request uri buffer.\n");
return -RT_ENOMEM;
}
webclient_get_comm(uri);
}
}
else if(argc == 3 && rt_strcmp(argv[1], "-s") == 0)
{
uri = web_strdup(argv[2]);
if(uri == RT_NULL)
{
rt_kprintf("no memory for create get request uri buffer.\n");
return -RT_ENOMEM;
}
webclient_get_smpl(uri);
}
else
{
rt_kprintf("web_get_test [URI] - webclient GET request test.\n");
rt_kprintf("web_get_test -s [URI] - webclient simplify GET request test.\n");
return -RT_ERROR;
}
if (uri)
{
web_free(uri);
}
return RT_EOK;
} }
#ifdef FINSH_USING_MSH #ifdef FINSH_USING_MSH
#include <finsh.h> #include <finsh.h>
MSH_CMD_EXPORT_ALIAS(webclient_get_test, web_get_test, web_get_test [URI] webclient GET request test); MSH_CMD_EXPORT_ALIAS(webclient_get_test, web_get_test, webclient get request test);
#endif /* FINSH_USING_MSH */ #endif /* FINSH_USING_MSH */

@ -20,45 +20,20 @@
const char *post_data = "RT-Thread is an open source IoT operating system from China!"; const char *post_data = "RT-Thread is an open source IoT operating system from China!";
int webclient_post_test(int argc, char **argv) /* send HTTP POST request by common request interface, it used to receive longer data */
static int webclient_post_comm(const char *uri, const void *post_data, size_t data_len)
{ {
struct webclient_session* session = RT_NULL; struct webclient_session* session = RT_NULL;
unsigned char *buffer = RT_NULL; unsigned char *buffer = RT_NULL;
char *URI = RT_NULL;
int index, ret = 0; int index, ret = 0;
int bytes_read, resp_status; int bytes_read, resp_status;
if (argc == 1)
{
URI = web_strdup(POST_LOCAL_URI);
if(URI == RT_NULL)
{
rt_kprintf("no memory for create URI buffer.\n");
return -1;
}
}
else if (argc == 2)
{
URI = web_strdup(argv[1]);
if(URI == RT_NULL)
{
rt_kprintf("no memory for create URI buffer.\n");
return -1;
}
}
else
{
rt_kprintf("webclient_post_test [URI] - webclient POST request test.\n");
return -1;
}
buffer = (unsigned char *) web_malloc(POST_RESP_BUFSZ); buffer = (unsigned char *) web_malloc(POST_RESP_BUFSZ);
if (buffer == RT_NULL) if (buffer == RT_NULL)
{ {
rt_kprintf("no memory for receive response buffer.\n"); rt_kprintf("no memory for receive response buffer.\n");
ret = -RT_ENOMEM; ret = -RT_ENOMEM;
goto __exit; goto __exit;
} }
/* create webclient session and set header response size */ /* create webclient session and set header response size */
@ -74,14 +49,14 @@ int webclient_post_test(int argc, char **argv)
webclient_header_fields_add(session, "Content-Type: application/octet-stream\r\n"); webclient_header_fields_add(session, "Content-Type: application/octet-stream\r\n");
/* send POST request by default header */ /* send POST request by default header */
if ((resp_status = webclient_post(session, URI, post_data)) != 200) if ((resp_status = webclient_post(session, uri, post_data, data_len)) != 200)
{ {
rt_kprintf("webclient POST request failed, response(%d) error.\n", resp_status); rt_kprintf("webclient POST request failed, response(%d) error.\n", resp_status);
ret = -RT_ERROR; ret = -RT_ERROR;
goto __exit; goto __exit;
} }
rt_kprintf("webclient POST request response data :\n"); rt_kprintf("webclient post response data: \n");
do do
{ {
bytes_read = webclient_read(session, buffer, POST_RESP_BUFSZ); bytes_read = webclient_read(session, buffer, POST_RESP_BUFSZ);
@ -109,15 +84,116 @@ __exit:
web_free(buffer); web_free(buffer);
} }
if (URI) return ret;
}
/* send HTTP POST request by simplify request interface, it used to received shorter data */
static int webclient_post_smpl(const char *uri, const char *post_data, size_t data_len)
{ {
web_free(URI); char *response = RT_NULL;
char *header = RT_NULL;
size_t resp_len = 0;
int index = 0;
webclient_request_header_add(&header, "Content-Length: %d\r\n", strlen(post_data));
webclient_request_header_add(&header, "Content-Type: application/octet-stream\r\n");
if (webclient_request(uri, header, post_data, data_len, (void **)&response, &resp_len) < 0)
{
rt_kprintf("webclient send post request failed.");
web_free(header);
return -RT_ERROR;
} }
return ret; rt_kprintf("webclient send post request by simplify request interface.\n");
rt_kprintf("webclient post response data: \n");
for (index = 0; index < resp_len; index++)
{
rt_kprintf("%c", response[index]);
}
rt_kprintf("\n");
if (header)
{
web_free(header);
} }
if (response)
{
web_free(response);
}
return 0;
}
int webclient_post_test(int argc, char **argv)
{
char *uri = RT_NULL;
if (argc == 1)
{
uri = web_strdup(POST_LOCAL_URI);
if(uri == RT_NULL)
{
rt_kprintf("no memory for create post request uri buffer.\n");
return -RT_ENOMEM;
}
webclient_post_comm(uri, (void *)post_data, rt_strlen(post_data));
}
else if (argc == 2)
{
if (rt_strcmp(argv[1], "-s") == 0)
{
uri = web_strdup(POST_LOCAL_URI);
if(uri == RT_NULL)
{
rt_kprintf("no memory for create post request uri buffer.\n");
return -RT_ENOMEM;
}
webclient_post_smpl(uri, (void *)post_data, rt_strlen(post_data));
}
else
{
uri = web_strdup(argv[1]);
if(uri == RT_NULL)
{
rt_kprintf("no memory for create post request uri buffer.\n");
return -RT_ENOMEM;
}
webclient_post_comm(uri, (void *)post_data, rt_strlen(post_data));
}
}
else if(argc == 3 && rt_strcmp(argv[1], "-s") == 0)
{
uri = web_strdup(argv[2]);
if(uri == RT_NULL)
{
rt_kprintf("no memory for create post request uri buffer.\n");
return -RT_ENOMEM;
}
webclient_post_smpl(uri, (void *)post_data, rt_strlen(post_data));
}
else
{
rt_kprintf("web_post_test [uri] - webclient post request test.\n");
rt_kprintf("web_post_test -s [uri] - webclient simplify post request test.\n");
return -RT_ERROR;
}
if (uri)
{
web_free(uri);
}
return RT_EOK;
}
#ifdef FINSH_USING_MSH #ifdef FINSH_USING_MSH
#include <finsh.h> #include <finsh.h>
MSH_CMD_EXPORT_ALIAS(webclient_post_test, web_post_test, webclient_post_test [URI] - webclient POST request test.); MSH_CMD_EXPORT_ALIAS(webclient_post_test, web_post_test, webclient post request test.);
#endif /* FINSH_USING_MSH */ #endif /* FINSH_USING_MSH */

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2006-2018, RT-Thread Development Team * Copyright (c) 2006-2019, RT-Thread Development Team
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
@ -14,11 +14,17 @@
* 2018-08-07 chenyong modify header processing * 2018-08-07 chenyong modify header processing
*/ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/time.h> #include <ctype.h>
#include <webclient.h> #include <webclient.h>
#if defined(RT_USING_LIBC) || defined(RT_USING_MINILIBC) || defined(RT_LIBC_USING_TIME)
#include <sys/time.h>
#endif
/* support both enable and disable "SAL_USING_POSIX" */ /* support both enable and disable "SAL_USING_POSIX" */
#if defined(RT_USING_SAL) #if defined(RT_USING_SAL)
#include <netdb.h> #include <netdb.h>
@ -43,7 +49,39 @@
extern long int strtol(const char *nptr, char **endptr, int base); extern long int strtol(const char *nptr, char **endptr, int base);
static int webclient_send(struct webclient_session* session, const unsigned char *buffer, size_t len, int flag) static int webclient_strncasecmp(const char *a, const char *b, size_t n)
{
uint8_t c1, c2;
if (n <= 0)
return 0;
do {
c1 = tolower(*a++);
c2 = tolower(*b++);
} while (--n && c1 && c1 == c2);
return c1 - c2;
}
static const char *webclient_strstri(const char* str, const char* subStr)
{
int len = strlen(subStr);
if(len == 0)
{
return RT_NULL;
}
while(*str)
{
if(webclient_strncasecmp(str, subStr, len) == 0)
{
return str;
}
++str;
}
return RT_NULL;
}
static int webclient_send(struct webclient_session* session, const void *buffer, size_t len, int flag)
{ {
#ifdef WEBCLIENT_USING_MBED_TLS #ifdef WEBCLIENT_USING_MBED_TLS
if (session->tls_session) if (session->tls_session)
@ -55,7 +93,7 @@ static int webclient_send(struct webclient_session* session, const unsigned char
return send(session->socket, buffer, len, flag); return send(session->socket, buffer, len, flag);
} }
static int webclient_recv(struct webclient_session* session, unsigned char *buffer, size_t len, int flag) static int webclient_recv(struct webclient_session* session, void *buffer, size_t len, int flag)
{ {
#ifdef WEBCLIENT_USING_MBED_TLS #ifdef WEBCLIENT_USING_MBED_TLS
if (session->tls_session) if (session->tls_session)
@ -116,17 +154,23 @@ static int webclient_read_line(struct webclient_session *session, char *buffer,
* @return 0 on resolve server address OK, others failed * @return 0 on resolve server address OK, others failed
* *
* URL example: * URL example:
* http://www.rt-thread.org/ * http://www.rt-thread.org
* http://www.rt-thread.org:80
* https://www.rt-thread.org/
* http://192.168.1.1:80/index.htm * http://192.168.1.1:80/index.htm
* http://[fe80::1]
* http://[fe80::1]/
* http://[fe80::1]/index.html * http://[fe80::1]/index.html
* http://[fe80::1]:80/index.html * http://[fe80::1]:80/index.html
*/ */
static int webclient_resolve_address(struct webclient_session *session, struct addrinfo **res, static int webclient_resolve_address(struct webclient_session *session, struct addrinfo **res,
const char *url, char **request) const char *url, const char **request)
{ {
int rc = WEBCLIENT_OK; int rc = WEBCLIENT_OK;
char *ptr; char *ptr;
char port_str[6] = "80"; /* default port of 80(http) */ char port_str[6] = "80"; /* default port of 80(http) */
const char *port_ptr;
const char *path_ptr;
const char *host_addr = 0; const char *host_addr = 0;
int url_len, host_addr_len = 0; int url_len, host_addr_len = 0;
@ -163,47 +207,41 @@ static int webclient_resolve_address(struct webclient_session *session, struct a
goto __exit; goto __exit;
} }
host_addr_len = ptr - host_addr; host_addr_len = ptr - host_addr;
ptr = rt_strstr(host_addr + host_addr_len, "/");
if (!ptr)
{
rc = -WEBCLIENT_ERROR;
goto __exit;
} }
else if (ptr != (host_addr + host_addr_len + 1))
path_ptr = rt_strstr(host_addr, "/");
*request = path_ptr ? path_ptr : "/";
/* resolve port */
port_ptr = rt_strstr(host_addr + host_addr_len, ":");
if (port_ptr && path_ptr && (port_ptr < path_ptr))
{ {
int port_len = ptr - host_addr - host_addr_len - 2; int port_len = path_ptr - port_ptr - 1;
rt_strncpy(port_str, host_addr + host_addr_len + 2, port_len); rt_strncpy(port_str, port_ptr + 1, port_len);
port_str[port_len] = '\0'; port_str[port_len] = '\0';
} }
*request = (char *) ptr; if (port_ptr && (!path_ptr))
}
else /* ipv4 or domain. */
{
char *port_ptr;
ptr = rt_strstr(host_addr, "/");
if (!ptr)
{ {
rc = -WEBCLIENT_ERROR; strcpy(port_str, port_ptr + 1);
goto __exit;
} }
host_addr_len = ptr - host_addr;
*request = (char *) ptr;
/* resolve port */ /* ipv4 or domain. */
port_ptr = rt_strstr(host_addr, ":"); if (!host_addr_len)
if (port_ptr && port_ptr < ptr) {
if (port_ptr)
{ {
int port_len = ptr - port_ptr - 1;
rt_strncpy(port_str, port_ptr + 1, port_len);
port_str[port_len] = '\0';
host_addr_len = port_ptr - host_addr; host_addr_len = port_ptr - host_addr;
} }
else if (path_ptr)
{
host_addr_len = path_ptr - host_addr;
}
else
{
host_addr_len = strlen(host_addr);
}
} }
if ((host_addr_len < 1) || (host_addr_len > url_len)) if ((host_addr_len < 1) || (host_addr_len > url_len))
@ -333,14 +371,11 @@ static int webclient_connect(struct webclient_session *session, const char *URI)
int socket_handle; int socket_handle;
struct timeval timeout; struct timeval timeout;
struct addrinfo *res = RT_NULL; struct addrinfo *res = RT_NULL;
char *req_url; const char *req_url;
RT_ASSERT(session); RT_ASSERT(session);
RT_ASSERT(URI); RT_ASSERT(URI);
/* initialize the socket of session */
session->socket = -1;
timeout.tv_sec = WEBCLIENT_DEFAULT_TIMEO; timeout.tv_sec = WEBCLIENT_DEFAULT_TIMEO;
timeout.tv_usec = 0; timeout.tv_usec = 0;
@ -527,7 +562,7 @@ const char *webclient_header_fields_get(struct webclient_session *session, const
resp_buf = session->header->buffer; resp_buf = session->header->buffer;
while (resp_buf_len < session->header->length) while (resp_buf_len < session->header->length)
{ {
if (rt_strstr(resp_buf, fields)) if (webclient_strstri(resp_buf, fields) == resp_buf)
{ {
char *mime_ptr = RT_NULL; char *mime_ptr = RT_NULL;
@ -652,7 +687,7 @@ static int webclient_send_header(struct webclient_session *session, int method)
} }
/* header data end */ /* header data end */
rt_snprintf(session->header->buffer + session->header->length, session->header->size, "\r\n"); rt_snprintf(session->header->buffer + session->header->length, session->header->size - session->header->length, "\r\n");
session->header->length += 2; session->header->length += 2;
/* check header size */ /* check header size */
@ -671,6 +706,27 @@ static int webclient_send_header(struct webclient_session *session, int method)
} }
} }
/* get and echo request header data */
{
char *header_str, *header_ptr;
int header_line_len;
LOG_D("request header:");
for(header_str = session->header->buffer; (header_ptr = rt_strstr(header_str, "\r\n")) != RT_NULL; )
{
header_line_len = header_ptr - header_str;
if (header_line_len > 0)
{
LOG_D("%.*s", header_line_len, header_str);
}
header_str = header_ptr + rt_strlen("\r\n");
}
#ifdef WEBCLIENT_DEBUG
LOG_RAW("\n");
#endif
}
__exit: __exit:
return rc; return rc;
} }
@ -697,6 +753,7 @@ int webclient_handle_response(struct webclient_session *session)
rt_memset(session->header->buffer, 0x00, session->header->size); rt_memset(session->header->buffer, 0x00, session->header->size);
session->header->length = 0; session->header->length = 0;
LOG_D("response header:");
/* We now need to read the header information */ /* We now need to read the header information */
while (1) while (1)
{ {
@ -719,6 +776,9 @@ int webclient_handle_response(struct webclient_session *session)
/* set terminal charater */ /* set terminal charater */
mime_buffer[rc - 1] = '\0'; mime_buffer[rc - 1] = '\0';
/* echo response header data */
LOG_D("%s", mime_buffer);
session->header->length += rc; session->header->length += rc;
if (session->header->length >= session->header->size) if (session->header->length >= session->header->size)
@ -803,6 +863,8 @@ struct webclient_session *webclient_session_create(size_t header_sz)
return RT_NULL; return RT_NULL;
} }
/* initialize the socket of session */
session->socket = -1;
session->content_length = -1; session->content_length = -1;
session->header = (struct webclient_header *) web_calloc(1, sizeof(struct webclient_header)); session->header = (struct webclient_header *) web_calloc(1, sizeof(struct webclient_header));
@ -815,7 +877,7 @@ struct webclient_session *webclient_session_create(size_t header_sz)
} }
session->header->size = header_sz; session->header->size = header_sz;
session->header->buffer = (char *) web_malloc(header_sz); session->header->buffer = (char *) web_calloc(1, header_sz);
if (session->header->buffer == RT_NULL) if (session->header->buffer == RT_NULL)
{ {
LOG_E("webclient create failed, no memory for session header buffer!"); LOG_E("webclient create failed, no memory for session header buffer!");
@ -828,6 +890,8 @@ struct webclient_session *webclient_session_create(size_t header_sz)
return session; return session;
} }
static int webclient_clean(struct webclient_session *session);
/** /**
* send GET request to http server and get response header. * send GET request to http server and get response header.
* *
@ -864,6 +928,9 @@ int webclient_get(struct webclient_session *session, const char *URI)
/* handle the response header of webclient server */ /* handle the response header of webclient server */
resp_status = webclient_handle_response(session); resp_status = webclient_handle_response(session);
LOG_D("get position handle response(%d).", resp_status);
if (resp_status > 0) if (resp_status > 0)
{ {
const char *location = webclient_header_fields_get(session, "Location"); const char *location = webclient_header_fields_get(session, "Location");
@ -879,26 +946,17 @@ int webclient_get(struct webclient_session *session, const char *URI)
return -WEBCLIENT_NOMEM; return -WEBCLIENT_NOMEM;
} }
/* close old client session */ /* clean webclient session */
webclient_close(session); webclient_clean(session);
/* clean webclient session header */
/* create new client session by location url */ session->header->length = 0;
session = webclient_session_create(WEBCLIENT_HEADER_BUFSZ); rt_memset(session->header->buffer, 0, session->header->size);
if (session == RT_NULL)
{
return -WEBCLIENT_NOMEM;
}
rc = webclient_get(session, new_url); rc = webclient_get(session, new_url);
web_free(new_url); web_free(new_url);
return rc; return rc;
} }
else if (resp_status != 200)
{
LOG_E("get failed, handle response(%d) error!", resp_status);
return resp_status;
}
} }
return resp_status; return resp_status;
@ -943,6 +1001,9 @@ int webclient_get_position(struct webclient_session *session, const char *URI, i
/* handle the response header of webclient server */ /* handle the response header of webclient server */
resp_status = webclient_handle_response(session); resp_status = webclient_handle_response(session);
LOG_D("get position handle response(%d).", resp_status);
if (resp_status > 0) if (resp_status > 0)
{ {
const char *location = webclient_header_fields_get(session, "Location"); const char *location = webclient_header_fields_get(session, "Location");
@ -958,26 +1019,17 @@ int webclient_get_position(struct webclient_session *session, const char *URI, i
return -WEBCLIENT_NOMEM; return -WEBCLIENT_NOMEM;
} }
/* close old client session */ /* clean webclient session */
webclient_close(session); webclient_clean(session);
/* clean webclient session header */
/* create new client session by location url */ session->header->length = 0;
session = webclient_session_create(WEBCLIENT_HEADER_BUFSZ); rt_memset(session->header->buffer, 0, session->header->size);
if (session == RT_NULL)
{
return -WEBCLIENT_NOMEM;
}
rc = webclient_get(session, new_url); rc = webclient_get_position(session, new_url, position);
web_free(new_url); web_free(new_url);
return rc; return rc;
} }
else if (resp_status != 206)
{
LOG_E("get failed, handle response(%d) error!", resp_status);
return resp_status;
}
} }
return resp_status; return resp_status;
@ -989,15 +1041,16 @@ int webclient_get_position(struct webclient_session *session, const char *URI, i
* @param session webclient session * @param session webclient session
* @param URI input server URI address * @param URI input server URI address
* @param header POST request header, can't be empty * @param header POST request header, can't be empty
* @param post_data data sent to the server * @param post_data data send to the server
* = NULL: just connect server and send header * = NULL: just connect server and send header
* != NULL: send header and body data, resolve response data * != NULL: send header and body data, resolve response data
* @param data_len the length of send data
* *
* @return <0: send POST request failed * @return <0: send POST request failed
* =0: send POST header success * =0: send POST header success
* >0: response http status code * >0: response http status code
*/ */
int webclient_post(struct webclient_session *session, const char *URI, const char *post_data) int webclient_post(struct webclient_session *session, const char *URI, const void *post_data, size_t data_len)
{ {
int rc = WEBCLIENT_OK; int rc = WEBCLIENT_OK;
int resp_status = 0; int resp_status = 0;
@ -1005,6 +1058,12 @@ int webclient_post(struct webclient_session *session, const char *URI, const cha
RT_ASSERT(session); RT_ASSERT(session);
RT_ASSERT(URI); RT_ASSERT(URI);
if ((post_data != RT_NULL) && (data_len == 0))
{
LOG_E("input post data length failed");
return -WEBCLIENT_ERROR;
}
rc = webclient_connect(session, URI); rc = webclient_connect(session, URI);
if (rc != WEBCLIENT_OK) if (rc != WEBCLIENT_OK)
{ {
@ -1019,17 +1078,13 @@ int webclient_post(struct webclient_session *session, const char *URI, const cha
return rc; return rc;
} }
if (post_data) if (post_data && (data_len > 0))
{ {
webclient_write(session, (unsigned char *) post_data, rt_strlen(post_data)); webclient_write(session, post_data, data_len);
/* resolve response data, get http status code */ /* resolve response data, get http status code */
resp_status = webclient_handle_response(session); resp_status = webclient_handle_response(session);
if (resp_status != 200) LOG_D("post handle response(%d).", resp_status);
{
LOG_E("post failed, handle response(%d) error.", resp_status);
return resp_status;
}
} }
return resp_status; return resp_status;
@ -1070,6 +1125,7 @@ static int webclient_next_chunk(struct webclient_session *session)
RT_ASSERT(session); RT_ASSERT(session);
rt_memset(line, 0x00, sizeof(line));
length = webclient_read_line(session, line, sizeof(line)); length = webclient_read_line(session, line, sizeof(line));
if (length > 0) if (length > 0)
{ {
@ -1100,6 +1156,7 @@ static int webclient_next_chunk(struct webclient_session *session)
/* end of chunks */ /* end of chunks */
closesocket(session->socket); closesocket(session->socket);
session->socket = -1; session->socket = -1;
session->chunk_sz = -1;
} }
return session->chunk_sz; return session->chunk_sz;
@ -1116,7 +1173,7 @@ static int webclient_next_chunk(struct webclient_session *session)
* =0: http server disconnect * =0: http server disconnect
* >0: successfully read data length * >0: successfully read data length
*/ */
int webclient_read(struct webclient_session *session, unsigned char *buffer, size_t length) int webclient_read(struct webclient_session *session, void *buffer, size_t length)
{ {
int bytes_read = 0; int bytes_read = 0;
int total_read = 0; int total_read = 0;
@ -1124,6 +1181,12 @@ int webclient_read(struct webclient_session *session, unsigned char *buffer, siz
RT_ASSERT(session); RT_ASSERT(session);
/* get next chunk size is zero, client is already closed, return zero */
if (session->chunk_sz < 0)
{
return 0;
}
if (session->socket < 0) if (session->socket < 0)
{ {
return -WEBCLIENT_DISCONNECT; return -WEBCLIENT_DISCONNECT;
@ -1187,7 +1250,7 @@ int webclient_read(struct webclient_session *session, unsigned char *buffer, siz
left = length; left = length;
do do
{ {
bytes_read = webclient_recv(session, buffer + total_read, left, 0); bytes_read = webclient_recv(session, (void *)((char *)buffer + total_read), left, 0);
if (bytes_read <= 0) if (bytes_read <= 0)
{ {
#if defined(WEBCLIENT_USING_SAL_TLS) || defined(WEBCLIENT_USING_MBED_TLS) #if defined(WEBCLIENT_USING_SAL_TLS) || defined(WEBCLIENT_USING_MBED_TLS)
@ -1198,7 +1261,7 @@ int webclient_read(struct webclient_session *session, unsigned char *buffer, siz
} }
#endif #endif
LOG_E("receive data error(%d).", bytes_read); LOG_D("receive data error(%d).", bytes_read);
if (total_read) if (total_read)
{ {
@ -1245,7 +1308,7 @@ int webclient_read(struct webclient_session *session, unsigned char *buffer, siz
* =0: http server disconnect * =0: http server disconnect
* >0: successfully write data length * >0: successfully write data length
*/ */
int webclient_write(struct webclient_session *session, const unsigned char *buffer, size_t length) int webclient_write(struct webclient_session *session, const void *buffer, size_t length)
{ {
int bytes_write = 0; int bytes_write = 0;
int total_write = 0; int total_write = 0;
@ -1266,7 +1329,7 @@ int webclient_write(struct webclient_session *session, const unsigned char *buff
/* send all of data on the buffer. */ /* send all of data on the buffer. */
do do
{ {
bytes_write = webclient_send(session, buffer + total_write, left, 0); bytes_write = webclient_send(session, (void *)((char *)buffer + total_write), left, 0);
if (bytes_write <= 0) if (bytes_write <= 0)
{ {
#if defined(WEBCLIENT_USING_SAL_TLS) || defined(WEBCLIENT_USING_MBED_TLS) #if defined(WEBCLIENT_USING_SAL_TLS) || defined(WEBCLIENT_USING_MBED_TLS)
@ -1308,17 +1371,9 @@ int webclient_write(struct webclient_session *session, const unsigned char *buff
return total_write; return total_write;
} }
/** /* close session socket, free host and request url */
* close a webclient client session. static int webclient_clean(struct webclient_session *session)
*
* @param session http client session
*
* @return 0: close success
*/
int webclient_close(struct webclient_session *session)
{ {
RT_ASSERT(session);
#ifdef WEBCLIENT_USING_MBED_TLS #ifdef WEBCLIENT_USING_MBED_TLS
if (session->tls_session) if (session->tls_session)
{ {
@ -1343,13 +1398,33 @@ int webclient_close(struct webclient_session *session)
if (session->host) if (session->host)
{ {
web_free(session->host); web_free(session->host);
session->host = RT_NULL;
} }
if (session->req_url) if (session->req_url)
{ {
web_free(session->req_url); web_free(session->req_url);
session->req_url = RT_NULL;
}
session->content_length = -1;
return 0;
} }
/**
* close a webclient client session.
*
* @param session http client session
*
* @return 0: close success
*/
int webclient_close(struct webclient_session *session)
{
RT_ASSERT(session);
webclient_clean(session);
if (session->header && session->header->buffer) if (session->header && session->header->buffer)
{ {
web_free(session->header->buffer); web_free(session->header->buffer);
@ -1374,10 +1449,11 @@ int webclient_close(struct webclient_session *session)
* *
* @param session wenclient session * @param session wenclient session
* @param response response buffer address * @param response response buffer address
* @param resp_len response buffer length
* *
* @return response data size * @return response data size
*/ */
int webclient_response(struct webclient_session *session, unsigned char **response) int webclient_response(struct webclient_session *session, void **response, size_t *resp_len)
{ {
unsigned char *buf_ptr; unsigned char *buf_ptr;
unsigned char *response_buf = 0; unsigned char *response_buf = 0;
@ -1423,8 +1499,8 @@ int webclient_response(struct webclient_session *session, unsigned char **respon
int result_sz; int result_sz;
result_sz = session->content_length; result_sz = session->content_length;
response_buf = web_malloc(result_sz + 1); response_buf = web_calloc(1, result_sz + 1);
if (!response_buf) if (response_buf == RT_NULL)
{ {
return -WEBCLIENT_NOMEM; return -WEBCLIENT_NOMEM;
} }
@ -1449,13 +1525,67 @@ int webclient_response(struct webclient_session *session, unsigned char **respon
if (response_buf) if (response_buf)
{ {
*response = response_buf; *response = (void *)response_buf;
*(response_buf + total_read) = '\0'; *(response_buf + total_read) = '\0';
*resp_len = total_read;
} }
return total_read; return total_read;
} }
/**
* add request(GET/POST) header data.
*
* @param request_header add request buffer address
* @param fmt fields format
*
* @return <=0: add header failed
* >0: add header data size
*/
int webclient_request_header_add(char **request_header, const char *fmt, ...)
{
rt_int32_t length, header_length;
char *header;
va_list args;
RT_ASSERT(request_header);
if (*request_header == RT_NULL)
{
header = rt_calloc(1, WEBCLIENT_HEADER_BUFSZ);
if (header == RT_NULL)
{
LOG_E("No memory for webclient request header add.");
return RT_NULL;
}
*request_header = header;
}
else
{
header = *request_header;
}
va_start(args, fmt);
header_length = rt_strlen(header);
length = rt_vsnprintf(header + header_length, WEBCLIENT_HEADER_BUFSZ - header_length, fmt, args);
if (length < 0)
{
LOG_E("add request header data failed, return length(%d) error.", length);
return -WEBCLIENT_ERROR;
}
va_end(args);
/* check header size */
if (rt_strlen(header) >= WEBCLIENT_HEADER_BUFSZ)
{
LOG_E("not enough request header data size(%d)!", WEBCLIENT_HEADER_BUFSZ);
return -WEBCLIENT_ERROR;
}
return length;
}
/** /**
* send request(GET/POST) to server and get response data. * send request(GET/POST) to server and get response data.
* *
@ -1466,16 +1596,18 @@ int webclient_response(struct webclient_session *session, unsigned char **respon
* @param post_data data sent to the server * @param post_data data sent to the server
* = NULL: it is GET request * = NULL: it is GET request
* != NULL: it is POST request * != NULL: it is POST request
* @param data_len send data length
* @param response response buffer address * @param response response buffer address
* @param resp_len response buffer length
* *
* @return <0: request failed * @return <0: request failed
* >=0: response buffer size * >=0: response buffer size
*/ */
int webclient_request(const char *URI, const char *header, const char *post_data, unsigned char **response) int webclient_request(const char *URI, const char *header, const void *post_data, size_t data_len, void **response, size_t *resp_len)
{ {
struct webclient_session *session; struct webclient_session *session = RT_NULL;
int rc = WEBCLIENT_OK; int rc = WEBCLIENT_OK;
int totle_length; int totle_length = 0;
RT_ASSERT(URI); RT_ASSERT(URI);
@ -1485,8 +1617,22 @@ int webclient_request(const char *URI, const char *header, const char *post_data
return -WEBCLIENT_ERROR; return -WEBCLIENT_ERROR;
} }
if ((post_data != RT_NULL) && (data_len == 0))
{
LOG_E("input post data length failed");
return -WEBCLIENT_ERROR;
}
if ((response != RT_NULL && resp_len == RT_NULL) ||
(response == RT_NULL && resp_len != RT_NULL))
{
LOG_E("input response data or length failed");
return -WEBCLIENT_ERROR;
}
if (post_data == RT_NULL) if (post_data == RT_NULL)
{ {
/* send get request */
session = webclient_session_create(WEBCLIENT_HEADER_BUFSZ); session = webclient_session_create(WEBCLIENT_HEADER_BUFSZ);
if (session == RT_NULL) if (session == RT_NULL)
{ {
@ -1496,7 +1642,15 @@ int webclient_request(const char *URI, const char *header, const char *post_data
if (header != RT_NULL) if (header != RT_NULL)
{ {
rt_strncpy(session->header->buffer, header, rt_strlen(header)); char *header_str, *header_ptr;
int header_line_length;
for(header_str = (char *)header; (header_ptr = rt_strstr(header_str, "\r\n")) != RT_NULL; )
{
header_line_length = header_ptr + rt_strlen("\r\n") - header_str;
webclient_header_fields_add(session, "%.*s", header_line_length, header_str);
header_str += header_line_length;
}
} }
if (webclient_get(session, URI) != 200) if (webclient_get(session, URI) != 200)
@ -1505,7 +1659,7 @@ int webclient_request(const char *URI, const char *header, const char *post_data
goto __exit; goto __exit;
} }
totle_length = webclient_response(session, response); totle_length = webclient_response(session, response, resp_len);
if (totle_length <= 0) if (totle_length <= 0)
{ {
rc = -WEBCLIENT_ERROR; rc = -WEBCLIENT_ERROR;
@ -1514,6 +1668,7 @@ int webclient_request(const char *URI, const char *header, const char *post_data
} }
else else
{ {
/* send post request */
session = webclient_session_create(WEBCLIENT_HEADER_BUFSZ); session = webclient_session_create(WEBCLIENT_HEADER_BUFSZ);
if (session == RT_NULL) if (session == RT_NULL)
{ {
@ -1523,22 +1678,34 @@ int webclient_request(const char *URI, const char *header, const char *post_data
if (header != RT_NULL) if (header != RT_NULL)
{ {
rt_strncpy(session->header->buffer, header, rt_strlen(header)); char *header_str, *header_ptr;
int header_line_length;
for(header_str = (char *)header; (header_ptr = rt_strstr(header_str, "\r\n")) != RT_NULL; )
{
header_line_length = header_ptr + rt_strlen("\r\n") - header_str;
webclient_header_fields_add(session, "%.*s", header_line_length, header_str);
header_str += header_line_length;
} }
else }
if (rt_strstr(session->header->buffer, "Content-Length") == RT_NULL)
{ {
/* build header for upload */
webclient_header_fields_add(session, "Content-Length: %d\r\n", rt_strlen(post_data)); webclient_header_fields_add(session, "Content-Length: %d\r\n", rt_strlen(post_data));
}
if (rt_strstr(session->header->buffer, "Content-Type") == RT_NULL)
{
webclient_header_fields_add(session, "Content-Type: application/octet-stream\r\n"); webclient_header_fields_add(session, "Content-Type: application/octet-stream\r\n");
} }
if (webclient_post(session, URI, post_data) != 200) if (webclient_post(session, URI, post_data, data_len) != 200)
{ {
rc = -WEBCLIENT_ERROR; rc = -WEBCLIENT_ERROR;
goto __exit; goto __exit;
} }
totle_length = webclient_response(session, response); totle_length = webclient_response(session, response, resp_len);
if (totle_length <= 0) if (totle_length <= 0)
{ {
rc = -WEBCLIENT_ERROR; rc = -WEBCLIENT_ERROR;
@ -1546,11 +1713,6 @@ int webclient_request(const char *URI, const char *header, const char *post_data
} }
} }
if (header != RT_NULL)
{
rt_strncpy(session->header->buffer, header, rt_strlen(header));
}
__exit: __exit:
if (session) if (session)
{ {

@ -158,6 +158,7 @@ int webclient_post_file(const char* URI, const char* filename,
char *header = RT_NULL, *header_ptr; char *header = RT_NULL, *header_ptr;
unsigned char *buffer = RT_NULL, *buffer_ptr; unsigned char *buffer = RT_NULL, *buffer_ptr;
struct webclient_session* session = RT_NULL; struct webclient_session* session = RT_NULL;
int resp_data_len = 0;
fd = open(filename, O_RDONLY, 0); fd = open(filename, O_RDONLY, 0);
if (fd < 0) if (fd < 0)
@ -171,7 +172,7 @@ int webclient_post_file(const char* URI, const char* filename,
length = lseek(fd, 0, SEEK_END); length = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET); lseek(fd, 0, SEEK_SET);
buffer = (unsigned char *) web_malloc(WEBCLIENT_RESPONSE_BUFSZ); buffer = (unsigned char *) web_calloc(1, WEBCLIENT_RESPONSE_BUFSZ);
if (buffer == RT_NULL) if (buffer == RT_NULL)
{ {
LOG_D("post file failed, no memory for response buffer."); LOG_D("post file failed, no memory for response buffer.");
@ -179,7 +180,7 @@ int webclient_post_file(const char* URI, const char* filename,
goto __exit; goto __exit;
} }
header = (char *) web_malloc(WEBCLIENT_HEADER_BUFSZ); header = (char *) web_calloc(1, WEBCLIENT_HEADER_BUFSZ);
if (header == RT_NULL) if (header == RT_NULL)
{ {
LOG_D("post file failed, no memory for header buffer."); LOG_D("post file failed, no memory for header buffer.");
@ -204,7 +205,7 @@ int webclient_post_file(const char* URI, const char* filename,
"Content-Type: application/octet-stream\r\n\r\n"); "Content-Type: application/octet-stream\r\n\r\n");
/* calculate content-length */ /* calculate content-length */
length += buffer_ptr - buffer; length += buffer_ptr - buffer;
length += rt_strlen(boundary) + 6; /* add the last boundary */ length += rt_strlen(boundary) + 8; /* add the last boundary */
/* build header for upload */ /* build header for upload */
header_ptr += rt_snprintf(header_ptr, header_ptr += rt_snprintf(header_ptr,
@ -221,9 +222,10 @@ int webclient_post_file(const char* URI, const char* filename,
goto __exit; goto __exit;
} }
session->header->buffer = web_strdup(header); rt_strncpy(session->header->buffer, header, rt_strlen(header));
session->header->length = rt_strlen(session->header->buffer);
rc = webclient_post(session, URI, NULL); rc = webclient_post(session, URI, NULL, 0);
if(rc < 0) if(rc < 0)
{ {
goto __exit; goto __exit;
@ -246,7 +248,32 @@ int webclient_post_file(const char* URI, const char* filename,
/* send last boundary */ /* send last boundary */
rt_snprintf((char*) buffer, WEBCLIENT_RESPONSE_BUFSZ, "\r\n--%s--\r\n", boundary); rt_snprintf((char*) buffer, WEBCLIENT_RESPONSE_BUFSZ, "\r\n--%s--\r\n", boundary);
webclient_write(session, buffer, rt_strlen(boundary) + 6); webclient_write(session, buffer, rt_strlen(boundary) + 8);
extern int webclient_handle_response(struct webclient_session *session);
if( webclient_handle_response(session) != 200)
{
rc = -WEBCLIENT_ERROR;
goto __exit;
}
resp_data_len = webclient_content_length_get(session);
if (resp_data_len > 0)
{
int bytes_read = 0;
rt_memset(buffer, 0x00, WEBCLIENT_RESPONSE_BUFSZ);
do
{
bytes_read = webclient_read(session, buffer,
resp_data_len < WEBCLIENT_RESPONSE_BUFSZ ? resp_data_len : WEBCLIENT_RESPONSE_BUFSZ);
if (bytes_read <= 0)
{
break;
}
resp_data_len -= bytes_read;
} while(resp_data_len > 0);
}
__exit: __exit:
if (fd >= 0) if (fd >= 0)
@ -269,15 +296,14 @@ __exit:
web_free(header); web_free(header);
} }
return 0; return rc;
} }
int wget(int argc, char** argv) int wget(int argc, char** argv)
{ {
if (argc != 3) if (argc != 3)
{ {
rt_kprintf("Please using: wget <URI> <filename>"); rt_kprintf("Please using: wget <URI> <filename>\n");
return -1; return -1;
} }

Loading…
Cancel
Save