Skip to content

Commit a192efb

Browse files
authored
Add GetHttpsCallableFromURL to Functions (#964)
* Add GetHttpsCallableFromURL to Functions * Add string includes for lint * Clang format files * Move the url methods to the cpp file
1 parent 0576371 commit a192efb

File tree

14 files changed

+176
-36
lines changed

14 files changed

+176
-36
lines changed

app/src/util_android.cc

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,15 @@ METHOD_LOOKUP_DECLARATION(uribuilder, URI_BUILDER_METHODS)
118118
METHOD_LOOKUP_DEFINITION(uribuilder, "android/net/Uri$Builder",
119119
URI_BUILDER_METHODS)
120120

121+
// Methods of the java.net.URL class.
122+
// clang-format off
123+
#define URL_METHODS(X) \
124+
X(Constructor, "<init>", "(Ljava/lang/String;)V"), \
125+
X(ConstructorWithURL, "<init>", "(Ljava/net/URL;Ljava/lang/String;)V")
126+
// clang-format on
127+
METHOD_LOOKUP_DECLARATION(url, URL_METHODS)
128+
METHOD_LOOKUP_DEFINITION(url, "java/net/URL", URL_METHODS)
129+
121130
// clang-format off
122131
#define FILE_OUTPUT_STREAM_METHODS(X) \
123132
X(ConstructorFile, "<init>", "(Ljava/io/File;)V"), \
@@ -151,13 +160,6 @@ METHOD_LOOKUP_DECLARATION(url_class_loader, URL_CLASS_LOADER_METHODS)
151160
METHOD_LOOKUP_DEFINITION(url_class_loader, "java/net/URLClassLoader",
152161
URL_CLASS_LOADER_METHODS)
153162

154-
// clang-format off
155-
#define URL_METHODS(X) \
156-
X(Constructor, "<init>", "(Ljava/net/URL;Ljava/lang/String;)V")
157-
// clang-format on
158-
METHOD_LOOKUP_DECLARATION(url, URL_METHODS)
159-
METHOD_LOOKUP_DEFINITION(url, "java/net/URL", URL_METHODS)
160-
161163
// clang-format off
162164
#define JAVA_URI_METHODS(X) X(ToUrl, "toURL", "()Ljava/net/URL;")
163165
// clang-format on
@@ -395,14 +397,14 @@ static void ReleaseClasses(JNIEnv* env) {
395397
uri::ReleaseClass(env);
396398
object::ReleaseClass(env);
397399
uribuilder::ReleaseClass(env);
400+
url::ReleaseClass(env);
398401
if (g_jniresultcallback_loaded) {
399402
jniresultcallback::ReleaseClass(env);
400403
g_jniresultcallback_loaded = false;
401404
}
402405
JavaThreadContext::Terminate(env);
403406
#if defined(FIREBASE_ANDROID_FOR_DESKTOP)
404407
java_uri::ReleaseClass(env);
405-
url::ReleaseClass(env);
406408
url_class_loader::ReleaseClass(env);
407409
#endif // defined(FIREBASE_ANDROID_FOR_DESKTOP)
408410
}
@@ -493,7 +495,8 @@ bool Initialize(JNIEnv* env, jobject activity_object) {
493495
throwable::CacheMethodIds(env, activity_object) &&
494496
uri::CacheMethodIds(env, activity_object) &&
495497
object::CacheMethodIds(env, activity_object) &&
496-
uribuilder::CacheMethodIds(env, activity_object))) {
498+
uribuilder::CacheMethodIds(env, activity_object) &&
499+
url::CacheMethodIds(env, activity_object))) {
497500
ReleaseClasses(env);
498501
TerminateActivityClasses(env);
499502
return false;
@@ -508,7 +511,6 @@ bool Initialize(JNIEnv* env, jobject activity_object) {
508511
#if defined(FIREBASE_ANDROID_FOR_DESKTOP)
509512
// Cache JVM class-loader for desktop.
510513
if (!(java_uri::CacheMethodIds(env, activity_object) &&
511-
url::CacheMethodIds(env, activity_object) &&
512514
url_class_loader::CacheMethodIds(env, activity_object))) {
513515
return false;
514516
}
@@ -1182,6 +1184,17 @@ jobject ParseUriString(JNIEnv* env, const char* uri_string) {
11821184
return uri;
11831185
}
11841186

1187+
// Convert a char array into a jobject of type java.net.URL.
1188+
// The caller must call env->DeleteLocalRef() on the returned jobject.
1189+
jobject CharsToURL(JNIEnv* env, const char* url_string) {
1190+
jobject url_jstring = env->NewStringUTF(url_string);
1191+
jobject url = env->NewObject(
1192+
url::GetClass(), url::GetMethodId(url::kConstructor), url_jstring);
1193+
CheckAndClearJniExceptions(env);
1194+
env->DeleteLocalRef(url_jstring);
1195+
return url;
1196+
}
1197+
11851198
// Convert a jbyteArray to a vector, releasing the reference to the
11861199
// jbyteArray.
11871200
std::vector<unsigned char> JniByteArrayToVector(JNIEnv* env, jobject array) {
@@ -1623,9 +1636,9 @@ jclass FindClassInFiles(
16231636
env->NewObjectArray(embedded_files.size(), url::GetClass(), nullptr);
16241637
for (int i = 0; i < embedded_files.size(); ++i) {
16251638
jstring embedded_file_string = env->NewStringUTF(embedded_files[i].name);
1626-
jobject jar_url =
1627-
env->NewObject(url::GetClass(), url::GetMethodId(url::kConstructor),
1628-
cache_url, embedded_file_string);
1639+
jobject jar_url = env->NewObject(url::GetClass(),
1640+
url::GetMethodId(url::kConstructorWithURL),
1641+
cache_url, embedded_file_string);
16291642
env->SetObjectArrayElement(url_path_array, i, jar_url);
16301643
env->DeleteLocalRef(jar_url);
16311644
env->DeleteLocalRef(embedded_file_string);

app/src/util_android.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,10 @@ jobject CharsToJniUri(JNIEnv* env, const char* uri);
942942
// The caller must call env->DeleteLocalRef() on the returned jobject.
943943
jobject ParseUriString(JNIEnv* env, const char* uri_string);
944944

945+
// Convert a char array into a jobject of type java.net.URL.
946+
// The caller must call env->DeleteLocalRef() on the returned jobject.
947+
jobject CharsToURL(JNIEnv* env, const char* url_string);
948+
945949
// Convert a jbyteArray to a vector, releasing the reference to the jbyteArray.
946950
std::vector<unsigned char> JniByteArrayToVector(JNIEnv* env, jobject array);
947951

functions/integration_test/src/integration_test.cc

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,27 @@ class FirebaseFunctionsTest : public FirebaseTest {
6565
// Sign in an anonymous user.
6666
void SignIn();
6767

68+
firebase::Future<firebase::functions::HttpsCallableResult> TestFunctionHelper(
69+
const char* function_name,
70+
firebase::functions::HttpsCallableReference& ref,
71+
const firebase::Variant* const function_data,
72+
const firebase::Variant& expected_result,
73+
firebase::functions::Error expected_error =
74+
firebase::functions::kErrorNone);
75+
6876
firebase::Future<firebase::functions::HttpsCallableResult> TestFunction(
6977
const char* function_name, const firebase::Variant* const function_data,
7078
const firebase::Variant& expected_result,
7179
firebase::functions::Error expected_error =
7280
firebase::functions::kErrorNone);
7381

82+
firebase::Future<firebase::functions::HttpsCallableResult>
83+
TestFunctionFromURL(const char* function_url,
84+
const firebase::Variant* const function_data,
85+
const firebase::Variant& expected_result,
86+
firebase::functions::Error expected_error =
87+
firebase::functions::kErrorNone);
88+
7489
bool initialized_;
7590
firebase::auth::Auth* auth_;
7691
firebase::functions::Functions* functions_;
@@ -181,15 +196,11 @@ void FirebaseFunctionsTest::SignIn() {
181196

182197
// A helper function for calling a Firebase Function and waiting on the result.
183198
firebase::Future<firebase::functions::HttpsCallableResult>
184-
FirebaseFunctionsTest::TestFunction(
185-
const char* function_name, const firebase::Variant* const function_data,
199+
FirebaseFunctionsTest::TestFunctionHelper(
200+
const char* function_name, firebase::functions::HttpsCallableReference& ref,
201+
const firebase::Variant* const function_data,
186202
const firebase::Variant& expected_result,
187203
firebase::functions::Error expected_error) {
188-
// Create a callable that we can run our test with.
189-
LogDebug("Calling %s", function_name);
190-
firebase::functions::HttpsCallableReference ref;
191-
ref = functions_->GetHttpsCallable(function_name);
192-
193204
firebase::Future<firebase::functions::HttpsCallableResult> future;
194205
if (function_data == nullptr) {
195206
future = ref.Call();
@@ -207,6 +218,34 @@ FirebaseFunctionsTest::TestFunction(
207218
return future;
208219
}
209220

221+
firebase::Future<firebase::functions::HttpsCallableResult>
222+
FirebaseFunctionsTest::TestFunction(
223+
const char* function_name, const firebase::Variant* const function_data,
224+
const firebase::Variant& expected_result,
225+
firebase::functions::Error expected_error) {
226+
// Create a callable that we can run our test with.
227+
LogDebug("Calling %s", function_name);
228+
firebase::functions::HttpsCallableReference ref;
229+
ref = functions_->GetHttpsCallable(function_name);
230+
231+
return TestFunctionHelper(function_name, ref, function_data, expected_result,
232+
expected_error);
233+
}
234+
235+
firebase::Future<firebase::functions::HttpsCallableResult>
236+
FirebaseFunctionsTest::TestFunctionFromURL(
237+
const char* function_url, const firebase::Variant* const function_data,
238+
const firebase::Variant& expected_result,
239+
firebase::functions::Error expected_error) {
240+
// Create a callable that we can run our test with.
241+
LogDebug("Calling by URL %s", function_url);
242+
firebase::functions::HttpsCallableReference ref;
243+
ref = functions_->GetHttpsCallableFromURL(function_url);
244+
245+
return TestFunctionHelper(function_url, ref, function_data, expected_result,
246+
expected_error);
247+
}
248+
210249
TEST_F(FirebaseFunctionsTest, TestInitializeAndTerminate) {
211250
// Already tested via SetUp() and TearDown().
212251
}
@@ -323,4 +362,22 @@ TEST_F(FirebaseFunctionsTest, TestErrorHandling) {
323362
firebase::functions::kErrorOutOfRange);
324363
}
325364

365+
TEST_F(FirebaseFunctionsTest, TestFunctionFromURL) {
366+
SignIn();
367+
368+
// addNumbers(4, 2) = 6
369+
firebase::Variant data(firebase::Variant::EmptyMap());
370+
data.map()["firstNumber"] = 4;
371+
data.map()["secondNumber"] = 2;
372+
std::string proj = app_->options().project_id();
373+
std::string url =
374+
"https://us-central1-" + proj + ".cloudfunctions.net/addNumbers";
375+
firebase::Variant result =
376+
TestFunctionFromURL(url.c_str(), &data, firebase::Variant::Null())
377+
.result()
378+
->data();
379+
EXPECT_TRUE(result.is_map());
380+
EXPECT_EQ(result.map()["operationResult"], 6);
381+
}
382+
326383
} // namespace firebase_testapp_automated

functions/src/android/functions_android.cc

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ const char kApiIdentifier[] = "Functions";
3535
X(GetHttpsCallable, "getHttpsCallable", \
3636
"(Ljava/lang/String;)" \
3737
"Lcom/google/firebase/functions/HttpsCallableReference;", \
38-
util::kMethodTypeInstance), \
38+
util::kMethodTypeInstance), \
39+
X(GetHttpsCallableFromURL, "getHttpsCallableFromUrl", \
40+
"(Ljava/net/URL;)" \
41+
"Lcom/google/firebase/functions/HttpsCallableReference;", \
42+
util::kMethodTypeInstance), \
3943
X(UseFunctionsEmulator, "useFunctionsEmulator", \
4044
"(Ljava/lang/String;)V", \
4145
util::kMethodTypeInstance)
@@ -137,6 +141,7 @@ void FunctionsInternal::Terminate(App* app) {
137141
JNIEnv* env = app->GetJNIEnv();
138142
firebase_functions::ReleaseClass(env);
139143
functions_exception::ReleaseClass(env);
144+
functions_exception_code::ReleaseClass(env);
140145

141146
// Call Terminate on all other Functions internal classes.
142147
HttpsCallableReferenceInternal::Terminate(app);
@@ -199,6 +204,29 @@ HttpsCallableReferenceInternal* FunctionsInternal::GetHttpsCallable(
199204
return internal;
200205
}
201206

207+
HttpsCallableReferenceInternal* FunctionsInternal::GetHttpsCallableFromURL(
208+
const char* url) const {
209+
FIREBASE_ASSERT_RETURN(nullptr, url != nullptr);
210+
JNIEnv* env = app_->GetJNIEnv();
211+
jobject url_object = util::CharsToURL(env, url);
212+
jobject callable_reference_obj =
213+
env->CallObjectMethod(obj_,
214+
firebase_functions::GetMethodId(
215+
firebase_functions::kGetHttpsCallableFromURL),
216+
url_object);
217+
env->DeleteLocalRef(url_object);
218+
if (util::LogException(
219+
env, kLogLevelError,
220+
"Functions::GetHttpsCallableFromURL() (url = %s) failed", url)) {
221+
return nullptr;
222+
}
223+
HttpsCallableReferenceInternal* internal = new HttpsCallableReferenceInternal(
224+
const_cast<FunctionsInternal*>(this), callable_reference_obj);
225+
env->DeleteLocalRef(callable_reference_obj);
226+
util::CheckAndClearJniExceptions(env);
227+
return internal;
228+
}
229+
202230
void FunctionsInternal::UseFunctionsEmulator(const char* origin) {
203231
FIREBASE_ASSERT(origin != nullptr);
204232
JNIEnv* env = app_->GetJNIEnv();

functions/src/android/functions_android.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ class FunctionsInternal {
5252

5353
HttpsCallableReferenceInternal* GetHttpsCallable(const char* name) const;
5454

55+
// Get a FunctionsReference for the specified URL.
56+
HttpsCallableReferenceInternal* GetHttpsCallableFromURL(
57+
const char* url) const;
58+
5559
void UseFunctionsEmulator(const char* origin);
5660

5761
// Convert an error code obtained from a Java FunctionsException into a C++

functions/src/common/functions.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,12 @@ HttpsCallableReference Functions::GetHttpsCallable(const char* name) const {
146146
return HttpsCallableReference(internal_->GetHttpsCallable(name));
147147
}
148148

149+
HttpsCallableReference Functions::GetHttpsCallableFromURL(
150+
const char* url) const {
151+
if (!internal_) return HttpsCallableReference();
152+
return HttpsCallableReference(internal_->GetHttpsCallableFromURL(url));
153+
}
154+
149155
void Functions::UseFunctionsEmulator(const char* origin) {
150156
if (!internal_) return;
151157
internal_->UseFunctionsEmulator(origin);

functions/src/desktop/callable_reference_desktop.cc

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
#include "functions/src/desktop/callable_reference_desktop.h"
1616

17+
#include <string>
18+
1719
#include "app/rest/request.h"
1820
#include "app/rest/util.h"
1921
#include "app/src/function_registry.h"
@@ -32,8 +34,8 @@ enum CallableReferenceFn {
3234
};
3335

3436
HttpsCallableReferenceInternal::HttpsCallableReferenceInternal(
35-
FunctionsInternal* functions, const char* name)
36-
: functions_(functions), name_(name) {
37+
FunctionsInternal* functions, const char* url)
38+
: functions_(functions), url_(url) {
3739
functions_->future_manager().AllocFutureApi(this, kCallableReferenceFnCount);
3840
rest::InitTransportCurl();
3941
transport_.set_is_async(true);
@@ -46,7 +48,7 @@ HttpsCallableReferenceInternal::~HttpsCallableReferenceInternal() {
4648

4749
HttpsCallableReferenceInternal::HttpsCallableReferenceInternal(
4850
const HttpsCallableReferenceInternal& other)
49-
: functions_(other.functions_), name_(other.name_) {
51+
: functions_(other.functions_), url_(other.url_) {
5052
functions_->future_manager().AllocFutureApi(this, kCallableReferenceFnCount);
5153
rest::InitTransportCurl();
5254
transport_.set_is_async(true);
@@ -55,14 +57,14 @@ HttpsCallableReferenceInternal::HttpsCallableReferenceInternal(
5557
HttpsCallableReferenceInternal& HttpsCallableReferenceInternal::operator=(
5658
const HttpsCallableReferenceInternal& other) {
5759
functions_ = other.functions_;
58-
name_ = other.name_;
60+
url_ = other.url_;
5961
return *this;
6062
}
6163

6264
#if defined(FIREBASE_USE_MOVE_OPERATORS) || defined(DOXYGEN)
6365
HttpsCallableReferenceInternal::HttpsCallableReferenceInternal(
6466
HttpsCallableReferenceInternal&& other)
65-
: functions_(other.functions_), name_(std::move(other.name_)) {
67+
: functions_(other.functions_), url_(std::move(other.url_)) {
6668
other.functions_ = nullptr;
6769
functions_->future_manager().MoveFutureApi(&other, this);
6870
rest::InitTransportCurl();
@@ -73,7 +75,7 @@ HttpsCallableReferenceInternal& HttpsCallableReferenceInternal::operator=(
7375
HttpsCallableReferenceInternal&& other) {
7476
functions_ = other.functions_;
7577
other.functions_ = nullptr;
76-
name_ = std::move(other.name_);
78+
url_ = std::move(other.url_);
7779
functions_->future_manager().MoveFutureApi(&other, this);
7880
return *this;
7981
}
@@ -300,8 +302,7 @@ void HttpsCallableReferenceInternal::ResolveFuture(
300302
Future<HttpsCallableResult> HttpsCallableReferenceInternal::Call(
301303
const Variant& data) {
302304
// Set up the request.
303-
std::string url = functions_->GetUrl(name_);
304-
request_.set_url(url.data());
305+
request_.set_url(url_.data());
305306
request_.set_method(rest::util::kPost);
306307
request_.add_header(rest::util::kContentType, rest::util::kApplicationJson);
307308

@@ -318,8 +319,8 @@ Future<HttpsCallableResult> HttpsCallableReferenceInternal::Call(
318319
std::string json = util::VariantToJson(body);
319320
request_.set_post_fields(json.data());
320321

321-
firebase::LogDebug("Calling Cloud Function with name: %s\nurl: %s\ndata: %s",
322-
name_.c_str(), url.c_str(), json.c_str());
322+
firebase::LogDebug("Calling Cloud Function with url: %s\ndata: %s",
323+
url_.c_str(), json.c_str());
323324

324325
// Set up the future to resolve when the request is complete.
325326
ReferenceCountedFutureImpl* future_impl = future();

functions/src/desktop/callable_reference_desktop.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#ifndef FIREBASE_FUNCTIONS_SRC_DESKTOP_CALLABLE_REFERENCE_DESKTOP_H_
1616
#define FIREBASE_FUNCTIONS_SRC_DESKTOP_CALLABLE_REFERENCE_DESKTOP_H_
1717

18+
#include <string>
19+
1820
#include "app/rest/transport_curl.h"
1921
#include "app/rest/transport_interface.h"
2022
#include "app/src/include/firebase/future.h"
@@ -52,8 +54,7 @@ class HttpsCallableRequest : public rest::Request {
5254

5355
class HttpsCallableReferenceInternal {
5456
public:
55-
HttpsCallableReferenceInternal(FunctionsInternal* functions,
56-
const char* name);
57+
HttpsCallableReferenceInternal(FunctionsInternal* functions, const char* url);
5758
~HttpsCallableReferenceInternal();
5859

5960
// Copy constructor. It's totally okay (and efficient) to copy
@@ -108,8 +109,8 @@ class HttpsCallableReferenceInternal {
108109
// Keep track of the Functions object for managing Futures.
109110
FunctionsInternal* functions_;
110111

111-
// The name of the endpoint this reference points to.
112-
std::string name_;
112+
// The URL of the endpoint this reference points to.
113+
std::string url_;
113114

114115
rest::TransportCurl transport_;
115116
// For now, we only allow one request per reference at a time in C++.

0 commit comments

Comments
 (0)