//
// Created by HISONA on 2016. 2. 29..
//
#include
#include
#include
#include
#include
#include
#include
#include
#include "mbedtls/net.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
#include "mbedtls/certs.h"
/*---------------------------------------------------------------------*/
#define H_FIELD_SIZE 512
#define H_READ_SIZE 2048
#define CLIENT_MAX 2
typedef struct
{
int status;
char cookie[H_FIELD_SIZE];
char location[H_FIELD_SIZE];
char referrer[H_FIELD_SIZE];
long content_length;
int chunked;
int close;
int https;
char host[256];
char port[10];
long length;
char r_buf[H_READ_SIZE];
long r_len;
int header_end;
char *body;
long body_size;
long body_len;
mbedtls_net_context ssl_fd;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
mbedtls_x509_crt cacert;
} HTTP_INFO;
/*---------------------------------------------------------------------*/
static HTTP_INFO http_info[CLIENT_MAX];
static int _error;
/*---------------------------------------------------------------------*/
char *strtoken(char *src, char *dst, int size);
static int parse_url(char *src_url, int *https, char *host, char *port, char *url);
static int http_header(HTTP_INFO *hi, char *param);
static int http_parse(HTTP_INFO *hi);
static int https_init(HTTP_INFO *hi, int https);
static int https_close(HTTP_INFO *hi);
static int https_connect(HTTP_INFO *hi, char *host, char *port);
static int https_write(HTTP_INFO *hi, char *buffer, int len);
static int https_read(HTTP_INFO *hi, char *buffer, int len);
int http_init(int id);
int http_close(int id);
int http_get(int id, char *url, char *response, int size);
int http_post(int id, char *url, char *data, char *response, int size);
void http_strerror(char *buf, int len);
int http_open_chunked(int id, char *url);
int http_write_chunked(int id, char *data, int len);
int http_read_chunked(int id, char *response, int size);
/*---------------------------------------------------------------------------*/
char *strtoken(char *src, char *dst, int size)
{
char *p, *st, *ed;
int len = 0;
// l-trim
p = src;
while(1)
{
if((*p == '\n') || (*p == 0)) return NULL; /* value is not exists */
if((*p != ' ') && (*p != '\t')) break;
p++;
}
st = p;
while(1)
{
ed = p;
if(*p == ' ') {
p++;
break;
}
if((*p == '\n') || (*p == 0)) break;
p++;
}
// r-trim
while(1)
{
ed--;
if(st == ed) break;
if((*ed != ' ') && (*ed != '\t')) break;
}
len = (int)(ed - st + 1);
if((size > 0) && (len >= size)) len = size - 1;
strncpy(dst, st, len);
dst[len]=0;
return p;
}
/*---------------------------------------------------------------------*/
static int parse_url(char *src_url, int *https, char *host, char *port, char *url)
{
char *p1, *p2;
char str[1024];
memset(str, 0, 1024);
if(strncmp(src_url, "http://", 7)==0) {
p1=&src_url[7];
*https = 0;
} else if(strncmp(src_url, "https://", 8)==0) {
p1=&src_url[8];
*https = 1;
} else {
p1 = &src_url[0];
*https = 0;
}
if((p2=strstr(p1, "/")) == NULL)
{
sprintf(str, "%s", p1);
sprintf(url, "/");
}
else
{
strncpy(str, p1, p2-p1);
snprintf(url, 256, "%s", p2);
}
if((p1=strstr(str, ":")) != NULL)
{
*p1=0;
snprintf(host, 256, "%s", str);
snprintf(port, 5, "%s", p1+1);
}
else
{
snprintf(host, 256, "%s", str);
if(*https == 0)
snprintf(port, 5, "80");
else
snprintf(port, 5, "443");
}
return 0;
}
/*---------------------------------------------------------------------*/
static int http_header(HTTP_INFO *hi, char *param)
{
char *token;
char t1[256], t2[256];
int len;
token = param;
if((token=strtoken(token, t1, 256)) == 0) return -1;
if((token=strtoken(token, t2, 256)) == 0) return -1;
if(strncasecmp(t1, "HTTP", 4) == 0)
{
hi->status = atoi(t2);
}
else if(strncasecmp(t1, "set-cookie:", 11) == 0)
{
snprintf(hi->cookie, 512, "Cookie: %s\r\n", t2);
}
else if(strncasecmp(t1, "location:", 9) == 0)
{
len = (int)strlen(t2);
strncpy(hi->location, t2, len);
hi->location[len] = 0;
}
else if(strncasecmp(t1, "content-length:", 15) == 0)
{
hi->content_length = atoi(t2);
}
else if(strncasecmp(t1, "transfer-encoding:", 18) == 0)
{
if(strncasecmp(t2, "chunked", 7) == 0)
{
hi->chunked = 1;
}
}
else if(strncasecmp(t1, "connection:", 11) == 0)
{
if(strncasecmp(t2, "close", 5) == 0)
{
hi->close = 1;
}
}
return 1;
}
/*---------------------------------------------------------------------*/
static int http_parse(HTTP_INFO *hi)
{
char *p1, *p2;
long len;
if(hi->r_len <= 0) return -1;
p1 = hi->r_buf;
while(1)
{
if(hi->header_end == 0) // header parser
{
if((p2 = strstr(p1, "\r\n")) != NULL)
{
len = (long)(p2 - p1);
*p2 = 0;
if(len > 0)
{
// printf("header: %s(%ld)\n", p1, len);
http_header(hi, p1);
p1 = p2 + 2; // skip CR+LF
}
else
{
hi->header_end = 1; // reach the header-end.
p1 = p2 + 2; // skip CR+LF
if(hi->chunked == 1)
{
len = hi->r_len - (p1 - hi->r_buf);
if(len > 0)
{
if((p2 = strstr(p1, "\r\n")) != NULL)
{
*p2 = 0;
if((hi->length = strtol(p1, NULL, 16)) == 0)
{
hi->chunked = 0;
}
else
{
hi->content_length += hi->length;
}
p1 = p2 + 2; // skip CR+LF
}
else
{
// copy the data as chunked size ...
strncpy(hi->r_buf, p1, len);
hi->r_buf[len] = 0;
hi->r_len = len;
hi->length = -1;
break;
}
}
else
{
hi->r_len = 0;
hi->length = -1;
break;
}
}
else
{
hi->length = hi->content_length;
}
}
}
else
{
len = hi->r_len - (p1 - hi->r_buf);
if(len > 0)
{
// keep the partial header data ...
strncpy(hi->r_buf, p1, len);
hi->r_buf[len] = 0;
hi->r_len = len;
}
else
{
hi->r_len = 0;
}
break;
}
}
else // body parser ...
{
if(hi->chunked == 1 && hi->length == -1)
{
// printf("parse chunked size. \n");
len = hi->r_len - (p1 - hi->r_buf);
if(len > 0)
{
if ((p2 = strstr(p1, "\r\n")) != NULL)
{
*p2 = 0;
if((hi->length = strtol(p1, NULL, 16)) == 0)
{
hi->chunked = 0;
}
else
{
hi->content_length += hi->length;
}
p1 = p2 + 2; // skip CR+LF
}
else
{
// copy the remain data as chunked size ...
strncpy(hi->r_buf, p1, len);
hi->r_buf[len] = 0;
hi->r_len = len;
hi->length = -1;
break;
}
}
else
{
hi->r_len = 0;
break;
}
}
else
{
if(hi->length > 0)
{
len = hi->r_len - (p1 - hi->r_buf);
if(len > hi->length)
{
// copy the data for response ..
if(hi->body_len < hi->body_size-1)
{
if (hi->body_size > (hi->body_len + hi->length))
{
strncpy(&(hi->body[hi->body_len]), p1, hi->length);
hi->body_len += hi->length;
hi->body[hi->body_len] = 0;
}
else
{
strncpy(&(hi->body[hi->body_len]), p1, hi->body_size - hi->body_len - 1);
hi->body_len = hi->body_size - 1;
hi->body[hi->body_len] = 0;
}
}
p1 += hi->length;
len -= hi->length;
if(hi->chunked == 1 && len >= 2)
{
p1 += 2; // skip CR+LF
hi->length = -1;
}
else
{
// printf("parse error ... \n");
return -1;
}
}
else
{
// copy the data for response ..
if(hi->body_len < hi->body_size-1)
{
if (hi->body_size > (hi->body_len + len))
{
strncpy(&(hi->body[hi->body_len]), p1, len);
hi->body_len += len;
hi->body[hi->body_len] = 0;
}
else
{
strncpy(&(hi->body[hi->body_len]), p1, hi->body_size - hi->body_len - 1);
hi->body_len = hi->body_size - 1;
hi->body[hi->body_len] = 0;
}
}
hi->length -= len;
hi->r_len = 0;
if(hi->chunked == 0 && hi->length <= 0) return 1;
break;
}
}
else
{
if(hi->chunked == 0) return 1;
hi->length = -1;
hi->r_len = 0;
}
}
}
}
return 0;
}
/*---------------------------------------------------------------------*/
static int https_init(HTTP_INFO *hi, int https)
{
memset(hi, 0, sizeof(HTTP_INFO));
if(https == 1)
{
mbedtls_ssl_init( &hi->ssl );
mbedtls_ssl_config_init( &hi->conf );
mbedtls_x509_crt_init( &hi->cacert );
mbedtls_ctr_drbg_init( &hi->ctr_drbg );
}
mbedtls_net_init(&hi->ssl_fd);
hi->https = https;
// printf("https_init ... \n");
return 0;
}
/*---------------------------------------------------------------------*/
static int https_close(HTTP_INFO *hi)
{
if(hi->https == 1)
{
mbedtls_ssl_close_notify(&hi->ssl);
}
mbedtls_net_free( &hi->ssl_fd );
if(hi->https == 1)
{
mbedtls_x509_crt_free(&hi->cacert);
mbedtls_ssl_free(&hi->ssl);
mbedtls_ssl_config_free(&hi->conf);
mbedtls_ctr_drbg_free(&hi->ctr_drbg);
mbedtls_entropy_free(&hi->entropy);
}
// printf("https_close ... \n");
return 0;
}
/*
* Initiate a TCP connection with host:port and the given protocol
* waiting for timeout (ms)
*/
static int mbedtls_net_connect_timeout( mbedtls_net_context *ctx, const char *host, const char *port,
int proto, uint32_t timeout )
{
int ret;
struct addrinfo hints, *addr_list, *cur;
signal( SIGPIPE, SIG_IGN );
/* Do name resolution with both IPv6 and IPv4 */
memset( &hints, 0, sizeof( hints ) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;
if( getaddrinfo( host, port, &hints, &addr_list ) != 0 )
return( MBEDTLS_ERR_NET_UNKNOWN_HOST );
/* Try the sockaddrs until a connection succeeds */
ret = MBEDTLS_ERR_NET_UNKNOWN_HOST;
for( cur = addr_list; cur != NULL; cur = cur->ai_next )
{
ctx->fd = (int) socket( cur->ai_family, cur->ai_socktype,
cur->ai_protocol );
if( ctx->fd < 0 )
{
ret = MBEDTLS_ERR_NET_SOCKET_FAILED;
continue;
}
if( mbedtls_net_set_nonblock( ctx ) < 0 )
{
close( ctx->fd );
ctx->fd = -1;
ret = MBEDTLS_ERR_NET_CONNECT_FAILED;
break;
}
if( connect( ctx->fd, cur->ai_addr, cur->ai_addrlen ) == 0 )
{
ret = 0;
break;
}
else if( errno == EINPROGRESS )
{
int fd = (int)ctx->fd;
int opt;
socklen_t slen;
struct timeval tv;
fd_set fds;
while(1)
{
FD_ZERO( &fds );
FD_SET( fd, &fds );
tv.tv_sec = timeout / 1000;
tv.tv_usec = ( timeout % 1000 ) * 1000;
ret = select( fd+1, NULL, &fds, NULL, timeout == 0 ? NULL : &tv );
if( ret == -1 )
{
if(errno == EINTR) continue;
}
else if( ret == 0 )
{
close( fd );
ctx->fd = -1;
ret = MBEDTLS_ERR_NET_CONNECT_FAILED;
}
else
{
ret = 0;
slen = sizeof(int);
if( (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&opt, &slen) == 0) && (opt > 0) )
{
close( fd );
ctx->fd = -1;
ret = MBEDTLS_ERR_NET_CONNECT_FAILED;
}
}
break;
}
break;
}
close( ctx->fd );
ctx->fd = -1;
ret = MBEDTLS_ERR_NET_CONNECT_FAILED;
}
freeaddrinfo( addr_list );
if( (ret == 0) && (mbedtls_net_set_block( ctx ) < 0) )
{
close( ctx->fd );
ctx->fd = -1;
ret = MBEDTLS_ERR_NET_CONNECT_FAILED;
}
return( ret );
}
/*---------------------------------------------------------------------*/
static int https_connect(HTTP_INFO *hi, char *host, char *port)
{
int ret, https;
https = hi->https;
if(https == 1)
{
mbedtls_entropy_init( &hi->entropy );
ret = mbedtls_ctr_drbg_seed( &hi->ctr_drbg, mbedtls_entropy_func, &hi->entropy, NULL, 0);
if( ret != 0 )
{
return ret;
}
ret = mbedtls_x509_crt_parse( &hi->cacert, (const u_char *) mbedtls_test_cas_pem,
mbedtls_test_cas_pem_len );
if( ret < 0 )
{
return ret;
}
ret = mbedtls_ssl_config_defaults( &hi->conf,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT );
if( ret != 0 )
{
return ret;
}
/* OPTIONAL is not optimal for security,
* but makes interop easier in this simplified example */
mbedtls_ssl_conf_authmode( &hi->conf, MBEDTLS_SSL_VERIFY_OPTIONAL );
mbedtls_ssl_conf_ca_chain( &hi->conf, &hi->cacert, NULL );
mbedtls_ssl_conf_rng( &hi->conf, mbedtls_ctr_drbg_random, &hi->ctr_drbg );
mbedtls_ssl_conf_read_timeout( &hi->conf, 5000 );
ret = mbedtls_ssl_setup( &hi->ssl, &hi->conf );
if( ret != 0 )
{
return ret;
}
ret = mbedtls_ssl_set_hostname( &hi->ssl, host );
if( ret != 0 )
{
return ret;
}
}
ret = mbedtls_net_connect_timeout(&hi->ssl_fd, host, port, MBEDTLS_NET_PROTO_TCP, 5000);
if( ret != 0 )
{
return ret;
}
if(https == 1)
{
mbedtls_ssl_set_bio(&hi->ssl, &hi->ssl_fd, mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout);
while ((ret = mbedtls_ssl_handshake(&hi->ssl)) != 0)
{
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
{
return ret;
}
}
}
return 0;
}
/*---------------------------------------------------------------------*/
static int https_write(HTTP_INFO *hi, char *buffer, int len)
{
int ret, slen = 0;
while(1)
{
if(hi->https == 1)
ret = mbedtls_ssl_write(&hi->ssl, (u_char *)&buffer[slen], (size_t)(len-slen));
else
ret = mbedtls_net_send(&hi->ssl_fd, (u_char *)&buffer[slen], (size_t)(len-slen));
if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) continue;
else if(ret <= 0) return ret;
slen += ret;
if(slen >= len) break;
}
return slen;
}
/*---------------------------------------------------------------------*/
static int https_read(HTTP_INFO *hi, char *buffer, int len)
{
if(hi->https == 1)
{
return mbedtls_ssl_read(&hi->ssl, (u_char *)buffer, (size_t)len);
}
else
{
return mbedtls_net_recv_timeout(&hi->ssl_fd, (u_char *)buffer, (size_t)len, 5000);
}
}
/*---------------------------------------------------------------------*/
int http_init(int id)
{
HTTP_INFO *hi;
if(id >= CLIENT_MAX) return -1;
hi = &http_info[id];
return https_init(hi, 0);
}
/*---------------------------------------------------------------------*/
int http_close(int id)
{
HTTP_INFO *hi;
if(id >= CLIENT_MAX) return -1;
hi = &http_info[id];
return https_close(hi);
}
/*---------------------------------------------------------------------*/
int http_get(int id, char *url, char *response, int size)
{
HTTP_INFO *hi;
char request[1024], err[100];
char host[256], port[10], dir[1024];
int sock_fd, https, ret, opt, len;
socklen_t slen;
if(id > 1) return -1;
hi = &http_info[id];
parse_url(url, &https, host, port, dir);
if( (hi->ssl_fd.fd == -1) || (hi->https != https) ||
(strcmp(hi->host, host) != 0) || (strcmp(hi->port, port) != 0) )
{
https_close(hi);
https_init(hi, https);
if((ret=https_connect(hi, host, port)) < 0)
{
https_close(hi);
mbedtls_strerror(ret, err, 100);
snprintf(response, 256, "socket error: %s(%d)", err, ret);
return -1;
}
}
else
{
sock_fd = hi->ssl_fd.fd;
slen = sizeof(int);
if((getsockopt(sock_fd, SOL_SOCKET, SO_ERROR, (void *)&opt, &slen) < 0) || (opt > 0))
{
https_close(hi);
https_init(hi, https);
if((ret=https_connect(hi, host, port)) < 0)
{
https_close(hi);
mbedtls_strerror(ret, err, 100);
snprintf(response, 256, "socket error: %s(%d)", err, ret);
return -1;
}
}
}
/* Send HTTP request. */
len = snprintf(request, 1024,
"GET %s HTTP/1.1\r\n"
"User-Agent: Mozilla/4.0\r\n"
"Host: %s:%s\r\n"
"Content-Type: application/json; charset=utf-8\r\n"
"Connection: Keep-Alive\r\n"
"%s\r\n",
dir, host, port, hi->cookie);
if((ret = https_write(hi, request, len)) != len)
{
https_close(hi);
mbedtls_strerror(ret, err, 100);
snprintf(response, 256, "socket error: %s(%d)", err, ret);
return -1;
}
// printf("request: %s \r\n\r\n", request);
hi->status = 0;
hi->r_len = 0;
hi->header_end = 0;
hi->content_length = 0;
hi->close = 0;
hi->body = response;
hi->body_size = size;
hi->body_len = 0;
while(1)
{
ret = https_read(hi, &hi->r_buf[hi->r_len], (int)(H_READ_SIZE - hi->r_len));
if(ret == MBEDTLS_ERR_SSL_WANT_READ) continue;
else if(ret < 0)
{
https_close(hi);
mbedtls_strerror(ret, err, 100);
snprintf(response, 256, "socket error: %s(%d)", err, ret);
return -1;
}
else if(ret == 0)
{
https_close(hi);
break;
}
hi->r_len += ret;
hi->r_buf[hi->r_len] = 0;
// printf("read(%ld): %s \n", hi->r_len, hi->r_buf);
// printf("read(%ld) ... \n", hi->r_len);
if(http_parse(hi) != 0) break;
}
if(hi->close == 1)
{
https_close(hi);
}
else
{
strncpy(hi->host, host, strlen(host));
strncpy(hi->port, port, strlen(port));
}
/*
printf("status: %d \n", hi->status);
printf("cookie: %s \n", hi->cookie);
printf("location: %s \n", hi->location);
printf("referrer: %s \n", hi->referrer);
printf("length: %ld \n", hi->content_length);
printf("body: %ld \n", hi->body_len);
*/
return hi->status;
}
/*---------------------------------------------------------------------*/
int http_post(int id, char *url, char *data, char *response, int size)
{
HTTP_INFO *hi;
char request[1024], err[100];
char host[256], port[10], dir[1024];
int sock_fd, https, ret, opt, len;
socklen_t slen;
if(id > 1) return -1;
hi = &http_info[id];
parse_url(url, &https, host, port, dir);
if( (hi->ssl_fd.fd == -1) || (hi->https != https) ||
(strcmp(hi->host, host) != 0) || (strcmp(hi->port, port) != 0) )
{
if(hi->ssl_fd.fd != -1)
https_close(hi);
https_init(hi, https);
if((ret=https_connect(hi, host, port)) < 0)
{
https_close(hi);
mbedtls_strerror(ret, err, 100);
snprintf(response, 256, "socket error: %s(%d)", err, ret);
return -1;
}
}
else
{
sock_fd = hi->ssl_fd.fd;
slen = sizeof(int);
if((getsockopt(sock_fd, SOL_SOCKET, SO_ERROR, (void *)&opt, &slen) < 0) || (opt > 0))
{
https_close(hi);
https_init(hi, https);
if((ret=https_connect(hi, host, port)) < 0)
{
https_close(hi);
mbedtls_strerror(ret, err, 100);
snprintf(response, 256, "socket error: %s(%d)", err, ret);
return -1;
}
}
// else
// printf("socket reuse: %d \n", sock_fd);
}
/* Send HTTP request. */
len = snprintf(request, 1024,
"POST %s HTTP/1.1\r\n"
"User-Agent: Mozilla/4.0\r\n"
"Host: %s:%s\r\n"
"Content-Type: application/json; charset=utf-8\r\n"
"Content-Length: %d\r\n"
"Connection: Keep-Alive\r\n"
"%s\r\n"
"%s",
dir, host, port, (int)strlen(data), hi->cookie, data);
if((ret = https_write(hi, request, len)) != len)
{
https_close(hi);
mbedtls_strerror(ret, err, 100);
snprintf(response, 256, "socket error: %s(%d)", err, ret);
return -1;
}
// printf("request: %s \r\n\r\n", request);
hi->status = 0;
hi->r_len = 0;
hi->header_end = 0;
hi->content_length = 0;
hi->close = 0;
hi->body = response;
hi->body_size = size;
hi->body_len = 0;
hi->body[0] = 0;
while(1)
{
ret = https_read(hi, &hi->r_buf[hi->r_len], (int)(H_READ_SIZE - hi->r_len));
if(ret == MBEDTLS_ERR_SSL_WANT_READ) continue;
else if(ret < 0)
{
https_close(hi);
mbedtls_strerror(ret, err, 100);
snprintf(response, 256, "socket error: %s(%d)", err, ret);
return -1;
}
else if(ret == 0)
{
https_close(hi);
break;
}
hi->r_len += ret;
hi->r_buf[hi->r_len] = 0;
// printf("read(%ld): %s \n", hi->r_len, hi->r_buf);
// printf("read(%ld) \n", hi->r_len);
if(http_parse(hi) != 0) break;
}
if(hi->close == 1)
{
https_close(hi);
}
else
{
strncpy(hi->host, host, strlen(host));
strncpy(hi->port, port, strlen(port));
}
/*
printf("status: %d \n", hi->status);
printf("cookie: %s \n", hi->cookie);
printf("location: %s \n", hi->location);
printf("referrer: %s \n", hi->referrer);
printf("length: %d \n", hi->content_length);
printf("body: %d \n", hi->body_len);
*/
return hi->status;
}
/*---------------------------------------------------------------------*/
void http_strerror(char *buf, int len)
{
mbedtls_strerror(_error, buf, len);
}
/*---------------------------------------------------------------------*/
int http_open_chunked(int id, char *url)
{
HTTP_INFO *hi;
char request[1024];
char host[256], port[10], dir[1024];
int sock_fd, https, ret, opt, len;
socklen_t slen;
if (id > 1) return -1;
hi = &http_info[id];
parse_url(url, &https, host, port, dir);
if ((hi->ssl_fd.fd == -1) || (hi->https != https) ||
(strcmp(hi->host, host) != 0) || (strcmp(hi->port, port) != 0))
{
if (hi->ssl_fd.fd != -1)
https_close(hi);
https_init(hi, https);
if ((ret = https_connect(hi, host, port)) < 0)
{
https_close(hi);
_error = ret;
return -1;
}
}
else
{
sock_fd = hi->ssl_fd.fd;
slen = sizeof(int);
if ((getsockopt(sock_fd, SOL_SOCKET, SO_ERROR, (void *) &opt, &slen) < 0) || (opt > 0))
{
https_close(hi);
https_init(hi, https);
if ((ret = https_connect(hi, host, port)) < 0)
{
https_close(hi);
_error = ret;
return -1;
}
}
// else
// printf("socket reuse: %d \n", sock_fd);
}
/* Send HTTP request. */
len = snprintf(request, 1024,
"POST %s HTTP/1.1\r\n"
"User-Agent: Mozilla/4.0\r\n"
"Host: %s:%s\r\n"
"Content-Type: application/json; charset=utf-8\r\n"
"Transfer-Encoding: chunked\r\n"
"Connection: Keep-Alive\r\n"
"%s\r\n",
dir, host, port, hi->cookie);
if ((ret = https_write(hi, request, len)) != len)
{
https_close(hi);
_error = ret;
return -1;
}
strncpy(hi->host, host, strlen(host));
strncpy(hi->port, port, strlen(port));
return 0;
}
/*---------------------------------------------------------------------*/
int http_write_chunked(int id, char *data, int len)
{
HTTP_INFO *hi;
char str[10];
int ret, l;
if (id > 1) return -1;
hi = &http_info[id];
l = snprintf(str, 10, "%x\r\n", len);
if ((ret = https_write(hi, str, l)) != l)
{
https_close(hi);
_error = ret;
return -1;
}
if ((ret = https_write(hi, data, len)) != len)
{
https_close(hi);
_error = ret;
return -1;
}
if ((ret = https_write(hi, "\r\n", 2)) != 2)
{
https_close(hi);
_error = ret;
return -1;
}
return len;
}
/*---------------------------------------------------------------------*/
int http_read_chunked(int id, char *response, int size)
{
HTTP_INFO *hi;
int ret;
if (id > 1) return -1;
hi = &http_info[id];
if ((ret = https_write(hi, "0\r\n\r\n", 5)) != 5)
{
https_close(hi);
_error = ret;
return -1;
}
// printf("request: %s \r\n\r\n", request);
hi->status = 0;
hi->r_len = 0;
hi->header_end = 0;
hi->content_length = 0;
hi->close = 0;
hi->body = response;
hi->body_size = size;
hi->body_len = 0;
hi->body[0] = 0;
while(1)
{
ret = https_read(hi, &hi->r_buf[hi->r_len], (int)(H_READ_SIZE - hi->r_len));
if(ret == MBEDTLS_ERR_SSL_WANT_READ) continue;
else if(ret < 0)
{
https_close(hi);
_error = ret;
return -1;
}
else if(ret == 0)
{
https_close(hi);
break;
}
hi->r_len += ret;
hi->r_buf[hi->r_len] = 0;
// printf("read(%ld): %s \n", hi->r_len, hi->r_buf);
// printf("read(%ld) \n", hi->r_len);
if(http_parse(hi) != 0) break;
}
if(hi->close == 1)
{
https_close(hi);
}
/*
printf("status: %d \n", hi->status);
printf("cookie: %s \n", hi->cookie);
printf("location: %s \n", hi->location);
printf("referrer: %s \n", hi->referrer);
printf("length: %d \n", hi->content_length);
printf("body: %d \n", hi->body_len);
*/
return hi->status;
}