grpc-dart icon indicating copy to clipboard operation
grpc-dart copied to clipboard

Use URI path in requests

Open metalmatze opened this issue 5 years ago • 8 comments

Hey, I'd like to pass a URI with a path to the client, so that I can use a proxy in front of my application on the server side to redirect to the correct service.

final channel = GrpcWebClientChannel.xhr(Uri.parse('http://localhost:6060/grpc'));

Now, looking at the source code after trying a couple of things, I can see that the path is simply overwritten by whatever the generated file has. As of now I am not sure if that's a gRPC requirement or just not implemented in this project.

In line 167 I can see that the path is simply passed into the URI. https://github.com/grpc/grpc-dart/blob/ae17e712e4f5431eb6664f0589899c77462e5475/lib/src/client/transport/xhr_transport.dart#L164-L167

Part of my pubspec.lock

  grpc:
    dependency: "direct main"
    description:
      name: grpc
      url: "https://pub.dartlang.org"
    source: hosted
    version: "2.1.3"

metalmatze avatar Dec 15 '19 20:12 metalmatze

This should work, try ending the Uri with a '/' then Uri.resolve is supposed to do the right thing

sigurdm avatar Dec 16 '19 07:12 sigurdm

Sadly that doesn't work... I think the uri.resolve(path).toString() overwrites the path entirely, if I'm not mistaken.

metalmatze avatar Dec 16 '19 08:12 metalmatze

I think I'm misunderstanding something. Why would it overwrite it?

void main() {
  final path = 'abc/def';
  final uri = Uri.parse('http://localhost:6060/grpc');
  final uri2 = Uri.parse('http://localhost:6060/grpc/');
  print(uri.resolve(path));
  print(uri2.resolve(path));
}

prints:

http://localhost:6060/abc/def
http://localhost:6060/grpc/abc/def

sigurdm avatar Dec 16 '19 13:12 sigurdm

Any update here? This is the problem with gRPC-dart not with Uri.parse

Uri correctly parse the sub path but the gRPC client code does not use it (https://github.com/grpc/grpc-dart/blob/e4947e290924f98de48437686122c2ba482d4326/lib/src/client/method.dart#L22).

For example, the generated code will pass down the path /some_random.Service/SomeMethod as the proto file does not need to know about the client path. This is correct.

And then it should be prefixed by the client method (/grpc/some_random.Service/SomeMethod). But, it just takes the path as is (/some_random.Service/SomeMethod)

kkweon avatar Jul 27 '20 19:07 kkweon

now i understand the problem. the generated code (stub output from protoc --dart_out=...) has a prefix "/" so the URI will ignore the path

kkweon avatar Jul 27 '20 19:07 kkweon

void main() {
  final path = '/abc/def';
  final uri = Uri.parse('http://localhost:6060/grpc');
  final uri2 = Uri.parse('http://localhost:6060/grpc/');
  print(uri.resolve(path));
  print(uri2.resolve(path));
}

prints

http://localhost:6060/abc/def
http://localhost:6060/abc/def

kkweon avatar Jul 27 '20 19:07 kkweon

Either the generated code should not be prefixed with "/" or we need to modify https://github.com/grpc/grpc-dart/blob/e4947e290924f98de48437686122c2ba482d4326/lib/src/client/transport/xhr_transport.dart#L138

or Uri.resolve should be fixed?

kkweon avatar Jul 27 '20 19:07 kkweon

Still waiting on this :(

For those that need somewhat of a fix, here is what I used:

import 'package:grpc/grpc_connection_interface.dart';

// ignore: implementation_imports
import 'package:grpc/src/client/transport/xhr_transport.dart';

///
/// This file exists because of IIS.
/// Applications hosted on IIS come prefixed with a base path.
///
/// Issue described here: https://github.com/grpc/grpc-dart/issues/258
/// The gRPC-dart team currently have a PR for this: https://github.com/grpc/grpc-dart/pull/335
///
/// Hopefully this can be removed in due time.
///
class IisWorkaroundChannel extends ClientChannelBase {
  final Uri uri;

  IisWorkaroundChannel.xhr(this.uri) : super();

  @override
  ClientConnection createConnection() {
    return IisClientConnection(uri);
  }
}

class IisClientConnection extends XhrClientConnection {
  IisClientConnection(Uri uri) : super(uri);

  @override
  GrpcTransportStream makeRequest(String path, Duration? timeout,
      Map<String, String> metadata, ErrorHandler onError,
      {CallOptions? callOptions}) {
    var pathWithoutFirstSlash = path.substring(1);
    return super.makeRequest(pathWithoutFirstSlash, timeout, metadata, onError,
        callOptions: callOptions);
  }
}

RyanSusana avatar Mar 27 '21 00:03 RyanSusana