awslabs / amazon-kinesis-video-streams-webrtc-sdk-android

Android SDK for interfacing with Amazon Kinesis Video Streams Signaling Service.
Apache License 2.0
58 stars 37 forks source link

Is it possible to replace Tyrus with other websocket clients? #15

Closed jarvislin closed 4 years ago

jarvislin commented 4 years ago

Hi, I found that Tyrus causes handshake failure on some Android devices, so I replace Tyrus with other websocket clients. (I tried OkHttp, nv-websocket-client and copy the URI to websocket.org)

But I just got 403 Forbidden when I tried to connect.

https://github.com/awslabs/amazon-kinesis-video-streams-webrtc-sdk-android/blob/master/src/main/java/com/amazonaws/kinesisvideo/signaling/tyrus/WebSocketClient.java#L45

It seems Tyrus uses RFC 6455 in the above file and I had tried other client which supports RFC 6455, but still got the same error.

I would like to know: Is there anything I have to notice if I want to connect to the WebSocket endpoint.

pozhega commented 4 years ago

@jarvislin hi, have you ever managed to solve this problem?

JeetSA commented 4 years ago

Hello @jarvislin ,

Did you resolve this issue? Can you please help me for the same?

Thanks in advance.

nickhuangcyh commented 2 years ago

@jarvislin @pozhega @JeetSA

I think the problem is that WSS URI is encoded twice and the 'tyrus' is work perfectly on that, but not 'okhttp' and 'Java-WebSocket'

  1. All query params are encoded in buildQueryParamsMap function (e.g. '/' -> '%2F')
  2. URI init will encode it again (e.g. '%' -> '%25' '%2F' -> '%252F')

Here is my solution below

AwsV4Signer.kt

fun sign(
        uri: URI, accessKey: String, secretKey: String,
        sessionToken: String, wssUri: URI, region: String
    ): URI? {
        val dateMilli = Date().time
        val amzDate = getTimeStamp(dateMilli)
        val datestamp = getDateStamp(dateMilli)
        val queryParamsMap =
            buildQueryParamsMap(uri, accessKey, sessionToken, region, amzDate, datestamp)
        val canonicalQuerystring = getCanonicalizedQueryString(queryParamsMap)
        val canonicalRequest = getCanonicalRequest(uri, canonicalQuerystring)
        val stringToSign =
            signString(amzDate, createCredentialScope(region, datestamp), canonicalRequest)
        val signatureKey = getSignatureKey(secretKey, datestamp, region, SERVICE)
        val signature = BinaryUtils.toHex(hmacSha256(stringToSign, signatureKey))
        val signedCanonicalQueryString =
            canonicalQuerystring + "&" + X_AMZ_SIGNATURE + "=" + signature
        var uriResult: URI? = null
        try {
-           uriResult = URI(
-                  wssUri.scheme,
-                  wssUri.rawAuthority,
-                  getCanonicalUri(uri),
-                  signedCanonicalQueryString,
-                  null
-           )
+           val scheme = wssUri.scheme
+           val rawAuthority = wssUri.rawAuthority
+           val path = getCanonicalUri(uri)
+           uriResult = URI("$scheme://$rawAuthority$path?$signedCanonicalQueryString")
        } catch (e: URISyntaxException) {
            Log.e(TAG, e.message ?: "")
        }
        return uriResult
    }

More information about java.net.URI encode https://stackoverflow.com/questions/4858108/url-to-uri-encoding-changes-a-3d-to-253d

also see https://github.com/awslabs/amazon-kinesis-video-streams-webrtc-sdk-android/issues/74