| /************************************************************* | 
 | Description: | 
 |     MBTK HTTP c file. | 
 | Author: | 
 |     LiuBin | 
 | Date: | 
 |     2020/4/30 13:51:42 | 
 | *************************************************************/ | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <ctype.h> | 
 | #include <string.h> | 
 | #include <fcntl.h> | 
 | #include <unistd.h> | 
 | #include <sys/stat.h> | 
 |  | 
 | #include "mbtk_http_base.h" | 
 | #include "mbtk_http.h" | 
 | #include "mbtk_http_chunks.h" | 
 |  | 
 | /************************************************************* | 
 |     Constants and Macros | 
 | *************************************************************/ | 
 |  | 
 | /************************************************************* | 
 |     Variables:local | 
 | *************************************************************/ | 
 | static mbtk_http_handle_t http_handles[HTTP_HANDLE_MAX] = | 
 | { | 
 |     { | 
 |         .id = -1, | 
 |         .data_cb = NULL, | 
 |         .session_cnt = 0, | 
 |         .session = {NULL} | 
 |     } | 
 | }; | 
 |  | 
 | /************************************************************* | 
 |     Variables:public | 
 | *************************************************************/ | 
 |  | 
 |  | 
 | /************************************************************* | 
 |     Local Function Declaration | 
 | *************************************************************/ | 
 |  | 
 |  | 
 | /************************************************************* | 
 |     Local Function Definitions | 
 | *************************************************************/ | 
 | static void http_session_free(mbtk_http_session_t *session) | 
 | { | 
 |     if(session) | 
 |     { | 
 |         if(session->req.header_cnt > 0) | 
 |         { | 
 |             int index; | 
 |             for(index = 0; index < HTTP_REQUEST_HEADER_MAX; index++) | 
 |             { | 
 |                 if(session->req.req_h[index] != NULL) | 
 |                 { | 
 |                     if(session->req.req_h[index]->value) | 
 |                         free(session->req.req_h[index]->value); | 
 |                     free(session->req.req_h[index]); | 
 |                     session->req.req_h[index] = NULL; | 
 |                 } | 
 |             } | 
 |             session->req.header_cnt = 0; | 
 |         } | 
 |  | 
 |         if(session->req.content) | 
 |         { | 
 |             free(session->req.content); | 
 |             session->req.content = NULL; | 
 |         } | 
 |  | 
 |         if(session->rsp.header_cnt > 0) | 
 |         { | 
 |             int index; | 
 |             for(index = 0; index < HTTP_REQUEST_HEADER_MAX; index++) | 
 |             { | 
 |                 if(session->rsp.rsp_h[index] != NULL) | 
 |                 { | 
 |                     if(session->rsp.rsp_h[index]->value) | 
 |                         free(session->rsp.rsp_h[index]->value); | 
 |                     free(session->rsp.rsp_h[index]); | 
 |                     session->rsp.rsp_h[index] = NULL; | 
 |                 } | 
 |             } | 
 |             session->rsp.header_cnt = 0; | 
 |         } | 
 |  | 
 |         free(session); | 
 |     } | 
 | } | 
 |  | 
 | static int http_session_close(mbtk_http_session_t *session) | 
 | { | 
 |     if(session) | 
 |     { | 
 |         if(session->sock_fd > 0) | 
 |         { | 
 |             if(mbtk_http_close(session->sock_fd)) | 
 |             { | 
 |                 LOGE("mbtk_http_close() fail."); | 
 |                 return -1; | 
 |             } | 
 |             session->sock_fd = -1; | 
 |         } | 
 |  | 
 |         session->state = HTTP_SESSION_STATE_NON; | 
 |  | 
 |         return 0; | 
 |     } | 
 |  | 
 |     return -1; | 
 | } | 
 |  | 
 |  | 
 | static bool http_handle_check(int handle_id) | 
 | { | 
 |     if(handle_id < 0 || handle_id >= HTTP_HANDLE_MAX | 
 |        || http_handles[handle_id].id < 0) | 
 |     { | 
 |         return FALSE; | 
 |     } | 
 |  | 
 |     return TRUE; | 
 | } | 
 |  | 
 | static bool http_session_check(int handle_id, int session_id) | 
 | { | 
 |     if(handle_id < 0 || handle_id >= HTTP_HANDLE_MAX | 
 |        || http_handles[handle_id].id < 0 | 
 |        || http_handles[handle_id].id != handle_id) | 
 |     { | 
 |         return FALSE; | 
 |     } | 
 |  | 
 |     if(session_id < 0 || session_id >= HTTP_SESSION_MAX | 
 |        || http_handles[handle_id].session[session_id] == NULL | 
 |        || http_handles[handle_id].session[session_id]->id != session_id) | 
 |     { | 
 |         return FALSE; | 
 |     } | 
 |  | 
 |     return TRUE; | 
 | } | 
 |  | 
 | static bool http_is_space_char(char ch) | 
 | { | 
 |     if(ch == ' ' || ch == '\r' || ch == '\t' || ch == '\n') | 
 |         return TRUE; | 
 |  | 
 |     return FALSE; | 
 | } | 
 |  | 
 | static bool http_str_empty(char *str) | 
 | { | 
 |     if(str == NULL || strlen(str) == 0) | 
 |         return TRUE; | 
 |  | 
 |     return FALSE; | 
 | } | 
 |  | 
 |  | 
 | static int http_url_parse | 
 | ( | 
 |     void* url, | 
 |     void *host, | 
 |     void *uri, | 
 |     int *port, | 
 |     bool *is_ssl | 
 | ) | 
 | { | 
 |     if(strlen(url) == 0) | 
 |     { | 
 |         return -1; | 
 |     } | 
 |     char *url_ptr = (char*)url; | 
 |     char *host_ptr = (char*)host; | 
 |  | 
 |     LOGI("URL[%d]:%s",strlen(url_ptr),url_ptr); | 
 |  | 
 |     if(!memcmp(url_ptr,"https://",8)) | 
 |     { | 
 |         *is_ssl = TRUE; | 
 |         url_ptr += 8; | 
 |     } | 
 |     else if(!memcmp(url_ptr,"http://",7)) | 
 |     { | 
 |         *is_ssl = FALSE; | 
 |         url_ptr += 7; | 
 |     } | 
 |     else | 
 |     { | 
 |         *is_ssl = FALSE; | 
 |     } | 
 |  | 
 |     // ptr point to host. | 
 |     while(*url_ptr) | 
 |     { | 
 |         if(*url_ptr == ':' || *url_ptr == '/') // Host end | 
 |             break; | 
 |         if(http_is_space_char(*url_ptr)) | 
 |         { | 
 |             url_ptr++; | 
 |             continue; | 
 |         } | 
 |         *host_ptr++ = *url_ptr++; | 
 |     } | 
 |  | 
 |     // "www.baidu.com" | 
 |     if(*url_ptr == '\0')   // No port and uri | 
 |     { | 
 |         if(*is_ssl) | 
 |         { | 
 |             *port = MBTK_HTTPS_PORT_DEF; | 
 |         } | 
 |         else | 
 |         { | 
 |             *port = MBTK_HTTP_PORT_DEF; | 
 |         } | 
 |         memcpy(uri,"/",1); | 
 |  | 
 |         LOGI("HTTP parse success:'%s','%s', %d, %d",(char*)host,(char*)uri,*port,*is_ssl); | 
 |         return 0; | 
 |     } | 
 |     else | 
 |     { | 
 |         //LOGI("Host end with:%x",*url_ptr); | 
 |         if(*url_ptr == ':')   // Port exist. | 
 |         { | 
 |             *port = atoi(url_ptr + 1); | 
 |  | 
 |             // Point to '/' or NULL | 
 |             while(*url_ptr && *url_ptr != '/') | 
 |             { | 
 |                 url_ptr++; | 
 |             } | 
 |  | 
 |             // "www.baidu.com:80" | 
 |             if(*url_ptr == '\0')   // No uri | 
 |             { | 
 |                 if(*port == 0) | 
 |                 { | 
 |                     if(*is_ssl) | 
 |                     { | 
 |                         *port = MBTK_HTTPS_PORT_DEF; | 
 |                     } | 
 |                     else | 
 |                     { | 
 |                         *port = MBTK_HTTP_PORT_DEF; | 
 |                     } | 
 |                 } | 
 |                 memcpy(uri,"/",1); | 
 |  | 
 |                 LOGI("HTTP parse success:'%s','%s', %d, %d",(char*)host,(char*)uri,*port,*is_ssl); | 
 |                 return 0; | 
 |             } | 
 |         } | 
 |  | 
 |         // "www.baidu.com/xxx" or "www.baidu.com:80/xxx" | 
 |         // Now,url_ptr point to '/' | 
 |         if(*url_ptr != '/') | 
 |         { | 
 |             LOGE("URI must start with '/'."); | 
 |             return -1; | 
 |         } | 
 |  | 
 |         //LOGI("URL3[%d]:%s",strlen(url_ptr),url_ptr); | 
 |  | 
 |         memcpy(uri,url_ptr,strlen(url_ptr)); | 
 |  | 
 |         if(*port == 0) | 
 |         { | 
 |             if(*is_ssl) | 
 |             { | 
 |                 *port = MBTK_HTTPS_PORT_DEF; | 
 |             } | 
 |             else | 
 |             { | 
 |                 *port = MBTK_HTTP_PORT_DEF; | 
 |             } | 
 |         } | 
 |  | 
 |         LOGI("HTTP parse success:'%s','%s', %d, %d",(char*)host,(char*)uri,*port,*is_ssl); | 
 |         return 0; | 
 |     } | 
 | } | 
 |  | 
 | static int http_session_req_head_add(mbtk_http_session_t *session,bool replace, | 
 |                                      char *name, char *value) | 
 | { | 
 |     if(session == NULL || value == NULL) | 
 |         return -1; | 
 |  | 
 |     LOGI("Add request header - %s:%s",name,value); | 
 |  | 
 |     int i = 0; | 
 |     while(i < HTTP_REQUEST_HEADER_MAX) | 
 |     { | 
 |         if(session->req.req_h[i] | 
 |            && !strncasecmp(session->req.req_h[i]->name,name,strlen(name)))   // Is change value | 
 |         { | 
 |             break; | 
 |         } | 
 |         i++; | 
 |     } | 
 |  | 
 |     if(i == HTTP_REQUEST_HEADER_MAX)   // Should add new header. | 
 |     { | 
 |         i = 0; | 
 |         while(i < HTTP_REQUEST_HEADER_MAX) | 
 |         { | 
 |             if(session->req.req_h[i] == NULL)   // Find NULL request. | 
 |             { | 
 |                 session->req.req_h[i] = (mbtk_http_header_t*)malloc(sizeof(mbtk_http_header_t)); | 
 |                 if(session->req.req_h[i] == NULL) | 
 |                 { | 
 |                     LOGE("malloc() fail."); | 
 |                     return -1; | 
 |                 } | 
 |  | 
 |                 memset(session->req.req_h[i],0x0,sizeof(mbtk_http_header_t)); | 
 |                 memcpy(session->req.req_h[i]->name, name, strlen(name)); | 
 |                 session->req.req_h[i]->value = NULL; | 
 |                 session->req.header_cnt++; | 
 |                 break; | 
 |             } | 
 |             i++; | 
 |         } | 
 |     } | 
 |     else     // Is change value | 
 |     { | 
 |         if(!replace) | 
 |         { | 
 |             LOGW("Found this header[%s],no replace.",name); | 
 |             return 0; | 
 |         } | 
 |     } | 
 |  | 
 |     if(i == HTTP_REQUEST_HEADER_MAX) | 
 |     { | 
 |         LOGE("Request header is full."); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     if(session->req.req_h[i]->value) | 
 |     { | 
 |         free(session->req.req_h[i]->value); | 
 |     } | 
 |     session->req.req_h[i]->value = (char*)malloc(strlen(value) + 1); | 
 |     if(session->req.req_h[i]->value == NULL) | 
 |     { | 
 |         LOGE("malloc() fail."); | 
 |         return -1; | 
 |     } | 
 |     memset(session->req.req_h[i]->value,0x0,strlen(value) + 1); | 
 |     memcpy(session->req.req_h[i]->value,value,strlen(value)); | 
 |  | 
 |     return 0; | 
 | } | 
 |  | 
 | #if 0 | 
 | static int http_session_rsp_head_add(mbtk_http_session_t *session, | 
 |                                      char *name, char *value) | 
 | { | 
 |     if(session == NULL || value == NULL) | 
 |         return -1; | 
 |  | 
 |     int i = 0; | 
 |     while(i < HTTP_REQUEST_HEADER_MAX) | 
 |     { | 
 |         if(session->rsp.rsp_h[i] == NULL)   // Find NULL request. | 
 |         { | 
 |             session->rsp.rsp_h[i] = (mbtk_http_header_t*)malloc(sizeof(mbtk_http_header_t)); | 
 |             if(session->rsp.rsp_h[i] == NULL) | 
 |             { | 
 |                 LOGE("malloc() fail."); | 
 |                 return -1; | 
 |             } | 
 |  | 
 |             memcpy(session->rsp.rsp_h[i]->name,name,strlen(name)); | 
 |             session->rsp.rsp_h[i]->value = (char*)malloc(strlen(value) + 1); | 
 |             if(session->rsp.rsp_h[i]->value == NULL) | 
 |             { | 
 |                 LOGE("malloc() fail."); | 
 |                 return -1; | 
 |             } | 
 |             memset(session->rsp.rsp_h[i]->value,0x0,strlen(value) + 1); | 
 |             memcpy(session->rsp.rsp_h[i]->value,value,strlen(value)); | 
 |  | 
 |             session->rsp.header_cnt++; | 
 |             return 0; | 
 |         } | 
 |         i++; | 
 |     } | 
 |  | 
 |     return -1; | 
 | } | 
 | #endif | 
 |  | 
 | static char* http_option_str_get(mbtk_http_option_enum option) | 
 | { | 
 |     switch(option) | 
 |     { | 
 |         case HTTP_OPTION_HEAD: | 
 |             return "HEAD"; | 
 |         case HTTP_OPTION_GET: | 
 |             return "GET"; | 
 |         case HTTP_OPTION_POST: | 
 |             return "POST"; | 
 |         case HTTP_OPTION_PUT: | 
 |             return "PUT"; | 
 |         case HTTP_OPTION_DELETE: | 
 |             return "DELETE"; | 
 |         case HTTP_OPTION_OPTIONS: | 
 |             return "OPTIONS"; | 
 |         case HTTP_OPTION_TRACE: | 
 |             return "TRACE"; | 
 |         case HTTP_OPTION_CONNECT: | 
 |             return "CONNECT"; | 
 |         case HTTP_OPTION_LINK: | 
 |             return "LINK"; | 
 |         case HTTP_OPTION_UNLINK: | 
 |             return "UNLINK"; | 
 |         default: | 
 |             return ""; | 
 |     } | 
 | } | 
 |  | 
 | static char* http_version_str_get(mbtk_http_version_enum version) | 
 | { | 
 |     switch(version) | 
 |     { | 
 |         case HTTP_VERSION_1_0: | 
 |             return "1.0"; | 
 |         case HTTP_VERSION_1_1: | 
 |             return "1.1"; | 
 |         case HTTP_VERSION_2: | 
 |             return "2"; | 
 |         case HTTP_VERSION_3: | 
 |             return "3"; | 
 |         default: | 
 |             return ""; | 
 |     } | 
 | } | 
 |  | 
 | static char* http_header_find(mbtk_http_session_t *session,char* name) | 
 | { | 
 |     int i = 0; | 
 |     while(i < HTTP_REQUEST_HEADER_MAX) | 
 |     { | 
 |         if(session->req.req_h[i] && | 
 |            !strncasecmp(session->req.req_h[i]->name,name,strlen(name))) | 
 |         { | 
 |             return session->req.req_h[i]->value; | 
 |         } | 
 |  | 
 |         i++; | 
 |     } | 
 |     return NULL; | 
 | } | 
 |  | 
 | static int http_header_str_get(mbtk_http_header_t *header,char *header_str,int header_str_len) | 
 | { | 
 |     if(header == NULL || header->value == NULL | 
 |        || header_str == NULL) | 
 |         return 0; | 
 |  | 
 |     int len = 0; | 
 |     len = snprintf(header_str,header_str_len,"%s: %s\r\n", | 
 |                    header->name, header->value); | 
 |  | 
 |     return len; | 
 | } | 
 |  | 
 | static mbtk_http_version_enum http_version_get_by_str(char *version_str) | 
 | { | 
 |     if(!memcmp(version_str,"1.0",3)) | 
 |         return HTTP_VERSION_1_0; | 
 |     else if(!memcmp(version_str,"1.1",3)) | 
 |         return HTTP_VERSION_1_1; | 
 |     else if(!memcmp(version_str,"2",1)) | 
 |         return HTTP_VERSION_2; | 
 |     else if(!memcmp(version_str,"3",1)) | 
 |         return HTTP_VERSION_3; | 
 |     else | 
 |         return HTTP_VERSION_1_1; | 
 | } | 
 |  | 
 | static int http_header_read(mbtk_http_session_t *session) | 
 | { | 
 | #define BUFFER_SIZE 2048 | 
 |     char line[BUFFER_SIZE]; | 
 |     char *ptr = NULL; | 
 |     int len = 0; | 
 |     while((len = mbtk_http_read_line(session->sock_fd,line,BUFFER_SIZE)) > 0) | 
 |     { | 
 |         if(!memcmp(line,"\r\n",2)) | 
 |         { | 
 |             LOGD("Read empty line."); | 
 |             break; | 
 |         } | 
 |  | 
 |         // Delete "\r\n" | 
 |         ptr = line + len - 1; // Point to last char. | 
 |         while(http_is_space_char(*ptr)) | 
 |         { | 
 |             *ptr = '\0'; | 
 |             len--; | 
 |             ptr--; | 
 |         } | 
 |  | 
 |         LOGV("LINE:%s",line); | 
 |  | 
 |         if(http_handles[session->handle_id].show_rsp_header && | 
 |            http_handles[session->handle_id].data_cb) | 
 |         { | 
 |             http_handles[session->handle_id].data_cb(session->id, | 
 |                     MBTK_HTTP_DATA_HEADER,line,len); | 
 |         } | 
 |  | 
 |         if(!memcmp(line,"HTTP/",5))   // "HTTP/1.1 200 OK" | 
 |         { | 
 |             session->rsp.state_code = atoi(line + 9); | 
 |             session->rsp.version = http_version_get_by_str(line + 5); | 
 |         } | 
 |         else     // Is response header item. | 
 |         { | 
 |             if(!strncasecmp(line,"Content-Length",14)) | 
 |             { | 
 |                 ptr = line + 14; | 
 |                 while(ptr && !isdigit(*ptr)) | 
 |                 { | 
 |                     ptr++; | 
 |                 } | 
 |  | 
 |                 if(ptr) | 
 |                 { | 
 |                     session->rsp.content_length = atol(ptr); | 
 |                 } | 
 |             } | 
 |             else if(!strncasecmp(line,"Transfer-Encoding",17)) | 
 |             { | 
 |                 ptr = line + 17; | 
 |                 while(ptr && !isalpha(*ptr)) | 
 |                 { | 
 |                     ptr++; | 
 |                 } | 
 |  | 
 |                 if(ptr && !memcmp(ptr,"chunked",7)) | 
 |                 { | 
 |                     session->rsp.is_chunked = TRUE; | 
 |                 } | 
 |             } | 
 |         } | 
 |     } | 
 | #undef BUFFER_SIZE | 
 |  | 
 |     LOGD("RSP:HTTP/%s %d, is_chunked:%d,Content-Length:%d",http_version_str_get(session->rsp.version), | 
 |          session->rsp.state_code,session->rsp.is_chunked,session->rsp.content_length); | 
 |  | 
 |     return 0; | 
 | } | 
 |  | 
 | static int http_session_start_write(mbtk_http_session_t *session) | 
 | { | 
 |     LOGI("Start HTTP write."); | 
 |  | 
 | #define BUFFER_SIZE 1024 | 
 |     session->state = HTTP_SESSION_STATE_WRITE_HEADER; | 
 |     char buff[BUFFER_SIZE]; | 
 |     int len = 0; | 
 |     int index = 0; | 
 |     len += snprintf(buff + len,BUFFER_SIZE - len,"%s %s HTTP/%s\r\n", | 
 |                     http_option_str_get(session->option), | 
 |                     session->uri, | 
 |                     http_version_str_get(session->version)); | 
 |  | 
 |     // if no set "Host",should set default host. | 
 |     char *host = http_header_find(session,"Host"); | 
 |     if(!host) | 
 |     { | 
 |         len += snprintf(buff + len,BUFFER_SIZE - len,"Host: %s\r\n", session->host); | 
 |     } | 
 |  | 
 |     if(mbtk_http_write(session->sock_fd,buff,len) != len) | 
 |     { | 
 |         LOGE("mbtk_http_write() fail."); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     char header_str[BUFFER_SIZE]; | 
 |     int header_str_len = 0; | 
 |     while(index < HTTP_REQUEST_HEADER_MAX) | 
 |     { | 
 |         if(session->req.req_h[index] && | 
 |            (header_str_len = http_header_str_get(session->req.req_h[index], header_str, BUFFER_SIZE)) > 0) | 
 |         { | 
 |             if(mbtk_http_write(session->sock_fd,header_str,header_str_len) != header_str_len) | 
 |             { | 
 |                 LOGE("mbtk_http_write() fail."); | 
 |                 return -1; | 
 |             } | 
 |         } | 
 |         index++; | 
 |     } | 
 |  | 
 |     // Write request header success. | 
 |     LOGI("HTTP write header complete."); | 
 |  | 
 | #undef BUFFER_SIZE | 
 |  | 
 |     // Write "\r\n" | 
 |     if(mbtk_http_write(session->sock_fd,"\r\n",2) != 2) | 
 |     { | 
 |         LOGE("mbtk_http_write() fail."); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     LOGI("Start write HTTPsession->option. %d", session->option); | 
 |     if(session->option == HTTP_OPTION_POST) | 
 |     { | 
 |         session->state = HTTP_SESSION_STATE_WRITE_CONTENT; | 
 |         LOGI("Start write HTTP content data."); | 
 |  | 
 |         if(session->req.content && session->req.content_len > 0) | 
 |         { | 
 |             if(mbtk_http_write(session->sock_fd,session->req.content,session->req.content_len) != session->req.content_len) | 
 |             { | 
 |                 LOGE("mbtk_http_write() fail."); | 
 |                 return -1; | 
 |             } | 
 |  | 
 |             session->state = HTTP_SESSION_STATE_WRITE_END; | 
 |         } | 
 |     } | 
 |     else | 
 |     { | 
 |         session->state = HTTP_SESSION_STATE_WRITE_END; | 
 |  | 
 |         LOGI("HTTP write complete."); | 
 |     } | 
 |     return 0; | 
 | } | 
 |  | 
 | static int http_session_read_by_chunk(mbtk_http_session_t *session) | 
 | { | 
 | #undef BUFFER_SIZE | 
 | #define BUFFER_SIZE 2048 | 
 |     http_chunk_code chunk_code; | 
 |     http_chunker_t chunker; | 
 |     char read_buf[BUFFER_SIZE + 1]; | 
 |     int read_len = 0; | 
 |     char chunk_buf[BUFFER_SIZE + 1]; | 
 |     int chunk_len; | 
 |     http_chunk_init(&chunker); | 
 |     while(TRUE) | 
 |     { | 
 |         read_len = mbtk_http_read(session->sock_fd,read_buf,BUFFER_SIZE,3000); | 
 |         //read_len = mbtk_http_read_line(session->sock_file,read_buf,BUFFER_SIZE); | 
 |         if(read_len <= 0) | 
 |         { | 
 |             LOGE("Read fail."); | 
 |             return -1; | 
 |         } | 
 |  | 
 |         chunk_code = http_chunk_parse(&chunker, read_buf, read_len, chunk_buf, &chunk_len); | 
 |         if(chunk_code > CHUNKE_OK)   // Fail. | 
 |         { | 
 |             LOGE("http_chunk_parse() fail[err - %d].",chunk_code); | 
 |             return -1; | 
 |         } | 
 |  | 
 |         LOGD("Read chunk_len:%d",chunk_len); | 
 |         chunk_buf[chunk_len] = '\0'; | 
 |  | 
 |         if(http_handles[session->handle_id].data_cb) | 
 |             http_handles[session->handle_id].data_cb(session->id, | 
 |                     MBTK_HTTP_DATA_CONTENT,chunk_buf,chunk_len); | 
 |  | 
 |         if(CHUNKE_STOP == chunk_code) | 
 |         { | 
 |             if(http_handles[session->handle_id].data_cb) | 
 |                 http_handles[session->handle_id].data_cb(session->id, | 
 |                         MBTK_HTTP_DATA_COMPLETE,NULL,0); | 
 |  | 
 |             break; | 
 |         } | 
 |     } | 
 |  | 
 |     LOGV("Chunk read success."); | 
 |  | 
 |     return 0; | 
 | } | 
 |  | 
 | static int http_session_read_by_length(mbtk_http_session_t *session) | 
 | { | 
 | #undef BUFFER_SIZE | 
 | #define BUFFER_SIZE 2048 | 
 |     char read_buf[BUFFER_SIZE + 1]; | 
 |     int read_len = 0; | 
 |     int64 read_count = 0; | 
 |     while(TRUE) | 
 |     { | 
 |         memset(read_buf,0x0,BUFFER_SIZE + 1); | 
 |         read_len = mbtk_http_read(session->sock_fd,read_buf,BUFFER_SIZE,3000); | 
 |         if(read_len <= 0) | 
 |         { | 
 |             LOGE("Read fail."); | 
 |             return -1; | 
 |         } | 
 |  | 
 |  | 
 |         if(read_count + read_len >= session->rsp.content_length)   // Read data complete. | 
 |         { | 
 |             if(http_handles[session->handle_id].data_cb) | 
 |             { | 
 |                 http_handles[session->handle_id].data_cb(session->id, | 
 |                         MBTK_HTTP_DATA_CONTENT,read_buf,session->rsp.content_length - read_count); | 
 |  | 
 |                 http_handles[session->handle_id].data_cb(session->id, | 
 |                         MBTK_HTTP_DATA_COMPLETE,NULL,0); | 
 |             } | 
 |             break; | 
 |         } | 
 |  | 
 |         if(http_handles[session->handle_id].data_cb) | 
 |             http_handles[session->handle_id].data_cb(session->id, | 
 |                     MBTK_HTTP_DATA_CONTENT,read_buf,read_len); | 
 |  | 
 |         read_count += read_len; | 
 |     } | 
 |  | 
 |     return 0; | 
 | } | 
 |  | 
 | static int http_session_read_by_general(mbtk_http_session_t *session) | 
 | { | 
 | #undef BUFFER_SIZE | 
 | #define BUFFER_SIZE 2048 | 
 |     char read_buf[BUFFER_SIZE + 1]; | 
 |     int read_len = 0; | 
 |     while(TRUE) | 
 |     { | 
 |         read_len = mbtk_http_read(session->sock_fd,read_buf,BUFFER_SIZE,1000); | 
 |         if(read_len <= 0) | 
 |         { | 
 |             if(read_len == -2 || read_len == 0) // Timeout or end | 
 |                 break; | 
 |  | 
 |             LOGW("Read end[read_len - %d].",read_len); | 
 |             //return -1; | 
 |             break; | 
 |         } | 
 |  | 
 |         read_buf[read_len] = '\0'; | 
 |  | 
 |         if(http_handles[session->handle_id].data_cb) | 
 |             http_handles[session->handle_id].data_cb(session->id, | 
 |                     MBTK_HTTP_DATA_CONTENT,read_buf,read_len); | 
 |     } | 
 |  | 
 |     if(http_handles[session->handle_id].data_cb) | 
 |         http_handles[session->handle_id].data_cb(session->id, | 
 |                 MBTK_HTTP_DATA_COMPLETE,NULL,0); | 
 |  | 
 |  | 
 |     return 0; | 
 | } | 
 |  | 
 | static int http_session_start_read(mbtk_http_session_t *session) | 
 | { | 
 |     LOGI("Start HTTP read."); | 
 |     int result = 0; | 
 | //    usleep(500000); | 
 |     session->state = HTTP_SESSION_STATE_READ_HEADER; | 
 |     if(http_header_read(session)) | 
 |     { | 
 |         result = -1; | 
 |         goto read_end; | 
 |     } | 
 |  | 
 |     if(session->option != HTTP_OPTION_HEAD) | 
 |     { | 
 |         session->state = HTTP_SESSION_STATE_READ_CONTENT; | 
 |         if(session->rsp.is_chunked) | 
 |         { | 
 |             if(http_session_read_by_chunk(session)) | 
 |             { | 
 |             	LOGE("http_session_read_by_chunk fail."); | 
 |                 result = -1; | 
 |                 goto read_end; | 
 |             } | 
 |         } | 
 |         else if(session->rsp.content_length > 0) | 
 |         { | 
 |             if(http_session_read_by_length(session)) | 
 |             { | 
 |             	LOGE("http_session_read_by_length fail."); | 
 |                 result = -1; | 
 |                 goto read_end; | 
 |             } | 
 |         } | 
 |         else | 
 |         { | 
 |             if(http_session_read_by_general(session)) | 
 |             { | 
 |             	LOGE("http_session_read_by_general fail."); | 
 |                 result = -1; | 
 |                 goto read_end; | 
 |             } | 
 |         } | 
 |     } | 
 |     else | 
 |     { | 
 |         if(http_handles[session->handle_id].data_cb) | 
 |             http_handles[session->handle_id].data_cb(session->id, | 
 |                     MBTK_HTTP_DATA_COMPLETE,NULL,0); | 
 |     } | 
 |  | 
 | read_end: | 
 |     session->state = HTTP_SESSION_STATE_READ_END; | 
 |  | 
 |     LOGI("HTTP request complete[result - %d].",result); | 
 |     if(http_session_close(session)) | 
 |     { | 
 |         return -1; | 
 |     } | 
 |  | 
 | #if 0 | 
 |     // Free session after HTTP request complete. | 
 |     http_session_free(session); | 
 |     http_handles[handle_id].session[session_id] = NULL; | 
 |     http_handles[handle_id].session_cnt--; | 
 | #endif | 
 |  | 
 |     return result; | 
 | } | 
 |  | 
 | static bool http_session_req_check(mbtk_http_session_t *session) | 
 | { | 
 |     if(session == NULL || session->port == 0 || | 
 |        strlen(session->host) == 0) | 
 |     { | 
 |         LOGE("Session not set host or port."); | 
 |         return FALSE; | 
 |     } | 
 |  | 
 |     if(session->option != HTTP_OPTION_HEAD && | 
 |        session->option != HTTP_OPTION_POST && | 
 |        session->option != HTTP_OPTION_GET) | 
 |     { | 
 |         LOGE("Only support HEAD/GET/POST"); | 
 |         return FALSE; | 
 |     } | 
 |  | 
 | #if 0 | 
 |     if(session->version != HTTP_VERSION_1_0 && | 
 |        session->version != HTTP_VERSION_1_1) | 
 |     { | 
 |         LOGE("Only support HTTP 1.0/1.1"); | 
 |         return FALSE; | 
 |     } | 
 | #endif | 
 |  | 
 |     if(session->option == HTTP_OPTION_POST) | 
 |     { | 
 |         char *value = NULL; | 
 |         value = http_header_find(session, "Content-Length"); | 
 |         if(!value) | 
 |         { | 
 |             LOGE("POST must set 'Content-Length'"); | 
 |             return FALSE; | 
 |         } | 
 |         if(session->req.content_len != atoi(value)) | 
 |         { | 
 |             LOGE("POST 'Content-Length' error."); | 
 |             return FALSE; | 
 |         } | 
 |  | 
 |         value = http_header_find(session, "Content-Type"); | 
 |         if(!value) | 
 |         { | 
 |             LOGE("POST must set 'Content-Type'"); | 
 |             return FALSE; | 
 |         } | 
 |     } | 
 |  | 
 |     return TRUE; | 
 | } | 
 |  | 
 | /************************************************************* | 
 |     Public Function Definitions | 
 | *************************************************************/ | 
 | int mbtk_http_handle_get(bool show_rsp_header,mbtk_http_data_callback_func data_cb) | 
 | { | 
 |     int index = 0; | 
 |     int i = 0; | 
 |     for(; index < HTTP_HANDLE_MAX; index++) | 
 |     { | 
 |         if(http_handles[index].id < 0)   // Find free handle | 
 |         { | 
 |             break; | 
 |         } | 
 |     } | 
 |  | 
 |     if(index == HTTP_HANDLE_MAX) | 
 |     { | 
 |         LOGE("HTTP Handle is full."); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     memset(&(http_handles[index]),0x0,sizeof(mbtk_http_handle_t)); | 
 |     http_handles[index].id = index; | 
 |     http_handles[index].show_rsp_header = show_rsp_header; | 
 |     http_handles[index].data_cb = data_cb; | 
 |     http_handles[index].session_cnt = 0; | 
 |     for(i = 0; i < HTTP_SESSION_MAX; i++) | 
 |     { | 
 |         http_handles[index].session[i] = NULL; | 
 |     } | 
 |  | 
 |     if(mbtk_http_init()) | 
 |     { | 
 |         LOGE("mbtk_http_init() fail."); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     return http_handles[index].id; | 
 | } | 
 |  | 
 | int mbtk_http_handle_free(int handle_id) | 
 | { | 
 |     int i = 0; | 
 |     if(!http_handle_check(handle_id)) | 
 |     { | 
 |         LOGE("Handle error."); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     http_handles[handle_id].id = -1; | 
 |     http_handles[handle_id].data_cb = NULL; | 
 |     if(http_handles[handle_id].session_cnt > 0) | 
 |     { | 
 |         for(i = 0; i < HTTP_SESSION_MAX; i++) | 
 |         { | 
 |             if(http_handles[handle_id].session[i] != NULL) | 
 |             { | 
 |                 if(http_handles[handle_id].session[i]->state != HTTP_SESSION_STATE_NON) | 
 |                 { | 
 |                     if(http_session_close(http_handles[handle_id].session[i])) | 
 |                     { | 
 |                         return -1; | 
 |                     } | 
 |                 } | 
 |  | 
 |                 http_session_free(http_handles[handle_id].session[i]); | 
 |                 http_handles[handle_id].session[i] = NULL; | 
 |             } | 
 |         } | 
 |  | 
 |         http_handles[handle_id].session_cnt = 0; | 
 |     } | 
 |  | 
 |     if(mbtk_http_deinit()) | 
 |     { | 
 |         LOGE("mbtk_http_deinit() fail."); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     return 0; | 
 | } | 
 |  | 
 | int mbtk_http_session_create(int handle_id, mbtk_http_option_enum option, | 
 |                              mbtk_http_version_enum version) | 
 | { | 
 |     int handle_index = 0; | 
 |     int session_index = 0; | 
 |     if(!http_handle_check(handle_id)) | 
 |     { | 
 |         LOGE("Handle error."); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     for(; handle_index < HTTP_HANDLE_MAX; handle_index++) | 
 |     { | 
 |         if(http_handles[handle_index].id == handle_id)   // Find handle | 
 |         { | 
 |             break; | 
 |         } | 
 |     } | 
 |  | 
 |     if(handle_index == HTTP_HANDLE_MAX) | 
 |     { | 
 |         LOGE("No found handle[handle - %d].",handle_id); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     if(http_handles[handle_index].session_cnt >= HTTP_SESSION_MAX) | 
 |     { | 
 |         LOGE("Session is full."); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     for(; session_index < HTTP_SESSION_MAX; session_index++) | 
 |     { | 
 |         if(http_handles[handle_index].session[session_index] == NULL)   // Find first NULL session | 
 |         { | 
 |             break; | 
 |         } | 
 |     } | 
 |  | 
 |     if(session_index == HTTP_SESSION_MAX) | 
 |     { | 
 |         LOGE("Session is full."); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     mbtk_http_session_t* session = (mbtk_http_session_t*)malloc(sizeof(mbtk_http_session_t)); | 
 |     if(session == NULL) | 
 |     { | 
 |         LOGE("malloc() fail."); | 
 |         return -1; | 
 |     } | 
 |     memset(session,0x0,sizeof(mbtk_http_session_t)); | 
 |     session->sock_fd = -1; | 
 |     session->file_fd = -1; | 
 |     session->handle_id = handle_id; | 
 |     session->id = session_index; | 
 |     session->state = HTTP_SESSION_STATE_NON; | 
 |     session->is_ssl = FALSE; | 
 |     session->ingnore_cert = TRUE; | 
 |     session->version = version; | 
 |     session->option = option; | 
 |     session->req.content_len = 0; | 
 |     session->req.content_len_send = 0; | 
 |     session->rsp.is_chunked = FALSE; | 
 |     session->rsp.content_length = 0; | 
 |     session->rsp.header_cnt = 0; | 
 |     http_handles[handle_index].session[session_index] = session; | 
 |     http_handles[handle_index].session_cnt++; | 
 |  | 
 |     return session->id; | 
 | } | 
 |  | 
 | int mbtk_http_session_option_reset(int handle_id, int session_id, mbtk_http_option_enum option) | 
 | { | 
 |     if(!http_session_check(handle_id,session_id)) | 
 |     { | 
 |         LOGE("Session error."); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     mbtk_http_session_t *session = http_handles[handle_id].session[session_id]; | 
 |     if(session->state != HTTP_SESSION_STATE_NON) | 
 |     { | 
 |         LOGE("Session state error.[%d]",session->state); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     session->option = option; | 
 |     return 0; | 
 | } | 
 |  | 
 |  | 
 | int mbtk_http_session_ingnore_cert_set(int handle_id, int session_id, bool ingnore_cert) | 
 | { | 
 |     if(!http_session_check(handle_id,session_id)) | 
 |     { | 
 |         LOGE("Session error."); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     mbtk_http_session_t *session = http_handles[handle_id].session[session_id]; | 
 |  | 
 |     session->ingnore_cert = ingnore_cert; | 
 |  | 
 |     LOGE("session->ingnore_cert:%d, ingnore_cert:%d\n", session->ingnore_cert, ingnore_cert); | 
 |     return 0; | 
 | } | 
 |  | 
 |  | 
 | int mbtk_http_session_free(int handle_id,int session_id) | 
 | { | 
 |     if(!http_session_check(handle_id,session_id)) | 
 |     { | 
 |         LOGE("Session error."); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     mbtk_http_session_t *session = http_handles[handle_id].session[session_id]; | 
 |     if(session->state != HTTP_SESSION_STATE_NON) | 
 |     { | 
 |         if(http_session_close(session)) | 
 |         { | 
 |             return -1; | 
 |         } | 
 |     } | 
 |  | 
 |     http_session_free(session); | 
 |     http_handles[handle_id].session[session_id] = NULL; | 
 |     http_handles[handle_id].session_cnt--; | 
 |     return 0; | 
 | } | 
 |  | 
 | int mbtk_http_session_url_set(int handle_id,int session_id,void *url) | 
 | { | 
 |     if(!http_session_check(handle_id,session_id)) | 
 |     { | 
 |         LOGE("Session error."); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     mbtk_http_session_t *session = http_handles[handle_id].session[session_id]; | 
 |     if(session->state == HTTP_SESSION_STATE_NON) | 
 |         return http_url_parse(url, session->host,session->uri,&(session->port),&(session->is_ssl)); | 
 |     else | 
 |     { | 
 |         LOGE("Currenr session is process[state - %d].",session->state); | 
 |         return -1; | 
 |     } | 
 | } | 
 |  | 
 | int mbtk_http_session_head_add(int handle_id,int session_id, | 
 |                                char *name, char *value) | 
 | { | 
 |     if(!http_session_check(handle_id,session_id)) | 
 |     { | 
 |         LOGE("Session error."); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     if(http_str_empty(name) || http_str_empty(value)) | 
 |     { | 
 |         LOGE("Param error."); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     mbtk_http_session_t *session = http_handles[handle_id].session[session_id]; | 
 |     if(session->state == HTTP_SESSION_STATE_NON) | 
 |     { | 
 |         int result = http_session_req_head_add(session,TRUE,name,value); | 
 |         if(!result && !strncasecmp(name,"Content-Length",14)) | 
 |         { | 
 |             session->req.content_len = atoi(value); | 
 |         } | 
 |         return result; | 
 |     } | 
 |     else | 
 |     { | 
 |         LOGE("Currenr session is process[state - %d].",session->state); | 
 |         return -1; | 
 |     } | 
 | } | 
 |  | 
 | int mbtk_http_session_content_set(int handle_id,int session_id, | 
 |                                   char *content,uint32 content_len) | 
 | { | 
 |     if(!http_session_check(handle_id,session_id)) | 
 |     { | 
 |         LOGE("Session error."); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     if(content_len <= 0 || content_len > HTTP_CONTENT_LEN_MAX) | 
 |     { | 
 |         LOGE("Content lenght error[%d].",content_len); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     mbtk_http_session_t *session = http_handles[handle_id].session[session_id]; | 
 |     if(session->state == HTTP_SESSION_STATE_NON) | 
 |     { | 
 |         if(session->option != HTTP_OPTION_POST) | 
 |         { | 
 |             LOGE("Content only for post."); | 
 |             return -1; | 
 |         } | 
 |  | 
 |         if(session->req.content) | 
 |         { | 
 |             free(session->req.content); | 
 |             session->req.content_len = 0; | 
 |         } | 
 |  | 
 |         session->req.content = (char*)malloc(content_len); | 
 |         if(session->req.content == NULL) | 
 |         { | 
 |             LOGE("malloc() fail."); | 
 |             return -1; | 
 |         } | 
 |  | 
 |         char *content_type = NULL; | 
 |         if(strlen(content) == content_len)   // | 
 |         { | 
 |             content_type = "text/plain"; | 
 |         } | 
 |         else | 
 |         { | 
 |             content_type = "application/octet-stream"; | 
 |         } | 
 |  | 
 |         if(http_session_req_head_add(session, FALSE, "Content-Type", content_type)) | 
 |         { | 
 |             LOGE("Set 'Content-Type' fail."); | 
 |             return -1; | 
 |         } | 
 |  | 
 |         memcpy(session->req.content,content,content_len); | 
 |         session->req.content_len = content_len; | 
 |  | 
 |         char len_str[20] = {0}; | 
 |         snprintf(len_str,20,"%d",content_len); | 
 |         if(http_session_req_head_add(session,FALSE,"Content-Length",len_str)) | 
 |         { | 
 |             LOGE("Set 'Content-Length' fail."); | 
 |             return -1; | 
 |         } | 
 |  | 
 |  | 
 |         return 0; | 
 |     } | 
 |     else | 
 |     { | 
 |         LOGE("Currenr session is process[state - %d].",session->state); | 
 |         return -1; | 
 |     } | 
 | } | 
 |  | 
 | int mbtk_http_session_start(int handle_id,int session_id) | 
 | { | 
 |     if(!http_session_check(handle_id,session_id)) | 
 |     { | 
 |         LOGE("Session error."); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     mbtk_http_session_t *session = http_handles[handle_id].session[session_id]; | 
 |     if(session->state == HTTP_SESSION_STATE_NON) | 
 |     { | 
 |         if(!http_session_req_check(session)) | 
 |         { | 
 |             LOGE("http_session_req_check() fail."); | 
 |             return -1; | 
 |         } | 
 |  | 
 |         // Must set "Connection" for post. | 
 |         if(session->option == HTTP_OPTION_POST) | 
 |         { | 
 |             if(http_session_req_head_add(session,FALSE,"Connection","KeepAlive")) | 
 |             { | 
 |                 LOGE("Set 'Content-Length' fail."); | 
 |                 return -1; | 
 |             } | 
 |         } | 
 |  | 
 |         LOGI("HTTP request start."); | 
 |         LOGI("host:%s, port:%d, uri:%s",session->host,session->port,session->uri); | 
 |         LOGI("is_ssl:%d,ingnore_cert:%d, version:%d, option:%d, content_len:%d",session->is_ssl, | 
 |             session->ingnore_cert, session->version,session->option,session->req.content_len); | 
 |  | 
 |         int sock_fd = mbtk_http_open(session->is_ssl,session->ingnore_cert,session->host,session->port); | 
 |  | 
 |         if(sock_fd < 0) | 
 |         { | 
 |             LOGE("mbtk_http_open() fail."); | 
 |             return -1; | 
 |         } | 
 |         session->sock_fd = sock_fd; | 
 | //        int fd = mbtk_sock_fd_get(sock_fd); | 
 | //        if(fd < 0) { | 
 | //            LOGE("mbtk_sock_fd_get() fail."); | 
 | //            return -1; | 
 | //        } | 
 |         // session->sock_file = fdopen(sock_fd,"r"); | 
 |         session->state = HTTP_SESSION_STATE_CONN; | 
 |  | 
 | //        if(!session->sock_file) { | 
 | //            LOGE("fdopen() fail."); | 
 | //            return -1; | 
 | //        } | 
 |  | 
 |         LOGI("HTTP connected."); | 
 |  | 
 |         if(http_session_start_write(session)) | 
 |         { | 
 |             return -1; | 
 |         } | 
 |  | 
 |         if(session->state == HTTP_SESSION_STATE_WRITE_END) | 
 |         { | 
 |             if(http_session_start_read(session)) | 
 |             { | 
 |                 return -1; | 
 |             } | 
 |         } | 
 |         else | 
 |         { | 
 |             LOGI("Waitting post content data..."); | 
 |         } | 
 |  | 
 |         return 0; | 
 |     } | 
 |     else | 
 |     { | 
 |         LOGE("Currenr session is process[state - %d].",session->state); | 
 |         return -1; | 
 |     } | 
 | } | 
 |  | 
 | int mbtk_http_session_content_send(int handle_id,int session_id, | 
 |                                    char *data,int data_len) | 
 | { | 
 |     if(!http_session_check(handle_id,session_id)) | 
 |     { | 
 |         LOGE("Session error."); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     if(data_len <= 0 || data_len > HTTP_CONTENT_LEN_MAX) | 
 |     { | 
 |         LOGE("Content lenght error[%d].",data_len); | 
 |         return -1; | 
 |     } | 
 |  | 
 |     LOGV("Post send:%d - %s",data_len,data); | 
 |  | 
 |     mbtk_http_session_t *session = http_handles[handle_id].session[session_id]; | 
 |     if(session->state == HTTP_SESSION_STATE_WRITE_CONTENT) | 
 |     { | 
 |         if(session->option != HTTP_OPTION_POST) | 
 |         { | 
 |             LOGE("Content only for post."); | 
 |             return -1; | 
 |         } | 
 |  | 
 |         if(session->req.content || session->req.content_len <= 0) | 
 |         { | 
 |             LOGE("This post not spit package."); | 
 |             return -1; | 
 |         } | 
 |  | 
 |         // Discard excess data. | 
 |         if(session->req.content_len_send + data_len > session->req.content_len) | 
 |             data_len = session->req.content_len - session->req.content_len_send; | 
 |  | 
 |         if(data_len != mbtk_http_write(session->sock_fd,data,data_len)) | 
 |         { | 
 |             return -1; | 
 |         } | 
 |  | 
 |         session->req.content_len_send += data_len; | 
 |  | 
 |         LOGI("HTTP post data send: %d / %d",session->req.content_len_send, | 
 |              session->req.content_len); | 
 |  | 
 |         // Post data send complete. | 
 |         if(session->req.content_len_send >= session->req.content_len) | 
 |         { | 
 |             session->state = HTTP_SESSION_STATE_WRITE_END; | 
 |  | 
 |             LOGI("HTTP write complete."); | 
 |             if(http_session_start_read(session)) | 
 |             { | 
 |                 return -1; | 
 |             } | 
 |         } | 
 |  | 
 |         return 0; | 
 |     } | 
 |     else | 
 |     { | 
 |         LOGE("Currenr session state error[%d].",session->state); | 
 |         return -1; | 
 |     } | 
 | } | 
 |  | 
 | const mbtk_http_session_t* mbtk_http_session_get(int handle_id,int session_id) | 
 | { | 
 |     if(!http_session_check(handle_id,session_id)) | 
 |     { | 
 |         LOGE("Session error."); | 
 |         return NULL; | 
 |     } | 
 |  | 
 |     return http_handles[handle_id].session[session_id]; | 
 | } | 
 |  | 
 | void mbtk_http_lib_info_print() | 
 | { | 
 |     MBTK_SOURCE_INFO_PRINT("mbtk_http_lib"); | 
 | } | 
 |  |