Search code examples
grpcsubdirectorygrpc-javagrpc-webgrpc-kotlin

GRPC call for a service which is inside a subdirectory? (Android grpc client)


This question is similar to below but my issue is with Android grpc client How can I make a GRPC call for a service which is inside a subdirectory? (in .Net Framework)

I am getting 404 error while accessing the grpc streaming api :

UNIMPLEMENTED: HTTP status code 404
    invalid content-type: text/html
    headers: Metadata(:status=404,content-length=1245,content-type=text/html,server=Microsoft-IIS/10.0,request-id=5154500d-fb58-7903-65d6-3d3711129101,strict-transport-security=max-age=31536000; includeSubDomains; preload,alt-svc=h3=":443",h3-29=":443",x-preferredroutingkeydiagnostics=1,x-calculatedfetarget=PS2PR02CU003.internal.outlook.com,x-backendhttpstatus=404,x-calculatedbetarget=PUZP153MB0788.APCP153.PROD.OUTLOOK.COM,x-backendhttpstatus=404,x-rum-validated=1,x-proxy-routingcorrectness=1,x-proxy-backendserverstatus=404,x-feproxyinfo=MA0PR01CA0051.INDPRD01.PROD.OUTLOOK.COM,x-feefzinfo=MAA,ms-cv=DVBUUVj7A3ll1j03ERKRAQ.1.1,x-feserver=PS2PR02CA0054,x-firsthopcafeefz=MAA,x-powered-by=ASP.NET,x-feserver=MA0PR01CA0051,date=Tue, 11 Oct 2022 06:24:18 GMT)

The issue is that the /subdirectory_path is getting ignored by the service in the final outgoing call. Here's the code I am using to create the grpc channel in android (gives 404)

   val uri =  Uri.parse("https://examplegrpcserver.com/subdirectory_path")
    private val channel = let {
        val builder = ManagedChannelBuilder.forTarget(uri.host+uri.path)
        if (uri.scheme == "https") {
            builder.useTransportSecurity()
        } else {
            builder.usePlaintext()
        }
        builder.executor(Dispatchers.IO.asExecutor()).build()
    }

The uri is correct since it works with web client. For web client the channel is defined like this (working)

 var handler = new SubdirectoryHandler(httpHandler, "/subdirectory_path");
            var userToken = "<token string>";

            var grpcWebHandler = new GrpcWebHandler(handler);

            using var channel = GrpcChannel.ForAddress("https://examplegrpcserver.com", new GrpcChannelOptions { HttpHandler = grpcWebHandler,
                Credentials = ChannelCredentials.Create(new SslCredentials(), CallCredentials.FromInterceptor((context, metadata) =>
                {
                    metadata.Add("Authorization", $"Bearer {userToken}");
                    return Task.CompletedTask;
                }))
            });

I tried to inject the subdirectory_path in the uri for my android client but unable to find appropriate api. grpc-kotlin doesn't expose the underlying http-client used in the channel.

Could someone please help me with this issue, how can I specify the subdirectory_path? (before the service and method name)


Solution

  • The path for an RPC is fixed by the .proto definition. Adding prefixes to the path is unsupported.

    The URI passed to forTarget() points to the resource containing the addresses to connect to. So the fully-qualified form is normally of the form dns:///example.com. If you specified a host in the URI like dns://1.1.1.1/example.com, then that would mean "look up example.com at the DNS server 1.1.1.1." But there's no place to put a path prefix in the target string, as that path would only be used for address lookup, not actual RPCs.

    If the web client supports path prefixes, that is a feature specific to it. It would also be using a tweaked grpc protocol that requires translation to normal backends.