See More

// // Created by HISONA on 2016. 2. 29.. // #include #include #include #include #include #include #include #include #include "ca_cert.h" #include "https.h" /*---------------------------------------------------------------------*/ 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, BOOL https, BOOL verify); 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); /*---------------------------------------------------------------------------*/ char *strtoken(char *src, char *dst, int size) { char *p, *st, *ed; int len = 0; // l-trim p = src; while(TRUE) { if((*p == '\n') || (*p == 0)) return NULL; /* value is not exists */ if((*p != ' ') && (*p != '\t')) break; p++; } st = p; while(TRUE) { ed = p; if(*p == ' ') { p++; break; } if((*p == '\n') || (*p == 0)) break; p++; } // r-trim while(TRUE) { 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->response.status = atoi(t2); } else if(strncasecmp(t1, "set-cookie:", 11) == 0) { snprintf(hi->response.cookie, 512, "%s", t2); } else if(strncasecmp(t1, "location:", 9) == 0) { len = (int)strlen(t2); strncpy(hi->response.location, t2, len); hi->response.location[len] = 0; } else if(strncasecmp(t1, "content-length:", 15) == 0) { hi->response.content_length = atoi(t2); } else if(strncasecmp(t1, "transfer-encoding:", 18) == 0) { if(strncasecmp(t2, "chunked", 7) == 0) { hi->response.chunked = TRUE; } } else if(strncasecmp(t1, "connection:", 11) == 0) { if(strncasecmp(t2, "close", 5) == 0) { hi->response.close = TRUE; } } 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 == FALSE) // 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 = TRUE; // reach the header-end. // printf("header_end .... \n"); p1 = p2 + 2; // skip CR+LF if(hi->response.chunked == TRUE) { 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->response.chunked = FALSE; } else { hi->response.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->response.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->response.chunked == TRUE && hi->length == -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->response.chunked = FALSE; } else { hi->response.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->response.chunked == TRUE && len >= 2) { p1 += 2; // skip CR+LF hi->length = -1; } else { 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->response.chunked == FALSE && hi->length <= 0) return 1; break; } } else { if(hi->response.chunked == FALSE) return 1; // chunked size check .. if((hi->r_len > 2) && (memcmp(p1, "\r\n", 2) == 0)) { p1 += 2; hi->length = -1; } else { hi->length = -1; hi->r_len = 0; } } } } } return 0; } /*---------------------------------------------------------------------*/ static int https_init(HTTP_INFO *hi, BOOL https, BOOL verify) { memset(hi, 0, sizeof(HTTP_INFO)); if(https == TRUE) { mbedtls_ssl_init( &hi->tls.ssl ); mbedtls_ssl_config_init( &hi->tls.conf ); mbedtls_x509_crt_init( &hi->tls.cacert ); mbedtls_ctr_drbg_init( &hi->tls.ctr_drbg ); } mbedtls_net_init(&hi->tls.ssl_fd); hi->tls.verify = verify; hi->url.https = https; // printf("https_init ... \n"); return 0; } /*---------------------------------------------------------------------*/ static int https_close(HTTP_INFO *hi) { if(hi->url.https == 1) { mbedtls_ssl_close_notify(&hi->tls.ssl); } mbedtls_net_free( &hi->tls.ssl_fd ); if(hi->url.https == 1) { mbedtls_x509_crt_free(&hi->tls.cacert); mbedtls_ssl_free(&hi->tls.ssl); mbedtls_ssl_config_free(&hi->tls.conf); mbedtls_ctr_drbg_free(&hi->tls.ctr_drbg); mbedtls_entropy_free(&hi->tls.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->url.https; if(https == 1) { mbedtls_entropy_init( &hi->tls.entropy ); ret = mbedtls_ctr_drbg_seed( &hi->tls.ctr_drbg, mbedtls_entropy_func, &hi->tls.entropy, NULL, 0); if( ret != 0 ) { return ret; } ca_crt_rsa[ca_crt_rsa_size - 1] = 0; ret = mbedtls_x509_crt_parse(&hi->tls.cacert, (uint8_t *)ca_crt_rsa, ca_crt_rsa_size); if( ret != 0 ) { return ret; } ret = mbedtls_ssl_config_defaults( &hi->tls.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->tls.conf, MBEDTLS_SSL_VERIFY_OPTIONAL ); mbedtls_ssl_conf_ca_chain( &hi->tls.conf, &hi->tls.cacert, NULL ); mbedtls_ssl_conf_rng( &hi->tls.conf, mbedtls_ctr_drbg_random, &hi->tls.ctr_drbg ); mbedtls_ssl_conf_read_timeout( &hi->tls.conf, 5000 ); ret = mbedtls_ssl_setup( &hi->tls.ssl, &hi->tls.conf ); if( ret != 0 ) { return ret; } ret = mbedtls_ssl_set_hostname( &hi->tls.ssl, host ); if( ret != 0 ) { return ret; } } ret = mbedtls_net_connect_timeout(&hi->tls.ssl_fd, host, port, MBEDTLS_NET_PROTO_TCP, 5000); if( ret != 0 ) { return ret; } if(https == 1) { mbedtls_ssl_set_bio(&hi->tls.ssl, &hi->tls.ssl_fd, mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout); while ((ret = mbedtls_ssl_handshake(&hi->tls.ssl)) != 0) { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { return ret; } } /* In real life, we probably want to bail out when ret != 0 */ if( hi->tls.verify && (mbedtls_ssl_get_verify_result(&hi->tls.ssl) != 0) ) { return MBEDTLS_ERR_X509_CERT_VERIFY_FAILED; } } return 0; } /*---------------------------------------------------------------------*/ static int https_write(HTTP_INFO *hi, char *buffer, int len) { int ret, slen = 0; while(1) { if(hi->url.https == 1) ret = mbedtls_ssl_write(&hi->tls.ssl, (u_char *)&buffer[slen], (size_t)(len-slen)); else ret = mbedtls_net_send(&hi->tls.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->url.https == 1) { return mbedtls_ssl_read(&hi->tls.ssl, (u_char *)buffer, (size_t)len); } else { return mbedtls_net_recv_timeout(&hi->tls.ssl_fd, (u_char *)buffer, (size_t)len, 5000); } } /*---------------------------------------------------------------------*/ int http_init(HTTP_INFO *hi, BOOL verify) { return https_init(hi, 0, verify); } /*---------------------------------------------------------------------*/ int http_close(HTTP_INFO *hi) { return https_close(hi); } /*---------------------------------------------------------------------*/ int http_get(HTTP_INFO *hi, char *url, char *response, int size) { char request[1024], err[100]; char host[256], port[10], dir[1024]; int sock_fd, https, verify; int ret, opt, len; socklen_t slen; if(NULL == hi) return -1; verify = hi->tls.verify; parse_url(url, &https, host, port, dir); if( (hi->tls.ssl_fd.fd == -1) || (hi->url.https != https) || (strcmp(hi->url.host, host) != 0) || (strcmp(hi->url.port, port) != 0) ) { https_close(hi); https_init(hi, https, verify); 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->tls.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, verify); 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->request.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->response.status = 0; hi->response.content_length = 0; hi->response.close = 0; hi->r_len = 0; hi->header_end = 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->response.close == 1) { https_close(hi); } else { strncpy(hi->url.host, host, strlen(host)); strncpy(hi->url.port, port, strlen(port)); strncpy(hi->url.path, dir, strlen(dir)); } /* printf("status: %d \n", hi->response.status); printf("cookie: %s \n", hi->response.cookie); printf("location: %s \n", hi->response.location); printf("referrer: %s \n", hi->response.referrer); printf("length: %ld \n", hi->response.content_length); printf("body: %ld \n", hi->body_len); */ return hi->response.status; } /*---------------------------------------------------------------------*/ int http_post(HTTP_INFO *hi, char *url, char *data, char *response, int size) { char request[1024], err[100]; char host[256], port[10], dir[1024]; int sock_fd, https, verify; int ret, opt, len; socklen_t slen; if(NULL == hi) return -1; verify = hi->tls.verify; parse_url(url, &https, host, port, dir); if( (hi->tls.ssl_fd.fd == -1) || (hi->url.https != https) || (strcmp(hi->url.host, host) != 0) || (strcmp(hi->url.port, port) != 0) ) { if(hi->tls.ssl_fd.fd != -1) https_close(hi); https_init(hi, https, verify); 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->tls.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, verify); 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" "Connection: Keep-Alive\r\n" "Accept: */*\r\n" "Content-Type: application/json; charset=utf-8\r\n" "Content-Length: %d\r\n" "%s\r\n" "%s", dir, host, port, (int)strlen(data), hi->request.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->response.status = 0; hi->response.content_length = 0; hi->response.close = 0; hi->r_len = 0; hi->header_end = 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->response.close == 1) { https_close(hi); } else { strncpy(hi->url.host, host, strlen(host)); strncpy(hi->url.port, port, strlen(port)); strncpy(hi->url.path, dir, strlen(dir)); } /* printf("status: %d \n", hi->response.status); printf("cookie: %s \n", hi->response.cookie); printf("location: %s \n", hi->response.location); printf("referrer: %s \n", hi->response.referrer); printf("length: %d \n", hi->response.content_length); printf("body: %d \n", hi->body_len); */ return hi->response.status; } /*---------------------------------------------------------------------*/ void http_strerror(char *buf, int len) { mbedtls_strerror(_error, buf, len); } /*---------------------------------------------------------------------*/ int http_open(HTTP_INFO *hi, char *url) { char host[256], port[10], dir[1024]; int sock_fd, https, verify; int ret, opt; socklen_t slen; if (NULL == hi) return -1; verify = hi->tls.verify; parse_url(url, &https, host, port, dir); if ((hi->tls.ssl_fd.fd == -1) || (hi->url.https != https) || (strcmp(hi->url.host, host) != 0) || (strcmp(hi->url.port, port) != 0)) { if (hi->tls.ssl_fd.fd != -1) https_close(hi); https_init(hi, https, verify); if ((ret = https_connect(hi, host, port)) < 0) { https_close(hi); _error = ret; return -1; } } else { sock_fd = hi->tls.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, verify); if ((ret = https_connect(hi, host, port)) < 0) { https_close(hi); _error = ret; return -1; } } // else // printf("socket reuse: %d \n", sock_fd); } strncpy(hi->url.host, host, strlen(host)); strncpy(hi->url.port, port, strlen(port)); strncpy(hi->url.path, dir, strlen(dir)); return 0; } /*---------------------------------------------------------------------*/ int http_write_header(HTTP_INFO *hi) { char request[4096], buf[H_FIELD_SIZE]; int ret, len, l; if (NULL == hi) return -1; /* Send HTTP request. */ len = snprintf(request, 1024, "%s %s HTTP/1.1\r\n" "User-Agent: Mozilla/4.0\r\n" "Host: %s:%s\r\n" "Content-Type: %s\r\n", hi->request.method, hi->url.path, hi->url.host, hi->url.port, hi->request.content_type); if(hi->request.referrer[0] != 0) { len += snprintf(&request[len], H_FIELD_SIZE, "Referer: %s\r\n", hi->request.referrer); } if(hi->request.chunked == TRUE) { len += snprintf(&request[len], H_FIELD_SIZE, "Transfer-Encoding: chunked\r\n"); } else { len += snprintf(&request[len], H_FIELD_SIZE, "Content-Length: %ld\r\n", hi->request.content_length); } if(hi->request.close == TRUE) { len += snprintf(&request[len], H_FIELD_SIZE, "Connection: close\r\n"); } else { len += snprintf(&request[len], H_FIELD_SIZE, "Connection: Keep-Alive\r\n"); } if(hi->request.cookie[0] != 0) { len += snprintf(&request[len], H_FIELD_SIZE, "Cookie: %s\r\n", hi->request.cookie); } len += snprintf(&request[len], H_FIELD_SIZE, "\r\n"); printf("%s", request); if ((ret = https_write(hi, request, len)) != len) { https_close(hi); _error = ret; return -1; } return 0; } /*---------------------------------------------------------------------*/ int http_write(HTTP_INFO *hi, char *data, int len) { char str[10]; int ret, l; if(NULL == hi || len <= 0) return -1; if(hi->request.chunked == TRUE) { 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(hi->request.chunked == TRUE) { if ((ret = https_write(hi, "\r\n", 2)) != 2) { https_close(hi); _error = ret; return -1; } } return len; } /*---------------------------------------------------------------------*/ int http_write_end(HTTP_INFO *hi) { char str[10]; int ret, len; if (NULL == hi) return -1; if(hi->request.chunked == TRUE) { len = snprintf(str, 10, "0\r\n\r\n"); } else { len = snprintf(str, 10, "\r\n\r\n"); } if ((ret = https_write(hi, str, len)) != len) { https_close(hi); _error = ret; return -1; } return len; } /*---------------------------------------------------------------------*/ int http_read_chunked(HTTP_INFO *hi, char *response, int size) { int ret; if (NULL == hi) return -1; // printf("request: %s \r\n\r\n", request); hi->response.status = 0; hi->response.content_length = 0; hi->response.close = 0; hi->r_len = 0; hi->header_end = 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->response.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->response.status; }