imgk / caddy-trojan

Caddy module for trojan proxy
GNU General Public License v3.0
204 stars 46 forks source link

add grpc conn #21

Closed WeidiDeng closed 2 years ago

WeidiDeng commented 2 years ago

Add grpc transport, it's easy enough to write own instead of importing v2ray.

WeidiDeng commented 2 years ago

Many thanks for you PR.

How about split Conn to Reader and Writer?

type Reader struct {
  r io.Reader
  n int
}

type Writer struct {
  w             http.ResponseWriter
  flusher       http.flusher
  headerWritten bool
}

Closer should be implemented. golang http guarantees when body is closed, read routine will be unblocked, but writer is not.

imgk commented 2 years ago

I'm ok with io.Closer for Writer. There is no need to close http.Request.Body.

WeidiDeng commented 2 years ago

I'm ok with io.Closer for Writer. There is no need to close http.Request.Body.

Writer can't be closed, only request.body can be closed

imgk commented 2 years ago

My mistake. I mean implementing io.Closer for Writer to set Header and other things.

WeidiDeng commented 2 years ago

pr既然关闭了,我也不多说什么了。你不需要这个功能也无所谓。

给你几个建议,bufio是可以选择buffer的size的。甚至可以使用sync.pool进行回收。标准库的http就对bufio进行pooling。

读取trojan请求头时没必要readfull,读一次,如果没有满足长度要求,包含特殊字符(除了a-z 0-9)以外的字符,就可以判断不是的,正常客户端都会把hash使用一次write发送的。

websocket没有判断path,你要在http_matcher做也是没有问题的。如果你想控制内存分配,使用gobwas/websocket,把这个做成listener wrapper,具体怎么回落自己研究,告诉你http.request的overhead更高,header map, body以及hijack的bufio.writer.

和标准golang http tls握手失败的响应不同,没有client send http request to https endpoints. 你可以自己使用curl试试,目前这个除了trojan和trojan-go有其他的都没有做这个,v2ray和xray.

没有设置读取的timeout.

你可以导入v2ray的grpc实现,grpc是有servehttp方法的。

还有就是example,现在是不需要开启h2c的。返回的是tls.conn就完全不需要。

imgk commented 2 years ago

你好,关闭PR是一时失误,因为git用的不熟,原来你提交的那个分支因为一些原因被删除了,PR也就关闭了,并不是有意为之。

我本职工作不是搞开发的,写这个只是兴趣使然和个人使用的目的,所以有很多自以为是的优化,也没有实际经验或者其它的证据来证明这些。

我很欢迎其他人向这个项目提交代码,最近因为换工作才有时间看看这个项目,之后忙起来的话也没时间打理。

因为一直是自用,也没把它当成正经开源项目去做,我也没参与过开源项目,如果有人有兴趣,可以讨论出一个方式,如何去更好的做这个。

WeidiDeng commented 2 years ago

我过段时间有空了,在提几个pr吧,我自己写了一个,那个listener wrapper使用channel的是参考你的实现的。golang的h2c实现并不优雅,是hijack以后的,当时我查看tls.Conn的read方式,发现可以直接修改input来修改读取缓存。h2c的方式自用是没有什么问题的,我caddy服务器上面是有真正网站的,之前trojan等回落h2c会导致caddy配置修改后出现各种奇怪的问题。我个人不喜欢重启caddy服务,觉得caddy既然自带了配置修改重新载入,就应该使用。

以上只是个人的看法,个人使用可以随便重启caddy服务。

使用v2ray的grpc我之前试过,在修改caddy配置后,会卡住,原因就是v2ray的grpc conn(Gun)的close方法并没有阻止底层的数据读取,同时grpc server shutdown是等待所有请求结束,不会强制关闭。自己写的将request.Body关闭是可以真正意义上停止底层的读取的。go的h2 流底层实现如果有兴趣可以看看,本质上是一个pipe, request和response writer是关联在同一个h2 stream上面的。

websocket和grpc都是可以确定path的,这点也可以作为流量的区分,授权失败的时候log一下。

go grpc使用的不是go http中的h2,是自己实现的,理论上性能更强,可以对底层的h2的frame进行详细的配置。但是如果前面使用caddy的反代,那性能就被caddy限制住了,caddy的反代每次都会获取两个32*1024的缓存,sync.pool只能降gc和创建的数量,不能降多链接时的内存使用。