فهرست منبع

Merge branch 'master' into readme-en

朱天龙 (Armink) 4 سال پیش
والد
کامیت
ee7794e983
11فایلهای تغییر یافته به همراه657 افزوده شده و 249 حذف شده
  1. 5 6
      README.md
  2. 4 1
      SConscript
  3. 26 5
      docs/api.md
  4. 35 6
      docs/migration-guide.md
  5. 20 8
      docs/samples.md
  6. 22 9
      docs/user-guide.md
  7. 9 8
      inc/webclient.h
  8. 101 35
      samples/webclient_get_sample.c
  9. 109 33
      samples/webclient_post_sample.c
  10. 289 127
      src/webclient.c
  11. 37 11
      src/webclient_file.c

+ 5 - 6
README.md

@@ -59,8 +59,10 @@ To use the WebClient software package, you need to select it in the RT-Thread pa
 RT-Thread online packages
     IoT-internet of things --->
          [*] WebClient: A HTTP/HTTPS Client for RT-Thread
-         [] Enable webclient GET/POST samples
-               Select TLS mode (Not support) --->
+         [ ]   Enable debug log output
+         [ ]   Enable webclient GET/POST samples
+         [ ]   Enable file download feature support
+               Select TLS mode (Not support)  --->
                    (x) Not support
                    () SAL TLS support
                    () MbedTLS support
@@ -68,13 +70,10 @@ RT-Thread online packages
 ```
 
 **Enable webclient GET/POST samples**: add sample code;
-
 **Select TLS mode**: Configure to enable HTTPS support and select the supported mode;
-
 - **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);
 - **MbedTLS support**: configure MbedTLS function support;
-
 **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.
@@ -90,10 +89,10 @@ After the configuration is complete, let the RT-Thread package manager automatic
 
 ## 4. Matters needing attention
 
+
  - 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).
 
-
 ## 5. Contact & Thanks
 
 - Maintenance: RT-Thread development team

+ 4 - 1
SConscript

@@ -3,7 +3,10 @@ from building import *
 cwd  = GetCurrentDir()
 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']):
     src += Glob('samples/*.c')

+ 26 - 5
docs/api.md

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

+ 35 - 6
docs/migration-guide.md

@@ -1,8 +1,10 @@
 # 迁移指南
 
+## 1、V1.0.0 -> V2.0.0 版本改动
+
 本节主要介绍 WebClient 软件包版本升级之后(`V1.0.0` -> 最近版本 `V2.0.0`),软件包的改动和适配最新版本的方式。
 
-## 函数改动
+### 函数改动
 
 1. 添加 `webclient_session_create()` 创建客户端结构体函数
 
@@ -29,9 +31,9 @@
 - 添加获取当前响应状态码函数(`webclient_resp_status_get` );
 - 添加获取当前响应 Content-Length 数据函数(`webclient_content_length_get`)。
 
-## 流程改动
+### 流程改动
 
-### GET 请求流程改动
+#### GET 请求流程改动
 
 下面以发送自定义头部数据的 GET 请求方式为例,介绍新版本软件包中 GET 流程改动。
 
@@ -93,7 +95,7 @@ while(1)
 webclient_close(session);
 ```
 
-### 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_post(session, URI, post_data);
+webclient_post(session, URI, post_data, rt_strlen(post_data));
 
 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`,用于适配非字符串数据接收和发送。
+

+ 20 - 8
docs/samples.md

@@ -23,8 +23,10 @@ WebClient 软件包提供两个 HTTP Client 示例程序, 分别用于演示软
 RT-Thread online packages
     IoT - internet of things  --->
         [*] WebClient: A HTTP/HTTPS Client for RT-Thread    
-        [ ]   Enable support tls protocol       
+        [ ]   Enable debug log output       
         [*]   Enable webclient GET/POST samples # 开启 WebClient 测试例程
+        [ ]   Enable file download feature support
+              Select TLS mode (Not support)  --->
               Version (latest)  --->            # 开启使用最新版本软件包
 ```
 
@@ -50,17 +52,22 @@ GET 请求示例流程:
 
 GET 请求示例使用方式有如下两种:
 
-- 在 MSH 中使用命令 `web_get_test` 执行 GET 请求示例程序,可以获取并打印显示默认网址下载的文件信息,如下图 LOG 显示:
+- 在 MSH 中使用命令 `web_get_test` 执行 GET 请求示例程序,可以获取并打印显示默认网址下载的文件信息;在 MSH 中使用命令 `web_get_test -s` 执行 POST 请求示例程序使用简化接口(webclient_request 接口)发送 GET请求,适用于简短数据的收发。如下图 LOG 显示:
 
 ```c
-msh />web_get_test
-webclient GET request response data :
+msh />web_get_test 
+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.
 
 msh />
 ```
 
-- 在 MSH 中使用命令 `web_get_test [URI]` 格式命令执行 GET 请求示例程序,其中 URI 为用户自定义的支持 GET 请求的地址。
+- 在 MSH 中使用命令 `web_get_test [URI]`  或 `web_get_test -s [URI]` 格式命令执行 GET 请求示例程序,其中 URI 为用户自定义的支持 GET 请求的地址。
 
 ### POST 请求示例
 
@@ -75,13 +82,18 @@ 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
 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!
+msh />
 ```
 
-- 在 MSH 中使用命令 `web_post_test [URI]` 格式命令执行 POST 请求示例程序,其中 URI 为用户自定义的支持 POST 请求的地址。
+- 在 MSH 中使用命令 `web_post_test [URI]` 或者 `web_post_test -s [URI]` 格式命令执行 POST 请求示例程序,其中 URI 为用户自定义的支持 POST 请求的地址。

+ 22 - 9
docs/user-guide.md

@@ -14,6 +14,7 @@
 RT-Thread online packages
     IoT - internet of things  --->
          [*] WebClient: A HTTP/HTTPS Client for RT-Thread
+         [ ]   Enable debug log output
          [ ]   Enable webclient GET/POST samples
                Select TLS mode (Not support)  --->
                    (x) Not support
@@ -22,6 +23,8 @@ RT-Thread online packages
               Version (latest)  --->
 ```
 
+**Enable debug log output**:开启调试日志显示,可以用于查看请求和响应的头部数据信息;
+
 **Enable webclient GET/POST samples** :添加示例代码;
 
 **Select TLS mode** :配置开启 HTTPS 支持,选择支持的模式;
@@ -135,7 +138,7 @@ if ((resp_status = webclient_get(session, URI)) != 200)
 
 (4) **接收响应的数据**
 
-发送 GET/POST 请求之后,可以使用 `webclient_read` 函数接收响应的实际数据。因为响应的实际数据可能比较长,所以往往我们需要循环接收响应数据,指导数据接收完毕。
+发送 GET/POST 请求之后,可以使用 `webclient_read` 函数接收响应的实际数据。因为响应的实际数据可能比较长,所以往往我们需要循环接收响应数据,直到数据接收完毕。
 
 如下所示为循环接收并打印响应数据方式:
 
@@ -253,6 +256,7 @@ webclient_close(session);
 
 ```c
 struct webclient_session *session = NULL;
+size_t length = 0;
 char *result;
 
 session = webclient_create(1024);
@@ -262,7 +266,7 @@ if(webclient_get(session, URI) != 200)
     LOG_E("error!");
 }
 
-webclient_response(session, &result);
+webclient_response(session, &result, &length);
 
 web_free(result);
 webclient_close(session);
@@ -273,9 +277,13 @@ webclient_close(session);
     多用于接收数据长度较小,且头部信息已经拼接给出的 GET 请求。
 
 ```c
-char *result;    
+size_t length = 0;
+char *result, *header = RT_NULL;
+
+/* 拼接自定义头部数据 */
+webclient_request_header_add(&header, "User-Agent: RT-Thread HTTP Agent\r\n");
 
-webclient_request(URI, header, NULL, &result);
+webclient_request(URI, header, NULL, 0, &result, &length);
 
 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_post 第三个传输上传数据为 NULL,改为下面循环上传数据*/
-if( webclient_post(session, URI, NULL) != 200)
+if( webclient_post(session, URI, NULL, 0) != 200)
 {
     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-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!");
 }
@@ -341,8 +349,13 @@ webclient_close(session);
 
 ```c
 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 支持。
 
-- 解决方法:在 WebClient 软件包 menuconfig 配置选项中开启 `Enable support tls protocol` 选项支持
+- 解决方法:在 WebClient 软件包 menuconfig 配置选项中  选择 `Select TLS mode` 选项为 `MbedTLS support` 或者 `SAL TLS support`
 
 ### 头部数据长度超出
 
@@ -365,4 +378,4 @@ webclient_request(URI, NULL, post_data, NULL);
 
 - 原因:添加的头部数据长度超过了最大支持的头部数据长度。
 
-- 解决方法:在创建客户端会话结构体的时候,增大传入的最大支持的头部数据长度。
+- 解决方法:在创建客户端会话结构体的时候,增大传入的最大支持的头部数据长度。

+ 9 - 8
inc/webclient.h

@@ -25,7 +25,7 @@
 
 #ifdef __cplusplus
 extern "C" {
-#endif   
+#endif
 
 #ifndef web_malloc
 #define web_malloc                     rt_malloc
@@ -47,8 +47,8 @@ extern "C" {
 #define web_strdup                     rt_strdup
 #endif
 
-#define WEBCLIENT_SW_VERSION           "2.0.1"
-#define WEBCLIENT_SW_VERSION_NUM       0x20001
+#define WEBCLIENT_SW_VERSION           "2.2.0"
+#define WEBCLIENT_SW_VERSION_NUM       0x20200
 
 #define WEBCLIENT_HEADER_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);
 
 /* 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 */
 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);
 
 /* send or receive data from server */
-int webclient_read(struct webclient_session *session, unsigned char *buffer, size_t size);
-int webclient_write(struct webclient_session *session, const 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 void *buffer, size_t size);
 
 /* webclient GET/POST header buffer operate by the header fields */
 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);
 
 /* send HTTP POST/GET request, and get response data */
-int webclient_response(struct webclient_session *session, unsigned char **response);
-int webclient_request(const char *URI, const char *header, const char *post_data, 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 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_content_length_get(struct webclient_session *session);
 

+ 101 - 35
samples/webclient_get_sample.c

@@ -16,40 +16,16 @@
 
 #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;
     unsigned char *buffer = RT_NULL;
-    char *URI = RT_NULL;
     int index, ret = 0;
     int bytes_read, resp_status;
     int content_length = -1;
 
-    if (argc == 1)
-    {
-        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);
+    buffer = (unsigned char *) web_malloc(GET_RESP_BUFSZ);
     if (buffer == RT_NULL)
     {
         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 */
-    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);
         ret = -RT_ERROR;
         goto __exit;
     }
 
-    rt_kprintf("webclient GET request response data :\n");
+    rt_kprintf("webclient get response data: \n");
 
     content_length = webclient_content_length_get(session);
     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");
         do
         {
-            bytes_read = webclient_read(session, buffer, GET_RESP_BUFSZ);
+            bytes_read = webclient_read(session, (void *)buffer, GET_RESP_BUFSZ);
             if (bytes_read <= 0)
             {
                 break;
@@ -102,7 +78,7 @@ int webclient_get_test(int argc, char **argv)
 
         do
         {
-            bytes_read = webclient_read(session, buffer, 
+            bytes_read = webclient_read(session, (void *)buffer, 
                     content_length - content_pos > GET_RESP_BUFSZ ?
                             GET_RESP_BUFSZ : content_length - content_pos);
             if (bytes_read <= 0)
@@ -132,15 +108,105 @@ __exit:
         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
 #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 */

+ 109 - 33
samples/webclient_post_sample.c

@@ -20,45 +20,20 @@
 
 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;
     unsigned char *buffer = RT_NULL;
-    char *URI = RT_NULL;
     int index, ret = 0;
     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);
     if (buffer == RT_NULL)
     {
         rt_kprintf("no memory for receive response buffer.\n");
         ret = -RT_ENOMEM;
         goto __exit;
-
     }
 
     /* 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");
 
     /* 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);
         ret = -RT_ERROR;
         goto __exit;
     }
 
-    rt_kprintf("webclient POST request response data :\n");
+    rt_kprintf("webclient post response data: \n");
     do
     {
         bytes_read = webclient_read(session, buffer, POST_RESP_BUFSZ);
@@ -109,15 +84,116 @@ __exit:
         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)
+{
+    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)
     {
-        web_free(URI);
+        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
 #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 */

+ 289 - 127
src/webclient.c

@@ -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
  *
@@ -14,11 +14,17 @@
  * 2018-08-07     chenyong     modify header processing
  */
 
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include <sys/time.h>
+#include <ctype.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" */
 #if defined(RT_USING_SAL)
 #include <netdb.h>
@@ -43,7 +49,39 @@
 
 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
     if (session->tls_session)
@@ -55,14 +93,14 @@ static int webclient_send(struct webclient_session* session, const unsigned char
     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
     if (session->tls_session)
     {
         return mbedtls_client_read(session->tls_session, buffer, len);
     }
-#endif 
+#endif
 
     return recv(session->socket, buffer, len, flag);
 }
@@ -83,8 +121,8 @@ static int webclient_read_line(struct webclient_session *session, char *buffer,
         if (session->is_tls && (rc == MBEDTLS_ERR_SSL_WANT_READ || rc == MBEDTLS_ERR_SSL_WANT_WRITE))
         {
             continue;
-        }    
-#endif 
+        }
+#endif
         if (rc <= 0)
             return rc;
 
@@ -116,17 +154,23 @@ static int webclient_read_line(struct webclient_session *session, char *buffer,
  * @return 0 on resolve server address OK, others failed
  *
  * 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://[fe80::1]
+ * http://[fe80::1]/
  * http://[fe80::1]/index.html
  * http://[fe80::1]:80/index.html
  */
 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;
     char *ptr;
     char port_str[6] = "80"; /* default port of 80(http) */
+    const char *port_ptr;
+    const char *path_ptr;
 
     const char *host_addr = 0;
     int url_len, host_addr_len = 0;
@@ -163,46 +207,40 @@ static int webclient_resolve_address(struct webclient_session *session, struct a
             goto __exit;
         }
         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))
-        {
-            int port_len = ptr - host_addr - host_addr_len - 2;
+    path_ptr = rt_strstr(host_addr, "/");
+    *request = path_ptr ? path_ptr : "/";
 
-            rt_strncpy(port_str, host_addr + host_addr_len + 2, port_len);
-            port_str[port_len] = '\0';
-        }
+    /* resolve port */
+    port_ptr = rt_strstr(host_addr + host_addr_len, ":");
+    if (port_ptr && path_ptr && (port_ptr < path_ptr))
+    {
+        int port_len = path_ptr - port_ptr - 1;
 
-        *request = (char *) ptr;
+        rt_strncpy(port_str, port_ptr + 1, port_len);
+        port_str[port_len] = '\0';
     }
-    else /* ipv4 or domain. */
+
+    if (port_ptr && (!path_ptr))
     {
-        char *port_ptr;
+        strcpy(port_str, port_ptr + 1);
+    }
 
-        ptr = rt_strstr(host_addr, "/");
-        if (!ptr)
+    /* ipv4 or domain. */
+    if (!host_addr_len)
+    {
+        if (port_ptr)
         {
-            rc = -WEBCLIENT_ERROR;
-            goto __exit;
+            host_addr_len = port_ptr - host_addr;
         }
-        host_addr_len = ptr - host_addr;
-        *request = (char *) ptr;
-        
-        /* resolve port */
-        port_ptr = rt_strstr(host_addr, ":");
-        if (port_ptr && port_ptr < ptr)
+        else if (path_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 = path_ptr - host_addr;
+        }
+        else
+        {
+            host_addr_len = strlen(host_addr);
         }
     }
 
@@ -238,7 +276,7 @@ static int webclient_resolve_address(struct webclient_session *session, struct a
         {
             return -WEBCLIENT_NOMEM;
         }
-        
+
         return rc;
     }
 #endif
@@ -333,14 +371,11 @@ static int webclient_connect(struct webclient_session *session, const char *URI)
     int socket_handle;
     struct timeval timeout;
     struct addrinfo *res = RT_NULL;
-    char *req_url;
+    const char *req_url;
 
     RT_ASSERT(session);
     RT_ASSERT(URI);
 
-    /* initialize the socket of session */
-    session->socket = -1;
-
     timeout.tv_sec = WEBCLIENT_DEFAULT_TIMEO;
     timeout.tv_usec = 0;
 
@@ -353,7 +388,7 @@ static int webclient_connect(struct webclient_session *session, const char *URI)
         {
             LOG_E("connect failed, https client open URI(%s) failed!", URI);
             return -WEBCLIENT_ERROR;
-        } 
+        }
         session->is_tls = RT_TRUE;
 #else
         LOG_E("not support https connect, please enable webclient https configure!");
@@ -527,7 +562,7 @@ const char *webclient_header_fields_get(struct webclient_session *session, const
     resp_buf = session->header->buffer;
     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;
 
@@ -652,7 +687,7 @@ static int webclient_send_header(struct webclient_session *session, int method)
             }
 
             /* 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;
 
             /* 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:
     return rc;
 }
@@ -697,6 +753,7 @@ int webclient_handle_response(struct webclient_session *session)
     rt_memset(session->header->buffer, 0x00, session->header->size);
     session->header->length = 0;
 
+    LOG_D("response header:");
     /* We now need to read the header information */
     while (1)
     {
@@ -719,6 +776,9 @@ int webclient_handle_response(struct webclient_session *session)
         /* set terminal charater */
         mime_buffer[rc - 1] = '\0';
 
+        /* echo response header data */
+        LOG_D("%s", mime_buffer);
+
         session->header->length += rc;
 
         if (session->header->length >= session->header->size)
@@ -803,6 +863,8 @@ struct webclient_session *webclient_session_create(size_t header_sz)
         return RT_NULL;
     }
 
+    /* initialize the socket of session */
+    session->socket = -1;
     session->content_length = -1;
 
     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->buffer = (char *) web_malloc(header_sz);
+    session->header->buffer = (char *) web_calloc(1, header_sz);
     if (session->header->buffer == RT_NULL)
     {
         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;
 }
 
+static int webclient_clean(struct webclient_session *session);
+
 /**
  *  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 */
     resp_status = webclient_handle_response(session);
+
+    LOG_D("get position handle response(%d).", resp_status);
+
     if (resp_status > 0)
     {
         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;
             }
 
-            /* close old client session */
-            webclient_close(session);
-
-            /* create new client session by location url */
-            session = webclient_session_create(WEBCLIENT_HEADER_BUFSZ);
-            if (session == RT_NULL)
-            {
-                return  -WEBCLIENT_NOMEM;
-            }
+            /* clean webclient session */
+            webclient_clean(session);
+            /* clean webclient session header */
+            session->header->length = 0;
+            rt_memset(session->header->buffer, 0, session->header->size);
 
             rc = webclient_get(session, new_url);
 
             web_free(new_url);
             return rc;
         }
-        else if (resp_status != 200)
-        {
-            LOG_E("get failed, handle response(%d) error!", 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 */
     resp_status = webclient_handle_response(session);
+
+    LOG_D("get position handle response(%d).", resp_status);
+
     if (resp_status > 0)
     {
         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;
             }
 
-            /* close old client session */
-            webclient_close(session);
-
-            /* create new client session by location url */
-            session = webclient_session_create(WEBCLIENT_HEADER_BUFSZ);
-            if (session == RT_NULL)
-            {
-                return  -WEBCLIENT_NOMEM;
-            }
+            /* clean webclient session */
+            webclient_clean(session);
+            /* clean webclient session header */
+            session->header->length = 0;
+            rt_memset(session->header->buffer, 0, session->header->size);
 
-            rc = webclient_get(session, new_url);
+            rc = webclient_get_position(session, new_url, position);
 
             web_free(new_url);
             return rc;
         }
-        else if (resp_status != 206)
-        {
-            LOG_E("get failed, handle response(%d) error!", 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 URI input server URI address
  * @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: send header and body data, resolve response data
+ * @param data_len the length of send data
  *
  * @return <0: send POST request failed
  *         =0: send POST header success
  *         >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 resp_status = 0;
@@ -1005,6 +1058,12 @@ int webclient_post(struct webclient_session *session, const char *URI, const cha
     RT_ASSERT(session);
     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);
     if (rc != WEBCLIENT_OK)
     {
@@ -1019,17 +1078,13 @@ int webclient_post(struct webclient_session *session, const char *URI, const cha
         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 */
         resp_status = webclient_handle_response(session);
-        if (resp_status != 200)
-        {
-            LOG_E("post failed, handle response(%d) error.", resp_status);
-            return resp_status;
-        }
+        LOG_D("post handle response(%d).", resp_status);
     }
 
     return resp_status;
@@ -1070,6 +1125,7 @@ static int webclient_next_chunk(struct webclient_session *session)
 
     RT_ASSERT(session);
 
+    rt_memset(line, 0x00, sizeof(line));
     length = webclient_read_line(session, line, sizeof(line));
     if (length > 0)
     {
@@ -1100,6 +1156,7 @@ static int webclient_next_chunk(struct webclient_session *session)
         /* end of chunks */
         closesocket(session->socket);
         session->socket = -1;
+        session->chunk_sz = -1;
     }
 
     return session->chunk_sz;
@@ -1116,7 +1173,7 @@ static int webclient_next_chunk(struct webclient_session *session)
  *         =0: http server disconnect
  *         >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 total_read = 0;
@@ -1124,6 +1181,12 @@ int webclient_read(struct webclient_session *session, unsigned char *buffer, siz
 
     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)
     {
         return -WEBCLIENT_DISCONNECT;
@@ -1187,18 +1250,18 @@ int webclient_read(struct webclient_session *session, unsigned char *buffer, siz
     left = length;
     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 defined(WEBCLIENT_USING_SAL_TLS) || defined(WEBCLIENT_USING_MBED_TLS)
-            if(session->is_tls && 
+            if(session->is_tls &&
                 (bytes_read == MBEDTLS_ERR_SSL_WANT_READ || bytes_read == MBEDTLS_ERR_SSL_WANT_WRITE))
             {
                 continue;
             }
-                
-#endif  
-            LOG_E("receive data error(%d).", bytes_read);
+
+#endif
+            LOG_D("receive data error(%d).", bytes_read);
 
             if (total_read)
             {
@@ -1245,7 +1308,7 @@ int webclient_read(struct webclient_session *session, unsigned char *buffer, siz
  *         =0: http server disconnect
  *         >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 total_write = 0;
@@ -1266,11 +1329,11 @@ int webclient_write(struct webclient_session *session, const unsigned char *buff
     /* send all of data on the buffer. */
     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 defined(WEBCLIENT_USING_SAL_TLS) || defined(WEBCLIENT_USING_MBED_TLS)
-            if(session->is_tls && 
+            if(session->is_tls &&
                 (bytes_write == MBEDTLS_ERR_SSL_WANT_READ || bytes_write == MBEDTLS_ERR_SSL_WANT_WRITE))
             {
                 continue;
@@ -1308,17 +1371,9 @@ int webclient_write(struct webclient_session *session, const unsigned char *buff
     return total_write;
 }
 
-/**
- * close a webclient client session.
- *
- * @param session http client session
- *
- * @return 0: close success
- */
-int webclient_close(struct webclient_session *session)
+/* close session socket, free host and request url */
+static int webclient_clean(struct webclient_session *session)
 {
-    RT_ASSERT(session);
-    
 #ifdef WEBCLIENT_USING_MBED_TLS
     if (session->tls_session)
     {
@@ -1328,7 +1383,7 @@ int webclient_close(struct webclient_session *session)
     {
         if (session->socket >= 0)
         {
-            closesocket(session->socket); 
+            closesocket(session->socket);
             session->socket = -1;
         }
     }
@@ -1343,13 +1398,33 @@ int webclient_close(struct webclient_session *session)
     if (session->host)
     {
         web_free(session->host);
+        session->host = RT_NULL;
     }
 
     if (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)
     {
         web_free(session->header->buffer);
@@ -1374,10 +1449,11 @@ int webclient_close(struct webclient_session *session)
  *
  * @param session wenclient session
  * @param response response buffer address
+ * @param resp_len response buffer length
  *
  * @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 *response_buf = 0;
@@ -1423,8 +1499,8 @@ int webclient_response(struct webclient_session *session, unsigned char **respon
         int result_sz;
 
         result_sz = session->content_length;
-        response_buf = web_malloc(result_sz + 1);
-        if (!response_buf)
+        response_buf = web_calloc(1, result_sz + 1);
+        if (response_buf == RT_NULL)
         {
             return -WEBCLIENT_NOMEM;
         }
@@ -1449,13 +1525,67 @@ int webclient_response(struct webclient_session *session, unsigned char **respon
 
     if (response_buf)
     {
-        *response = response_buf;
+        *response = (void *)response_buf;
         *(response_buf + total_read) = '\0';
+        *resp_len = 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.
  *
@@ -1466,16 +1596,18 @@ int webclient_response(struct webclient_session *session, unsigned char **respon
  * @param post_data data sent to the server
  *             = NULL: it is GET request
  *            != NULL: it is POST request
+ * @param data_len send data length
  * @param response response buffer address
+ * @param resp_len response buffer length
  *
  * @return <0: request failed
  *        >=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 totle_length;
+    int totle_length = 0;
 
     RT_ASSERT(URI);
 
@@ -1485,8 +1617,22 @@ int webclient_request(const char *URI, const char *header, const char *post_data
         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)
     {
+        /* send get request */
         session = webclient_session_create(WEBCLIENT_HEADER_BUFSZ);
         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)
         {
-            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)
@@ -1505,7 +1659,7 @@ int webclient_request(const char *URI, const char *header, const char *post_data
             goto __exit;
         }
 
-        totle_length = webclient_response(session, response);
+        totle_length = webclient_response(session, response, resp_len);
         if (totle_length <= 0)
         {
             rc = -WEBCLIENT_ERROR;
@@ -1514,6 +1668,7 @@ int webclient_request(const char *URI, const char *header, const char *post_data
     }
     else
     {
+        /* send post request */
         session = webclient_session_create(WEBCLIENT_HEADER_BUFSZ);
         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)
         {
-            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));
+        }
+
+        if (rt_strstr(session->header->buffer, "Content-Type") == RT_NULL)
+        {
             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;
             goto __exit;
         }
-        
-        totle_length = webclient_response(session, response);
+
+        totle_length = webclient_response(session, response, resp_len);
         if (totle_length <= 0)
         {
             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:
     if (session)
     {

+ 37 - 11
src/webclient_file.c

@@ -74,7 +74,7 @@ int webclient_get_file(const char* URI, const char* filename)
         rc = -WEBCLIENT_NOMEM;
         goto __exit;
     }
-	
+
     if (session->content_length < 0)
     {
         while (1)
@@ -158,6 +158,7 @@ int webclient_post_file(const char* URI, const char* filename,
     char *header = RT_NULL, *header_ptr;
     unsigned char *buffer = RT_NULL, *buffer_ptr;
     struct webclient_session* session = RT_NULL;
+    int resp_data_len = 0;
 
     fd = open(filename, O_RDONLY, 0);
     if (fd < 0)
@@ -171,7 +172,7 @@ int webclient_post_file(const char* URI, const char* filename,
     length = lseek(fd, 0, SEEK_END);
     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)
     {
         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;
     }
 
-    header = (char *) web_malloc(WEBCLIENT_HEADER_BUFSZ);
+    header = (char *) web_calloc(1, WEBCLIENT_HEADER_BUFSZ);
     if (header == RT_NULL)
     {
         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");
     /* calculate content-length */
     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 */
     header_ptr += rt_snprintf(header_ptr,
@@ -221,10 +222,11 @@ int webclient_post_file(const char* URI, const char* filename,
         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);
-    if( rc< 0)
+    rc = webclient_post(session, URI, NULL, 0);
+    if(rc < 0)
     {
         goto __exit;
     }
@@ -246,7 +248,32 @@ int webclient_post_file(const char* URI, const char* filename,
 
     /* send last 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:
     if (fd >= 0)
@@ -269,15 +296,14 @@ __exit:
         web_free(header);
     }
 
-    return 0;
+    return rc;
 }
 
-
 int wget(int argc, char** argv)
 {
     if (argc != 3)
     {
-        rt_kprintf("Please using: wget <URI> <filename>");
+        rt_kprintf("Please using: wget <URI> <filename>\n");
         return -1;
     }