See More

// // Created by HISONA on 2016. 2. 29.. // #include #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_field(HTTP_INFO *hi, char *param); 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_field(HTTP_INFO *hi, char *param) { char *token; char t1[256], t2[256]; int len; // printf("* header: %s \n", param); token = param; if((token=strtoken(token, t1, 256)) == 0) return -1; if(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) { len = (int)strlen(t2); strncpy(hi->response.cookie, t2, len); hi->response.cookie[len] = 0; } 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-type:", 13) == 0) { len = (int)strlen(t2); strncpy(hi->response.content_type, t2, len); hi->response.content_type[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; } /*---------------------------------------------------------------------*/ int http_parse(HTTP_INFO *hi) { char *p1, *p2; long len; p1 = hi->r_ptr; if(p1 == NULL || hi->r_len == 0) { if(p1 == NULL && hi->r_len == 0) return HTTP_PARSE_READ; else return HTTP_PARSE_ERROR; } while(1) { if(HTTP_STATUS_HEADER == hi->status) // header parser { if((p2 = strstr(p1, "\r\n")) != NULL) { len = (long)(p2 - p1); *p2 = 0; if(len > 0) { http_header_field(hi, p1); p1 = p2 + 2; // skip CR+LF } else { hi->status = HTTP_STATUS_BODY; // reach the header-end. p1 = p2 + 2; // skip CR+LF if(TRUE == hi->response.chunked) { len = hi->r_len - (p1 - hi->r_buf); if(len > 0) { if((p2 = strstr(p1, "\r\n")) != NULL) { *p2 = 0; if((hi->chunk_size = strtol(p1, NULL, 16)) > 0) { hi->response.content_length += hi->chunk_size; hi->remain_size = hi->chunk_size; hi->r_ptr = p2 + 2; // skip CR+LF return HTTP_PARSE_CHUNK; } else { hi->status = HTTP_PARSE_END; hi->remain_size = 0; return HTTP_PARSE_END; } } else { // copy the data as chunked size ... memcpy(hi->r_buf, p1, len); hi->r_buf[len] = 0; hi->r_len = len; hi->remain_size = -1; return HTTP_PARSE_READ; } } else { hi->r_len = 0; hi->remain_size = -1; return HTTP_PARSE_READ; } } else { // In HTTP/1.0, Read in content_length size. if(hi->response.content_length == 0) hi->remain_size = -1; else hi->remain_size = hi->response.content_length; } } } else { len = hi->r_len - (p1 - hi->r_buf); if(len > 0) { // keep the partial header data ... memcpy(hi->r_buf, p1, len); hi->r_buf[len] = 0; hi->r_len = len; } else { hi->r_len = 0; } return HTTP_PARSE_READ; } } else if(HTTP_STATUS_BODY == hi->status) // body parser ... { if(TRUE == hi->response.chunked && hi->remain_size == -1) { len = hi->r_len - (p1 - hi->r_buf); if(len > 0) { if ((p2 = strstr(p1, "\r\n")) != NULL) { *p2 = 0; if((hi->chunk_size = strtol(p1, NULL, 16)) > 0) { hi->response.content_length += hi->chunk_size; hi->remain_size = hi->chunk_size; hi->r_ptr = p2 + 2; // skip CR+LF return HTTP_PARSE_CHUNK; } else { hi->status = HTTP_PARSE_END; hi->remain_size = 0; return HTTP_PARSE_END; } } else { // copy the remain data as chunked size ... memcpy(hi->r_buf, p1, len); hi->r_buf[len] = 0; hi->r_len = len; hi->remain_size = -1; return HTTP_PARSE_READ; } } else { hi->r_len = 0; return HTTP_PARSE_READ; } } else { if(hi->remain_size > 0) { len = hi->r_len - (p1 - hi->r_buf); if(hi->remain_size < len) { // copy the data for response .. hi->body = p1; hi->body_len = hi->remain_size; p1 += hi->remain_size; len -= hi->remain_size; if(hi->response.chunked == TRUE && len >= 2) { p1 += 2; // skip CR+LF hi->remain_size = -1; hi->r_ptr = p1; return HTTP_PARSE_WRITE; } else { return HTTP_PARSE_WRITE|HTTP_PARSE_ERROR; } } else { hi->body = p1; hi->body_len = len; hi->remain_size -= len; hi->r_len = 0; if(FALSE == hi->response.chunked && hi->remain_size == 0) { return HTTP_PARSE_WRITE|HTTP_PARSE_END; } return HTTP_PARSE_WRITE|HTTP_PARSE_READ; } } else { if(TRUE == hi->response.chunked) { // chunked size check .. if ((hi->r_len > 2) && (memcmp(p1, "\r\n", 2) == 0)) { p1 += 2; hi->remain_size = -1; } else { hi->remain_size = -1; hi->r_len = 0; } } else { len = hi->r_len - (p1 - hi->r_buf); hi->body = p1; hi->body_len = len; if(hi->remain_size == -1) hi->response.content_length += len; hi->r_len = 0; return HTTP_PARSE_WRITE|HTTP_PARSE_READ; } } } } } } /*---------------------------------------------------------------------*/ 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; hi->init = TRUE; // printf("https_init ... \n"); return 0; } /*---------------------------------------------------------------------*/ static int https_close(HTTP_INFO *hi) { if(hi == NULL || hi->init == FALSE) return -1; 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 ); } hi->init = FALSE; 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) { int ret; while(1) { if(hi->url.https == 1) ret = mbedtls_ssl_read(&hi->tls.ssl, (u_char *) buffer, (size_t) len); else ret = mbedtls_net_recv_timeout(&hi->tls.ssl_fd, (u_char *)buffer, (size_t)len, 5000); if (ret != MBEDTLS_ERR_SSL_WANT_READ) break; } return ret; } /*---------------------------------------------------------------------*/ 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[2048], err[100]; char host[256], port[10], dir[1024]; int sock_fd, https, verify; int ret, mode, 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, 2048, "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; } http_read_init(hi); len = 0; while(1) { mode = http_parse(hi); if((mode & HTTP_PARSE_WRITE) == HTTP_PARSE_WRITE) { if(len < size - 1) { if (len + hi->body_len > size) { strncpy(&response[len], hi->body, size - len - 1); len = size - 1; response[len] = 0; } else { strncpy(&response[len], hi->body, hi->body_len); len += hi->body_len; response[len] = 0; } } } if((mode & HTTP_PARSE_READ) == HTTP_PARSE_READ) { ret = https_read(hi, &hi->r_buf[hi->r_len], (int) (H_READ_SIZE - hi->r_len)); 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; hi->r_ptr = hi->r_buf; } else if((mode & HTTP_PARSE_CHUNK) == HTTP_PARSE_CHUNK) { // printf("return: HTTP_PARSE_CHUNK: chunk_size: %ld \n", hi->chunk_size); } else if((mode & HTTP_PARSE_END) == HTTP_PARSE_END) { // printf("return: HTTP_PARSE_END: content_length: %ld \n", hi->response.content_length); break; } else if((mode & HTTP_PARSE_ERROR) == HTTP_PARSE_ERROR) { snprintf(response, 256, "http parse error."); return -1; } } if(hi->response.close == TRUE) { 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); return len; } /*---------------------------------------------------------------------*/ 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, mode, 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); http_read_init(hi); len = 0; while(1) { mode = http_parse(hi); if((mode & HTTP_PARSE_WRITE) == HTTP_PARSE_WRITE) { if(len < size - 1) { if (len + hi->body_len > size) { strncpy(&response[len], hi->body, size - len - 1); len = size - 1; response[len] = 0; } else { strncpy(&response[len], hi->body, hi->body_len); len += hi->body_len; response[len] = 0; } } } if((mode & HTTP_PARSE_READ) == HTTP_PARSE_READ) { ret = https_read(hi, &hi->r_buf[hi->r_len], (int) (H_READ_SIZE - hi->r_len)); 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; hi->r_ptr = hi->r_buf; } else if((mode & HTTP_PARSE_CHUNK) == HTTP_PARSE_CHUNK) { // printf("return: HTTP_PARSE_CHUNK: chunk_size: %ld \n", hi->chunk_size); } else if((mode & HTTP_PARSE_END) == HTTP_PARSE_END) { // printf("return: HTTP_PARSE_END: content_length: %ld \n", hi->response.content_length); break; } else if((mode & HTTP_PARSE_ERROR) == HTTP_PARSE_ERROR) { snprintf(response, 256, "http parse error."); return -1; } } if(hi->response.close == TRUE) { 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 len; } /*---------------------------------------------------------------------*/ 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_init(HTTP_INFO *hi) { int ret; if (NULL == hi) return -1; memset(&hi->response, 0, sizeof(HTTP_HEADER)); hi->response.status = 0; hi->response.content_length = 0; hi->response.close = 0; hi->r_ptr = NULL; hi->r_len = 0; hi->status = HTTP_STATUS_HEADER; return 0; } /*---------------------------------------------------------------------*/ int http_read(HTTP_INFO *hi) { int ret; if (NULL == hi) return -1; ret = https_read(hi, &hi->r_buf[hi->r_len], (int) (H_READ_SIZE - hi->r_len)); if (ret <= 0) { https_close(hi); return ret; } hi->r_len += ret; hi->r_buf[hi->r_len] = 0; hi->r_ptr = hi->r_buf; return ret; }