Skip to content

Commit 4de7a58

Browse files
committed
Fix Android WebSocket cookie lookup stripping the URL path
1 parent 8cfde6d commit 4de7a58

2 files changed

Lines changed: 73 additions & 9 deletions

File tree

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.kt

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ public class WebSocketModule(context: ReactApplicationContext) :
427427
*/
428428
private fun getCookie(uri: String): String? {
429429
try {
430-
val origin = URI(getDefaultOrigin(uri))
430+
val origin = getCookieLookupUri(uri)
431431
val cookieMap = cookieHandler.get(origin, HashMap<String, List<String>>())
432432
val cookieList = cookieMap["Cookie"]
433433
if (cookieList.isNullOrEmpty()) {
@@ -459,6 +459,16 @@ public class WebSocketModule(context: ReactApplicationContext) :
459459
customClientBuilder?.apply(builder)
460460
}
461461

462+
/** Map a WebSocket URI's scheme to its HTTP(S) equivalent, e.g. "wss" -> "https". */
463+
private fun httpSchemeFor(requestURI: URI): String =
464+
when (requestURI.scheme) {
465+
"wss" -> "https"
466+
"ws" -> "http"
467+
"http",
468+
"https" -> requestURI.scheme
469+
else -> ""
470+
}
471+
462472
/**
463473
* Get the default HTTP(S) origin for a specific WebSocket URI
464474
*
@@ -468,14 +478,7 @@ public class WebSocketModule(context: ReactApplicationContext) :
468478
private fun getDefaultOrigin(uri: String): String {
469479
try {
470480
val requestURI = URI(uri)
471-
val scheme =
472-
when (requestURI.scheme) {
473-
"wss" -> "https"
474-
"ws" -> "http"
475-
"http",
476-
"https" -> requestURI.scheme
477-
else -> ""
478-
}
481+
val scheme = httpSchemeFor(requestURI)
479482

480483
val defaultOrigin =
481484
if (requestURI.port != -1) {
@@ -489,5 +492,29 @@ public class WebSocketModule(context: ReactApplicationContext) :
489492
throw IllegalArgumentException("Unable to set $uri as default origin header")
490493
}
491494
}
495+
496+
/**
497+
* Get the URI used to look up cookies for a specific WebSocket URI, keeping its path so that
498+
* path-scoped cookies are matched correctly
499+
*
500+
* @param uri
501+
* @return A URI with the endpoint converted to HTTP protocol (http[s]://host[:port]/path)
502+
*/
503+
private fun getCookieLookupUri(uri: String): URI {
504+
try {
505+
val requestURI = URI(uri)
506+
return URI(
507+
httpSchemeFor(requestURI),
508+
null,
509+
requestURI.host,
510+
requestURI.port,
511+
requestURI.path,
512+
requestURI.query,
513+
requestURI.fragment,
514+
)
515+
} catch (e: URISyntaxException) {
516+
throw IllegalArgumentException("Unable to get cookie lookup URI from $uri")
517+
}
518+
}
492519
}
493520
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.facebook.react.modules.websocket
9+
10+
import java.net.URI
11+
import org.assertj.core.api.Assertions.assertThat
12+
import org.junit.Test
13+
14+
class WebSocketModuleTest {
15+
16+
private fun getCookieLookupUri(uri: String): URI {
17+
val method =
18+
WebSocketModule.Companion::class.java.getDeclaredMethod(
19+
"getCookieLookupUri", String::class.java)
20+
method.isAccessible = true
21+
return method.invoke(WebSocketModule.Companion, uri) as URI
22+
}
23+
24+
@Test
25+
fun getCookieLookupUri_keepsPathForCookieMatching() {
26+
val uri = getCookieLookupUri("wss://my.domain/signal-r/hubs/messages")
27+
28+
assertThat(uri.toString()).isEqualTo("https://my.domain/signal-r/hubs/messages")
29+
}
30+
31+
@Test
32+
fun getCookieLookupUri_keepsPortAndQuery() {
33+
val uri = getCookieLookupUri("ws://my.domain:8080/path?token=abc")
34+
35+
assertThat(uri.toString()).isEqualTo("http://my.domain:8080/path?token=abc")
36+
}
37+
}

0 commit comments

Comments
 (0)