Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #5
0
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);
}
Пример #6
0
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);
}
Пример #7
0
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);
}
Пример #8
0
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;
}