diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 40fa9fb6..473fe9ae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: CI on: push: - branches: [ main, dev, imagine ] + branches: [ dev, imagine ] pull_request: branches: [ main ] diff --git a/libs/template/index.b b/libs/template/index.b index c5a993aa..fc184307 100644 --- a/libs/template/index.b +++ b/libs/template/index.b @@ -737,8 +737,9 @@ class Template { for key, value in data { if value_name for_vars.set('${value_name}', value) if key_name for_vars.set('${key_name}', key) + result.append( - self._process(path, json.decode(json.encode(element)), for_vars) + self._process(path, element.clone(), for_vars) ) } } diff --git a/packages/ssl/ssl.c b/packages/ssl/ssl.c index bba21f6e..9dfd6a5e 100644 --- a/packages/ssl/ssl.c +++ b/packages/ssl/ssl.c @@ -1,7 +1,26 @@ #include +#ifdef _WIN32 // wrapping to disable annoying messages from getopt.h in ming2 +#define message(ignore) +#endif #include +#ifdef _WIN32 +#undef message +#endif #include "ssl.h" +#ifdef _WIN32 +# define _WINSOCK_DEPRECATED_NO_WARNINGS 1 +# include +# include +# include + +# define sleep _sleep +# define ioctl ioctlsocket +#else +# include +# include +#endif + DEFINE_SSL_CONSTANT(SSL_FILETYPE_PEM) DEFINE_SSL_CONSTANT(SSL_FILETYPE_ASN1) @@ -142,6 +161,15 @@ DECLARE_MODULE_METHOD(ssl_set_accept_state) { RETURN; } +DECLARE_MODULE_METHOD(ssl_set_tlsext_host_name) { + ENFORCE_ARG_COUNT(set_tlsext_host_name, 2); + ENFORCE_ARG_TYPE(set_tlsext_host_name, 0, IS_PTR); + ENFORCE_ARG_TYPE(set_tlsext_host_name, 1, IS_STRING); + + SSL *ssl = (SSL*)AS_PTR(args[0])->pointer; + RETURN_BOOL(SSL_set_tlsext_host_name(ssl, AS_C_STRING(args[1])) == 0); +} + DECLARE_MODULE_METHOD(ssl_new_bio) { ENFORCE_ARG_COUNT(new_bio, 1); ENFORCE_ARG_TYPE(new_bio, 0, IS_PTR); @@ -359,19 +387,59 @@ DECLARE_MODULE_METHOD(ssl_read) { char buffer[1025]; ERR_clear_error(); + int ssl_fd = SSL_get_fd(ssl); + + fd_set read_fds; + FD_ZERO(&read_fds); + FD_SET(ssl_fd, &read_fds); + + // struct timeval timeout = { .tv_sec = 0, .tv_usec = 500000 }; + + struct timeval timeout; + int option_length = sizeof(timeout); + +#ifndef _WIN32 + int rc = getsockopt(ssl_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, (socklen_t *) &option_length); +#else + int rc = getsockopt(ssl_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, (socklen_t*)&option_length); +#endif // !_WIN32 + + if (rc != 0 || sizeof(timeout) != option_length || (timeout.tv_sec == 0 && timeout.tv_usec == 0)) { + // set default timeout to 0.5 seconds + timeout.tv_sec = 0; + timeout.tv_usec = 500000; + } + + int ret = select(ssl_fd + 1, &read_fds, NULL, NULL, &timeout); + if (ret == 0) { + free(data); + RETURN_STRING(""); + } else if (ret < 0) { + // Error + } + do { - int bytes = SSL_read(ssl, buffer, 1024); + int read_count = length == -1 ? 1024 : ( + (length - total) < 1024 ? (length - total) : 1024 + ); + + int bytes = SSL_read(ssl, buffer, read_count); + // printf("READ COUNT = %d, TOTAL: %d, LENGTH = %d, BYTE = %d\n", read_count, total, length, bytes); + if(bytes > 0) { - data = GROW_ARRAY(char, data,total, total + bytes); + data = GROW_ARRAY(char, data, total, total + bytes + 1); if(data == NULL) { RETURN_ERROR("device out of memory."); } - vm->bytes_allocated += bytes; memcpy(data + total, buffer, bytes); total += bytes; + data[total] = '\0'; - if(total > length && length != -1) break; + if(total >= length && length != -1) break; + if((bytes == 1024 && length == -1)) { + continue; + } } else { int error = SSL_get_error(ssl, bytes); if(error == SSL_ERROR_WANT_READ) { @@ -470,7 +538,8 @@ DECLARE_MODULE_METHOD(ssl_error_string) { SSL *ssl = (SSL*)AS_PTR(args[0])->pointer; int code = SSL_get_error(ssl, ret); if(code != SSL_ERROR_SYSCALL) { - const char *err = ERR_reason_error_string(ERR_get_error()); + // const char *err = ERR_reason_error_string(ERR_get_error()); + char *err = ossl_err_as_string(); RETURN_STRING(err); } else { char *error = strerror(errno); @@ -497,10 +566,12 @@ DECLARE_MODULE_METHOD(ssl_connect) { res = SSL_connect(ssl); int error = SSL_get_error(ssl, res); if(error != SSL_ERROR_WANT_READ && error != SSL_ERROR_WANT_WRITE && error != SSL_ERROR_WANT_CONNECT) { + if(error == SSL_ERROR_SSL || error == SSL_ERROR_SYSCALL) { + RETURN_SSL_ERROR(); + } break; } } while(res == -1); - RETURN_BOOL(res > 0); } @@ -628,6 +699,7 @@ CREATE_MODULE_LOADER(ssl) { {"ssl_free", true, GET_MODULE_METHOD(ssl_ssl_free)}, {"set_connect_state", true, GET_MODULE_METHOD(ssl_set_connect_state)}, {"set_accept_state", true, GET_MODULE_METHOD(ssl_set_accept_state)}, + {"set_tlsext_host_name", true, GET_MODULE_METHOD(ssl_set_tlsext_host_name)}, {"new_bio", true, GET_MODULE_METHOD(ssl_new_bio)}, {"set_ssl", true, GET_MODULE_METHOD(ssl_bio_set_ssl)}, {"set_conn_hostname", true, GET_MODULE_METHOD(ssl_set_conn_hostname)}, diff --git a/packages/ssl/ssl/context.b b/packages/ssl/ssl/context.b index 94cd8212..f45e6529 100644 --- a/packages/ssl/ssl/context.b +++ b/packages/ssl/ssl/context.b @@ -106,7 +106,7 @@ class TLSContext < SSLContext { * @constructor */ TLSContext() { - parent(TLS_method) + parent(_ssl.TLS_method()) } } @@ -121,7 +121,7 @@ class TLSClientContext < SSLContext { * @constructor */ TLSClientContext() { - parent(TLS_client_method) + parent(_ssl.TLS_client_method()) } } @@ -136,7 +136,7 @@ class TLSServerContext < SSLContext { * @constructor */ TLSServerContext() { - parent(TLS_server_method) + parent(_ssl.TLS_server_method()) } } @@ -150,7 +150,7 @@ class SSLv23Context < SSLContext { * @constructor */ SSLv23Context() { - parent(SSLv23_method) + parent(_ssl.SSLv23_method()) } } @@ -165,7 +165,7 @@ class SSLv23ClientContext < SSLContext { * @constructor */ SSLv23ClientContext() { - parent(SSLv23_client_method) + parent(_ssl.SSLv23_client_method()) } } @@ -180,6 +180,6 @@ class SSLv23ServerContext < SSLContext { * @constructor */ SSLv23ServerContext() { - parent(SSLv23_server_method) + parent(_ssl.SSLv23_server_method()) } } diff --git a/packages/ssl/ssl/socket.b b/packages/ssl/ssl/socket.b index 300dff89..8c6533ac 100644 --- a/packages/ssl/ssl/socket.b +++ b/packages/ssl/ssl/socket.b @@ -151,7 +151,7 @@ class TLSSocket { if !context self._context = SSLContext(TLS_method) else self._context = context - self._ssl = ssl + self._ssl = ssl ? ssl : SSL(self._context) } /** @@ -165,7 +165,6 @@ class TLSSocket { */ connect(host, port, timeout) { if self._socket.connect(host, port, timeout) { - self._ssl = SSL(self._context) if self._ssl.set_fd(self._socket.id) { return self._ssl.connect() } diff --git a/packages/ssl/ssl/ssl.b b/packages/ssl/ssl/ssl.b index 764ecdf5..f399103d 100644 --- a/packages/ssl/ssl/ssl.b +++ b/packages/ssl/ssl/ssl.b @@ -71,8 +71,21 @@ class SSL { * Connects to an SSL server instance. * * @return bool + * @throws */ connect() { + /* try { + var res = _ssl.connect(self._ptr) + return res + } catch Exception e { + if e.message.index_of('eof while reading') { + die Exception('timeout') + } + + die e + } */ + + # _ssl.set_connect_state(self._ptr) return _ssl.connect(self._ptr) } @@ -134,6 +147,19 @@ class SSL { _ssl.shutdown(self._ptr) } + /** + * Sets the Server Name Indication (SNI) for use by Secure Sockets + * Layer (SSL). This function should be called on a client SSL + * session before the TLS handshake for the SNI extension + * to be set properly. + * + * @param string name + * @return bool + */ + set_tlsext_host_name(name) { + return _ssl.set_tlsext_host_name(self._ptr, name) + } + /** * Frees this SSL and all associated resources. */ diff --git a/src/blade.c b/src/blade.c index f7ebc2ca..f5a8d23d 100644 --- a/src/blade.c +++ b/src/blade.c @@ -327,11 +327,11 @@ int main(int argc, char *argv[]) { char **std_args = (char**)calloc(opt_deviation, sizeof(char *)); if(std_args != NULL) { if(optind > 0) { - std_args[0] = strdup(argv[0]); + std_args[0] = argv[0]; } for(int i = optind; i < argc; i++) { - std_args[i - optind + 1] = strdup(argv[i]); + std_args[i - optind + 1] = argv[i]; } vm->std_args = std_args; diff --git a/src/bstring.c b/src/bstring.c index af27ba5b..d1272a22 100644 --- a/src/bstring.c +++ b/src/bstring.c @@ -973,13 +973,13 @@ DECLARE_STRING_METHOD(split) { if ((int)compile_options == -1) { // not a regex, do a regular split if (delimeter->length > 0) { - int start = 0; - for(int i = 0; i <= string->length; i++) { + // int start = 0; + for(int start = 0, i = 0; i <= string->length; i++) { // match found. if(memcmp(string->chars + i, delimeter->chars, delimeter->length) == 0 || i == string->length) { write_list(vm, list, STRING_L_VAL(string->chars + start, i - start)); - i += delimeter->length - 1; - start = i + 1; + i += delimeter->length; + start = i; } } } else { diff --git a/src/bytes.c b/src/bytes.c index b9014e45..f260873a 100644 --- a/src/bytes.c +++ b/src/bytes.c @@ -111,9 +111,8 @@ DECLARE_BYTES_METHOD(extend) { DECLARE_BYTES_METHOD(index_of) { ENFORCE_ARG_RANGE(index_of, 1, 2); - ENFORCE_ARG_TYPE(index_of, 0, IS_NUMBER); + ENFORCE_ARG_TYPES(index_of, 0, IS_NUMBER, IS_BYTES); b_obj_bytes *bytes = AS_BYTES(METHOD_OBJECT); - uint8_t needle = AS_NUMBER(args[0]); int start_index = 0; if(arg_count == 2) { @@ -121,10 +120,23 @@ DECLARE_BYTES_METHOD(index_of) { start_index = AS_NUMBER(args[1]); } - if(bytes->bytes.count > 0 && start_index >= 0 && start_index < bytes->bytes.count - 1) { - for (int i = start_index; i < bytes->bytes.count; i++) { - if (bytes->bytes.bytes[i] == needle) { - RETURN_NUMBER(i); + if(IS_NUMBER(args[0])) { + uint8_t needle = AS_NUMBER(args[0]); + if(bytes->bytes.count > 0 && start_index >= 0 && start_index < bytes->bytes.count - 1) { + for (int i = start_index; i < bytes->bytes.count; i++) { + if (bytes->bytes.bytes[i] == needle) { + RETURN_NUMBER(i); + } + } + } + } else { + b_obj_bytes *needle = AS_BYTES(args[0]); + + if(bytes->bytes.count > 0 && start_index >= 0 && start_index < bytes->bytes.count - 1) { + for (int i = start_index; i < bytes->bytes.count; i++) { + if (memcmp(bytes->bytes.bytes + i, needle->bytes.bytes, needle->bytes.count) == 0) { + RETURN_NUMBER(i); + } } } } diff --git a/src/compiler.c b/src/compiler.c index 5c348759..625b2598 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -2147,6 +2147,7 @@ static void import_statement(b_parser *p) { emit_byte_and_short(p, OP_NATIVE_MODULE, module); parse_specific_import(p, module_name, module, false, true); + free(module_name); return; } @@ -2191,10 +2192,13 @@ static void import_statement(b_parser *p) { pop(p->vm); parse_specific_import(p, module_name, module, false, true); + free(module_name); return; } free(module_path); + free(module_file); + free(module_name); error(p, "module not found"); return; } @@ -2207,6 +2211,7 @@ static void import_statement(b_parser *p) { char *source = read_file(module_path); if (source == NULL) { error(p, "could not read import file %s", module_path); + free(module_file); return; } @@ -2220,6 +2225,7 @@ static void import_statement(b_parser *p) { if (function == NULL) { error(p, "failed to import %s", module_name); + free(module_file); return; } @@ -2237,6 +2243,7 @@ static void import_statement(b_parser *p) { register_module__FILE__(p->vm, module); parse_specific_import(p, module_name, import_constant, was_renamed, false); + free(module_file); } static void assert_statement(b_parser *p) { diff --git a/src/dict.c b/src/dict.c index 28b31e9a..b6d1943c 100644 --- a/src/dict.c +++ b/src/dict.c @@ -55,7 +55,7 @@ DECLARE_DICT_METHOD(clone) { b_obj_dict *dict = AS_DICT(METHOD_OBJECT); b_obj_dict *n_dict = (b_obj_dict *) GC(new_dict(vm)); - table_add_all(vm, &dict->items, &n_dict->items); + table_copy(vm, &dict->items, &n_dict->items); for (int i = 0; i < dict->names.count; i++) { write_value_arr(vm, &n_dict->names, dict->names.values[i]); diff --git a/src/list.c b/src/list.c index a2428905..556535c8 100644 --- a/src/list.c +++ b/src/list.c @@ -15,7 +15,7 @@ b_obj_list *copy_list(b_vm *vm, b_obj_list *list, int start, int length) { if(length == -1) length = list->items.count - start; for(int i = start; i < start + length; i++) { - write_list(vm, _list, list->items.values[i]); + write_list(vm, _list, copy_value(vm, list->items.values[i])); } return _list; diff --git a/src/module.c b/src/module.c index 6b8b7fd0..7a12edad 100644 --- a/src/module.c +++ b/src/module.c @@ -192,6 +192,8 @@ void bind_user_modules(b_vm *vm, char *pkg_root) { } } } + + free(path); } closedir(dir); } @@ -203,6 +205,7 @@ void bind_native_modules(b_vm *vm) { for (int i = 0; modules[i] != NULL; i++) { load_module(vm, modules[i], NULL, strdup("<__native__>"), NULL); } + bind_user_modules(vm, merge_paths(get_exe_dir(), "dist")); bind_user_modules(vm, merge_paths(getcwd(NULL, 0), LOCAL_PACKAGES_DIRECTORY LOCAL_EXT_DIRECTORY)); } diff --git a/src/pathinfo.c b/src/pathinfo.c index feda8ea1..53a60a1b 100644 --- a/src/pathinfo.c +++ b/src/pathinfo.c @@ -148,6 +148,7 @@ char *resolve_import_path(char *module_name, const char *current_file, char *roo if (path1 != NULL) { if (path2 == NULL || memcmp(path1, path2, (int) strlen(path2)) != 0) { + free(current_dir); free(path2); free(vendor_file); free(blade_file_name); @@ -171,6 +172,7 @@ char *resolve_import_path(char *module_name, const char *current_file, char *roo if (path1 != NULL) { if (path2 == NULL || memcmp(path1, path2, (int) strlen(path2)) != 0) { + free(current_dir); free(path2); free(vendor_index_file); free(blade_file_name); @@ -191,6 +193,7 @@ char *resolve_import_path(char *module_name, const char *current_file, char *roo if (path1 != NULL) { if (path2 == NULL || memcmp(path1, path2, (int) strlen(path2)) != 0) { + free(current_dir); free(path2); free(current_vendor_file); free(blade_file_name); @@ -214,6 +217,7 @@ char *resolve_import_path(char *module_name, const char *current_file, char *roo if (path1 != NULL) { if (path2 == NULL || memcmp(path1, path2, (int) strlen(path2)) != 0) { + free(current_dir); free(path2); free(current_vendor_index_file); free(blade_file_name); @@ -222,6 +226,7 @@ char *resolve_import_path(char *module_name, const char *current_file, char *roo } } free(current_vendor_index_file); + free(current_dir); // then, check in blade's default locations char *exe_dir = get_exe_dir(); @@ -236,6 +241,7 @@ char *resolve_import_path(char *module_name, const char *current_file, char *roo if (path1 != NULL) { if (path2 == NULL || memcmp(path1, path2, (int) strlen(path2)) != 0) { + free(blade_directory); free(path2); free(library_file); free(blade_file_name); @@ -256,6 +262,7 @@ char *resolve_import_path(char *module_name, const char *current_file, char *roo if (path1 != NULL) { if (path2 == NULL || memcmp(path1, path2, (int) strlen(path2)) != 0) { + free(blade_directory); free(path2); free(library_index_file); free(blade_file_name); diff --git a/src/standard/os.c b/src/standard/os.c index b38180ba..752a184d 100644 --- a/src/standard/os.c +++ b/src/standard/os.c @@ -196,7 +196,10 @@ b_value get_blade_os_path_separator(b_vm *vm) { b_value get_blade_os_exe_path(b_vm *vm) { char *path = get_exe_path(); - return STRING_VAL(path); + if(path) { + return STRING_TT_VAL(path); + } + return NIL_VAL; } DECLARE_MODULE_METHOD(os_getenv) { @@ -336,9 +339,9 @@ static int remove_directory(char *path, int path_length, bool recursive) { } else if(unlink(path_string) == -1) { free(path_string); return -1; - } else { - free(path_string); } + + free(path_string); } else { free(path_string); return -1; diff --git a/src/standard/socket.c b/src/standard/socket.c index c196ff22..204521b8 100644 --- a/src/standard/socket.c +++ b/src/standard/socket.c @@ -302,9 +302,9 @@ DECLARE_MODULE_METHOD(socket__recv) { #endif // !_WIN32 if (rc != 0 || sizeof(timeout) != option_length || (timeout.tv_sec == 0 && timeout.tv_usec == 0)) { - // set default timeout to 5 minutes - timeout.tv_sec = 300; - timeout.tv_usec = 0; + // set default timeout to 0.5 seconds + timeout.tv_sec = 0; + timeout.tv_usec = 500000; } fd_set read_set; diff --git a/src/utf8.c b/src/utf8.c index 9404e32b..194a40ec 100644 --- a/src/utf8.c +++ b/src/utf8.c @@ -3015,6 +3015,7 @@ char *utf8_case_fold(char *str, int str_len, bool simple, size_t *out_length) { } } + free(s); return result; } diff --git a/src/value.c b/src/value.c index 1999910e..916e9080 100644 --- a/src/value.c +++ b/src/value.c @@ -537,19 +537,28 @@ b_value copy_value(b_vm *vm, b_value value) { push(vm, OBJ_VAL(n_list)); for (int i = 0; i < list->items.count; i++) { - write_value_arr(vm, &n_list->items, list->items.values[i]); + write_value_arr(vm, &n_list->items, copy_value(vm, list->items.values[i])); } pop(vm); return OBJ_VAL(n_list); } - /*case OBJ_DICT: { + case OBJ_DICT: { b_obj_dict *dict = AS_DICT(value); b_obj_dict *n_dict = new_dict(vm); + push(vm, OBJ_VAL(n_dict)); - // @TODO: Figure out how to handle dictionary values correctly - // remember that copying keys is redundant and unnecessary - }*/ + // copy names + for(int i = 0; i < dict->names.count; i++) { + write_value_arr(vm, &n_dict->names, copy_value(vm, dict->names.values[i])); + } + + // copy values + table_copy(vm, &dict->items, &n_dict->items); + + pop(vm); + return OBJ_VAL(n_dict); + } default: return value; } diff --git a/src/vm.c b/src/vm.c index df2c775c..eae3f389 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1414,8 +1414,10 @@ static bool concatenate(b_vm *vm) { memcpy(chars + a->length, b->chars, b->length); chars[length] = '\0'; + // int new_utf8_length = utf8length(chars); b_obj_string *result = take_string(vm, chars, length); result->utf8_length = a->utf8_length + b->utf8_length; + // result->utf8_length = new_utf8_length; pop_n(vm, 2); push(vm, OBJ_VAL(result));