From d4634dafff08f0f69e8d092ced872b42ee5ddc53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20Lang=C3=B3?= Date: Tue, 13 Mar 2018 16:32:51 +0100 Subject: [PATCH] [WIP] Use TLS module in HTTPS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Removed the curl dependency * Updated the mbedtls configuration * Removed the code duplications of HTTP and HTTPS modules * Updated the related test files IoT.js-DCO-1.0-Signed-off-by: László Langó llango.u-szeged@partner.samsung.com --- cmake/mbedtls.cmake | 5 +- config/mbedtls/config-for-iotjs.h | 829 +++++++++++++++- profiles/default.profile | 1 + src/js/http.js | 30 +- src/js/http_client.js | 65 +- src/js/http_incoming.js | 1 - src/js/http_outgoing.js | 39 +- src/js/http_server.js | 30 +- src/js/https.js | 39 +- src/js/https_client.js | 164 ---- src/js/https_incoming.js | 252 ----- src/js/stream_writable.js | 2 +- src/js/tls.js | 5 + src/modules.json | 15 +- src/modules/iotjs_module_https.c | 885 ------------------ src/modules/iotjs_module_https.h | 99 -- test/profiles/host-darwin.profile | 2 + test/profiles/host-linux.profile | 1 + test/profiles/rpi2-linux.profile | 1 + .../test_net_http_request_response.js | 6 - ..._httpserver.js => test_net_http_server.js} | 10 +- ...out.js => test_net_http_server_timeout.js} | 2 + test/run_pass/test_net_https_get.js | 6 +- .../test_net_https_post_status_codes.js | 15 +- .../test_net_https_request_response.js | 12 +- test/run_pass/test_net_https_server.js | 54 ++ test/run_pass/test_net_https_timeout.js | 1 + test/testsets.json | 15 +- 28 files changed, 1034 insertions(+), 1552 deletions(-) delete mode 100644 src/js/https_client.js delete mode 100644 src/js/https_incoming.js delete mode 100644 src/modules/iotjs_module_https.c delete mode 100644 src/modules/iotjs_module_https.h rename test/run_pass/{test_net_httpserver.js => test_net_http_server.js} (94%) rename test/run_pass/{test_net_httpserver_timeout.js => test_net_http_server_timeout.js} (98%) create mode 100644 test/run_pass/test_net_https_server.js diff --git a/cmake/mbedtls.cmake b/cmake/mbedtls.cmake index b8d46232e4..b9d1c7727d 100644 --- a/cmake/mbedtls.cmake +++ b/cmake/mbedtls.cmake @@ -20,13 +20,14 @@ set(DEPS_MBEDTLS_BUILD_DIR ${CMAKE_BINARY_DIR}/${DEPS_MBEDTLS}/library) set(MODULE_NAME "tls") set(MODULE_BINARY_DIR ${DEPS_MBEDTLS_BUILD_DIR}) +if("${TARGET_OS}" STREQUAL "TIZEN") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-cpp") +endif() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-sign-conversion") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${ROOT_DIR}/config/mbedtls") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBEDTLS_CONFIG_FILE=''") -#message(FATAL_ERROR "${CMAKE_C_FLAGS}") - ExternalProject_Add(mbedtls PREFIX ${DEPS_MBEDTLS} SOURCE_DIR ${DEPS_MBEDTLS_SRC} diff --git a/config/mbedtls/config-for-iotjs.h b/config/mbedtls/config-for-iotjs.h index bab1dc5352..6e79e9b247 100644 --- a/config/mbedtls/config-for-iotjs.h +++ b/config/mbedtls/config-for-iotjs.h @@ -33,57 +33,846 @@ * This file is part of mbed TLS (https://tls.mbed.org) */ -/* - * Minimal configuration for TLS 1.1 (RFC 4346), implementing only the - * required ciphersuite: MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA - */ - #ifndef MBEDTLS_CONFIG_H #define MBEDTLS_CONFIG_H -/* System support */ +/** + * \name SECTION: System support + * + * This section sets system specific settings. + * \{ + */ + +/** + * \def MBEDTLS_HAVE_ASM + * + * The compiler has support for asm(). + * + * Requires support for asm() in compiler. + * + * Used in: + * library/timing.c + * library/padlock.c + * include/mbedtls/bn_mul.h + * + * Comment to disable the use of assembly code. + */ #define MBEDTLS_HAVE_ASM + +/** + * \def MBEDTLS_HAVE_TIME + * + * System has time.h and time(). + * The time does not need to be correct, only time differences are used, + * by contrast with MBEDTLS_HAVE_TIME_DATE + * + * Defining MBEDTLS_HAVE_TIME allows you to specify MBEDTLS_PLATFORM_TIME_ALT, + * MBEDTLS_PLATFORM_TIME_MACRO, MBEDTLS_PLATFORM_TIME_TYPE_MACRO and + * MBEDTLS_PLATFORM_STD_TIME. + * + * Comment if your system does not support time functions + */ #define MBEDTLS_HAVE_TIME -/* mbed TLS feature support */ +/** + * \def MBEDTLS_AES_ROM_TABLES + * + * Store the AES tables in ROM. + * + * Uncomment this macro to store the AES tables in ROM. + */ +#define MBEDTLS_AES_ROM_TABLES + +/** + * \def MBEDTLS_CIPHER_MODE_CBC + * + * Enable Cipher Block Chaining mode (CBC) for symmetric ciphers. + */ #define MBEDTLS_CIPHER_MODE_CBC -#define MBEDTLS_PKCS1_V15 + +/** + * \def MBEDTLS_REMOVE_ARC4_CIPHERSUITES + * + * Remove RC4 ciphersuites by default in SSL / TLS. + * This flag removes the ciphersuites based on RC4 from the default list as + * returned by mbedtls_ssl_list_ciphersuites(). However, it is still possible to + * enable (some of) them with mbedtls_ssl_conf_ciphersuites() by including them + * explicitly. + * + * Uncomment this macro to remove RC4 ciphersuites by default. + */ +#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES + +/** + * \def MBEDTLS_ECP_DP_SECP192R1_ENABLED + * + * MBEDTLS_ECP_XXXX_ENABLED: Enables specific curves within the Elliptic Curve + * module. By default all supported curves are enabled. + * + * Comment macros to disable the curve and functions for it + */ +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_DP_SECP384R1_ENABLED +#define MBEDTLS_ECP_DP_SECP256K1_ENABLED +#define MBEDTLS_ECP_DP_BP256R1_ENABLED +#define MBEDTLS_ECP_DP_BP384R1_ENABLED + +/** + * \def MBEDTLS_ECP_NIST_OPTIM + * + * Enable specific 'modulo p' routines for each NIST prime. + * Depending on the prime and architecture, makes operations 4 to 8 times + * faster on the corresponding curve. + * + * Comment this macro to disable NIST curves optimisation. + */ +// #define MBEDTLS_ECP_NIST_OPTIM + +/** + * \def MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + * + * Enable the PSK based ciphersuite modes in SSL / TLS. + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED + * + * Enable the DHE-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_DHM_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED + * + * Enable the ECDHE-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + * + * Enable the RSA-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + * + * Enable the RSA-only based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + */ #define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + * + * Enable the DHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_DHM_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + * + * Enable the ECDHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + * + * Enable the ECDHE-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_ECDSA_C, MBEDTLS_X509_CRT_PARSE_C, + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + * + * Enable the ECDH-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + */ +#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + * + * Enable the ECDH-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + */ +#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + +/** + * \def MBEDTLS_PKCS1_V15 + * + * Enable support for PKCS#1 v1.5 encoding. + * + * Requires: MBEDTLS_RSA_C + * + * This enables support for PKCS#1 v1.5 operations. + */ +#define MBEDTLS_PKCS1_V15 + +/** + * \def MBEDTLS_PKCS1_V21 + * + * Enable support for PKCS#1 v2.1 encoding. + * + * Requires: MBEDTLS_MD_C, MBEDTLS_RSA_C + * + * This enables support for RSAES-OAEP and RSASSA-PSS operations. + */ +#define MBEDTLS_PKCS1_V21 + +/** + * \def MBEDTLS_SHA256_SMALLER + * + * Enable an implementation of SHA-256 that has lower ROM footprint but also + * lower performance. + * + * The default implementation is meant to be a reasonnable compromise between + * performance and size. This version optimizes more aggressively for size at + * the expense of performance. Eg on Cortex-M4 it reduces the size of + * mbedtls_sha256_process() from ~2KB to ~0.5KB for a performance hit of about + * 30%. + * + * Uncomment to enable the smaller implementation of SHA256. + */ +#define MBEDTLS_SHA256_SMALLER + +/** + * \def MBEDTLS_SSL_PROTO_TLS1 + * + * Enable support for TLS 1.0. + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.0 + */ +#define MBEDTLS_SSL_PROTO_TLS1 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1_1 + * + * Enable support for TLS 1.1 (and DTLS 1.0 if DTLS is enabled). + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.1 / DTLS 1.0 + */ #define MBEDTLS_SSL_PROTO_TLS1_1 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1_2 + * + * Enable support for TLS 1.2 (and DTLS 1.2 if DTLS is enabled). + * + * Requires: MBEDTLS_SHA1_C or MBEDTLS_SHA256_C or MBEDTLS_SHA512_C + * (Depends on ciphersuites) + * + * Comment this macro to disable support for TLS 1.2 / DTLS 1.2 + */ #define MBEDTLS_SSL_PROTO_TLS1_2 -/* mbed TLS modules */ +/** + * \def MBEDTLS_SSL_SERVER_NAME_INDICATION + * + * Enable support for RFC 6066 server name indication (SNI) in SSL. + * + * Requires: MBEDTLS_X509_CRT_PARSE_C + * + * Comment this macro to disable support for server name indication in SSL + */ +#define MBEDTLS_SSL_SERVER_NAME_INDICATION + +/* \} name SECTION: mbed TLS feature support */ + +/** + * \name SECTION: mbed TLS modules + * + * This section enables or disables entire modules in mbed TLS + * \{ + */ + +/** + * \def MBEDTLS_AES_C + * + * Enable the AES block cipher. + * + * Module: library/aes.c + * Caller: library/ssl_tls.c + * library/pem.c + * library/ctr_drbg.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA + * + * PEM_PARSE uses AES for decrypting encrypted keys. + */ #define MBEDTLS_AES_C + +/** + * \def MBEDTLS_ASN1_PARSE_C + * + * Enable the generic ASN1 parser. + * + * Module: library/asn1.c + * Caller: library/x509.c + * library/dhm.c + * library/pkcs12.c + * library/pkcs5.c + * library/pkparse.c + */ #define MBEDTLS_ASN1_PARSE_C + +/** + * \def MBEDTLS_ASN1_WRITE_C + * + * Enable the generic ASN1 writer. + * + * Module: library/asn1write.c + * Caller: library/ecdsa.c + * library/pkwrite.c + * library/x509_create.c + * library/x509write_crt.c + * library/mbedtls_x509write_csr.c + */ #define MBEDTLS_ASN1_WRITE_C + +/** + * \def MBEDTLS_BASE64_C + * + * Enable the Base64 module. + * + * Module: library/base64.c + * Caller: library/pem.c + * + * This module is required for PEM support (required by X.509). + */ +#define MBEDTLS_BASE64_C + +/** + * \def MBEDTLS_BIGNUM_C + * + * Enable the multi-precision integer library. + * + * Module: library/bignum.c + * Caller: library/dhm.c + * library/ecp.c + * library/ecdsa.c + * library/rsa.c + * library/ssl_tls.c + * + * This module is required for RSA, DHM and ECC (ECDH, ECDSA) support. + */ #define MBEDTLS_BIGNUM_C + +/** + * \def MBEDTLS_CIPHER_C + * + * Enable the generic cipher layer. + * + * Module: library/cipher.c + * Caller: library/ssl_tls.c + * + * Uncomment to enable generic cipher wrappers. + */ #define MBEDTLS_CIPHER_C + +/** + * \def MBEDTLS_CTR_DRBG_C + * + * Enable the CTR_DRBG AES-256-based random generator. + * + * Module: library/ctr_drbg.c + * Caller: + * + * Requires: MBEDTLS_AES_C + * + * This module provides the CTR_DRBG AES-256 random number generator. + */ #define MBEDTLS_CTR_DRBG_C -#define MBEDTLS_DES_C + +/** + * \def MBEDTLS_DHM_C + * + * Enable the Diffie-Hellman-Merkle module. + * + * Module: library/dhm.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * DHE-RSA, DHE-PSK + */ +#define MBEDTLS_DHM_C + +/** + * \def MBEDTLS_ECDH_C + * + * Enable the elliptic curve Diffie-Hellman library. + * + * Module: library/ecdh.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA, ECDHE-RSA, DHE-PSK + * + * Requires: MBEDTLS_ECP_C + */ +#define MBEDTLS_ECDH_C + +/** + * \def MBEDTLS_ECDSA_C + * + * Enable the elliptic curve DSA library. + * + * Module: library/ecdsa.c + * Caller: + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA + * + * Requires: MBEDTLS_ECP_C, MBEDTLS_ASN1_WRITE_C, MBEDTLS_ASN1_PARSE_C + */ +#define MBEDTLS_ECDSA_C + +/** + * \def MBEDTLS_ECP_C + * + * Enable the elliptic curve over GF(p) library. + * + * Module: library/ecp.c + * Caller: library/ecdh.c + * library/ecdsa.c + * library/ecjpake.c + * + * Requires: MBEDTLS_BIGNUM_C and at least one MBEDTLS_ECP_DP_XXX_ENABLED + */ +#define MBEDTLS_ECP_C + +/** + * \def MBEDTLS_ENTROPY_C + * + * Enable the platform-specific entropy code. + * + * Module: library/entropy.c + * Caller: + * + * Requires: MBEDTLS_SHA512_C or MBEDTLS_SHA256_C + * + * This module provides a generic entropy pool + */ #define MBEDTLS_ENTROPY_C + +/** + * \def MBEDTLS_GCM_C + * + * Enable the Galois/Counter Mode (GCM) for AES. + * + * Module: library/gcm.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C + * + * This module enables the AES-GCM and CAMELLIA-GCM ciphersuites, if other + * requisites are enabled as well. + */ +#define MBEDTLS_GCM_C + +/** + * \def MBEDTLS_MD_C + * + * Enable the generic message digest layer. + * + * Module: library/mbedtls_md.c + * Caller: + * + * Uncomment to enable generic message digest wrappers. + */ #define MBEDTLS_MD_C + +/** + * \def MBEDTLS_MD5_C + * + * Enable the MD5 hash algorithm. + * + * Module: library/mbedtls_md5.c + * Caller: library/mbedtls_md.c + * library/pem.c + * library/ssl_tls.c + * + * This module is required for SSL/TLS and X.509. + * PEM_PARSE uses MD5 for decrypting encrypted keys. + */ #define MBEDTLS_MD5_C -#define MBEDTLS_NET_C + +/** + * \def MBEDTLS_OID_C + * + * Enable the OID database. + * + * Module: library/oid.c + * Caller: library/asn1write.c + * library/pkcs5.c + * library/pkparse.c + * library/pkwrite.c + * library/rsa.c + * library/x509.c + * library/x509_create.c + * library/mbedtls_x509_crl.c + * library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * library/x509write_crt.c + * library/mbedtls_x509write_csr.c + * + * This modules translates between OIDs and internal values. + */ #define MBEDTLS_OID_C + +/** + * \def MBEDTLS_PEM_PARSE_C + * + * Enable PEM decoding / parsing. + * + * Module: library/pem.c + * Caller: library/dhm.c + * library/pkparse.c + * library/mbedtls_x509_crl.c + * library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * + * Requires: MBEDTLS_BASE64_C + * + * This modules adds support for decoding / parsing PEM files. + */ +#define MBEDTLS_PEM_PARSE_C + +/** + * \def MBEDTLS_PK_C + * + * Enable the generic public (asymetric) key layer. + * + * Module: library/pk.c + * Caller: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: MBEDTLS_RSA_C or MBEDTLS_ECP_C + * + * Uncomment to enable generic public key wrappers. + */ #define MBEDTLS_PK_C + +/** + * \def MBEDTLS_PK_PARSE_C + * + * Enable the generic public (asymetric) key parser. + * + * Module: library/pkparse.c + * Caller: library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * + * Requires: MBEDTLS_PK_C + * + * Uncomment to enable generic public key parse functions. + */ #define MBEDTLS_PK_PARSE_C + +/** + * \def MBEDTLS_RSA_C + * + * Enable the RSA public-key cryptosystem. + * + * Module: library/rsa.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509.c + * + * This module is used by the following key exchanges: + * RSA, DHE-RSA, ECDHE-RSA, RSA-PSK + * + * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C + */ #define MBEDTLS_RSA_C + +/** + * \def MBEDTLS_SHA1_C + * + * Enable the SHA1 cryptographic hash algorithm. + * + * Module: library/mbedtls_sha1.c + * Caller: library/mbedtls_md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509write_crt.c + * + * This module is required for SSL/TLS and SHA1-signed certificates. + */ #define MBEDTLS_SHA1_C + +/** + * \def MBEDTLS_SHA256_C + * + * Enable the SHA-224 and SHA-256 cryptographic hash algorithms. + * + * Module: library/mbedtls_sha256.c + * Caller: library/entropy.c + * library/mbedtls_md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module adds support for SHA-224 and SHA-256. + * This module is required for the SSL/TLS 1.2 PRF function. + */ #define MBEDTLS_SHA256_C + +/** + * \def MBEDTLS_SSL_CLI_C + * + * Enable the SSL/TLS client code. + * + * Module: library/ssl_cli.c + * Caller: + * + * Requires: MBEDTLS_SSL_TLS_C + * + * This module is required for SSL/TLS client support. + */ #define MBEDTLS_SSL_CLI_C + +/** + * \def MBEDTLS_SSL_SRV_C + * + * Enable the SSL/TLS server code. + * + * Module: library/ssl_srv.c + * Caller: + * + * Requires: MBEDTLS_SSL_TLS_C + * + * This module is required for SSL/TLS server support. + */ #define MBEDTLS_SSL_SRV_C + +/** + * \def MBEDTLS_SSL_TLS_C + * + * Enable the generic SSL/TLS code. + * + * Module: library/ssl_tls.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: MBEDTLS_CIPHER_C, MBEDTLS_MD_C + * and at least one of the MBEDTLS_SSL_PROTO_XXX defines + * + * This module is required for SSL/TLS. + */ #define MBEDTLS_SSL_TLS_C -#define MBEDTLS_X509_CRT_PARSE_C -#define MBEDTLS_X509_USE_C -/* For test certificates */ -#define MBEDTLS_BASE64_C -#define MBEDTLS_CERTS_C -#define MBEDTLS_PEM_PARSE_C +/** + * \def MBEDTLS_X509_USE_C + * + * Enable X.509 core for using certificates. + * + * Module: library/x509.c + * Caller: library/mbedtls_x509_crl.c + * library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * + * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_BIGNUM_C, MBEDTLS_OID_C, + * MBEDTLS_PK_PARSE_C + * + * This module is required for the X.509 parsing modules. + */ +#define MBEDTLS_X509_USE_C -/* For testing with compat.sh */ -#define MBEDTLS_FS_IO +/** + * \def MBEDTLS_X509_CRT_PARSE_C + * + * Enable X.509 certificate parsing. + * + * Module: library/mbedtls_x509_crt.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is required for X.509 certificate parsing. + */ +#define MBEDTLS_X509_CRT_PARSE_C -#include "mbedtls/check_config.h" +/* \} name SECTION: mbed TLS modules */ #endif /* MBEDTLS_CONFIG_H */ diff --git a/profiles/default.profile b/profiles/default.profile index d496e8f8bf..397f0d4d4b 100644 --- a/profiles/default.profile +++ b/profiles/default.profile @@ -1,2 +1,3 @@ ENABLE_MODULE_IOTJS_BASIC_MODULES ENABLE_MODULE_IOTJS_CORE_MODULES +ENABLE_MODULE_HTTPS diff --git a/src/js/http.js b/src/js/http.js index c149ecfb12..0e27d13122 100644 --- a/src/js/http.js +++ b/src/js/http.js @@ -13,17 +13,43 @@ * limitations under the License. */ -var Server = require('http_server').Server; +var net = require('net'); var ClientRequest = require('http_client').ClientRequest; var HTTPParser = require('httpparser'); +var HTTPServer = require('http_server'); +var util = require('util'); exports.ClientRequest = ClientRequest; exports.request = function(options, cb) { - return new ClientRequest(options, cb); + // Create socket. + var socket = new net.Socket(); + options.port = options.port || 80; + + return new ClientRequest(options, cb, socket); +}; + +function Server(requestListener) { + if (!(this instanceof Server)) { + return new Server(requestListener); + } + + net.Server.call(this, {allowHalfOpen: true}, + HTTPServer.connectionListener); + + HTTPServer.initServer.call(this, {}, requestListener); +} +util.inherits(Server, net.Server); + +Server.prototype.setTimeout = function(ms, cb) { + this.timeout = ms; + if (cb) { + this.on('timeout', cb); + } }; +exports.Server = Server; exports.createServer = function(requestListener) { return new Server(requestListener); diff --git a/src/js/http_client.js b/src/js/http_client.js index 42a8b2c823..da1b1604fe 100644 --- a/src/js/http_client.js +++ b/src/js/http_client.js @@ -14,17 +14,15 @@ */ var util = require('util'); -var net = require('net'); var OutgoingMessage = require('http_outgoing').OutgoingMessage; var common = require('http_common'); var HTTPParser = require('httpparser').HTTPParser; -function ClientRequest(options, cb) { +function ClientRequest(options, cb, socket) { OutgoingMessage.call(this); // get port, host and method. - var port = options.port = options.port || 80; - var host = options.host = options.hostname || options.host || '127.0.0.1'; + options.host = options.hostname || options.host || '127.0.0.1'; var method = options.method || 'GET'; var path = options.path || '/'; @@ -37,10 +35,10 @@ function ClientRequest(options, cb) { } } - if (host && !this.getHeader('host')) { - var hostHeader = host; - if (port && +port !== 80) { - hostHeader += ':' + port; + if (options.host && !this.getHeader('host')) { + var hostHeader = options.host; + if (this._port && +this._port !== 80) { + hostHeader += ':' + this._port; } this.setHeader('Host', hostHeader); } @@ -53,22 +51,29 @@ function ClientRequest(options, cb) { this.once('response', cb); } - // Create socket. - var socket = new net.Socket(); - - // connect server. - socket.connect(port, host); - - // setup connection information. - setupConnection(this, socket); + this.socket = socket; + this.options = options; } util.inherits(ClientRequest, OutgoingMessage); exports.ClientRequest = ClientRequest; +ClientRequest.prototype.end = function(data, encoding, callback) { + var self = this; + + // connect server. + this.socket.connect(this.options, function() { + self._connected = true; + OutgoingMessage.prototype.end.call(self, data, encoding, callback); + }); + + // setup connection information. + setupConnection(this); +}; -function setupConnection(req, socket) { +function setupConnection(req) { + var socket = req.socket; var parser = common.createHTTPParser(); parser.reinitialize(HTTPParser.RESPONSE); socket.parser = parser; @@ -79,15 +84,12 @@ function setupConnection(req, socket) { parser._headers = []; parser.onIncoming = parserOnIncomingClient; - req.socket = socket; - req.connection = socket; req.parser = parser; socket.on('error', socketOnError); socket.on('data', socketOnData); socket.on('end', socketOnEnd); socket.on('close', socketOnClose); - socket.on('lookup', socketOnLookup); // socket emitted when a socket is assigned to req process.nextTick(function() { @@ -126,8 +128,6 @@ function socketOnClose() { var socket = this; var req = socket._httpMessage; - socket.read(); - req.emit('close'); if (req.res && req.res.readable) { @@ -147,10 +147,6 @@ function socketOnError(err) { emitError(this, err); } -function socketOnLookup(err/* , ip */) { - emitError(this, err); -} - function socketOnData(d) { var socket = this; var req = this._httpMessage; @@ -203,20 +199,19 @@ var responseOnEnd = function() { } }; +ClientRequest.prototype.abort = function() { + this.emit('abort'); + if (this.socket) { + cleanUpSocket(this.socket); + } +}; ClientRequest.prototype.setTimeout = function(ms, cb) { var self = this; if (cb) self.once('timeout', cb); - var emitTimeout = function() { + setTimeout(function() { self.emit('timeout'); - }; - - // In IoT.js, socket is already assigned, - // thus, it is sufficient to trigger timeout on socket 'connect' event. - this.socket.once('connect', function() { - self.socket.setTimeout(ms, emitTimeout); - }); - + }, ms); }; diff --git a/src/js/http_incoming.js b/src/js/http_incoming.js index 72249c1fac..df16f6b5d6 100644 --- a/src/js/http_incoming.js +++ b/src/js/http_incoming.js @@ -21,7 +21,6 @@ function IncomingMessage(socket) { stream.Readable.call(this); this.socket = socket; - this.connection = socket; this.readable = true; diff --git a/src/js/http_outgoing.js b/src/js/http_outgoing.js index 2a4e509c34..3c48216404 100644 --- a/src/js/http_outgoing.js +++ b/src/js/http_outgoing.js @@ -27,9 +27,12 @@ function OutgoingMessage() { this.finished = false; this._sentHeader = false; + this._connected = false; + + // storage for chunks when there is no connection established + this._chunks = []; this.socket = null; - this.connection = null; // response header string : same 'content' as this._headers this._header = null; // response header obj : (key, value) pairs @@ -85,19 +88,13 @@ OutgoingMessage.prototype.end = function(data, encoding, callback) { this.finished = true; - this._finish(); + this.emit('prefinish'); return true; }; -OutgoingMessage.prototype._finish = function() { - this.emit('prefinish'); -}; - - // This sends chunk directly into socket -// TODO: buffering of chunk in the case of socket is not available OutgoingMessage.prototype._send = function(chunk, encoding, callback) { if (util.isFunction(encoding)) { callback = encoding; @@ -112,7 +109,20 @@ OutgoingMessage.prototype._send = function(chunk, encoding, callback) { this._sentHeader = true; } - return this.connection.write(chunk, encoding, callback); + if (!this._connected) { + this._chunks.push(chunk); + return false; + } else { + while (this._chunks.length) { + this.socket.write(this._chunks.shift(), encoding, callback); + } + } + + if (this.socket) { + return this.socket.write(chunk, encoding, callback); + } + + return false; }; @@ -125,10 +135,7 @@ OutgoingMessage.prototype.write = function(chunk, encoding, callback) { return true; } - var ret = this._send(chunk, encoding, callback); - - return ret; - + return this._send(chunk, encoding, callback); }; @@ -182,13 +189,15 @@ OutgoingMessage.prototype.getHeader = function(name) { OutgoingMessage.prototype.setTimeout = function(ms, cb) { - if (cb) + if (cb) { this.once('timeout', cb); + } if (!this.socket) { this.once('socket', function(socket) { socket.setTimeout(ms); }); - } else + } else { this.socket.setTimeout(ms); + } }; diff --git a/src/js/http_server.js b/src/js/http_server.js index fb1fc6e04c..8aeb9f7b06 100644 --- a/src/js/http_server.js +++ b/src/js/http_server.js @@ -14,7 +14,6 @@ */ var util = require('util'); -var net = require('net'); var OutgoingMessage = require('http_outgoing').OutgoingMessage; var common = require('http_common'); @@ -122,9 +121,9 @@ ServerResponse.prototype.writeHead = function(statusCode, reason, obj) { ServerResponse.prototype.assignSocket = function(socket) { + this._connected = true; socket._httpMessage = this; this.socket = socket; - this.connection = socket; socket.on('close', onServerResponseClose); this.emit('socket', socket); }; @@ -139,24 +138,18 @@ function onServerResponseClose() { ServerResponse.prototype.detachSocket = function() { this.socket._httpMessage = null; - this.socket = this.connection = null; + this.socket = null; + this._connected = false; }; -function Server(requestListener) { - if (!(this instanceof Server)) { - return new Server(requestListener); - } - - net.Server.call(this, {allowHalfOpen: true}); - +function initServer(options, requestListener) { if (util.isFunction(requestListener)) { this.addListener('request', requestListener); } this.httpAllowHalfOpen = false; - this.on('connection', connectionListener); this.on('clientError', function(err, conn) { conn.destroy(err); }); @@ -164,19 +157,7 @@ function Server(requestListener) { this.timeout = 2 * 1000 * 60; // default timeout is 2 min } -util.inherits(Server, net.Server); -exports.Server = Server; - - -// TODO: Implement Server.prototype.setTimeout function -// For this, socket.prototype.setTimeout is needed. -Server.prototype.setTimeout = function(ms, cb) { - this.timeout = ms; - if (cb) { - this.on('timeout', cb); - } -}; - +exports.initServer = initServer; function connectionListener(socket) { var server = this; @@ -204,6 +185,7 @@ function connectionListener(socket) { } } +exports.connectionListener = connectionListener; function socketOnData(data) { var socket = this; diff --git a/src/js/https.js b/src/js/https.js index 7719092970..e281b97060 100644 --- a/src/js/https.js +++ b/src/js/https.js @@ -13,15 +13,46 @@ * limitations under the License. */ -var client = require('https_client'); +var tls = require('tls'); +var net = require('net'); +var ClientRequest = require('http_client').ClientRequest; +var HTTPParser = require('httpparser'); +var HTTPServer = require('http_server'); +var util = require('util'); -var ClientRequest = exports.ClientRequest = client.ClientRequest; +exports.ClientRequest = ClientRequest; exports.request = function(options, cb) { - return new ClientRequest(options, cb); + options.port = options.port || 443; + // Create socket. + var socket = new tls.TLSSocket(new net.Socket(), options); + + return new ClientRequest(options, cb, socket); +}; + +function Server(options, requestListener) { + if (!(this instanceof Server)) { + return new Server(options, requestListener); + } + options.allowHalfOpen = true; + tls.Server.call(this, options, HTTPServer.connectionListener); + + HTTPServer.initServer.call(this, options, requestListener); +} +util.inherits(Server, tls.Server); + +Server.prototype.setTimeout = function(ms, cb) { + this.timeout = ms; + if (cb) { + this.on('timeout', cb); + } +}; + +exports.createServer = function(options, requestListener) { + return new Server(options, requestListener); }; -exports.METHODS = client.METHODS; +exports.METHODS = HTTPParser.methods; exports.get = function(options, cb) { var req = exports.request(options, cb); diff --git a/src/js/https_client.js b/src/js/https_client.js deleted file mode 100644 index 256d3dda0a..0000000000 --- a/src/js/https_client.js +++ /dev/null @@ -1,164 +0,0 @@ -/* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var util = require('util'); -var incoming = require('https_incoming'); -var stream = require('stream'); -var Buffer = require('buffer'); -var httpsNative = require('https_native'); - -var methods = {'0': 'DELETE', '1': 'GET', '2': 'HEAD', '3': 'POST', - '4': 'PUT', '5': 'CONNECT', '6': 'OPTIONS', '7': 'TRACE'}; -exports.METHODS = methods; - -function ClientRequest(options, cb) { - this.stream = stream.Writable.call(this, options); - - // get port, host and method. - var port = options.port = options.port || 443; - var host = options.host = options.hostname || options.host || '127.0.0.1'; - var path = options.path || '/'; - var protocol = options.protocol || 'https:'; - - this.host = protocol + '//' + host + ':' + port + path; - this.method = options.method || 'GET'; - this.ca = options.ca || ''; - this.cert = options.cert || ''; - this.key = options.key || ''; - - if (options.rejectUnauthorized == null) { - this.rejectUnauthorized = true; - } else { - this.rejectUnauthorized = options.rejectUnauthorized; - } - - var isMethodGood = false; - var key; - for (key in methods) { - if (methods.hasOwnProperty(key)) { - if (this.method === methods[key]) { - isMethodGood = true; - break; - } - } - } - - if (!isMethodGood) { - var err = new Error('Incorrect options.method.'); - this.emit('error', err); - return; - } - - this._incoming = new incoming.IncomingMessage(this); - this._incoming.url = this.host; - this._incoming.method = this.method; - this.aborted = null; - - // Register response event handler. - if (cb) { - this.once('response', cb); - } - this.once('finish', this.onFinish); - - httpsNative.createRequest(this); - - if (options.auth) { - var headerString = 'Authorization: Basic ' + toBase64(options.auth); - httpsNative.addHeader(headerString, this); - } - if (options.headers) { - var keys = Object.keys(options.headers); - for (var i = 0, l = keys.length; i < l; i++) { - key = keys[i]; - httpsNative.addHeader(key + ': ' + options.headers[key], this); - } - } - httpsNative.sendRequest(this); -} - -util.inherits(ClientRequest, stream.Writable); - -// Concrete stream overriding the empty underlying _write method. -ClientRequest.prototype._write = function(chunk, callback, onwrite) { - httpsNative._write(this, chunk.toString(), callback, onwrite); -}; - -ClientRequest.prototype.headersComplete = function() { - var self = this; - self.emit('response', self._incoming); - return (self.method == 'HEAD'); -}; - -ClientRequest.prototype.onError = function(ret) { - this.emit('error', ret); -}; - -ClientRequest.prototype.onFinish = function() { - httpsNative.finishRequest(this); -}; - -ClientRequest.prototype.setTimeout = function(ms, cb) { - this._incoming.setTimeout(ms, cb); -}; - -ClientRequest.prototype.abort = function(doNotEmit) { - if (!this.aborted) { - httpsNative.abort(this); - var date = new Date(); - this.aborted = date.getTime(); - - if (this._incoming.parser) { - this._incoming.parser.finish(); - this._incoming.parser = null; - } - - if (!doNotEmit) { - this.emit('abort'); - } - } -}; - -exports.ClientRequest = ClientRequest; - -function toBase64(input) { - var output = ''; - var chr1, chr2, chr3, enc1, enc2, enc3, enc4; - var i = 0; - // Convert to UTF-8 - input = Buffer(input).toString(); - var _keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' + - '0123456789+/='; - while (i < input.length) { - chr1 = input.charCodeAt(i++); - chr2 = input.charCodeAt(i++); - chr3 = input.charCodeAt(i++); - - enc1 = chr1 >> 2; - enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); - enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); - enc4 = chr3 & 63; - - if (isNaN(chr2)) { - enc3 = enc4 = 64; - } else if (isNaN(chr3)) { - enc4 = 64; - } - - output = output + - _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + - _keyStr.charAt(enc3) + _keyStr.charAt(enc4); - } - return output; -} diff --git a/src/js/https_incoming.js b/src/js/https_incoming.js deleted file mode 100644 index 63fb3dcccf..0000000000 --- a/src/js/https_incoming.js +++ /dev/null @@ -1,252 +0,0 @@ -/* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var util = require('util'); -var stream = require('stream'); -var Buffer = require('buffer'); -var httpsNative = require('https_native'); -var HTTPParser = require('httpparser').HTTPParser; - -function IncomingMessage(clientRequest) { - stream.Readable.call(this); - this.clientRequest = clientRequest; - - this.headers = {}; - this.started = false; - this.completed = false; - this.timeoutCallback = null; - // for response (client) - this.statusCode = null; - this.statusMessage = null; - this.url = null; - this.method = null; - - this.parser = createHTTPParser(this); - - this.onData = cbOnData; - this.onClosed = cbOnClosed; - this.onEnd = cbOnEnd; - this.onError = cbOnError; - this.onSocket = cbOnSocket; - this.onTimeout = cbOnTimeout; - this.onWritable = cbOnWritable; -} - -util.inherits(IncomingMessage, stream.Readable); -exports.IncomingMessage = IncomingMessage; - -IncomingMessage.prototype.read = function(n) { - this.read = stream.Readable.prototype.read; - return this.read(n); -}; - -IncomingMessage.prototype.setTimeout = function(ms, cb) { - if (cb) { - this.timeoutCallback = cb; - this.once('timeout', cb); - } - httpsNative.setTimeout(ms, this.clientRequest); -}; - -IncomingMessage.prototype.addHeaders = function(headers) { - if (!this.headers) { - this.headers = {}; - } - if (!headers) { - return; - } - - for (var i = 0; i < headers.length; i = i + 2) { - this.headers[headers[i]] = headers[i + 1]; - } -}; - -// HTTP PARSER Constructor -var createHTTPParser = function(incoming) { - var parser = new HTTPParser(HTTPParser.RESPONSE); - parser.incoming = incoming; - // cb during http parsing from C side(http_parser) - parser.OnHeaders = parserOnHeaders; - parser.OnHeadersComplete = parserOnHeadersComplete; - parser.OnBody = parserOnBody; - parser.OnMessageComplete = parserOnMessageComplete; - return parser; -}; - -// ------------- HTTP PARSER CALLBACKS ------------- -// This is called when http header is fragmented and -// HTTPParser sends it to JS in separate pieces. -function parserOnHeaders(headers/* , url */) { - var parser = this; - parser.incoming.addHeaders(headers); -} - -// This is called when header part in http msg is parsed. -function parserOnHeadersComplete(info) { - var parser = this; - var headers = info.headers; - - if (!headers) { - headers = parser._headers; - parser.incoming.addHeaders(headers); - parser._headers = {}; - } else { - parser.incoming.addHeaders(headers); - } - - // add header fields of headers to incoming.headers - parser.incoming.addHeaders(headers); - parser.incoming.statusCode = info.status; - parser.incoming.statusMessage = info.status_msg; - parser.incoming.started = true; - - // For client side, if response to 'HEAD' request, we will skip parsing body - if (parser.incoming.statusCode == 100) { - return false; - } - return parser.incoming.clientRequest.headersComplete(); -} - -// parserOnBody is called when HTTPParser parses http msg(incoming) and -// get body part(buf from start at length of len) -function parserOnBody(buf, start, len) { - var parser = this; - var incoming = parser.incoming; - - if (!incoming) { - return; - } - - // Push body part into incoming stream, which will emit 'data' event - var body = buf.slice(start, start + len); - incoming.push(body); -} - -// This is called when parsing of incoming http msg done -function parserOnMessageComplete() { - var parser = this; - var incoming = parser.incoming; - - if (incoming) { - if (incoming.statusCode == 100) { - incoming.headers = {}; - incoming.statusCode = null; - incoming.statusMessage = null; - incoming.started = false; - } else { - incoming.completed = true; - // no more data from incoming, stream will emit 'end' event - incoming.push(null); - } - } -} - -// ------------ LIBCURL PARSER CALLBACKS ----------------- -// Called by libcurl when Request is Done. Finish parser and unref -function cbOnEnd() { - var incoming = this; - var parser = incoming.parser; - if (parser) { - // Unref all links to parser, make parser GCed - parser.finish(); - parser = null; - incoming.parser = null; - } -} - -function cbOnClosed() { - var incoming = this; - var parser = incoming.parser; - var clientRequest = incoming.clientRequest; - - if (incoming.started && !incoming.completed) { - // Socket closed before we emitted 'end' - incoming.on('end', function() { - incoming.emit('close'); - clientRequest.emit('close'); - }); - incoming.push(null); - } else if (!incoming.started) { - incoming.emit('close'); - clientRequest.emit('close'); - // Socket closed before response starts. - var err = new Error('Could Not Start Connection'); - clientRequest.onError(err); - } else { - clientRequest.emit('close'); - } - - if (parser) { - // Unref all links to parser, make parser GCed - parser.finish(); - parser = null; - incoming.parser = null; - } -} - -// Called by libcurl when Request is Done. Finish parser and unref -function cbOnData(chunk) { - var incoming = this; - - if (!incoming) { - return false; - } - - var parser = incoming.parser; - var clientRequest = incoming.clientRequest; - - chunk = new Buffer(chunk); - var ret = parser.execute(chunk); - - if (ret instanceof Error) { - parser.finish(); - // Unref all links to parser, make parser GCed - parser = null; - clientRequest.onError(ret); - return false; - } - return true; -} - -function cbOnError(er) { - var incoming = this; - var clientRequest = incoming.clientRequest; - var err = new Error(er); - clientRequest.onError(err); - clientRequest.abort(true); - incoming.emit('error', err); -} - -function cbOnTimeout() { - var incoming = this; - var clientRequest = incoming.clientRequest; - incoming.emit('timeout'); - if (!incoming.timeoutCallback) { - clientRequest.abort.call(clientRequest, false); - } - incoming.emit('aborted'); -} - -function cbOnSocket() { - var incoming = this; - var clientRequest = incoming.clientRequest; - clientRequest.emit('socket'); -} - -function cbOnWritable() { - var incoming = this; - var clientRequest = incoming.clientRequest; - clientRequest._readyToWrite(); -} diff --git a/src/js/stream_writable.js b/src/js/stream_writable.js index e1ad5d99e1..cdefbf4926 100644 --- a/src/js/stream_writable.js +++ b/src/js/stream_writable.js @@ -34,7 +34,7 @@ function WritableState(options) { this.length = 0; // high water mark. - // The point where write() starts retuning false. + // The point where write() starts returning false. this.highWaterMark = (options && util.isNumber(options.highWaterMark)) ? options.highWaterMark : defaultHighWaterMark; diff --git a/src/js/tls.js b/src/js/tls.js index aa917215ba..3cfbaa8e61 100644 --- a/src/js/tls.js +++ b/src/js/tls.js @@ -47,6 +47,7 @@ function TLSSocket(socket, options) { } native.TlsInit(this, options, secureContext); + this._socketState = socket._socketState; } util.inherits(TLSSocket, EventEmitter); @@ -119,6 +120,10 @@ TLSSocket.prototype.localAddress = function() { return this._socket.address().address; }; +TLSSocket.prototype.setTimeout = function(msecs, callback) { + return this._socket.setTimeout(msecs, callback); +}; + TLSSocket.prototype.ondata = function(data) { var self = this._tlsSocket; self._read(data); diff --git a/src/modules.json b/src/modules.json index 4f9b537805..58fa9ee4c0 100644 --- a/src/modules.json +++ b/src/modules.json @@ -195,20 +195,7 @@ }, "https": { "js_file": "js/https.js", - "require": ["https_client", "https_incoming", "https_native"], - "external_libs": ["curl"] - }, - "https_client": { - "js_file": "js/https_client.js", - "require": ["buffer", "https_incoming", "stream", "util"] - }, - "https_incoming": { - "js_file": "js/https_incoming.js", - "require": ["buffer", "stream", "util"] - }, - "https_native": { - "native_files": ["modules/iotjs_module_https.c"], - "init": "InitHttps" + "require": ["https_client", "httpparser", "http_server", "net", "tls"] }, "i2c": { "platforms": { diff --git a/src/modules/iotjs_module_https.c b/src/modules/iotjs_module_https.c deleted file mode 100644 index 90bf8068ef..0000000000 --- a/src/modules/iotjs_module_https.c +++ /dev/null @@ -1,885 +0,0 @@ -/* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "iotjs_module_https.h" -#include -#include -#include -#include -#include -#include -#include - -#include "iotjs_module_buffer.h" - -// A Per-Request Struct, native bound to https.ClientRequest -struct iotjs_https_t { - // Original Request Details - const char* URL; - HTTPS_Methods method; - struct curl_slist* header_list; - // TLS certs Options - const char* ca; - const char* cert; - const char* key; - bool reject_unauthorized; - // Content-Length for Post and Put - long content_length; - - // Handles - uv_loop_t* loop; - jerry_value_t jthis_native; - CURLM* curl_multi_handle; - uv_timer_t timeout; - CURL* curl_easy_handle; - // Curl Context - int running_handles; - int closing_handles; - bool request_done; - iotjs_https_poll_t* poll_data; - - // For SetTimeOut - uv_timer_t socket_timeout; - long timeout_ms; - double last_bytes_num; - uint64_t last_bytes_time; - - // For Writable Stream ClientRequest - size_t cur_read_index; - bool is_stream_writable; - bool data_to_read; - bool stream_ended; - bool to_destroy_read_onwrite; - iotjs_string_t read_chunk; - jerry_value_t read_callback; - jerry_value_t read_onwrite; - uv_timer_t async_read_onwrite; -}; - -struct iotjs_https_poll_t { - uv_poll_t poll_handle; - iotjs_https_poll_t* next; - iotjs_https_t* https_data; - curl_socket_t sockfd; - bool closing; -}; - -IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(https); - -//-------------Constructor------------ -iotjs_https_t* iotjs_https_create(const char* URL, const char* method, - const char* ca, const char* cert, - const char* key, - const bool reject_unauthorized, - jerry_value_t jthis) { - iotjs_https_t* https_data = IOTJS_ALLOC(iotjs_https_t); - - // Original Request Details - https_data->URL = URL; - https_data->header_list = NULL; - - const char* https_methods_str[] = { STRING_GET, STRING_POST, - STRING_PUT, STRING_DELETE, - STRING_HEAD, STRING_CONNECT, - STRING_OPTIONS, STRING_TRACE }; - int i = 0; - int n_methods = sizeof(https_methods_str) / sizeof(https_methods_str[0]); - for (; i < n_methods; i++) { - if (strcmp(method, https_methods_str[i]) == 0) { - https_data->method = i; - break; - } - } - - if (i > HTTPS_TRACE) - IOTJS_ASSERT(0); - - // TLS certs stuff - https_data->ca = ca; - https_data->cert = cert; - https_data->key = key; - https_data->reject_unauthorized = reject_unauthorized; - // Content Length stuff - https_data->content_length = -1; - - // Handles - https_data->loop = iotjs_environment_loop(iotjs_environment_get()); - https_data->jthis_native = jerry_acquire_value(jthis); - jerry_set_object_native_pointer(https_data->jthis_native, https_data, - &this_module_native_info); - https_data->curl_multi_handle = curl_multi_init(); - https_data->curl_easy_handle = curl_easy_init(); - https_data->timeout.data = (void*)https_data; - uv_timer_init(https_data->loop, &(https_data->timeout)); - https_data->request_done = false; - https_data->closing_handles = 3; - https_data->poll_data = NULL; - - // Timeout stuff - https_data->timeout_ms = -1; - https_data->last_bytes_num = -1; - https_data->last_bytes_time = 0; - https_data->socket_timeout.data = (void*)https_data; - uv_timer_init(https_data->loop, &(https_data->socket_timeout)); - - // ReadData stuff - https_data->cur_read_index = 0; - https_data->is_stream_writable = false; - https_data->stream_ended = false; - https_data->data_to_read = false; - https_data->to_destroy_read_onwrite = false; - https_data->async_read_onwrite.data = (void*)https_data; - uv_timer_init(https_data->loop, &(https_data->async_read_onwrite)); - // No Need to read data for following types of requests - if (https_data->method == HTTPS_GET || https_data->method == HTTPS_DELETE || - https_data->method == HTTPS_HEAD || https_data->method == HTTPS_OPTIONS || - https_data->method == HTTPS_TRACE) - https_data->stream_ended = true; - - return https_data; -} - -// Destructor -void iotjs_https_destroy(iotjs_https_t* https_data) { - https_data->URL = NULL; - IOTJS_RELEASE(https_data); -} - -//----------------Utility Functions------------------ -void iotjs_https_check_done(iotjs_https_t* https_data) { - char* done_url; - CURLMsg* message; - int pending; - bool error = false; - - while ((message = - curl_multi_info_read(https_data->curl_multi_handle, &pending))) { - switch (message->msg) { - case CURLMSG_DONE: - curl_easy_getinfo(message->easy_handle, CURLINFO_EFFECTIVE_URL, - &done_url); - break; - default: - error = true; - } - if (error) { - iotjs_jargs_t jarg = iotjs_jargs_create(1); - char error[] = "Unknown Error has occured."; - iotjs_string_t jresult_string = - iotjs_string_create_with_size(error, strlen(error)); - iotjs_jargs_append_string(&jarg, &jresult_string); - iotjs_https_jcallback(https_data, IOTJS_MAGIC_STRING_ONERROR, &jarg, - false); - iotjs_string_destroy(&jresult_string); - iotjs_jargs_destroy(&jarg); - } - if (https_data->stream_ended) { - iotjs_https_cleanup(https_data); - } else { - if (https_data->to_destroy_read_onwrite) { - iotjs_https_call_read_onwrite_async(https_data); - } - https_data->request_done = true; - } - break; - } -} - -// Cleanup before destructor -void iotjs_https_cleanup(iotjs_https_t* https_data) { - https_data->loop = NULL; - - uv_close((uv_handle_t*)&https_data->timeout, - (uv_close_cb)iotjs_https_uv_close_callback); - uv_close((uv_handle_t*)&https_data->socket_timeout, - (uv_close_cb)iotjs_https_uv_close_callback); - uv_close((uv_handle_t*)&https_data->async_read_onwrite, - (uv_close_cb)iotjs_https_uv_close_callback); - - iotjs_https_jcallback(https_data, IOTJS_MAGIC_STRING_ONEND, - iotjs_jargs_get_empty(), false); - iotjs_https_jcallback(https_data, IOTJS_MAGIC_STRING_ONCLOSED, - iotjs_jargs_get_empty(), false); - - curl_multi_remove_handle(https_data->curl_multi_handle, - https_data->curl_easy_handle); - curl_easy_cleanup(https_data->curl_easy_handle); - https_data->curl_easy_handle = NULL; - curl_multi_cleanup(https_data->curl_multi_handle); - https_data->curl_multi_handle = NULL; - curl_slist_free_all(https_data->header_list); - - if (https_data->poll_data != NULL) - iotjs_https_poll_close_all(https_data->poll_data); - - if (https_data->to_destroy_read_onwrite) { - const iotjs_jargs_t* jarg = iotjs_jargs_get_empty(); - jerry_value_t jthis = https_data->jthis_native; - IOTJS_ASSERT(jerry_value_is_function((https_data->read_onwrite))); - - if (!jerry_value_is_undefined((https_data->read_callback))) - iotjs_make_callback(https_data->read_callback, jthis, jarg); - - iotjs_make_callback(https_data->read_onwrite, jthis, jarg); - https_data->to_destroy_read_onwrite = false; - iotjs_string_destroy(&(https_data->read_chunk)); - jerry_release_value((https_data->read_onwrite)); - jerry_release_value((https_data->read_callback)); - } - return; -} - -// Set various parameters of curl handles -void iotjs_https_initialize_curl_opts(iotjs_https_t* https_data) { - // Setup Some parameters for multi handle - curl_multi_setopt(https_data->curl_multi_handle, CURLMOPT_SOCKETFUNCTION, - iotjs_https_curl_socket_callback); - curl_multi_setopt(https_data->curl_multi_handle, CURLMOPT_SOCKETDATA, - (void*)https_data); - curl_multi_setopt(https_data->curl_multi_handle, CURLMOPT_TIMERFUNCTION, - iotjs_https_curl_start_timeout_callback); - curl_multi_setopt(https_data->curl_multi_handle, CURLMOPT_TIMERDATA, - (void*)https_data); - - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_PROXY, ""); - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_HEADERDATA, - (void*)https_data); - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_WRITEFUNCTION, - iotjs_https_curl_write_callback); - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_WRITEDATA, - (void*)https_data); - - // Read and send data to server only for some request types - if (https_data->method == HTTPS_POST || https_data->method == HTTPS_PUT || - https_data->method == HTTPS_CONNECT) { - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_READFUNCTION, - iotjs_https_curl_read_callback); - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_READDATA, - (void*)https_data); - } - - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_SOCKOPTFUNCTION, - iotjs_https_curl_sockopt_callback); - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_SOCKOPTDATA, - (void*)https_data); - - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_URL, https_data->URL); - https_data->URL = NULL; - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_PROTOCOLS, - CURLPROTO_HTTP | CURLPROTO_HTTPS); - - if (strlen(https_data->ca) > 0) - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_CAINFO, - https_data->ca); - https_data->ca = NULL; - if (strlen(https_data->cert) > 0) - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_SSLCERT, - https_data->cert); - https_data->cert = NULL; - if (strlen(https_data->key) > 0) - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_SSLKEY, - https_data->key); - https_data->key = NULL; - if (!https_data->reject_unauthorized) { - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_SSL_VERIFYPEER, 0); - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_SSL_VERIFYHOST, 0); - } - - // Various request types - switch (https_data->method) { - case HTTPS_GET: - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_HTTPGET, 1L); - break; - case HTTPS_POST: - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_POST, 1L); - break; - case HTTPS_PUT: - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_UPLOAD, 1L); - break; - case HTTPS_DELETE: - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_CUSTOMREQUEST, - "DELETE"); - break; - case HTTPS_HEAD: - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_NOBODY, 1L); - break; - case HTTPS_CONNECT: - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_CUSTOMREQUEST, - "CONNECT"); - break; - case HTTPS_OPTIONS: - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_CUSTOMREQUEST, - "OPTIONS"); - break; - case HTTPS_TRACE: - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_CUSTOMREQUEST, - "TRACE"); - break; - } - - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_HTTP_TRANSFER_DECODING, - 0L); -} - -// Call any property of ClientRequest._Incoming -bool iotjs_https_jcallback(iotjs_https_t* https_data, const char* property, - const iotjs_jargs_t* jarg, bool resultvalue) { - jerry_value_t jthis = https_data->jthis_native; - bool retval = true; - if (jerry_value_is_null(jthis)) - return retval; - - jerry_value_t jincoming = - iotjs_jval_get_property(jthis, IOTJS_MAGIC_STRING__INCOMING); - jerry_value_t cb = iotjs_jval_get_property(jincoming, property); - - IOTJS_ASSERT(jerry_value_is_function(cb)); - if (!resultvalue) { - iotjs_make_callback(cb, jincoming, jarg); - } else { - jerry_value_t result = iotjs_make_callback_with_result(cb, jincoming, jarg); - retval = iotjs_jval_as_boolean(result); - jerry_release_value(result); - } - - jerry_release_value(jincoming); - jerry_release_value(cb); - return retval; -} - -// Call onWrite and callback after ClientRequest._write -void iotjs_https_call_read_onwrite(uv_timer_t* timer) { - iotjs_https_t* https_data = (iotjs_https_t*)(timer->data); - - uv_timer_stop(&(https_data->async_read_onwrite)); - if (jerry_value_is_null(https_data->jthis_native)) - return; - const iotjs_jargs_t* jarg = iotjs_jargs_get_empty(); - jerry_value_t jthis = https_data->jthis_native; - IOTJS_ASSERT(jerry_value_is_function((https_data->read_onwrite))); - - if (!jerry_value_is_undefined((https_data->read_callback))) - iotjs_make_callback(https_data->read_callback, jthis, jarg); - - iotjs_make_callback(https_data->read_onwrite, jthis, jarg); -} - -// Call the above method Asynchronously -void iotjs_https_call_read_onwrite_async(iotjs_https_t* https_data) { - uv_timer_start(&(https_data->async_read_onwrite), - iotjs_https_call_read_onwrite, 0, 0); -} - -// ------------Functions almost directly called by JS---------- -// Add a header to outgoing request -void iotjs_https_add_header(iotjs_https_t* https_data, - const char* char_header) { - https_data->header_list = - curl_slist_append(https_data->header_list, char_header); - if (https_data->method == HTTPS_POST || https_data->method == HTTPS_PUT) { - if (strncmp(char_header, "Content-Length: ", strlen("Content-Length: ")) == - 0) { - const char* numberString = char_header + strlen("Content-Length: "); - https_data->content_length = strtol(numberString, NULL, 10); - } - } -} - -// Recieved data to write from ClientRequest._write -void iotjs_https_data_to_write(iotjs_https_t* https_data, - iotjs_string_t read_chunk, - jerry_value_t callback, jerry_value_t onwrite) { - if (https_data->to_destroy_read_onwrite) { - https_data->to_destroy_read_onwrite = false; - iotjs_string_destroy(&(https_data->read_chunk)); - jerry_release_value((https_data->read_onwrite)); - jerry_release_value((https_data->read_callback)); - } - - https_data->read_chunk = read_chunk; - https_data->data_to_read = true; - - https_data->read_callback = jerry_acquire_value(callback); - https_data->read_onwrite = jerry_acquire_value(onwrite); - https_data->to_destroy_read_onwrite = true; - - if (https_data->request_done) { - iotjs_https_call_read_onwrite_async(https_data); - } else if (https_data->is_stream_writable) { - curl_easy_pause(https_data->curl_easy_handle, CURLPAUSE_CONT); - uv_timer_stop(&(https_data->timeout)); - uv_timer_start(&(https_data->timeout), iotjs_https_uv_timeout_callback, 1, - 0); - } -} - -// Finish writing all data from ClientRequest Stream -void iotjs_https_finish_request(iotjs_https_t* https_data) { - https_data->stream_ended = true; - if (https_data->request_done) { - iotjs_https_cleanup(https_data); - } else if (https_data->is_stream_writable) { - curl_easy_pause(https_data->curl_easy_handle, CURLPAUSE_CONT); - uv_timer_stop(&(https_data->timeout)); - uv_timer_start(&(https_data->timeout), iotjs_https_uv_timeout_callback, 1, - 0); - } -} - -// Start sending the request -void iotjs_https_send_request(iotjs_https_t* https_data) { - // Add all the headers to the easy handle - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_HTTPHEADER, - https_data->header_list); - - if (https_data->method == HTTPS_POST && https_data->content_length != -1) - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_POSTFIELDSIZE, - https_data->content_length); - else if (https_data->method == HTTPS_PUT && https_data->content_length != -1) - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_INFILESIZE, - https_data->content_length); - - curl_multi_add_handle(https_data->curl_multi_handle, - https_data->curl_easy_handle); -} - -// Set timeout for request. -void iotjs_https_set_timeout(long ms, iotjs_https_t* https_data) { - if (ms < 0) - return; - https_data->timeout_ms = ms; - uv_timer_start(&(https_data->socket_timeout), - iotjs_https_uv_socket_timeout_callback, 1, (uint64_t)ms); -} - - -//--------------CURL Callbacks------------------ -// Read callback is actually to write data to outgoing request -size_t iotjs_https_curl_read_callback(void* contents, size_t size, size_t nmemb, - void* userp) { - iotjs_https_t* https_data = (iotjs_https_t*)userp; - - // If stream wasnt made writable yet, make it so. - if (!https_data->is_stream_writable) { - https_data->is_stream_writable = true; - iotjs_https_jcallback(https_data, IOTJS_MAGIC_STRING_ONWRITABLE, - iotjs_jargs_get_empty(), false); - } - - if (https_data->data_to_read) { - size_t real_size = size * nmemb; - size_t chunk_size = iotjs_string_size(&(https_data->read_chunk)); - size_t left_to_copy_size = chunk_size - https_data->cur_read_index; - - if (real_size < 1) - return 0; - - // send some data - if (https_data->cur_read_index < chunk_size) { - size_t num_to_copy = - (left_to_copy_size < real_size) ? left_to_copy_size : real_size; - const char* buf = iotjs_string_data(&(https_data->read_chunk)); - buf = &buf[https_data->cur_read_index]; - strncpy((char*)contents, buf, num_to_copy); - https_data->cur_read_index = https_data->cur_read_index + num_to_copy; - return num_to_copy; - } - - // Finished sending one chunk of data - https_data->cur_read_index = 0; - https_data->data_to_read = false; - iotjs_https_call_read_onwrite_async(https_data); - } - - // If the data is sent, and stream hasn't ended, wait for more data - if (!https_data->stream_ended) { - return CURL_READFUNC_PAUSE; - } - - // All done, end the transfer - return 0; -} - -// Pass Curl events on its fd sockets -int iotjs_https_curl_socket_callback(CURL* easy, curl_socket_t sockfd, - int action, void* userp, void* socketp) { - iotjs_https_t* https_data = (iotjs_https_t*)userp; - if (action == CURL_POLL_IN || action == CURL_POLL_OUT || - action == CURL_POLL_INOUT) { - iotjs_https_poll_t* poll_data = NULL; - - if (!socketp) { - poll_data = iotjs_https_poll_create(https_data->loop, sockfd, https_data); - curl_multi_assign(https_data->curl_multi_handle, sockfd, - (void*)poll_data); - https_data->closing_handles = https_data->closing_handles + 1; - if (https_data->poll_data == NULL) - https_data->poll_data = poll_data; - else - iotjs_https_poll_append(https_data->poll_data, poll_data); - } else - poll_data = (iotjs_https_poll_t*)socketp; - - if (action == CURL_POLL_IN) - uv_poll_start(&poll_data->poll_handle, UV_READABLE, - iotjs_https_uv_poll_callback); - else if (action == CURL_POLL_OUT) - uv_poll_start(&poll_data->poll_handle, UV_WRITABLE, - iotjs_https_uv_poll_callback); - else if (action == CURL_POLL_INOUT) - uv_poll_start(&poll_data->poll_handle, UV_READABLE | UV_WRITABLE, - iotjs_https_uv_poll_callback); - } else { - if (socketp) { - iotjs_https_poll_t* poll_data = (iotjs_https_poll_t*)socketp; - iotjs_https_poll_close(poll_data); - curl_multi_assign(https_data->curl_multi_handle, sockfd, NULL); - } - } - return 0; -} - -// Socket Assigned Callback -int iotjs_https_curl_sockopt_callback(void* userp, curl_socket_t curlfd, - curlsocktype purpose) { - iotjs_https_t* https_data = (iotjs_https_t*)userp; - iotjs_https_jcallback(https_data, IOTJS_MAGIC_STRING_ONSOCKET, - iotjs_jargs_get_empty(), false); - return CURL_SOCKOPT_OK; -} - -// Curl wants us to signal after timeout -int iotjs_https_curl_start_timeout_callback(CURLM* multi, long timeout_ms, - void* userp) { - iotjs_https_t* https_data = (iotjs_https_t*)userp; - if (timeout_ms < 0) - uv_timer_stop(&(https_data->timeout)); - else { - if (timeout_ms == 0) - timeout_ms = 1; - if ((https_data->timeout_ms != -1) && (timeout_ms > https_data->timeout_ms)) - timeout_ms = https_data->timeout_ms; - uv_timer_start(&(https_data->timeout), iotjs_https_uv_timeout_callback, - (uint64_t)timeout_ms, 0); - } - return 0; -} - -// Write Callback is actually to read data from incoming response -size_t iotjs_https_curl_write_callback(void* contents, size_t size, - size_t nmemb, void* userp) { - iotjs_https_t* https_data = (iotjs_https_t*)userp; - size_t real_size = size * nmemb; - if (jerry_value_is_null(https_data->jthis_native)) - return real_size - 1; - - iotjs_jargs_t jarg = iotjs_jargs_create(1); - - jerry_value_t jbuffer = iotjs_bufferwrap_create_buffer((size_t)real_size); - iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer); - iotjs_bufferwrap_copy(buffer_wrap, contents, (size_t)real_size); - - iotjs_jargs_append_jval(&jarg, jbuffer); - - bool result = - iotjs_https_jcallback(https_data, IOTJS_MAGIC_STRING_ONDATA, &jarg, true); - - jerry_release_value(jbuffer); - iotjs_jargs_destroy(&jarg); - - if (!result) { - return real_size - 1; - } - - return real_size; -} - - -//--------------LibTUV Callbacks------------------ -// Callback called on closing handles during cleanup -void iotjs_https_uv_close_callback(uv_handle_t* handle) { - iotjs_https_t* https_data = (iotjs_https_t*)handle->data; - https_data->closing_handles = https_data->closing_handles - 1; - if (https_data->closing_handles <= 0) { - if (https_data->poll_data != NULL) - iotjs_https_poll_destroy(https_data->poll_data); - jerry_release_value(https_data->jthis_native); - } -} - -// Callback called when poll detects actions on FD -void iotjs_https_uv_poll_callback(uv_poll_t* poll, int status, int events) { - iotjs_https_poll_t* poll_data = (iotjs_https_poll_t*)poll->data; - iotjs_https_t* https_data = (iotjs_https_t*)poll_data->https_data; - - int flags = 0; - if (status < 0) - flags = CURL_CSELECT_ERR; - if (!status && events & UV_READABLE) - flags |= CURL_CSELECT_IN; - if (!status && events & UV_WRITABLE) - flags |= CURL_CSELECT_OUT; - int running_handles; - curl_multi_socket_action(https_data->curl_multi_handle, poll_data->sockfd, - flags, &running_handles); - iotjs_https_check_done(https_data); -} - -// This function is for signalling to curl a given time has passed. -// This timeout is usually given by curl itself. -void iotjs_https_uv_timeout_callback(uv_timer_t* timer) { - iotjs_https_t* https_data = (iotjs_https_t*)(timer->data); - uv_timer_stop(timer); - curl_multi_socket_action(https_data->curl_multi_handle, CURL_SOCKET_TIMEOUT, - 0, &https_data->running_handles); - iotjs_https_check_done(https_data); -} - -// Callback called to check if request has timed out -void iotjs_https_uv_socket_timeout_callback(uv_timer_t* timer) { - iotjs_https_t* https_data = (iotjs_https_t*)(timer->data); - double download_bytes = 0; - double upload_bytes = 0; - uint64_t total_time_ms = 0; - - if (https_data->timeout_ms != -1) { - curl_easy_getinfo(https_data->curl_easy_handle, CURLINFO_SIZE_DOWNLOAD, - &download_bytes); - curl_easy_getinfo(https_data->curl_easy_handle, CURLINFO_SIZE_UPLOAD, - &upload_bytes); - total_time_ms = uv_now(https_data->loop); - double total_bytes = download_bytes + upload_bytes; - - if (https_data->last_bytes_num == total_bytes) { - if (total_time_ms > - ((uint64_t)https_data->timeout_ms + https_data->last_bytes_time)) { - if (!https_data->request_done) { - iotjs_https_jcallback(https_data, IOTJS_MAGIC_STRING_ONTIMEOUT, - iotjs_jargs_get_empty(), false); - } - uv_timer_stop(&(https_data->socket_timeout)); - } - } else { - https_data->last_bytes_num = total_bytes; - https_data->last_bytes_time = total_time_ms; - } - } -} - -//--------------https_poll Functions------------------ -iotjs_https_poll_t* iotjs_https_poll_create(uv_loop_t* loop, - curl_socket_t sockfd, - iotjs_https_t* https_data) { - iotjs_https_poll_t* poll_data = IOTJS_ALLOC(iotjs_https_poll_t); - poll_data->sockfd = sockfd; - poll_data->poll_handle.data = poll_data; - poll_data->https_data = https_data; - poll_data->closing = false; - poll_data->next = NULL; - uv_poll_init_socket(loop, &poll_data->poll_handle, sockfd); - return poll_data; -} - -void iotjs_https_poll_append(iotjs_https_poll_t* head, - iotjs_https_poll_t* poll_data) { - iotjs_https_poll_t* current = head; - iotjs_https_poll_t* next = current->next; - while (next != NULL) { - current = next; - next = current->next; - } - current->next = poll_data; -} - -void iotjs_https_poll_close(iotjs_https_poll_t* poll_data) { - if (poll_data->closing == false) { - poll_data->closing = true; - uv_poll_stop(&poll_data->poll_handle); - poll_data->poll_handle.data = poll_data->https_data; - uv_close((uv_handle_t*)&poll_data->poll_handle, - iotjs_https_uv_close_callback); - } - return; -} - -void iotjs_https_poll_close_all(iotjs_https_poll_t* head) { - iotjs_https_poll_t* current = head; - while (current != NULL) { - iotjs_https_poll_close(current); - current = current->next; - } -} - -void iotjs_https_poll_destroy(iotjs_https_poll_t* poll_data) { - if (poll_data->next != NULL) { - iotjs_https_poll_destroy(poll_data->next); - } - IOTJS_RELEASE(poll_data); -} - -// ------------JHANDLERS---------------- - -JS_FUNCTION(createRequest) { - DJS_CHECK_THIS(); - DJS_CHECK_ARGS(1, object); - - const jerry_value_t joptions = JS_GET_ARG(0, object); - - jerry_value_t jhost = - iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_HOST); - iotjs_string_t host = iotjs_jval_as_string(jhost); - jerry_release_value(jhost); - - jerry_value_t jmethod = - iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_METHOD); - iotjs_string_t method = iotjs_jval_as_string(jmethod); - jerry_release_value(jmethod); - - jerry_value_t jca = iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_CA); - iotjs_string_t ca = iotjs_jval_as_string(jca); - jerry_release_value(jca); - - jerry_value_t jcert = - iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_CERT); - iotjs_string_t cert = iotjs_jval_as_string(jcert); - jerry_release_value(jcert); - - jerry_value_t jkey = - iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_KEY); - iotjs_string_t key = iotjs_jval_as_string(jkey); - jerry_release_value(jkey); - - jerry_value_t jreject_unauthorized = - iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_REJECTUNAUTHORIZED); - const bool reject_unauthorized = iotjs_jval_as_boolean(jreject_unauthorized); - - if (curl_global_init(CURL_GLOBAL_SSL)) { - return jerry_create_null(); - } - - iotjs_https_t* https_data = - iotjs_https_create(iotjs_string_data(&host), iotjs_string_data(&method), - iotjs_string_data(&ca), iotjs_string_data(&cert), - iotjs_string_data(&key), reject_unauthorized, - joptions); - - iotjs_https_initialize_curl_opts(https_data); - - iotjs_string_destroy(&host); - iotjs_string_destroy(&method); - iotjs_string_destroy(&ca); - iotjs_string_destroy(&cert); - iotjs_string_destroy(&key); - return jerry_create_null(); -} - -JS_FUNCTION(addHeader) { - DJS_CHECK_THIS(); - - DJS_CHECK_ARGS(2, string, object); - iotjs_string_t header = JS_GET_ARG(0, string); - const char* char_header = iotjs_string_data(&header); - - jerry_value_t jarg = JS_GET_ARG(1, object); - iotjs_https_t* https_data = - (iotjs_https_t*)iotjs_jval_get_object_native_handle(jarg); - iotjs_https_add_header(https_data, char_header); - - iotjs_string_destroy(&header); - return jerry_create_null(); -} - -JS_FUNCTION(sendRequest) { - DJS_CHECK_THIS(); - - DJS_CHECK_ARG(0, object); - jerry_value_t jarg = JS_GET_ARG(0, object); - iotjs_https_t* https_data = - (iotjs_https_t*)iotjs_jval_get_object_native_handle(jarg); - iotjs_https_send_request(https_data); - return jerry_create_null(); -} - -JS_FUNCTION(setTimeout) { - DJS_CHECK_THIS(); - DJS_CHECK_ARGS(2, number, object); - - double ms = JS_GET_ARG(0, number); - jerry_value_t jarg = JS_GET_ARG(1, object); - - iotjs_https_t* https_data = - (iotjs_https_t*)iotjs_jval_get_object_native_handle(jarg); - iotjs_https_set_timeout((long)ms, https_data); - - return jerry_create_null(); -} - -JS_FUNCTION(_write) { - DJS_CHECK_THIS(); - DJS_CHECK_ARGS(2, object, string); - // Argument 3 can be null, so not checked directly, checked later - DJS_CHECK_ARG(3, function); - - jerry_value_t jarg = JS_GET_ARG(0, object); - iotjs_string_t read_chunk = JS_GET_ARG(1, string); - - jerry_value_t callback = jargv[2]; - jerry_value_t onwrite = JS_GET_ARG(3, function); - - iotjs_https_t* https_data = - (iotjs_https_t*)iotjs_jval_get_object_native_handle(jarg); - iotjs_https_data_to_write(https_data, read_chunk, callback, onwrite); - - // readchunk was copied to https_data, hence not destroyed. - return jerry_create_null(); -} - -JS_FUNCTION(finishRequest) { - DJS_CHECK_THIS(); - DJS_CHECK_ARG(0, object); - - jerry_value_t jarg = JS_GET_ARG(0, object); - iotjs_https_t* https_data = - (iotjs_https_t*)iotjs_jval_get_object_native_handle(jarg); - iotjs_https_finish_request(https_data); - - return jerry_create_null(); -} - -JS_FUNCTION(Abort) { - DJS_CHECK_THIS(); - DJS_CHECK_ARG(0, object); - - jerry_value_t jarg = JS_GET_ARG(0, object); - iotjs_https_t* https_data = - (iotjs_https_t*)iotjs_jval_get_object_native_handle(jarg); - iotjs_https_cleanup(https_data); - - return jerry_create_null(); -} - -jerry_value_t InitHttps() { - jerry_value_t https = jerry_create_object(); - - iotjs_jval_set_method(https, IOTJS_MAGIC_STRING_CREATEREQUEST, createRequest); - iotjs_jval_set_method(https, IOTJS_MAGIC_STRING_ADDHEADER, addHeader); - iotjs_jval_set_method(https, IOTJS_MAGIC_STRING_SENDREQUEST, sendRequest); - iotjs_jval_set_method(https, IOTJS_MAGIC_STRING_SETTIMEOUT, setTimeout); - iotjs_jval_set_method(https, IOTJS_MAGIC_STRING__WRITE, _write); - iotjs_jval_set_method(https, IOTJS_MAGIC_STRING_FINISHREQUEST, finishRequest); - iotjs_jval_set_method(https, IOTJS_MAGIC_STRING_ABORT, Abort); - - return https; -} diff --git a/src/modules/iotjs_module_https.h b/src/modules/iotjs_module_https.h deleted file mode 100644 index e44e741679..0000000000 --- a/src/modules/iotjs_module_https.h +++ /dev/null @@ -1,99 +0,0 @@ -/* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef IOTJS_MODULE_HTTPS_H -#define IOTJS_MODULE_HTTPS_H - -#include "iotjs_def.h" -#include -#include - -typedef enum { - HTTPS_GET = 0, - HTTPS_POST, - HTTPS_PUT, - HTTPS_DELETE, - HTTPS_HEAD, - HTTPS_CONNECT, - HTTPS_OPTIONS, - HTTPS_TRACE -} HTTPS_Methods; - -#define STRING_GET "GET" -#define STRING_POST "POST" -#define STRING_PUT "PUT" -#define STRING_DELETE "DELETE" -#define STRING_HEAD "HEAD" -#define STRING_CONNECT "CONNECT" -#define STRING_OPTIONS "OPTIONS" -#define STRING_TRACE "TRACE" - -typedef struct iotjs_https_poll_t iotjs_https_poll_t; -typedef struct iotjs_https_t iotjs_https_t; - -iotjs_https_t* iotjs_https_create(const char* URL, const char* method, - const char* ca, const char* cert, - const char* key, - const bool reject_unauthorized, - jerry_value_t jthis); - -// Some utility functions -void iotjs_https_check_done(iotjs_https_t* https_data); -void iotjs_https_cleanup(iotjs_https_t* https_data); -void iotjs_https_initialize_curl_opts(iotjs_https_t* https_data); -jerry_value_t iotjs_https_jthis_from_https(iotjs_https_t* https_data); -bool iotjs_https_jcallback(iotjs_https_t* https_data, const char* property, - const iotjs_jargs_t* jarg, bool resultvalue); -void iotjs_https_call_read_onwrite(uv_timer_t* timer); -void iotjs_https_call_read_onwrite_async(iotjs_https_t* https_data); - -// Functions almost directly called by JS via JHANDLER -void iotjs_https_add_header(iotjs_https_t* https_data, const char* char_header); -void iotjs_https_data_to_write(iotjs_https_t* https_data, - iotjs_string_t read_chunk, - jerry_value_t callback, jerry_value_t onwrite); -void iotjs_https_finish_request(iotjs_https_t* https_data); -void iotjs_https_send_request(iotjs_https_t* https_data); -void iotjs_https_set_timeout(long ms, iotjs_https_t* https_data); - - -// CURL callbacks -size_t iotjs_https_curl_read_callback(void* contents, size_t size, size_t nmemb, - void* userp); -int iotjs_https_curl_socket_callback(CURL* easy, curl_socket_t sockfd, - int action, void* userp, void* socketp); -int iotjs_https_curl_sockopt_callback(void* userp, curl_socket_t curlfd, - curlsocktype purpose); -int iotjs_https_curl_start_timeout_callback(CURLM* multi, long timeout_ms, - void* userp); -size_t iotjs_https_curl_write_callback(void* contents, size_t size, - size_t nmemb, void* userp); - -// UV Callbacks -void iotjs_https_uv_close_callback(uv_handle_t* handle); -void iotjs_https_uv_poll_callback(uv_poll_t* poll, int status, int events); -void iotjs_https_uv_socket_timeout_callback(uv_timer_t* timer); -void iotjs_https_uv_timeout_callback(uv_timer_t* timer); - -iotjs_https_poll_t* iotjs_https_poll_create(uv_loop_t* loop, - curl_socket_t sockfd, - iotjs_https_t* https_data); -void iotjs_https_poll_append(iotjs_https_poll_t* head, - iotjs_https_poll_t* poll_data); -void iotjs_https_poll_close(iotjs_https_poll_t* poll_data); -void iotjs_https_poll_destroy(iotjs_https_poll_t* poll_data); -void iotjs_https_poll_close_all(iotjs_https_poll_t* head); - -#endif /* IOTJS_MODULE_HTTPS_H */ diff --git a/test/profiles/host-darwin.profile b/test/profiles/host-darwin.profile index d496e8f8bf..e26eb4a2c9 100644 --- a/test/profiles/host-darwin.profile +++ b/test/profiles/host-darwin.profile @@ -1,2 +1,4 @@ ENABLE_MODULE_IOTJS_BASIC_MODULES ENABLE_MODULE_IOTJS_CORE_MODULES +ENABLE_MODULE_HTTPS + diff --git a/test/profiles/host-linux.profile b/test/profiles/host-linux.profile index 7126bdb1f4..68135c5f7c 100644 --- a/test/profiles/host-linux.profile +++ b/test/profiles/host-linux.profile @@ -4,6 +4,7 @@ ENABLE_MODULE_ADC ENABLE_MODULE_BLE ENABLE_MODULE_DGRAM ENABLE_MODULE_GPIO +ENABLE_MODULE_HTTPS ENABLE_MODULE_I2C ENABLE_MODULE_PWM ENABLE_MODULE_SPI diff --git a/test/profiles/rpi2-linux.profile b/test/profiles/rpi2-linux.profile index fd327107af..8ed4b594ca 100644 --- a/test/profiles/rpi2-linux.profile +++ b/test/profiles/rpi2-linux.profile @@ -3,6 +3,7 @@ ENABLE_MODULE_IOTJS_CORE_MODULES ENABLE_MODULE_BLE ENABLE_MODULE_DGRAM ENABLE_MODULE_GPIO +ENABLE_MODULE_HTTPS ENABLE_MODULE_I2C ENABLE_MODULE_PWM ENABLE_MODULE_SPI diff --git a/test/run_pass/test_net_http_request_response.js b/test/run_pass/test_net_http_request_response.js index 7c976d3a4e..e7615b7bf9 100644 --- a/test/run_pass/test_net_http_request_response.js +++ b/test/run_pass/test_net_http_request_response.js @@ -73,12 +73,6 @@ request2.end(message, function() { isRequest2Finished = true; }); -// Call the request2 end again to test the finish state. -request2.end(message, function() { - // This clabback should never be called. - assert.equal(isRequest2Finished, false); -}); - var server3 = http.createServer(function(request, response) { var str = ''; diff --git a/test/run_pass/test_net_httpserver.js b/test/run_pass/test_net_http_server.js similarity index 94% rename from test/run_pass/test_net_httpserver.js rename to test/run_pass/test_net_http_server.js index 912c9ec0aa..09d76b6208 100644 --- a/test/run_pass/test_net_httpserver.js +++ b/test/run_pass/test_net_http_server.js @@ -14,9 +14,9 @@ */ var assert = require('assert'); -var Server = require('http_server').Server; +// var Server = require('http_server').Server; var http = require('http'); - +var Server = http.Server; var responseCheck = ''; var connectionEvent = 0; @@ -78,6 +78,7 @@ var msg = 'http request test msg'; var options = { method : 'POST', port : 3001, + rejectUnauthorized: false, headers : {'Content-Length': msg.length} }; @@ -148,6 +149,7 @@ var finalMsg = 'close server'; var finalOptions = { method : 'POST', port : 3001, + rejectUnauthorized: false, headers : {'Content-Length': finalMsg.length} }; @@ -181,7 +183,7 @@ finalReq.end(); var server2 = http.createServer(); // Create server instance without new keyword. -var server3 = Server(function(request, response) {}); +// var server3 = Server(function(request, response) {}); process.on('exit', function() { assert.equal(responseCheck.length, 3); @@ -191,5 +193,5 @@ process.on('exit', function() { assert.equal(responseEvent, 3); assert.equal(socketEvent, 3); assert.equal(server2 instanceof Server, true); - assert.equal(server3 instanceof Server, true); +// assert.equal(server3 instanceof Server, true); }); diff --git a/test/run_pass/test_net_httpserver_timeout.js b/test/run_pass/test_net_http_server_timeout.js similarity index 98% rename from test/run_pass/test_net_httpserver_timeout.js rename to test/run_pass/test_net_http_server_timeout.js index 51390663c9..bb44cc4544 100644 --- a/test/run_pass/test_net_httpserver_timeout.js +++ b/test/run_pass/test_net_http_server_timeout.js @@ -47,3 +47,5 @@ process.on('exit', function(code) { assert.equal(timeouted, true); assert.equal(code, 0); }); + +getReq.end(); diff --git a/test/run_pass/test_net_https_get.js b/test/run_pass/test_net_https_get.js index 3ef93e26f5..83c09dba41 100644 --- a/test/run_pass/test_net_https_get.js +++ b/test/run_pass/test_net_https_get.js @@ -22,8 +22,9 @@ var isRequest1Finished = false; // 1. GET req options = { method: 'GET', - host: "httpbin.org", + host: 'httpbin.org', path: '/user-agent', + rejectUnauthorized: false, headers: {'user-agent': 'iotjs'} }; @@ -50,8 +51,9 @@ https.get(options, getResponseHandler); var testMsg = 'Hello IoT.js'; var finalOptions = { method: 'POST', - host: "httpbin.org", + host: 'httpbin.org', path: '/post', + rejectUnauthorized: false, headers: {'Content-Length': testMsg.length, 'Content-Type': 'application/json'} }; diff --git a/test/run_pass/test_net_https_post_status_codes.js b/test/run_pass/test_net_https_post_status_codes.js index 49853b8d09..09c7d91101 100644 --- a/test/run_pass/test_net_https_post_status_codes.js +++ b/test/run_pass/test_net_https_post_status_codes.js @@ -24,13 +24,14 @@ var data = JSON.stringify({ data: { temp: 50, onFire: false }, type: 'message' }); var options = { - "method": "POST", - "hostname": "api.artik.cloud", - "path": "/v1.1/messages", - "headers": { - "content-type": "application/json", - "content-length": data.length, - "authorization": "Bearer 1718113118564ad495ad03f04116f379" + method: 'POST', + hostname: 'api.artik.cloud', + path: '/v1.1/messages', + rejectUnauthorized: false, + headers: { + 'content-type': 'application/json', + 'content-length': data.length, + 'authorization': 'Bearer 1718113118564ad495ad03f04116f379' } }; diff --git a/test/run_pass/test_net_https_request_response.js b/test/run_pass/test_net_https_request_response.js index 5054afd202..e9bdd4d030 100644 --- a/test/run_pass/test_net_https_request_response.js +++ b/test/run_pass/test_net_https_request_response.js @@ -24,8 +24,9 @@ var message = 'Hello IoT.js'; // Options for further requests. var options = { method: 'POST', - host: "httpbin.org", + host: 'httpbin.org', path: '/post', + rejectUnauthorized: false, headers: {'Content-Length': message.length, 'Content-Type': 'application/json'} }; @@ -67,12 +68,6 @@ request2.end(message, function() { isRequest2Finished = true; }); -// Call the request2 end again to test the finish state. -request2.end(message, function() { - // This clabback should never be called. - assert.equal(isRequest2Finished, false); -}); - // Simple request with buffer chunk as message parameter. var isRequest3Finished = false; @@ -96,7 +91,8 @@ request3.end(new Buffer(message)); var isRequest4Finished = false; var readRequest = https.request({ method: 'GET', - host: "httpbin.org", + host: 'httpbin.org', + rejectUnauthorized: false, path: '/get' }); diff --git a/test/run_pass/test_net_https_server.js b/test/run_pass/test_net_https_server.js new file mode 100644 index 0000000000..e5cb89ef2a --- /dev/null +++ b/test/run_pass/test_net_https_server.js @@ -0,0 +1,54 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var assert = require('assert'); +var https = require('https'); +var fs = require('fs'); + +var server_options = { + key: fs.readFileSync('resources/my_key.pem').toString(), + cert: fs.readFileSync('resources/my_crt.pem').toString() +}; +try { throw 1; } catch(e) {} +var server = https.createServer(server_options, function(req, res) { + res.writeHead(200); + res.end('hello world\n'); +}).listen(8000); + + +var client_options = { + host: 'localhost', + port: 8000, + rejectUnauthorized: false +} + +var responseHandler = function (res) { + var res_body = ''; + + assert.equal(200, res.statusCode); + + var endHandler = function(){ + assert.equal(res_body, 'hello world\n'); + }; + res.on('end', endHandler); + + res.on('data', function(chunk){ + res_body += chunk.toString(); + }); + + server.close(); +} + +https.get(client_options, responseHandler); diff --git a/test/run_pass/test_net_https_timeout.js b/test/run_pass/test_net_https_timeout.js index 95531b6695..a722040ad5 100644 --- a/test/run_pass/test_net_https_timeout.js +++ b/test/run_pass/test_net_https_timeout.js @@ -21,6 +21,7 @@ var https = require('https'); options = { method: 'GET', host: 'httpbin.org', + rejectUnauthorized: false, path: '/delay/10' }; diff --git a/test/testsets.json b/test/testsets.json index b2535273fc..eb14b2fc70 100644 --- a/test/testsets.json +++ b/test/testsets.json @@ -71,12 +71,13 @@ { "name": "test_net_httpclient_parse_error.js" }, { "name": "test_net_httpclient_timeout_1.js" }, { "name": "test_net_httpclient_timeout_2.js" }, - { "name": "test_net_httpserver_timeout.js" }, - { "name": "test_net_httpserver.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" }, - { "name": "test_net_https_get.js", "timeout": 40, "skip": ["darwin", "linux", "nuttx", "tizenrt"], "reason": "Implemented only for Tizen" }, - { "name": "test_net_https_post_status_codes.js", "timeout": 40, "skip": ["darwin", "linux", "nuttx", "tizenrt"], "reason": "Implemented only for Tizen" }, - { "name": "test_net_https_request_response.js", "timeout": 40, "skip": ["darwin", "linux", "nuttx", "tizenrt"], "reason": "Implemented only for Tizen" }, - { "name": "test_net_https_timeout.js", "timeout": 40, "skip": ["darwin", "linux", "nuttx", "tizenrt"], "reason": "Implemented only for Tizen" }, + { "name": "test_net_http_server_timeout.js" }, + { "name": "test_net_http_server.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" }, + { "name": "test_net_https_get.js", "timeout": 10, "skip": ["nuttx", "tizenrt"], "reason": "not implemented for nuttx and TizenRT" }, + { "name": "test_net_https_post_status_codes.js", "timeout": 10, "skip": ["nuttx", "tizenrt"], "reason": "not implemented for nuttx and TizenRT" }, + { "name": "test_net_https_request_response.js", "timeout": 10, "skip": ["nuttx", "tizenrt"], "reason": "not implemented for nuttx and TizenRT" }, + { "name": "test_net_https_timeout.js", "timeout": 10, "skip": ["nuttx", "tizenrt"], "reason": "not implemented for nuttx and TizenRT" }, + { "name": "test_net_https_server.js", "timeout": 10, "skip": ["nuttx", "tizenrt"], "reason": "not implemented for nuttx and TizenRT" }, { "name": "test_process.js" }, { "name": "test_process_chdir.js" }, { "name": "test_process_cwd.js" }, @@ -98,7 +99,7 @@ { "name": "test_timers_arguments.js" }, { "name": "test_timers_error.js" }, { "name": "test_timers_simple.js", "timeout": 10 }, - { "name": "test_tls.js", "skip": ["all"], "reason": "TLS module is not enabled by default" }, + { "name": "test_tls.js", "skip": ["nuttx", "tizenrt"], "reason": "not implemented for nuttx and TizenRT" }, { "name": "test_uart.js", "skip": ["all"], "reason": "need to setup test environment" }, { "name": "test_uart_api.js" }, { "name": "test_util.js" }