blob: 482386147a6a4b7035d7ebf672ed0377d16c2089 [file] [log] [blame]
// Copyright 2021-2023 Buf Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package triple_protocol_test
import (
"context"
"errors"
"net"
"net/http"
"net/http/httptest"
"sync"
"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1/pingv1connect"
)
var examplePingServer *inMemoryServer
func init() {
// Generally, init functions are bad.
//
// To write testable examples that users can grok *and* can execute in the
// playground, where networking is disabled, we need an HTTP server that uses
// in-memory pipes instead of TCP. We don't want to pollute every example
// with this setup code.
//
// The least-awful option is to set up the server in init().
mux := http.NewServeMux()
mux.Handle(pingv1connect.NewPingServiceHandler(pingServer{}))
examplePingServer = newInMemoryServer(mux)
}
// inMemoryServer is an HTTP server that uses in-memory pipes instead of TCP.
// It supports HTTP/2 and has TLS enabled.
//
// The Go Playground panics if we try to start a TCP-backed server. If you're
// not familiar with the Playground's behavior, it looks like our examples are
// broken. This server lets us write examples that work in the playground
// without abstracting over HTTP.
type inMemoryServer struct {
server *httptest.Server
listener *memoryListener
}
// newInMemoryServer constructs and starts an inMemoryServer.
func newInMemoryServer(handler http.Handler) *inMemoryServer {
lis := &memoryListener{
conns: make(chan net.Conn),
closed: make(chan struct{}),
}
server := httptest.NewUnstartedServer(handler)
server.Listener = lis
server.EnableHTTP2 = true
server.StartTLS()
return &inMemoryServer{
server: server,
listener: lis,
}
}
// Client returns an HTTP client configured to trust the server's TLS
// certificate and use HTTP/2 over an in-memory pipe. Automatic HTTP-level gzip
// compression is disabled. It closes its idle connections when the server is
// closed.
func (s *inMemoryServer) Client() *http.Client {
client := s.server.Client()
if transport, ok := client.Transport.(*http.Transport); ok {
transport.DialContext = s.listener.DialContext
transport.DisableCompression = true
}
return client
}
// URL is the server's URL.
func (s *inMemoryServer) URL() string {
return s.server.URL
}
// Close shuts down the server, blocking until all outstanding requests have
// completed.
func (s *inMemoryServer) Close() {
s.server.Close()
}
type memoryListener struct {
conns chan net.Conn
once sync.Once
closed chan struct{}
}
// Accept implements net.Listener.
func (l *memoryListener) Accept() (net.Conn, error) {
select {
case conn := <-l.conns:
return conn, nil
case <-l.closed:
return nil, errors.New("listener closed")
}
}
// Close implements net.Listener.
func (l *memoryListener) Close() error {
l.once.Do(func() {
close(l.closed)
})
return nil
}
// Addr implements net.Listener.
func (l *memoryListener) Addr() net.Addr {
return &memoryAddr{}
}
// DialContext is the type expected by http.Transport.DialContext.
func (l *memoryListener) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
select {
case <-l.closed:
return nil, errors.New("listener closed")
default:
}
server, client := net.Pipe()
l.conns <- server
return client, nil
}
type memoryAddr struct{}
// Network implements net.Addr.
func (*memoryAddr) Network() string { return "memory" }
// String implements io.Stringer, returning a value that matches the
// certificates used by net/http/httptest.
func (*memoryAddr) String() string { return "example.com" }