@@ -26,6 +26,8 @@ type GrpcDialer interface {
2626 Dial (ctx context.Context ) (* grpc.ClientConn , error )
2727}
2828
29+ // CompatV1 is a shim that acts like a plugin server and delegates request to
30+ // something that implements a V1-style API interface.
2931type CompatV1 struct {
3032 GetPluginInfo func () * papiv1.Info
3133 GetInstance func (user * papiv1.UserContext ) (papiv1.Plugin , error )
@@ -75,23 +77,106 @@ type CompatV1Shim struct {
7577 http.Server
7678}
7779
78- type compatV1ShimServer struct {
79- shim * CompatV1Shim
80- protobuf.UnimplementedPluginServer
81- protobuf.UnimplementedDisplayerServer
82- protobuf.UnimplementedConfigurerServer
80+ // NewCompatV1Rpc creates a new CompatV1Shim server.
81+ func NewCompatV1Rpc (compatV1 * CompatV1 , cliArgs []string ) (* CompatV1Shim , error ) {
82+ pluginInfo := compatV1 .GetPluginInfo ()
83+ tlsName := BuildPluginTLSName (purposePluginRPC , pluginInfo .Name )
84+
85+ cliFlags , err := ParsePluginCLIFlags (cliArgs )
86+ if err != nil {
87+ log .Fatalf ("Failed to parse CLI flags: %v" , err )
88+ }
89+ rootCAs := x509 .NewCertPool ()
90+ caCert , err := x509 .ParseCertificate (cliFlags .CAData )
91+ if err != nil {
92+ return nil , err
93+ }
94+ rootCAs .AddCert (caCert )
95+
96+ leafCert , err := x509 .ParseCertificate (cliFlags .CertData )
97+ if err != nil {
98+ return nil , err
99+ }
100+
101+ tlsConfig := & tls.Config {
102+ Certificates : []tls.Certificate {
103+ {
104+ Certificate : [][]byte {cliFlags .CertData },
105+ PrivateKey : cliFlags .KeyData ,
106+ Leaf : leafCert ,
107+ },
108+ {
109+ Certificate : [][]byte {caCert .Raw },
110+ },
111+ },
112+ RootCAs : rootCAs ,
113+ ServerName : tlsName ,
114+ ClientAuth : tls .RequireAndVerifyClientCert ,
115+ ClientCAs : rootCAs ,
116+ }
117+
118+ rpcServer := grpc .NewServer ()
119+
120+ gin := gin .Default ()
121+
122+ self := & CompatV1Shim {
123+ mu : & sync.RWMutex {},
124+ instances : make (map [uint64 ]papiv1.Plugin ),
125+ compatV1 : compatV1 ,
126+ gin : gin ,
127+ pluginServer : rpcServer ,
128+ pluginInfo : pluginInfo ,
129+ }
130+
131+ selfServer := & compatV1ShimServer {
132+ shim : self ,
133+ }
134+
135+ protobuf .RegisterPluginServer (rpcServer , selfServer )
136+ protobuf .RegisterDisplayerServer (rpcServer , selfServer )
137+ protobuf .RegisterConfigurerServer (rpcServer , selfServer )
138+
139+ protocols := new (http.Protocols )
140+ protocols .SetHTTP1 (true )
141+ protocols .SetHTTP2 (true )
142+ self .Server = http.Server {
143+ Handler : self ,
144+ TLSConfig : tlsConfig ,
145+ Protocols : protocols ,
146+ }
147+
148+ return self , nil
83149}
84150
85- func (s * compatV1ShimServer ) GetPluginInfo (ctx context.Context , req * emptypb.Empty ) (* protobuf.Info , error ) {
86- return & protobuf.Info {
87- Version : s .shim .pluginInfo .Version ,
88- Author : s .shim .pluginInfo .Author ,
89- Name : s .shim .pluginInfo .Name ,
90- Website : s .shim .pluginInfo .Website ,
91- Description : s .shim .pluginInfo .Description ,
92- License : s .shim .pluginInfo .License ,
93- ModulePath : s .shim .pluginInfo .ModulePath ,
94- }, nil
151+ func (h * CompatV1Shim ) ServeHTTP (w http.ResponseWriter , r * http.Request ) {
152+ if r .TLS == nil {
153+ http .Error (w , "Must use TLS" , http .StatusUpgradeRequired )
154+ return
155+ }
156+
157+ pluginRpcHostName := BuildPluginTLSName (purposePluginRPC , h .pluginInfo .ModulePath )
158+
159+ if r .TLS .ServerName == pluginRpcHostName {
160+ if r .ProtoMajor != 2 {
161+ http .Error (w , "Must use HTTP/2" , http .StatusHTTPVersionNotSupported )
162+ return
163+ }
164+ if ! strings .HasPrefix (r .Header .Get ("Content-Type" ), "application/grpc" ) {
165+ http .Error (w , "Must use application/grpc content type" , http .StatusUnsupportedMediaType )
166+ return
167+ }
168+ h .pluginServer .ServeHTTP (w , r )
169+
170+ return
171+ }
172+
173+ pluginWebhookHostName := BuildPluginTLSName (purposePluginWebhook , h .pluginInfo .ModulePath )
174+ if r .TLS .ServerName == pluginWebhookHostName {
175+ h .gin .ServeHTTP (w , r )
176+ return
177+ }
178+
179+ http .Error (w , "Virtual host not found" , http .StatusNotFound )
95180}
96181
97182type shimV1MessageHandler struct {
@@ -126,6 +211,25 @@ func (h *shimV1StorageHandler) Load() (b []byte, err error) {
126211 return
127212}
128213
214+ type compatV1ShimServer struct {
215+ shim * CompatV1Shim
216+ protobuf.UnimplementedPluginServer
217+ protobuf.UnimplementedDisplayerServer
218+ protobuf.UnimplementedConfigurerServer
219+ }
220+
221+ func (s * compatV1ShimServer ) GetPluginInfo (ctx context.Context , req * emptypb.Empty ) (* protobuf.Info , error ) {
222+ return & protobuf.Info {
223+ Version : s .shim .pluginInfo .Version ,
224+ Author : s .shim .pluginInfo .Author ,
225+ Name : s .shim .pluginInfo .Name ,
226+ Website : s .shim .pluginInfo .Website ,
227+ Description : s .shim .pluginInfo .Description ,
228+ License : s .shim .pluginInfo .License ,
229+ ModulePath : s .shim .pluginInfo .ModulePath ,
230+ }, nil
231+ }
232+
129233func (s * compatV1ShimServer ) SetEnable (ctx context.Context , req * protobuf.SetEnableRequest ) (* emptypb.Empty , error ) {
130234 s .shim .mu .RLock ()
131235 instance , ok := s .shim .instances [req .User .Id ]
@@ -287,104 +391,3 @@ func (s *compatV1ShimServer) RunUserInstance(req *protobuf.UserInstanceRequest,
287391
288392 return nil
289393}
290-
291- func NewPluginRpc (compatV1 * CompatV1 , cliArgs []string ) (* CompatV1Shim , error ) {
292- pluginInfo := compatV1 .GetPluginInfo ()
293- tlsName := BuildPluginTLSName (purposePluginRPC , pluginInfo .Name )
294-
295- cliFlags , err := ParsePluginCLIFlags (cliArgs )
296- if err != nil {
297- log .Fatalf ("Failed to parse CLI flags: %v" , err )
298- }
299- rootCAs := x509 .NewCertPool ()
300- caCert , err := x509 .ParseCertificate (cliFlags .CAData )
301- if err != nil {
302- return nil , err
303- }
304- rootCAs .AddCert (caCert )
305-
306- leafCert , err := x509 .ParseCertificate (cliFlags .CertData )
307- if err != nil {
308- return nil , err
309- }
310-
311- tlsConfig := & tls.Config {
312- Certificates : []tls.Certificate {
313- {
314- Certificate : [][]byte {cliFlags .CertData },
315- PrivateKey : cliFlags .KeyData ,
316- Leaf : leafCert ,
317- },
318- {
319- Certificate : [][]byte {caCert .Raw },
320- },
321- },
322- RootCAs : rootCAs ,
323- ServerName : tlsName ,
324- ClientAuth : tls .RequireAndVerifyClientCert ,
325- ClientCAs : rootCAs ,
326- }
327-
328- rpcServer := grpc .NewServer ()
329-
330- gin := gin .Default ()
331-
332- self := & CompatV1Shim {
333- mu : & sync.RWMutex {},
334- instances : make (map [uint64 ]papiv1.Plugin ),
335- compatV1 : compatV1 ,
336- gin : gin ,
337- pluginServer : rpcServer ,
338- pluginInfo : pluginInfo ,
339- }
340-
341- selfServer := & compatV1ShimServer {
342- shim : self ,
343- }
344-
345- protobuf .RegisterPluginServer (rpcServer , selfServer )
346- protobuf .RegisterDisplayerServer (rpcServer , selfServer )
347- protobuf .RegisterConfigurerServer (rpcServer , selfServer )
348-
349- protocols := new (http.Protocols )
350- protocols .SetHTTP1 (true )
351- protocols .SetHTTP2 (true )
352- self .Server = http.Server {
353- Handler : self ,
354- TLSConfig : tlsConfig ,
355- Protocols : protocols ,
356- }
357-
358- return self , nil
359- }
360-
361- func (h * CompatV1Shim ) ServeHTTP (w http.ResponseWriter , r * http.Request ) {
362- if r .TLS == nil {
363- http .Error (w , "Must use TLS" , http .StatusUpgradeRequired )
364- return
365- }
366-
367- pluginRpcHostName := BuildPluginTLSName (purposePluginRPC , h .pluginInfo .ModulePath )
368-
369- if r .TLS .ServerName == pluginRpcHostName {
370- if r .ProtoMajor != 2 {
371- http .Error (w , "Must use HTTP/2" , http .StatusHTTPVersionNotSupported )
372- return
373- }
374- if ! strings .HasPrefix (r .Header .Get ("Content-Type" ), "application/grpc" ) {
375- http .Error (w , "Must use application/grpc content type" , http .StatusUnsupportedMediaType )
376- return
377- }
378- h .pluginServer .ServeHTTP (w , r )
379-
380- return
381- }
382-
383- pluginWebhookHostName := BuildPluginTLSName (purposePluginWebhook , h .pluginInfo .ModulePath )
384- if r .TLS .ServerName == pluginWebhookHostName {
385- h .gin .ServeHTTP (w , r )
386- return
387- }
388-
389- http .Error (w , "Virtual host not found" , http .StatusNotFound )
390- }
0 commit comments