Bladeren bron

【重构】修改 HTTP 头数据添加和发送方式,添加对头数据的解析方式

Signed-off-by: chenyong <1521761801@qq.com>
chenyong 7 jaren geleden
bovenliggende
commit
b5a9d4a83d
5 gewijzigde bestanden met toevoegingen van 371 en 380 verwijderingen
  1. 25 35
      inc/webclient.h
  2. 24 9
      samples/webclient_get_sample.c
  3. 18 23
      samples/webclient_post_sample.c
  4. 293 305
      src/webclient.c
  5. 11 8
      src/webclient_file.c

+ 25 - 35
inc/webclient.h

@@ -24,6 +24,7 @@
  * 2017-12-23     aozima       update gethostbyname to getaddrinfo.
  * 2018-01-04     aozima       add ipv6 address support.
  * 2018-07-26     chenyong     modify log information
+ * 2018-08-07     chenyong     modify header processing
  */
 
 #ifndef __WEBCLIENT_H__
@@ -96,59 +97,43 @@ enum WEBCLIENT_METHOD
     WEBCLIENT_POST,
 };
 
+struct  webclient_header
+{
+    char *buffer;
+    size_t length;                      /* content header buffer size */
+
+    size_t size;                        /* maximum support header size */
+};
+
 struct webclient_session
 {
-    /* the session socket */
+    struct webclient_header *header;    /* webclient response header information */
     int socket;
-    /* the response code of HTTP request */
-    int response;
+    int resp_status;
+
+    char *host;                         /* server host */
+    char *request;                      /* HTTP request address*/
 
-    /* transfer encoding */
-    char *transfer_encoding;
     int chunk_sz;
     int chunk_offset;
 
-    /* content_type of HTTP response */
-    char *content_type;
-    /* content_length of HTTP response */
-    int  content_length;
-
-    /* last modified timestamp of resource */
-    char *last_modified;
-
-    /* location */
-    char *location;
-
-    /* server host */
-    char *host;
-    /* HTTP request */
-    char *request;
-
-    /* position of reading */
-    unsigned int position;
-
-    /* remainder of content reading */
-    size_t content_length_remainder;
-    
-    int header_sz;
-    int resp_sz;
+    int content_length;
+    size_t content_remainder;           /* remainder of content length */
 
 #ifdef WEBCLIENT_USING_TLS
-        /* mbedtls connect session */
-        MbedTLSSession *tls_session;
+    MbedTLSSession *tls_session;        /* mbedtls connect session */
 #endif
 };
 
 /* create webclient session and set header response size */
-struct webclient_session *webclient_session_create(size_t header_sz, size_t resp_sz);
+struct webclient_session *webclient_session_create(size_t header_sz);
 
 /* send HTTP GET request */
-int webclient_get(struct webclient_session *session, const char *URI, const char *header);
+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 *header, const char *post_data);
+int webclient_post(struct webclient_session *session, const char *URI, const char *post_data);
 
 /* close and release wenclient session */
 int webclient_close(struct webclient_session *session);
@@ -159,6 +144,11 @@ int webclient_set_timeout(struct webclient_session *session, int millisecond);
 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);
 
+/* webclient GET/POST header buffer operate by the header fields */
+int webclient_header_fields_add(struct webclient_session *session, const char *fmt, ...);
+char *webclient_header_fields_get(struct webclient_session *session, const char *fields);
+int webclient_header_resp_status_get(struct webclient_session *session);
+
 /* 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);

+ 24 - 9
samples/webclient_get_sample.c

@@ -24,8 +24,8 @@
 #include <rtthread.h>
 #include <webclient.h>
 
-#define GET_RESP_BUFSZ                 1024
 #define GET_HEADER_BUFSZ               1024
+#define GET_RESP_BUFSZ                 1024
 
 #define GET_LOCAL_URI                  "http://www.rt-thread.com/service/rt-thread.txt"
 
@@ -35,15 +35,26 @@ int webclient_get_test(int argc, char **argv)
     unsigned char *buffer = RT_NULL;
     char *URI = RT_NULL;
     int index, ret = 0;
-    int bytes_read;
+    int bytes_read, resp_status;
+    int content_length = -1;
 
     if (argc == 1)
     {
         URI = web_strdup(GET_LOCAL_URI);
+        if(URI == RT_NULL)
+        {
+            LOG_E("no memory for create URI buffer.");
+            return -1;
+        }
     }
     else if (argc == 2)
     {
         URI = web_strdup(argv[1]);
+        if(URI == RT_NULL)
+        {
+            LOG_E("no memory for create URI buffer.");
+            return -1;
+        }
     }
     else
     {
@@ -51,7 +62,7 @@ int webclient_get_test(int argc, char **argv)
         return -1;
     }
 
-    buffer = (unsigned char *) web_malloc(GET_RESP_BUFSZ);
+    buffer = (unsigned char *) web_malloc(GET_HEADER_BUFSZ);
     if (buffer == RT_NULL)
     {
         LOG_E("no memory for receive buffer.");
@@ -61,7 +72,7 @@ int webclient_get_test(int argc, char **argv)
     }
 
     /* create webclient session and set header response size */
-    session = webclient_session_create(GET_HEADER_BUFSZ, GET_RESP_BUFSZ);
+    session = webclient_session_create(GET_HEADER_BUFSZ);
     if (session == RT_NULL)
     {
         ret = -RT_ENOMEM;
@@ -69,16 +80,21 @@ int webclient_get_test(int argc, char **argv)
     }
 
     /* send GET request by default header */
-    if (webclient_get(session, URI, NULL) != 200)
+    if ((resp_status = webclient_get(session, URI)) != 200)
     {
-        LOG_E("webclient GET request failed, response(%d) error.", session->response);
+        LOG_E("webclient GET request failed, response(%d) error.", resp_status);
         ret = -RT_ERROR;
         goto __exit;
     }
 
     LOG_I("webclient GET request response data :");
 
-    if (session->content_length < 0)
+    if(webclient_header_fields_get(session, "Content-Length"))
+    {
+        content_length = atoi(webclient_header_fields_get(session, "Content-Length"));
+    }
+
+    if (content_length < 0)
     {
         LOG_D("The webclient GET request type is chunked.");
         do
@@ -100,7 +116,6 @@ int webclient_get_test(int argc, char **argv)
     else
     {
         int content_pos = 0;
-        int content_length = session->content_length;
 
         do
         {
@@ -142,5 +157,5 @@ __exit:
 
 #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, web_get_test [URI]  webclient GET request test);
 #endif /* FINSH_USING_MSH */

+ 18 - 23
samples/webclient_post_sample.c

@@ -37,18 +37,27 @@ int webclient_post_test(int argc, char **argv)
 {
     struct webclient_session* session = RT_NULL;
     unsigned char *buffer = RT_NULL;
-    char *header = RT_NULL;
     char *URI = RT_NULL;
     int index, ret = 0;
-    int bytes_read;
+    int bytes_read, resp_status;
 
     if (argc == 1)
     {
         URI = web_strdup(POST_LOCAL_URI);
+        if(URI == RT_NULL)
+        {
+            LOG_E("no memory for create URI buffer.");
+            return -1;
+        }
     }
     else if (argc == 2)
     {
         URI = web_strdup(argv[1]);
+        if(URI == RT_NULL)
+        {
+            LOG_E("no memory for create URI buffer.");
+            return -1;
+        }
     }
     else
     {
@@ -56,15 +65,6 @@ int webclient_post_test(int argc, char **argv)
         return -1;
     }
 
-    header = (char *) web_malloc(POST_HEADER_BUFSZ);
-    if (header == RT_NULL)
-    {
-        LOG_E("no memory for header data.");
-        ret = -RT_ENOMEM;
-        goto __exit;
-
-    }
-
     buffer = (unsigned char *) web_malloc(POST_RESP_BUFSZ);
     if (buffer == RT_NULL)
     {
@@ -74,22 +74,22 @@ int webclient_post_test(int argc, char **argv)
 
     }
 
-    /* build header for upload */
-    rt_snprintf(header, POST_HEADER_BUFSZ, "Content-Length: %d\r\n", strlen(post_data));
-    rt_snprintf(header, POST_HEADER_BUFSZ, "%sContent-Type: application/octet-stream\r\n", header);
-
     /* create webclient session and set header response size */
-    session = webclient_session_create(POST_HEADER_BUFSZ, POST_RESP_BUFSZ);
+    session = webclient_session_create(POST_HEADER_BUFSZ);
     if (session == RT_NULL)
     {
         ret = -RT_ENOMEM;
         goto __exit;
     }
 
+    /* build header for upload */
+    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");
+
     /* send POST request by default header */
-    if (webclient_post(session, URI, header, post_data) != 200)
+    if ((resp_status = webclient_post(session, URI, post_data)) != 200)
     {
-        LOG_E("webclient POST request failed, response(%d) error.", session->response);
+        LOG_E("webclient POST request failed, response(%d) error.", resp_status);
         ret = -RT_ERROR;
         goto __exit;
     }
@@ -122,11 +122,6 @@ __exit:
         web_free(buffer);
     }
 
-    if (header)
-    {
-        web_free(header);
-    }
-
     if (URI)
     {
         web_free(URI);

+ 293 - 305
src/webclient.c

@@ -24,6 +24,7 @@
  * 2017-12-23     aozima       update gethostbyname to getaddrinfo.
  * 2018-01-04     aozima       add ipv6 address support.
  * 2018-07-26     chenyong     modify log information
+ * 2018-08-07     chenyong     modify header processing
  */
 
 #include <string.h>
@@ -68,45 +69,10 @@ static int webclient_recv(struct webclient_session* session, unsigned char *buff
     return recv(session->socket, buffer, len, flag);
 }
 
-static char *webclient_header_skip_prefix(char *line, const char *prefix)
-{
-    char *ptr;
-    size_t len;
-
-    RT_ASSERT(line);
-    RT_ASSERT(prefix);
-
-    len = strlen(prefix);
-
-    if (strncmp(line, prefix, len))
-        return RT_NULL;
-
-    ptr = line + len;
-
-    /* skip whitespace */
-    while (*ptr && (*ptr == ' ' || *ptr == '\t'))
-        ptr += 1;
-
-    /* remove '\r\n' */
-    line = ptr;
-    ptr = strstr(line, "\r\n");
-    if (ptr != RT_NULL)
-    {
-        *ptr = '\0';
-    }
-
-    return line;
-}
-
-/*
- * When a request has been sent, we can expect mime headers to be
- * before the data.  We need to read exactly to the end of the headers
- * and no more data.  This readline reads a single char at a time.
- */
 static int webclient_read_line(struct webclient_session *session, char *buffer, int size)
 {
-    char *ptr = buffer;
     int rc, count = 0;
+    char ch = 0, last_ch = 0;
 
     RT_ASSERT(session);
     RT_ASSERT(buffer);
@@ -114,7 +80,7 @@ static int webclient_read_line(struct webclient_session *session, char *buffer,
     /* Keep reading until we fill the buffer. */
     while (count < size)
     {
-        rc = webclient_recv(session, (unsigned char *)ptr, 1, 0);
+        rc = webclient_recv(session, (unsigned char *)&ch, 1, 0);
 #ifdef WEBCLIENT_USING_TLS
         if(session->tls_session && rc == MBEDTLS_ERR_SSL_WANT_READ)
             continue;
@@ -122,22 +88,19 @@ static int webclient_read_line(struct webclient_session *session, char *buffer,
         if (rc <= 0)
             return rc;
 
-        if (*ptr == '\n')
-        {
-            ptr++;
-            count++;
+        if (ch == '\n' && last_ch == '\r')
             break;
-        }
 
-        /* increment after check for cr.  Don't want to count the cr. */
-        count++;
-        ptr++;
-    }
+        buffer[count++] = ch;
 
-    /* add terminate string */
-    *ptr = '\0';
+        last_ch = ch;
+    }
 
-    LOG_D("read line: %s", buffer);
+    if(count > size)
+    {
+        LOG_E("read line failed. The line data length is out of buffer size(%d)!", count);
+        return -WEBCLIENT_ERROR;
+    }
 
     return count;
 }
@@ -344,7 +307,7 @@ static int webclient_open_tls(struct webclient_session *session, const char *URI
         return -WEBCLIENT_NOMEM;
     }
 
-    session->tls_session->buffer_len = session->resp_sz;
+    session->tls_session->buffer_len = WEBCLIENT_RESPONSE_BUFSZ;
     session->tls_session->buffer = web_malloc(session->tls_session->buffer_len);
     if(session->tls_session->buffer == RT_NULL)
     {
@@ -491,118 +454,179 @@ __exit:
     return rc;
 }
 
-static int webclient_send_header(struct webclient_session *session, int method,
-                          const char *header, size_t header_sz)
+/**
+ * add fields data to request header data.
+ *
+ * @param session webclient session
+ * @param fmt fields format
+ *
+ * @return >0: Number of successfully added
+ *         <0: not enough header buffer size
+ */
+int webclient_header_fields_add(struct webclient_session *session, const char *fmt, ...)
+{
+    rt_int32_t length;
+    va_list args;
+
+    RT_ASSERT(session);
+    RT_ASSERT(session->header->buffer);
+
+    va_start(args, fmt);
+    length = rt_vsnprintf(session->header->buffer + session->header->length, session->header->size, fmt, args);
+    va_end(args);
+
+    session->header->length += length;
+
+    /* check header size */
+    if(session->header->length >= session->header->size)
+    {
+        LOG_E("not enough header buffer size(%d)!", session->header->size);
+        return -WEBCLIENT_ERROR;
+    }
+
+    return length;
+}
+
+/**
+ * get fields information from request/response header data.
+ *
+ * @param session webclient session
+ * @param fields fields keyword
+ *
+ * @return = NULL: get fields data filed
+ *        != NULL: success get fields data
+ */
+char *webclient_header_fields_get(struct webclient_session *session, const char *fields)
 {
-    int rc = WEBCLIENT_OK;
-    unsigned char *header_buffer = RT_NULL, *header_ptr;
+    char *resp_buf = RT_NULL;
+    size_t resp_buf_len = 0;
 
     RT_ASSERT(session);
+    RT_ASSERT(session->header->buffer);
 
-    if (header == RT_NULL)
+    resp_buf = session->header->buffer;
+    while(resp_buf_len < session->header->length)
     {
-        header_buffer = web_malloc(session->header_sz);
-        if (header_buffer == RT_NULL)
+        if(strstr(resp_buf, fields))
         {
-            LOG_E("send header failed, no memory for header buffer!");
-            rc = -WEBCLIENT_NOMEM;
-            goto __exit;
+            char *mime_ptr = RT_NULL;
+
+            /* jump space */
+            mime_ptr = strstr(resp_buf, ":");
+            if(mime_ptr != NULL)
+            {
+                mime_ptr += 1;
+
+                while(*mime_ptr && (*mime_ptr == ' ' || *mime_ptr == '\t'))
+                    mime_ptr++;
+
+                return mime_ptr;
+            }
         }
 
-        header_ptr = header_buffer;
-        header_ptr += rt_snprintf((char *) header_ptr,
-                                  session->header_sz - (header_ptr - header_buffer),
-                                  "GET %s HTTP/1.1\r\n",
-                                  session->request ? session->request : "/");
-        header_ptr += rt_snprintf((char *) header_ptr,
-                                  session->header_sz - (header_ptr - header_buffer),
-                                  "Host: %s\r\n", session->host);
-        header_ptr += rt_snprintf((char *) header_ptr,
-                                  session->header_sz - (header_ptr - header_buffer),
-                                  "User-Agent: RT-Thread HTTP Agent\r\n\r\n");
+        if(*resp_buf == '\0')
+            break;
+
+        resp_buf += strlen(resp_buf) + 1;
+        resp_buf_len += strlen(resp_buf) + 1;
+    }
+
+    return RT_NULL;
+}
+
+/**
+ * get http response status code.
+ *
+ * @param session webclient session
+ *
+ * @return response status code
+ */
+int webclient_resp_status_get(struct webclient_session *session)
+{
+    return session->resp_status;
+}
+
+static int webclient_send_header(struct webclient_session *session, int method)
+{
+    int rc = WEBCLIENT_OK;
+    char *header = RT_NULL;
+
+    RT_ASSERT(session);
+
+    header = session->header->buffer;
 
-        webclient_write(session, header_buffer, header_ptr - header_buffer);
+    if(session->header->length == 0)
+    {
+        webclient_header_fields_add(session, "GET %s HTTP/1.1\r\n", session->request);
+        webclient_header_fields_add(session, "Host: %s\r\n", session->host);
+        webclient_header_fields_add(session, "User-Agent: RT-Thread HTTP Agent\r\n\r\n");
+
+        webclient_write(session, (unsigned char *)session->header->buffer, session->header->length);
     }
     else
     {
         if (method != WEBCLIENT_USER_METHOD)
         {
-            header_buffer = web_malloc(session->header_sz);
-            if (header_buffer == RT_NULL)
+            if (memcmp(header, "HTTP/1.", strlen("HTTP/1.")))
             {
-                LOG_E("send header failed, no memory for header buffer!");
-                rc = -WEBCLIENT_NOMEM;
-                goto __exit;
-            }
+                char *header_buffer = RT_NULL;
+                int length = 0;
 
-            header_ptr = header_buffer;
+                header_buffer = web_strdup(session->header->buffer);
+                if(header_buffer == RT_NULL)
+                {
+                    LOG_E("no memory for header buffer!");
+                    rc = -WEBCLIENT_NOMEM;
+                    goto __exit;
+                }
 
-            if (strstr(header, "HTTP/1.") == RT_NULL)
-            {
                 if (method == WEBCLIENT_GET)
-                    header_ptr += rt_snprintf((char *) header_ptr,
-                                              session->header_sz
-                                              - (header_ptr - header_buffer),
-                                              "GET %s HTTP/1.1\r\n",
-                                              session->request ? session->request : "/");
+                    length = rt_snprintf(session->header->buffer, session->header->size, "GET %s HTTP/1.1\r\n%s",
+                            session->request ? session->request : "/", header_buffer);
                 else if (method == WEBCLIENT_POST)
-                    header_ptr += rt_snprintf((char *) header_ptr,
-                                              session->header_sz
-                                              - (header_ptr - header_buffer),
-                                              "POST %s HTTP/1.1\r\n",
-                                              session->request ? session->request : "/");
+                    length = rt_snprintf(session->header->buffer, session->header->size, "POST %s HTTP/1.1\r\n%s",
+                            session->request ? session->request : "/", header_buffer);
+                session->header->length = length;
+
+                web_free(header_buffer);
             }
 
-            if (strstr(header, "Host:") == RT_NULL)
+            if (memcmp(header, "Host:", strlen("Host:")))
             {
-                header_ptr += rt_snprintf((char *) header_ptr,
-                                          session->header_sz - (header_ptr - header_buffer),
-                                          "Host: %s\r\n", session->host);
+                webclient_header_fields_add(session, "Host: %s\r\n", session->host);
             }
 
-            if (strstr(header, "User-Agent:") == RT_NULL)
+            if (memcmp(header, "User-Agent:", strlen("User-Agent:")))
             {
-                header_ptr += rt_snprintf((char *) header_ptr,
-                                          session->header_sz - (header_ptr - header_buffer),
-                                          "User-Agent: RT-Thread HTTP Agent\r\n");
+                webclient_header_fields_add(session, "User-Agent: RT-Thread HTTP Agent\r\n");
             }
 
-            if (strstr(header, "Accept: ") == RT_NULL)
+            if (memcmp(header, "Accept:", strlen("Accept:")))
             {
-                header_ptr += rt_snprintf((char *) header_ptr,
-                                          session->header_sz - (header_ptr - header_buffer),
-                                          "Accept: */*\r\n");
+                webclient_header_fields_add(session, "Accept: */*\r\n");
             }
 
-            if ((session->header_sz - (header_ptr - header_buffer))
-                    < (int) header_sz + 3)
+            /* append user's header */
+            rt_snprintf(session->header->buffer + session->header->length, session->header->size, "\r\n");
+            session->header->length += 2;
+
+            /* check header size */
+            if (session->header->length > session->header->size)
             {
-                LOG_E("send header failed, not enough header buffer size(%d)!", session->header_sz);
+                LOG_E("send header failed, not enough header buffer size(%d)!", session->header->size);
                 rc = -WEBCLIENT_NOBUFFER;
                 goto __exit;
             }
 
-            /* append user's header */
-            memcpy(header_ptr, header, header_sz);
-            header_ptr += header_sz;
-            header_ptr += rt_snprintf((char *) header_ptr,
-                                      session->header_sz - (header_ptr - header_buffer),
-                                      "\r\n");
-
-            webclient_write(session, header_buffer, header_ptr - header_buffer);
+            webclient_write(session, (unsigned char *)session->header->buffer, session->header->length);
         }
         else
         {
-            webclient_write(session, (unsigned char *) header, header_sz);
+            webclient_write(session, (unsigned char *)session->header->buffer, session->header->length);
         }
     }
 
 __exit:
-    if(header_buffer)
-    {
-        web_free(header_buffer);
-    }
-
     return rc;
 }
 
@@ -617,119 +641,74 @@ __exit:
 int webclient_handle_response(struct webclient_session *session)
 {
     int rc = WEBCLIENT_OK;
-    char *mime_buffer, *mime_ptr;
+    char *mime_buffer = RT_NULL;
+    char *mime_ptr = RT_NULL;
+    char *transfer_encoding = RT_NULL;
+    int i;
 
     RT_ASSERT(session);
 
-    /* set content length of session */
-    session->content_length = -1;
-
-    mime_buffer = (char *) web_malloc(session->resp_sz + 1);
-    if (!mime_buffer)
-    {
-        LOG_E("handle response failed, no memory for mime buffer!");
-        return -WEBCLIENT_NOMEM;
-    }
+    /* clean header buffer and size */
+    memset(session->header->buffer, 0x00, session->header->size);
+    session->header->length = 0;
 
     /* We now need to read the header information */
-    while (1)
+    while(1)
     {
-        int i;
+        mime_buffer = session->header->buffer + session->header->length;
 
         /* read a line from the header information. */
-        rc = webclient_read_line(session, mime_buffer, session->resp_sz);
-        if (rc < 0)
+        rc = webclient_read_line(session, mime_buffer, session->header->size - session->header->length);
+        if(rc < 0)
             break;
 
-        /* set terminal charater */
-        mime_buffer[rc] = '\0';
-
         /* End of headers is a blank line.  exit. */
         if (rc == 0)
             break;
-        if ((rc == 2) && (mime_buffer[0] == '\r'))
-            break;
-
-        mime_ptr = webclient_header_skip_prefix(mime_buffer, "HTTP/1.");
-        if (mime_ptr != RT_NULL)
-        {
-            mime_ptr += 1;
-            while (*mime_ptr && (*mime_ptr == ' ' || *mime_ptr == '\t'))
-                mime_ptr++;
-            /* Terminate string after status code */
-            for (i = 0; ((mime_ptr[i] != ' ') && (mime_ptr[i] != '\t')); i++);
-            mime_ptr[i] = '\0';
-
-            session->response = (int) strtol(mime_ptr, RT_NULL, 10);
-        }
-
-        mime_ptr = webclient_header_skip_prefix(mime_buffer, "Last-Modified:");
-        if (mime_ptr != RT_NULL)
-        {
-            session->last_modified = web_strdup(mime_ptr);
-        }
-
-        mime_ptr = webclient_header_skip_prefix(mime_buffer, "Transfer-Encoding: ");
-        if (mime_ptr != RT_NULL)
+        if ((rc == 1) && (mime_buffer[0] == '\r'))
         {
-            session->transfer_encoding = web_strdup(mime_ptr);
+            mime_buffer[0] = '\0';
+            break;
         }
 
-        mime_ptr = webclient_header_skip_prefix(mime_buffer, "Content-Type:");
-        if (mime_ptr != RT_NULL)
-        {
-            session->content_type = web_strdup(mime_ptr);
-        }
+        /* set terminal charater */
+        mime_buffer[rc-1] = '\0';
 
-        mime_ptr = webclient_header_skip_prefix(mime_buffer, "Content-Length:");
-        if (mime_ptr != RT_NULL)
-        {
-            session->content_length = (int) strtol(mime_ptr, RT_NULL, 10);
-        }
+        session->header->length += rc;
+    }
 
-        mime_ptr = webclient_header_skip_prefix(mime_buffer, "Location: ");
-        if (mime_ptr != RT_NULL)
-        {
-            session->location = web_strdup(mime_ptr);
-        }
+    /* get HTTP status code */
+    mime_ptr = strstr(session->header->buffer, "HTTP/1.");
+    if(mime_ptr != RT_NULL)
+    {
+        mime_ptr += strlen("HTTP/1.x");
 
-        mime_ptr = webclient_header_skip_prefix(mime_buffer, "Content-Range:");
-        if (mime_ptr != RT_NULL)
-        {
-            char *ptr = RT_NULL;
-            int totle_length;
+        while (*mime_ptr && (*mime_ptr == ' ' || *mime_ptr == '\t'))
+            mime_ptr++;
 
-            mime_ptr = webclient_header_skip_prefix(mime_ptr, "bytes");
-            while (*mime_ptr == ' ')
-                mime_ptr++;
+        /* Terminate string after status code */
+        for (i = 0; ((mime_ptr[i] != ' ') && (mime_ptr[i] != '\t')); i++);
+        mime_ptr[i] = '\0';
 
-            session->position = atoi(mime_ptr);
-            ptr = strstr(mime_ptr, "/");
-            if (ptr)
-            {
-                ptr ++;
-                /* The total length of the get data */
-                totle_length = atoi(ptr);
-                //TODO: process total length
-            }
-        }
+        session->resp_status = (int) strtol(mime_ptr, RT_NULL, 10);
     }
 
-    session->content_length_remainder =
-        (session->content_length) ? (size_t) session->content_length : 0xFFFFFFFF;
-
-    if (session->transfer_encoding && strcmp(session->transfer_encoding, "chunked") == 0)
+    /* get content length */
+    if(webclient_header_fields_get(session, "Content-Length") != RT_NULL)
     {
-        /* chunk mode, we should get the first chunk size */
-        webclient_read_line(session, mime_buffer, session->resp_sz);
-        session->chunk_sz = strtol(mime_buffer, RT_NULL, 16);
-        session->chunk_offset = 0;
+        session->content_length = atoi(webclient_header_fields_get(session, "Content-Length"));
     }
+    session->content_remainder = session->content_length ? (size_t) session->content_length : 0xFFFFFFFF;
 
-    /* release buffer */
-    if(mime_buffer)
+    transfer_encoding = webclient_header_fields_get(session, "Transfer-Encoding");
+    if (transfer_encoding && strcmp(transfer_encoding, "chunked") == 0)
     {
-        web_free(mime_buffer);
+        char line[16];
+
+        /* chunk mode, we should get the first chunk size */
+        webclient_read_line(session, line, session->header->size);
+        session->chunk_sz = strtol(line, RT_NULL, 16);
+        session->chunk_offset = 0;
     }
 
     if (rc < 0)
@@ -737,7 +716,7 @@ int webclient_handle_response(struct webclient_session *session)
         return rc;
     }
 
-    return session->response;
+    return webclient_resp_status_get(session);
 }
 
 /**
@@ -748,7 +727,7 @@ int webclient_handle_response(struct webclient_session *session)
  *
  * @return  webclient session structure
  */
-struct webclient_session *webclient_session_create(size_t header_sz, size_t resp_sz)
+struct webclient_session *webclient_session_create(size_t header_sz)
 {
     struct webclient_session *session;
 
@@ -756,12 +735,31 @@ struct webclient_session *webclient_session_create(size_t header_sz, size_t resp
     session = (struct webclient_session *) web_calloc(1, sizeof(struct webclient_session));
     if (session == RT_NULL)
     {
-        LOG_E("webclient create failed, no memory for session!");
+        LOG_E("webclient create failed, no memory for webclient session!");
+        return RT_NULL;
+    }
+
+    session->content_length = -1;
+
+    session->header = (struct webclient_header *) web_calloc(1, sizeof(struct webclient_header));
+    if (session->header == RT_NULL)
+    {
+        LOG_E("webclient create failed, no memory for session header!");
+        web_free(session);
+        session = RT_NULL;
         return RT_NULL;
     }
 
-    session->header_sz = header_sz;
-    session->resp_sz = resp_sz;
+    session->header->size = header_sz;
+    session->header->buffer = (char *) web_malloc(header_sz);
+    if(session->header->buffer == RT_NULL)
+    {
+        LOG_E("webclient create failed, no memory for session header buffer!");
+        web_free(session->header);
+        web_free(session);
+        session = RT_NULL;
+        return RT_NULL;
+    }
 
     return session;
 }
@@ -778,9 +776,10 @@ struct webclient_session *webclient_session_create(size_t header_sz, size_t resp
  * @return <0: send GET request failed
  *         >0: response http status code
  */
-int webclient_get(struct webclient_session *session, const char *URI, const char *header)
+int webclient_get(struct webclient_session *session, const char *URI)
 {
     int rc = WEBCLIENT_OK;
+    int resp_status = 0;
 
     RT_ASSERT(session);
     RT_ASSERT(URI);
@@ -792,7 +791,7 @@ int webclient_get(struct webclient_session *session, const char *URI, const char
         goto __exit;
     }
 
-    rc = webclient_send_header(session, WEBCLIENT_GET, header, strlen(header));
+    rc = webclient_send_header(session, WEBCLIENT_GET);
     if (rc != WEBCLIENT_OK)
     {
         /* send header to webclient server failed. */
@@ -800,40 +799,38 @@ int webclient_get(struct webclient_session *session, const char *URI, const char
     }
 
     /* handle the response header of webclient server */
-    rc = webclient_handle_response(session);
-    if (rc > 0)
+    resp_status = webclient_handle_response(session);
+    if (resp_status > 0)
     {
+        char *location = webclient_header_fields_get(session, "Location");
+
         /* relocation */
-        if ((session->response == 302 || session->response == 301) && session->location)
+        if ((resp_status == 302 || resp_status == 301) && location)
         {
-            char *location = web_strdup(session->location);
-            if (location)
+            webclient_close(session);
+            resp_status = webclient_get(session, location);
+            if (resp_status < 0)
             {
-                webclient_close(session);
-                rc = webclient_get(session, location, header);
-                if (rc != WEBCLIENT_OK)
-                {
-                    goto __exit;
-                }
-
-                web_free(location);
-                return session->response;
+                rc = resp_status;
+                goto __exit;
             }
+
+            return resp_status;
         }
-        else if (session->response != 200)
+        else if (resp_status != 200)
         {
-            LOG_E("get failed, handle response(%d) error!", session->response);
+            LOG_E("get failed, handle response(%d) error!", resp_status);
             goto __exit;
         }
     }
 
 __exit:
-    if (rc < 0)
+    if(resp_status)
     {
-        return rc;
+        return resp_status;
     }
 
-    return session->response;
+    return rc;
 }
 
 /**
@@ -848,8 +845,8 @@ __exit:
  */
 int webclient_get_position(struct webclient_session *session, const char *URI, int position)
 {
-    char *range_header = RT_NULL;
     int rc = WEBCLIENT_OK;
+    int resp_status = 0;
 
     RT_ASSERT(session);
     RT_ASSERT(URI);
@@ -860,64 +857,52 @@ int webclient_get_position(struct webclient_session *session, const char *URI, i
         goto __exit;
     }
 
-    range_header = (char *) web_malloc(session->header_sz);
-    if (range_header == RT_NULL)
+    /* splice header*/
+    if(webclient_header_fields_add(session, "Range: bytes=%d-\r\n", position) <= 0)
     {
-        LOG_E("open position failed, no memory for range header!");
-        rc = -WEBCLIENT_NOMEM;
+        rc = WEBCLIENT_ERROR;
         goto __exit;
     }
 
-    /* splice header*/
-    rt_snprintf(range_header, session->header_sz - 1,
-                "Range: bytes=%d-\r\n", position);
-
-    rc = webclient_send_header(session, WEBCLIENT_GET, range_header, strlen(range_header));
+    rc = webclient_send_header(session, WEBCLIENT_GET);
     if (rc != WEBCLIENT_OK)
     {
         goto __exit;
     }
 
     /* handle the response header of webclient server */
-    rc = webclient_handle_response(session);
+    resp_status = webclient_handle_response(session);
     if (rc > 0)
     {
+        char *location = webclient_header_fields_get(session, "Location");
+
         /* relocation */
-        if ((session->response == 302 || session->response == 301) && session->location)
+        if ((resp_status == 302 || resp_status == 301) && location)
         {
-            char *location = web_strdup(session->location);
-            if (location)
+            webclient_close(session);
+            resp_status = webclient_get_position(session, location, position);
+            if (resp_status < 0)
             {
-                webclient_close(session);
-                rc = webclient_get_position(session, location, position);
-                if (rc != WEBCLIENT_OK)
-                {
-                    goto __exit;
-                }
-
-                web_free(location);
-                return session->response;
+                rc = resp_status;
+                goto __exit;
             }
+
+            return resp_status;
         }
-        else if (session->response != 206)
+        else if (resp_status != 206)
         {
-            LOG_E("get failed, handle response(%d) error!", session->response);
+            LOG_E("get failed, handle response(%d) error!", resp_status);
             goto __exit;
         }
     }
 
 __exit:
-    if (range_header)
-    {
-        web_free(range_header);
-    }
-
-    if (rc < 0)
+    if(resp_status)
     {
-        return rc;
+        return resp_status;
     }
 
-    return session->response;
+    return rc;
 }
 
 /**
@@ -934,10 +919,10 @@ __exit:
  *         =0: send POST header success
  *         >0: response http status code
  */
-int webclient_post(struct webclient_session *session, const char *URI,
-        const char *header, const char *post_data)
+int webclient_post(struct webclient_session *session, const char *URI, const char *post_data)
 {
     int rc = WEBCLIENT_OK;
+    int resp_status = 0;
 
     RT_ASSERT(session);
     RT_ASSERT(URI);
@@ -949,7 +934,7 @@ int webclient_post(struct webclient_session *session, const char *URI,
         goto __exit;
     }
 
-    rc = webclient_send_header(session, WEBCLIENT_POST, header, strlen(header));
+    rc = webclient_send_header(session, WEBCLIENT_POST);
     if (rc != WEBCLIENT_OK)
     {
         /* send header to webclient server failed. */
@@ -961,28 +946,21 @@ int webclient_post(struct webclient_session *session, const char *URI,
         webclient_write(session, (unsigned char *)post_data, strlen(post_data));
 
         /* resolve response data, get http status code */
-        rc = webclient_handle_response(session);
-        if (rc > 0)
+        resp_status = webclient_handle_response(session);
+        if (resp_status != 200)
         {
-            if (session->response != 200)
-            {
-                LOG_E("post failed, handle response(%d) error.", session->response);
-                goto __exit;
-            }
+            LOG_E("post failed, handle response(%d) error.", resp_status);
+            goto __exit;
         }
     }
-    else
-    {
-        return rc;
-    }
 
 __exit:
-    if (rc < 0)
+    if(resp_status)
     {
-        return rc;
+        return resp_status;
     }
 
-    return session->response;
+    return rc;
 }
 
 
@@ -1021,9 +999,9 @@ static int webclient_next_chunk(struct webclient_session *session)
     RT_ASSERT(session);
 
     length = webclient_read_line(session, line, sizeof(line));
-    if (length)
+    if (length > 0)
     {
-        if (strcmp(line, "\r\n") == 0)
+        if (strcmp(line, "\r") == 0)
         {
             length = webclient_read_line(session, line, sizeof(line));
             if (length <= 0)
@@ -1119,9 +1097,9 @@ int webclient_read(struct webclient_session *session, unsigned char *buffer, siz
 
     if (session->content_length > 0)
     {
-        if (length > session->content_length_remainder)
+        if (length > session->content_remainder)
         {
-            length = session->content_length_remainder;
+            length = session->content_remainder;
         }
 
         if (length == 0)
@@ -1174,7 +1152,7 @@ int webclient_read(struct webclient_session *session, unsigned char *buffer, siz
 
     if (session->content_length > 0)
     {
-        session->content_length_remainder -= total_read;
+        session->content_remainder -= total_read;
     }
 
     return total_read;
@@ -1283,23 +1261,21 @@ int webclient_close(struct webclient_session *session)
     }
 #endif
 
-    if(session->transfer_encoding)
-        web_free(session->transfer_encoding);
-
-    if(session->content_type)
-        web_free(session->content_type);
-
-    if(session->last_modified)
-        web_free(session->last_modified);
-
     if(session->host)
         web_free(session->host);
 
     if(session->request)
         web_free(session->request);
 
-    if(session->location)
-        web_free(session->location);
+    if(session->header && session->header->buffer)
+    {
+        web_free(session->header->buffer);
+    }
+
+    if(session->header)
+    {
+        web_free(session->header);
+    }
 
     if(session)
     {
@@ -1340,7 +1316,7 @@ int webclient_response(struct webclient_session *session, unsigned char **respon
         {
             unsigned char *new_resp = RT_NULL;
 
-            result_sz = total_read + session->resp_sz;
+            result_sz = total_read + WEBCLIENT_RESPONSE_BUFSZ;
             new_resp = web_realloc(response_buf, result_sz + 1);
             if (new_resp == RT_NULL)
             {
@@ -1434,14 +1410,19 @@ int webclient_request(const char *URI, const char *header, const char *post_data
 
     if(post_data == RT_NULL)
     {
-        session = webclient_session_create(WEBCLIENT_HEADER_BUFSZ, WEBCLIENT_RESPONSE_BUFSZ);
+        session = webclient_session_create(WEBCLIENT_HEADER_BUFSZ);
         if(session == RT_NULL)
         {
             rc = -WEBCLIENT_NOMEM;
             goto __exit;
         }
 
-        if(webclient_get(session, URI, header) != 200)
+        if(header != RT_NULL)
+        {
+            strncpy(session->header->buffer, header, strlen(header));
+        }
+
+        if(webclient_get(session, URI) != 200)
         {
             rc = -WEBCLIENT_ERROR;
             goto __exit;
@@ -1456,20 +1437,28 @@ int webclient_request(const char *URI, const char *header, const char *post_data
     }
     else
     {
-        session = webclient_session_create(WEBCLIENT_HEADER_BUFSZ, WEBCLIENT_RESPONSE_BUFSZ);
+        session = webclient_session_create(WEBCLIENT_HEADER_BUFSZ);
         if(session == RT_NULL)
         {
             rc = -WEBCLIENT_NOMEM;
             goto __exit;
         }
 
-        if(webclient_post(session, URI, header, post_data) != 200)
+        if(header != RT_NULL)
+        {
+            strncpy(session->header->buffer, header, strlen(header));
+        }
+
+        if(webclient_post(session, URI, post_data) != 200)
         {
             rc = -WEBCLIENT_ERROR;
             goto __exit;
         }
     }
-
+    if(header != RT_NULL)
+    {
+        strncpy(session->header->buffer, header, strlen(header));
+    }
 __exit:
     if(session)
     {
@@ -1483,5 +1472,4 @@ __exit:
     }
 
     return totle_length;
-
 }

+ 11 - 8
src/webclient_file.c

@@ -46,17 +46,18 @@ int webclient_get_file(const char* URI, const char* filename)
     size_t length, total_length = 0;
     unsigned char *ptr = RT_NULL;
     struct webclient_session* session = RT_NULL;
+    int resp_status = 0, content_length = -1;
 
-    session = webclient_session_create(WEBCLIENT_HEADER_BUFSZ, WEBCLIENT_RESPONSE_BUFSZ);
+    session = webclient_session_create(WEBCLIENT_HEADER_BUFSZ);
     if(session == RT_NULL)
     {
         rc = -WEBCLIENT_NOMEM;
         goto __exit;
     }
 
-    if (webclient_get(session, URI, RT_NULL) != 200)
+    if ((resp_status = webclient_get(session, URI)) != 200)
     {
-        LOG_E("get file failed, wrong response: %d.", session->response);
+        LOG_E("get file failed, wrong response: %d.", resp_status);
         rc = -WEBCLIENT_ERROR;
         goto __exit;
     }
@@ -76,8 +77,8 @@ int webclient_get_file(const char* URI, const char* filename)
         rc = -WEBCLIENT_NOMEM;
         goto __exit;
     }
-
-    if (session->content_length == 0)
+	
+    if (session->content_length < 0)
     {
         while (1)
         {
@@ -96,7 +97,7 @@ int webclient_get_file(const char* URI, const char* filename)
     }
     else
     {
-        for (offset = 0; offset < session->content_length;)
+        for (offset = 0; offset < (size_t) session->content_length;)
         {
             length = webclient_read(session, ptr,
                     session->content_length - offset > WEBCLIENT_RESPONSE_BUFSZ ?
@@ -216,14 +217,16 @@ int webclient_post_file(const char* URI, const char* filename,
             WEBCLIENT_HEADER_BUFSZ - (header_ptr - header),
             "Content-Type: multipart/form-data; boundary=%s\r\n", boundary);
 
-    session = webclient_session_create(WEBCLIENT_HEADER_BUFSZ, WEBCLIENT_RESPONSE_BUFSZ);
+    session = webclient_session_create(WEBCLIENT_HEADER_BUFSZ);
     if(session == RT_NULL)
     {
         rc = -WEBCLIENT_NOMEM;
         goto __exit;
     }
 
-    rc = webclient_post(session, URI, header, NULL);
+    session->header->buffer = web_strdup(header);
+
+    rc = webclient_post(session, URI, NULL);
     if( rc< 0)
     {
         goto __exit;