blob: f83ae359f7a51fec73512fbcae9e21237a6e8af1 [file] [log] [blame]
/*************************************************************
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");
}