godot_pool_string_array GDAPI godot_variant_as_pool_string_array(const godot_variant *p_self) { godot_pool_string_array raw_dest; const Variant *self = (const Variant *)p_self; PoolStringArray *dest = (PoolStringArray *)&raw_dest; memnew_placement(dest, PoolStringArray(self->operator PoolStringArray())); // operator = is overloaded by PoolStringArray *dest = *self; return raw_dest; }
Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_headers, bool p_ssl_validate_domain, HTTPClient::Method p_method, const String &p_request_data) { ERR_FAIL_COND_V(!is_inside_tree(), ERR_UNCONFIGURED); if (requesting) { ERR_EXPLAIN("HTTPRequest is processing a request. Wait for completion or cancel it before attempting a new one."); ERR_FAIL_V(ERR_BUSY); } method = p_method; Error err = _parse_url(p_url); if (err) return err; validate_ssl = p_ssl_validate_domain; bool has_user_agent = false; bool has_accept = false; headers = p_custom_headers; request_data = p_request_data; for (int i = 0; i < headers.size(); i++) { if (headers[i].findn("user-agent:") == 0) has_user_agent = true; if (headers[i].findn("Accept:") == 0) has_accept = true; } if (!has_user_agent) { headers.push_back("User-Agent: GodotEngine/" + String(VERSION_MKSTRING) + " (" + OS::get_singleton()->get_name() + ")"); } if (!has_accept) { headers.push_back("Accept: */*"); } requesting = true; if (use_threads) { thread_done = false; thread_request_quit = false; client->set_blocking_mode(true); thread = Thread::create(_thread_func, this); } else { client->set_blocking_mode(false); err = _request(); if (err != OK) { call_deferred("_request_done", RESULT_CANT_CONNECT, 0, PoolStringArray(), PoolByteArray()); return ERR_CANT_CONNECT; } set_process_internal(true); } return OK; }
void HTTPRequest::_thread_func(void *p_userdata) { HTTPRequest *hr = (HTTPRequest *)p_userdata; Error err = hr->_request(); if (err != OK) { hr->call_deferred("_request_done", RESULT_CANT_CONNECT, 0, PoolStringArray(), PoolByteArray()); } else { while (!hr->thread_request_quit) { bool exit = hr->_update_connection(); if (exit) break; OS::get_singleton()->delay_usec(1); } } hr->thread_done = true; }
Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_headers, bool p_ssl_validate_domain, HTTPClient::Method p_method, const String &p_request_data) { ERR_FAIL_COND_V(!is_inside_tree(), ERR_UNCONFIGURED); if (requesting) { ERR_EXPLAIN("HTTPRequest is processing a request. Wait for completion or cancel it before attempting a new one."); ERR_FAIL_V(ERR_BUSY); } method = p_method; Error err = _parse_url(p_url); if (err) return err; validate_ssl = p_ssl_validate_domain; headers = p_custom_headers; request_data = p_request_data; requesting = true; if (use_threads) { thread_done = false; thread_request_quit = false; client->set_blocking_mode(true); thread = Thread::create(_thread_func, this); } else { client->set_blocking_mode(false); err = _request(); if (err != OK) { call_deferred("_request_done", RESULT_CANT_CONNECT, 0, PoolStringArray(), PoolByteArray()); return ERR_CANT_CONNECT; } set_process_internal(true); } return OK; }
MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type) { switch (p_type.type_encoding) { case MONO_TYPE_BOOLEAN: { MonoBoolean val = p_var->operator bool(); return BOX_BOOLEAN(val); } case MONO_TYPE_I1: { char val = p_var->operator signed char(); return BOX_INT8(val); } case MONO_TYPE_I2: { short val = p_var->operator signed short(); return BOX_INT16(val); } case MONO_TYPE_I4: { int val = p_var->operator signed int(); return BOX_INT32(val); } case MONO_TYPE_I8: { int64_t val = p_var->operator int64_t(); return BOX_INT64(val); } case MONO_TYPE_U1: { char val = p_var->operator unsigned char(); return BOX_UINT8(val); } case MONO_TYPE_U2: { short val = p_var->operator unsigned short(); return BOX_UINT16(val); } case MONO_TYPE_U4: { int val = p_var->operator unsigned int(); return BOX_UINT32(val); } case MONO_TYPE_U8: { uint64_t val = p_var->operator uint64_t(); return BOX_UINT64(val); } case MONO_TYPE_R4: { float val = p_var->operator float(); return BOX_FLOAT(val); } case MONO_TYPE_R8: { double val = p_var->operator double(); return BOX_DOUBLE(val); } case MONO_TYPE_STRING: { return (MonoObject *)mono_string_from_godot(p_var->operator String()); } break; case MONO_TYPE_VALUETYPE: { GDMonoClass *tclass = p_type.type_class; if (tclass == CACHED_CLASS(Vector2)) RETURN_BOXED_STRUCT(Vector2, p_var); if (tclass == CACHED_CLASS(Rect2)) RETURN_BOXED_STRUCT(Rect2, p_var); if (tclass == CACHED_CLASS(Transform2D)) RETURN_BOXED_STRUCT(Transform2D, p_var); if (tclass == CACHED_CLASS(Vector3)) RETURN_BOXED_STRUCT(Vector3, p_var); if (tclass == CACHED_CLASS(Basis)) RETURN_BOXED_STRUCT(Basis, p_var); if (tclass == CACHED_CLASS(Quat)) RETURN_BOXED_STRUCT(Quat, p_var); if (tclass == CACHED_CLASS(Transform)) RETURN_BOXED_STRUCT(Transform, p_var); if (tclass == CACHED_CLASS(Rect3)) RETURN_BOXED_STRUCT(Rect3, p_var); if (tclass == CACHED_CLASS(Color)) RETURN_BOXED_STRUCT(Color, p_var); if (tclass == CACHED_CLASS(Plane)) RETURN_BOXED_STRUCT(Plane, p_var); if (mono_class_is_enum(tclass->get_raw())) { int val = p_var->operator signed int(); return BOX_ENUM(tclass->get_raw(), val); } } break; case MONO_TYPE_ARRAY: case MONO_TYPE_SZARRAY: { MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(p_type.type_class)); if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) return (MonoObject *)Array_to_mono_array(p_var->operator Array()); if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) return (MonoObject *)PoolByteArray_to_mono_array(p_var->operator PoolByteArray()); if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) return (MonoObject *)PoolIntArray_to_mono_array(p_var->operator PoolIntArray()); if (array_type->eklass == REAL_T_MONOCLASS) return (MonoObject *)PoolRealArray_to_mono_array(p_var->operator PoolRealArray()); if (array_type->eklass == CACHED_CLASS_RAW(String)) return (MonoObject *)PoolStringArray_to_mono_array(p_var->operator PoolStringArray()); if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) return (MonoObject *)PoolVector2Array_to_mono_array(p_var->operator PoolVector2Array()); if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) return (MonoObject *)PoolVector3Array_to_mono_array(p_var->operator PoolVector3Array()); if (array_type->eklass == CACHED_CLASS_RAW(Color)) return (MonoObject *)PoolColorArray_to_mono_array(p_var->operator PoolColorArray()); ERR_EXPLAIN(String() + "Attempted to convert Variant to a managed array of unmarshallable element type."); ERR_FAIL_V(NULL); } break; case MONO_TYPE_CLASS: { GDMonoClass *type_class = p_type.type_class; // GodotObject if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) { return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *()); } if (CACHED_CLASS(NodePath) == type_class) { return GDMonoUtils::create_managed_from(p_var->operator NodePath()); } if (CACHED_CLASS(RID) == type_class) { return GDMonoUtils::create_managed_from(p_var->operator RID()); } } break; case MONO_TYPE_OBJECT: { // Variant switch (p_var->get_type()) { case Variant::BOOL: { MonoBoolean val = p_var->operator bool(); return BOX_BOOLEAN(val); } case Variant::INT: { int val = p_var->operator signed int(); return BOX_INT32(val); } case Variant::REAL: { #ifdef REAL_T_IS_DOUBLE double val = p_var->operator double(); return BOX_DOUBLE(val); #else float val = p_var->operator float(); return BOX_FLOAT(val); #endif } case Variant::STRING: return (MonoObject *)mono_string_from_godot(p_var->operator String()); case Variant::VECTOR2: RETURN_BOXED_STRUCT(Vector2, p_var); case Variant::RECT2: RETURN_BOXED_STRUCT(Rect2, p_var); case Variant::VECTOR3: RETURN_BOXED_STRUCT(Vector3, p_var); case Variant::TRANSFORM2D: RETURN_BOXED_STRUCT(Transform2D, p_var); case Variant::PLANE: RETURN_BOXED_STRUCT(Plane, p_var); case Variant::QUAT: RETURN_BOXED_STRUCT(Quat, p_var); case Variant::RECT3: RETURN_BOXED_STRUCT(Rect3, p_var); case Variant::BASIS: RETURN_BOXED_STRUCT(Basis, p_var); case Variant::TRANSFORM: RETURN_BOXED_STRUCT(Transform, p_var); case Variant::COLOR: RETURN_BOXED_STRUCT(Color, p_var); case Variant::NODE_PATH: return GDMonoUtils::create_managed_from(p_var->operator NodePath()); case Variant::_RID: return GDMonoUtils::create_managed_from(p_var->operator RID()); case Variant::OBJECT: { return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *()); } case Variant::DICTIONARY: return Dictionary_to_mono_object(p_var->operator Dictionary()); case Variant::ARRAY: return (MonoObject *)Array_to_mono_array(p_var->operator Array()); case Variant::POOL_BYTE_ARRAY: return (MonoObject *)PoolByteArray_to_mono_array(p_var->operator PoolByteArray()); case Variant::POOL_INT_ARRAY: return (MonoObject *)PoolIntArray_to_mono_array(p_var->operator PoolIntArray()); case Variant::POOL_REAL_ARRAY: return (MonoObject *)PoolRealArray_to_mono_array(p_var->operator PoolRealArray()); case Variant::POOL_STRING_ARRAY: return (MonoObject *)PoolStringArray_to_mono_array(p_var->operator PoolStringArray()); case Variant::POOL_VECTOR2_ARRAY: return (MonoObject *)PoolVector2Array_to_mono_array(p_var->operator PoolVector2Array()); case Variant::POOL_VECTOR3_ARRAY: return (MonoObject *)PoolVector3Array_to_mono_array(p_var->operator PoolVector3Array()); case Variant::POOL_COLOR_ARRAY: return (MonoObject *)PoolColorArray_to_mono_array(p_var->operator PoolColorArray()); default: return NULL; } break; case MONO_TYPE_GENERICINST: { if (CACHED_RAW_MONO_CLASS(Dictionary) == p_type.type_class->get_raw()) { return Dictionary_to_mono_object(p_var->operator Dictionary()); } } break; } break; } ERR_EXPLAIN(String() + "Attempted to convert Variant to an unmarshallable managed type. Name: \'" + p_type.type_class->get_name() + "\' Encoding: " + itos(p_type.type_encoding)); ERR_FAIL_V(NULL); }
void HTTPRequest::_bind_methods() { ClassDB::bind_method(D_METHOD("request", "url", "custom_headers", "ssl_validate_domain", "method", "request_data"), &HTTPRequest::request, DEFVAL(PoolStringArray()), DEFVAL(true), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(String())); ClassDB::bind_method(D_METHOD("cancel_request"), &HTTPRequest::cancel_request); ClassDB::bind_method(D_METHOD("get_http_client_status"), &HTTPRequest::get_http_client_status); ClassDB::bind_method(D_METHOD("set_use_threads", "enable"), &HTTPRequest::set_use_threads); ClassDB::bind_method(D_METHOD("is_using_threads"), &HTTPRequest::is_using_threads); ClassDB::bind_method(D_METHOD("set_body_size_limit", "bytes"), &HTTPRequest::set_body_size_limit); ClassDB::bind_method(D_METHOD("get_body_size_limit"), &HTTPRequest::get_body_size_limit); ClassDB::bind_method(D_METHOD("set_max_redirects", "amount"), &HTTPRequest::set_max_redirects); ClassDB::bind_method(D_METHOD("get_max_redirects"), &HTTPRequest::get_max_redirects); ClassDB::bind_method(D_METHOD("set_download_file", "path"), &HTTPRequest::set_download_file); ClassDB::bind_method(D_METHOD("get_download_file"), &HTTPRequest::get_download_file); ClassDB::bind_method(D_METHOD("get_downloaded_bytes"), &HTTPRequest::get_downloaded_bytes); ClassDB::bind_method(D_METHOD("get_body_size"), &HTTPRequest::get_body_size); ClassDB::bind_method(D_METHOD("_redirect_request"), &HTTPRequest::_redirect_request); ClassDB::bind_method(D_METHOD("_request_done"), &HTTPRequest::_request_done); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_threads"), "set_use_threads", "is_using_threads"); ADD_PROPERTY(PropertyInfo(Variant::INT, "body_size_limit", PROPERTY_HINT_RANGE, "-1,2000000000"), "set_body_size_limit", "get_body_size_limit"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_redirects", PROPERTY_HINT_RANGE, "-1,1024"), "set_max_redirects", "get_max_redirects"); ADD_SIGNAL(MethodInfo("request_completed", PropertyInfo(Variant::INT, "result"), PropertyInfo(Variant::INT, "response_code"), PropertyInfo(Variant::POOL_STRING_ARRAY, "headers"), PropertyInfo(Variant::POOL_BYTE_ARRAY, "body"))); BIND_ENUM_CONSTANT(RESULT_SUCCESS); //BIND_ENUM_CONSTANT( RESULT_NO_BODY ); BIND_ENUM_CONSTANT(RESULT_CHUNKED_BODY_SIZE_MISMATCH); BIND_ENUM_CONSTANT(RESULT_CANT_CONNECT); BIND_ENUM_CONSTANT(RESULT_CANT_RESOLVE); BIND_ENUM_CONSTANT(RESULT_CONNECTION_ERROR); BIND_ENUM_CONSTANT(RESULT_SSL_HANDSHAKE_ERROR); BIND_ENUM_CONSTANT(RESULT_NO_RESPONSE); BIND_ENUM_CONSTANT(RESULT_BODY_SIZE_LIMIT_EXCEEDED); BIND_ENUM_CONSTANT(RESULT_REQUEST_FAILED); BIND_ENUM_CONSTANT(RESULT_DOWNLOAD_FILE_CANT_OPEN); BIND_ENUM_CONSTANT(RESULT_DOWNLOAD_FILE_WRITE_ERROR); BIND_ENUM_CONSTANT(RESULT_REDIRECT_LIMIT_REACHED); }
bool HTTPRequest::_update_connection() { switch (client->get_status()) { case HTTPClient::STATUS_DISCONNECTED: { call_deferred("_request_done", RESULT_CANT_CONNECT, 0, PoolStringArray(), PoolByteArray()); return true; //end it, since it's doing something } break; case HTTPClient::STATUS_RESOLVING: { client->poll(); //must wait return false; } break; case HTTPClient::STATUS_CANT_RESOLVE: { call_deferred("_request_done", RESULT_CANT_RESOLVE, 0, PoolStringArray(), PoolByteArray()); return true; } break; case HTTPClient::STATUS_CONNECTING: { client->poll(); //must wait return false; } break; //connecting to ip case HTTPClient::STATUS_CANT_CONNECT: { call_deferred("_request_done", RESULT_CANT_CONNECT, 0, PoolStringArray(), PoolByteArray()); return true; } break; case HTTPClient::STATUS_CONNECTED: { if (request_sent) { if (!got_response) { //no body bool ret_value; if (_handle_response(&ret_value)) return ret_value; call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, PoolByteArray()); return true; } if (got_response && body_len < 0) { //chunked transfer is done call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body); return true; } call_deferred("_request_done", RESULT_CHUNKED_BODY_SIZE_MISMATCH, response_code, response_headers, PoolByteArray()); return true; //request migh have been done } else { //did not request yet, do request Error err = client->request(method, request_string, headers, request_data); if (err != OK) { call_deferred("_request_done", RESULT_CONNECTION_ERROR, 0, PoolStringArray(), PoolByteArray()); return true; } request_sent = true; return false; } } break; //connected: { } break requests only accepted here case HTTPClient::STATUS_REQUESTING: { //must wait, it's requesting client->poll(); return false; } break; // request in progress case HTTPClient::STATUS_BODY: { if (!got_response) { bool ret_value; if (_handle_response(&ret_value)) return ret_value; if (!client->is_response_chunked() && client->get_response_body_length() == 0) { call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, PoolByteArray()); return true; } if (client->is_response_chunked()) { body_len = -1; //no body len because chunked, change your webserver configuration if you want body len } else { body_len = client->get_response_body_length(); if (body_size_limit >= 0 && body_len > body_size_limit) { call_deferred("_request_done", RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PoolByteArray()); return true; } } if (download_to_file != String()) { file = FileAccess::open(download_to_file, FileAccess::WRITE); if (!file) { call_deferred("_request_done", RESULT_DOWNLOAD_FILE_CANT_OPEN, response_code, response_headers, PoolByteArray()); return true; } } } //print_line("BODY: "+itos(body.size())); client->poll(); PoolByteArray chunk = client->read_response_body_chunk(); downloaded += chunk.size(); if (file) { PoolByteArray::Read r = chunk.read(); file->store_buffer(r.ptr(), chunk.size()); if (file->get_error() != OK) { call_deferred("_request_done", RESULT_DOWNLOAD_FILE_WRITE_ERROR, response_code, response_headers, PoolByteArray()); return true; } } else { body.append_array(chunk); } if (body_size_limit >= 0 && downloaded > body_size_limit) { call_deferred("_request_done", RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PoolByteArray()); return true; } if (body_len >= 0) { if (downloaded == body_len) { call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body); return true; } /*if (body.size()>=body_len) { call_deferred("_request_done",RESULT_BODY_SIZE_MISMATCH,response_code,response_headers,ByteArray()); return true; }*/ } return false; } break; // request resulted in body: { } break which must be read case HTTPClient::STATUS_CONNECTION_ERROR: { call_deferred("_request_done", RESULT_CONNECTION_ERROR, 0, PoolStringArray(), PoolByteArray()); return true; } break; case HTTPClient::STATUS_SSL_HANDSHAKE_ERROR: { call_deferred("_request_done", RESULT_SSL_HANDSHAKE_ERROR, 0, PoolStringArray(), PoolByteArray()); return true; } break; } ERR_FAIL_V(false); }
bool HTTPRequest::_handle_response(bool *ret_value) { if (!client->has_response()) { call_deferred("_request_done", RESULT_NO_RESPONSE, 0, PoolStringArray(), PoolByteArray()); *ret_value = true; return true; } got_response = true; response_code = client->get_response_code(); List<String> rheaders; client->get_response_headers(&rheaders); response_headers.resize(0); downloaded = 0; for (List<String>::Element *E = rheaders.front(); E; E = E->next()) { //print_line("HEADER: "+E->get()); response_headers.push_back(E->get()); } if (response_code == 301 || response_code == 302) { //redirect if (max_redirects >= 0 && redirections >= max_redirects) { call_deferred("_request_done", RESULT_REDIRECT_LIMIT_REACHED, response_code, response_headers, PoolByteArray()); *ret_value = true; return true; } String new_request; for (List<String>::Element *E = rheaders.front(); E; E = E->next()) { if (E->get().findn("Location: ") != -1) { new_request = E->get().substr(9, E->get().length()).strip_edges(); } } //print_line("NEW LOCATION: "+new_request); if (new_request != "") { //process redirect client->close(); int new_redirs = redirections + 1; //because _request() will clear it Error err; if (new_request.begins_with("http")) { //new url, request all again err = _parse_url(new_request); } else { request_string = new_request; } err = _request(); //print_line("new connection: "+itos(err)); if (err == OK) { request_sent = false; got_response = false; body_len = -1; body.resize(0); downloaded = 0; redirections = new_redirs; *ret_value = false; return true; } } } return false; }