Skip to content

Commit 8305f35

Browse files
committed
Add custom headers to HttpsCallableReference
1 parent 7b828fc commit 8305f35

File tree

4 files changed

+71
-12
lines changed

4 files changed

+71
-12
lines changed

firebase-functions/src/androidTest/backend/functions/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,7 @@ exports.timeoutTest = functions.https.onRequest((request, response) => {
122122
// Wait for longer than 500ms.
123123
setTimeout(() => response.send({data: true}), 500);
124124
});
125+
126+
exports.headersTest = functions.https.onRequest((request, response) => {
127+
response.status(200).send({data: request.headers});
128+
});

firebase-functions/src/androidTest/java/com/google/firebase/functions/CallTests.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,18 @@ class CallTests {
9090

9191
assertThat(actual).isNull()
9292
}
93+
94+
@Test
95+
fun testCustomHeaders() {
96+
val functions = Firebase.functions(app)
97+
val function = functions.getHttpsCallable("headersTest")
98+
.addHeader("Header1", "value1")
99+
.addHeader("Header2", "value2")
100+
.addHeader("Header1", "value3")
101+
val actual = Tasks.await(function.call()).getData() as? Map<*, *>
102+
103+
assertThat(actual).isNotNull()
104+
assertThat(actual?.get("Header1")).isEqualTo("value3")
105+
assertThat(actual?.get("Header2")).isEqualTo("value2")
106+
}
93107
}

firebase-functions/src/main/java/com/google/firebase/functions/FirebaseFunctions.kt

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import java.util.concurrent.Executor
3838
import javax.inject.Named
3939
import okhttp3.Call
4040
import okhttp3.Callback
41+
import okhttp3.Headers
4142
import okhttp3.MediaType
4243
import okhttp3.OkHttpClient
4344
import okhttp3.Request
@@ -174,7 +175,8 @@ internal constructor(
174175
internal fun call(
175176
name: String,
176177
data: Any?,
177-
options: HttpsCallOptions
178+
options: HttpsCallOptions,
179+
headers: Map<String, String>,
178180
): Task<HttpsCallableResult> {
179181
return providerInstalled.task
180182
.continueWithTask(executor) { contextProvider.getContext(options.limitedUseAppCheckTokens) }
@@ -184,7 +186,7 @@ internal constructor(
184186
}
185187
val context = task.result
186188
val url = getURL(name)
187-
call(url, data, context, options)
189+
call(url, data, context, options, headers)
188190
}
189191
}
190192

@@ -195,15 +197,20 @@ internal constructor(
195197
* @param data Parameters to pass to the function. Can be anything encodable as JSON.
196198
* @return A Task that will be completed when the request is complete.
197199
*/
198-
internal fun call(url: URL, data: Any?, options: HttpsCallOptions): Task<HttpsCallableResult> {
200+
internal fun call(
201+
url: URL,
202+
data: Any?,
203+
options: HttpsCallOptions,
204+
headers: Map<String, String>,
205+
): Task<HttpsCallableResult> {
199206
return providerInstalled.task
200207
.continueWithTask(executor) { contextProvider.getContext(options.limitedUseAppCheckTokens) }
201208
.continueWithTask(executor) { task: Task<HttpsCallableContext?> ->
202209
if (!task.isSuccessful) {
203210
return@continueWithTask Tasks.forException<HttpsCallableResult>(task.exception!!)
204211
}
205212
val context = task.result
206-
call(url, data, context, options)
213+
call(url, data, context, options, headers)
207214
}
208215
}
209216

@@ -219,7 +226,8 @@ internal constructor(
219226
url: URL,
220227
data: Any?,
221228
context: HttpsCallableContext?,
222-
options: HttpsCallOptions
229+
options: HttpsCallOptions,
230+
headers: Map<String, String>,
223231
): Task<HttpsCallableResult?> {
224232
Preconditions.checkNotNull(url, "url cannot be null")
225233
val body: MutableMap<String?, Any?> = HashMap()
@@ -228,7 +236,9 @@ internal constructor(
228236
val bodyJSON = JSONObject(body)
229237
val contentType = MediaType.parse("application/json")
230238
val requestBody = RequestBody.create(contentType, bodyJSON.toString())
231-
var request = Request.Builder().url(url).post(requestBody)
239+
// Add custom headers first so that internal headers cannot be overwritten
240+
val customHeaders = Headers.of(headers)
241+
var request = Request.Builder().url(url).post(requestBody).headers(customHeaders)
232242
if (context!!.authToken != null) {
233243
request = request.header("Authorization", "Bearer " + context.authToken)
234244
}

firebase-functions/src/main/java/com/google/firebase/functions/HttpsCallableReference.kt

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,33 @@ public class HttpsCallableReference {
3434
// Options for how to do the HTTPS call.
3535
@VisibleForTesting public val options: HttpsCallOptions
3636

37+
private val headers: MutableMap<String, String>
38+
39+
/** Creates a new reference with the given options. */
40+
internal constructor(
41+
functionsClient: FirebaseFunctions,
42+
name: String?,
43+
options: HttpsCallOptions,
44+
headers: MutableMap<String, String>,
45+
) {
46+
this.functionsClient = functionsClient
47+
this.name = name
48+
url = null
49+
this.options = options
50+
this.headers = headers
51+
}
52+
3753
/** Creates a new reference with the given options. */
3854
internal constructor(
3955
functionsClient: FirebaseFunctions,
4056
name: String?,
41-
options: HttpsCallOptions
57+
options: HttpsCallOptions,
4258
) {
4359
this.functionsClient = functionsClient
4460
this.name = name
4561
url = null
4662
this.options = options
63+
this.headers = mutableMapOf()
4764
}
4865

4966
/** Creates a new reference with the given options. */
@@ -52,6 +69,7 @@ public class HttpsCallableReference {
5269
name = null
5370
this.url = url
5471
this.options = options
72+
this.headers = mutableMapOf()
5573
}
5674

5775
/**
@@ -97,9 +115,9 @@ public class HttpsCallableReference {
97115
*/
98116
public fun call(data: Any?): Task<HttpsCallableResult> {
99117
return if (name != null) {
100-
functionsClient.call(name, data, options)
118+
functionsClient.call(name, data, options, headers)
101119
} else {
102-
functionsClient.call(url!!, data, options)
120+
functionsClient.call(url!!, data, options, headers)
103121
}
104122
}
105123

@@ -119,9 +137,9 @@ public class HttpsCallableReference {
119137
*/
120138
public fun call(): Task<HttpsCallableResult> {
121139
return if (name != null) {
122-
functionsClient.call(name, null, options)
140+
functionsClient.call(name, null, options, headers)
123141
} else {
124-
functionsClient.call(url!!, null, options)
142+
functionsClient.call(url!!, null, options, headers)
125143
}
126144
}
127145

@@ -150,8 +168,21 @@ public class HttpsCallableReference {
150168
* @param units The units for the specified timeout.
151169
*/
152170
public fun withTimeout(timeout: Long, units: TimeUnit): HttpsCallableReference {
153-
val other = HttpsCallableReference(functionsClient, name, options)
171+
val other = HttpsCallableReference(functionsClient, name, options, headers)
154172
other.setTimeout(timeout, units)
155173
return other
156174
}
175+
176+
/**
177+
* Adds an HTTP header for calls from this instance of Functions.
178+
*
179+
* Note that an existing header with the same name will be overwritten.
180+
*
181+
* @param name Name of HTTP header
182+
* @param value Value of HTTP header
183+
*/
184+
public fun addHeader(name: String, value: String): HttpsCallableReference {
185+
headers[name] = value
186+
return this
187+
}
157188
}

0 commit comments

Comments
 (0)