Test coverage for unary (#2393)

diff --git a/protocol/triple/triple_protocol/bench_test.go b/protocol/triple/triple_protocol/bench_test.go
index 28b3ec9..d4b0207 100644
--- a/protocol/triple/triple_protocol/bench_test.go
+++ b/protocol/triple/triple_protocol/bench_test.go
@@ -1,176 +1,177 @@
-// // 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.
+// 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 (
-//	"bytes"
-//	"compress/gzip"
-//	"context"
-//	tri "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
-//	"encoding/json"
-//	"io"
-//	"net/http"
-//	"net/http/httptest"
-//	"strings"
-//	"testing"
-//
-//	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/assert"
-//	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/proto/connect/ping/v1"
-//	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/proto/connect/ping/v1/pingv1connect"
-//)
-//
-//func BenchmarkTriple(b *testing.B) {
-//	mux := http.NewServeMux()
-//	mux.Handle(
-//		pingv1connect.NewPingServiceHandler(
-//			&ExamplePingServer{},
-//		),
-//	)
-//	server := httptest.NewUnstartedServer(mux)
-//	server.EnableHTTP2 = true
-//	server.StartTLS()
-//	defer server.Close()
-//
-//	httpClient := server.Client()
-//	httpTransport, ok := httpClient.Transport.(*http.Transport)
-//	assert.True(b, ok)
-//	httpTransport.DisableCompression = true
-//
-//	client := pingv1connect.NewPingServiceClient(
-//		httpClient,
-//		server.URL,
-//		tri.WithGRPC(),
-//		tri.WithSendGzip(),
-//	)
-//	twoMiB := strings.Repeat("a", 2*1024*1024)
-//	b.ResetTimer()
-//
-//	b.Run("unary", func(b *testing.B) {
-//		b.RunParallel(func(pb *testing.PB) {
-//			for pb.Next() {
-//				_, _ = client.Ping(
-//					context.Background(),
-//					tri.NewRequest(&pingv1.PingRequest{Text: twoMiB}),
-//				)
-//			}
-//		})
-//	})
-//}
-//
-//type ping struct {
-//	Text string `json:"text"`
-//}
-//
-//func BenchmarkREST(b *testing.B) {
-//	handler := func(writer http.ResponseWriter, request *http.Request) {
-//		defer request.Body.Close()
-//		defer func() {
-//			_, err := io.Copy(io.Discard, request.Body)
-//			assert.Nil(b, err)
-//		}()
-//		writer.Header().Set("Content-Type", "application/json")
-//		var body io.Reader = request.Body
-//		if request.Header.Get("Content-Encoding") == "gzip" {
-//			gzipReader, err := gzip.NewReader(body)
-//			if err != nil {
-//				b.Fatalf("get gzip reader: %v", err)
-//			}
-//			defer gzipReader.Close()
-//			body = gzipReader
-//		}
-//		var out io.Writer = writer
-//		if strings.Contains(request.Header.Get("Accept-Encoding"), "gzip") {
-//			writer.Header().Set("Content-Encoding", "gzip")
-//			gzipWriter := gzip.NewWriter(writer)
-//			defer gzipWriter.Close()
-//			out = gzipWriter
-//		}
-//		raw, err := io.ReadAll(body)
-//		if err != nil {
-//			b.Fatalf("read body: %v", err)
-//		}
-//		var pingRequest ping
-//		if err := json.Unmarshal(raw, &pingRequest); err != nil {
-//			b.Fatalf("json unmarshal: %v", err)
-//		}
-//		bs, err := json.Marshal(&pingRequest)
-//		if err != nil {
-//			b.Fatalf("json marshal: %v", err)
-//		}
-//		_, err = out.Write(bs)
-//		assert.Nil(b, err)
-//	}
-//
-//	server := httptest.NewUnstartedServer(http.HandlerFunc(handler))
-//	server.EnableHTTP2 = true
-//	server.StartTLS()
-//	defer server.Close()
-//	twoMiB := strings.Repeat("a", 2*1024*1024)
-//	b.ResetTimer()
-//
-//	b.Run("unary", func(b *testing.B) {
-//		b.RunParallel(func(pb *testing.PB) {
-//			for pb.Next() {
-//				unaryRESTIteration(b, server.Client(), server.URL, twoMiB)
-//			}
-//		})
-//	})
-//}
-//
-//func unaryRESTIteration(b *testing.B, client *http.Client, url string, text string) {
-//	b.Helper()
-//	rawRequestBody := bytes.NewBuffer(nil)
-//	compressedRequestBody := gzip.NewWriter(rawRequestBody)
-//	encoder := json.NewEncoder(compressedRequestBody)
-//	if err := encoder.Encode(&ping{text}); err != nil {
-//		b.Fatalf("marshal request: %v", err)
-//	}
-//	compressedRequestBody.Close()
-//	request, err := http.NewRequestWithContext(
-//		context.Background(),
-//		http.MethodPost,
-//		url,
-//		rawRequestBody,
-//	)
-//	if err != nil {
-//		b.Fatalf("construct request: %v", err)
-//	}
-//	request.Header.Set("Content-Encoding", "gzip")
-//	request.Header.Set("Accept-Encoding", "gzip")
-//	request.Header.Set("Content-Type", "application/json")
-//	response, err := client.Do(request)
-//	if err != nil {
-//		b.Fatalf("do request: %v", err)
-//	}
-//	defer func() {
-//		_, err := io.Copy(io.Discard, response.Body)
-//		assert.Nil(b, err)
-//	}()
-//	if response.StatusCode != http.StatusOK {
-//		b.Fatalf("response status: %v", response.Status)
-//	}
-//	uncompressed, err := gzip.NewReader(response.Body)
-//	if err != nil {
-//		b.Fatalf("uncompress response: %v", err)
-//	}
-//	raw, err := io.ReadAll(uncompressed)
-//	if err != nil {
-//		b.Fatalf("read response: %v", err)
-//	}
-//	var got ping
-//	if err := json.Unmarshal(raw, &got); err != nil {
-//		b.Fatalf("unmarshal: %v", err)
-//	}
-//}
+import (
+	"bytes"
+	"compress/gzip"
+	"context"
+	"encoding/json"
+	"io"
+	"net/http"
+	"net/http/httptest"
+	"strings"
+	"testing"
+
+	tri "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
+	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1"
+
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/assert"
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1/pingv1connect"
+)
+
+func BenchmarkTriple(b *testing.B) {
+	mux := http.NewServeMux()
+	mux.Handle(
+		pingv1connect.NewPingServiceHandler(
+			&ExamplePingServer{},
+		),
+	)
+	server := httptest.NewUnstartedServer(mux)
+	server.EnableHTTP2 = true
+	server.StartTLS()
+	defer server.Close()
+
+	httpClient := server.Client()
+	httpTransport, ok := httpClient.Transport.(*http.Transport)
+	assert.True(b, ok)
+	httpTransport.DisableCompression = true
+
+	client := pingv1connect.NewPingServiceClient(
+		httpClient,
+		server.URL,
+		tri.WithGRPC(),
+		tri.WithSendGzip(),
+	)
+	twoMiB := strings.Repeat("a", 2*1024*1024)
+	b.ResetTimer()
+
+	b.Run("unary", func(b *testing.B) {
+		b.RunParallel(func(pb *testing.PB) {
+			for pb.Next() {
+				_ = client.Ping(
+					context.Background(),
+					tri.NewRequest(&pingv1.PingRequest{Text: twoMiB}),
+					tri.NewResponse(&pingv1.PingResponse{}),
+				)
+			}
+		})
+	})
+}
+
+type ping struct {
+	Text string `json:"text"`
+}
+
+func BenchmarkREST(b *testing.B) {
+	handler := func(writer http.ResponseWriter, request *http.Request) {
+		defer request.Body.Close()
+		defer func() {
+			_, err := io.Copy(io.Discard, request.Body)
+			assert.Nil(b, err)
+		}()
+		writer.Header().Set("Content-Type", "application/json")
+		var body io.Reader = request.Body
+		if request.Header.Get("Content-Encoding") == "gzip" {
+			gzipReader, err := gzip.NewReader(body)
+			if err != nil {
+				b.Fatalf("get gzip reader: %v", err)
+			}
+			defer gzipReader.Close()
+			body = gzipReader
+		}
+		var out io.Writer = writer
+		if strings.Contains(request.Header.Get("Accept-Encoding"), "gzip") {
+			writer.Header().Set("Content-Encoding", "gzip")
+			gzipWriter := gzip.NewWriter(writer)
+			defer gzipWriter.Close()
+			out = gzipWriter
+		}
+		raw, err := io.ReadAll(body)
+		if err != nil {
+			b.Fatalf("read body: %v", err)
+		}
+		var pingRequest ping
+		if err := json.Unmarshal(raw, &pingRequest); err != nil {
+			b.Fatalf("json unmarshal: %v", err)
+		}
+		bs, err := json.Marshal(&pingRequest)
+		if err != nil {
+			b.Fatalf("json marshal: %v", err)
+		}
+		_, err = out.Write(bs)
+		assert.Nil(b, err)
+	}
+
+	server := httptest.NewUnstartedServer(http.HandlerFunc(handler))
+	server.EnableHTTP2 = true
+	server.StartTLS()
+	defer server.Close()
+	twoMiB := strings.Repeat("a", 2*1024*1024)
+	b.ResetTimer()
+
+	b.Run("unary", func(b *testing.B) {
+		b.RunParallel(func(pb *testing.PB) {
+			for pb.Next() {
+				unaryRESTIteration(b, server.Client(), server.URL, twoMiB)
+			}
+		})
+	})
+}
+
+func unaryRESTIteration(b *testing.B, client *http.Client, url string, text string) {
+	b.Helper()
+	rawRequestBody := bytes.NewBuffer(nil)
+	compressedRequestBody := gzip.NewWriter(rawRequestBody)
+	encoder := json.NewEncoder(compressedRequestBody)
+	if err := encoder.Encode(&ping{text}); err != nil {
+		b.Fatalf("marshal request: %v", err)
+	}
+	compressedRequestBody.Close()
+	request, err := http.NewRequestWithContext(
+		context.Background(),
+		http.MethodPost,
+		url,
+		rawRequestBody,
+	)
+	if err != nil {
+		b.Fatalf("construct request: %v", err)
+	}
+	request.Header.Set("Content-Encoding", "gzip")
+	request.Header.Set("Accept-Encoding", "gzip")
+	request.Header.Set("Content-Type", "application/json")
+	response, err := client.Do(request)
+	if err != nil {
+		b.Fatalf("do request: %v", err)
+	}
+	defer func() {
+		_, err := io.Copy(io.Discard, response.Body)
+		assert.Nil(b, err)
+	}()
+	if response.StatusCode != http.StatusOK {
+		b.Fatalf("response status: %v", response.Status)
+	}
+	uncompressed, err := gzip.NewReader(response.Body)
+	if err != nil {
+		b.Fatalf("uncompress response: %v", err)
+	}
+	raw, err := io.ReadAll(uncompressed)
+	if err != nil {
+		b.Fatalf("read response: %v", err)
+	}
+	var got ping
+	if err := json.Unmarshal(raw, &got); err != nil {
+		b.Fatalf("unmarshal: %v", err)
+	}
+}
diff --git a/protocol/triple/triple_protocol/client_example_test.go b/protocol/triple/triple_protocol/client_example_test.go
index fa40d91..061a7e5 100644
--- a/protocol/triple/triple_protocol/client_example_test.go
+++ b/protocol/triple/triple_protocol/client_example_test.go
@@ -1,57 +1,55 @@
-// // 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.
+// 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"
-//	tri "dubbo.apache.org/dubbo-go/v3/protocol//triple/triple_protocol"
-//	"log"
-//	"net/http"
-//	"os"
-//
-//	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/proto/connect/ping/v1"
-//	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/proto/connect/ping/v1/pingv1connect"
-//)
-//
-//func Example_client() {
-//	logger := log.New(os.Stdout, "" /* prefix */, 0 /* flags */)
-//	// Unfortunately, pkg.go.dev can't run examples that actually use the
-//	// network. To keep this example runnable, we'll use an HTTP server and
-//	// client that communicate over in-memory pipes. The client is still a plain
-//	// *http.Client!
-//	var httpClient *http.Client = examplePingServer.Client()
-//
-//	// By default, clients use the Connect protocol. Add connect.WithGRPC() or
-//	// connect.WithGRPCWeb() to switch protocols.
-//	client := pingv1connect.NewPingServiceClient(
-//		httpClient,
-//		examplePingServer.URL(),
-//	)
-//	response, err := client.Ping(
-//		context.Background(),
-//		tri.NewRequest(&pingv1.PingRequest{Number: 42}),
-//	)
-//	if err != nil {
-//		logger.Println("error:", err)
-//		return
-//	}
-//	logger.Println("response content-type:", response.Header().Get("Content-Type"))
-//	logger.Println("response message:", response.Msg)
-//
-//	// Output:
-//	// response content-type: application/proto
-//	// response message: number:42
-//}
+import (
+	"context"
+	"log"
+	"os"
+
+	tri "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
+	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1"
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1/pingv1connect"
+)
+
+func Example_client() {
+	logger := log.New(os.Stdout, "" /* prefix */, 0 /* flags */)
+	// Unfortunately, pkg.go.dev can't run examples that actually use the
+	// network. To keep this example runnable, we'll use an HTTP server and
+	// client that communicate over in-memory pipes. The client is still a plain
+	// *http.Client!
+	httpClient := examplePingServer.Client()
+
+	// By default, clients use the Triple protocol. Add triple.WithGRPC() or
+	// triple.WithGRPCWeb() to switch protocols.
+	client := pingv1connect.NewPingServiceClient(
+		httpClient,
+		examplePingServer.URL(),
+	)
+	response := tri.NewResponse(&pingv1.PingResponse{})
+	if err := client.Ping(
+		context.Background(),
+		tri.NewRequest(&pingv1.PingRequest{Number: 42}),
+		response,
+	); err != nil {
+		logger.Println("error:", err)
+		return
+	}
+	logger.Println("response content-type:", response.Header().Get("Content-Type"))
+	logger.Println("response message:", response.Msg)
+
+	// Output:
+	// response content-type: application/proto
+	// response message: number:42
+}
diff --git a/protocol/triple/triple_protocol/client_ext_test.go b/protocol/triple/triple_protocol/client_ext_test.go
index 77909c1..a751af8 100644
--- a/protocol/triple/triple_protocol/client_ext_test.go
+++ b/protocol/triple/triple_protocol/client_ext_test.go
@@ -1,181 +1,157 @@
-// // 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.
+// 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"
-//	"dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/triple"
-//	"errors"
-//	"net/http"
-//	"net/http/httptest"
-//	"strings"
-//	"testing"
-//
-//	"dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/assert"
-//	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/proto/connect/ping/v1"
-//	"dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/proto/connect/ping/v1/pingv1connect"
-//)
-//
-//func TestNewClient_InitFailure(t *testing.T) {
-//	t.Parallel()
-//	client := pingv1connect.NewPingServiceClient(
-//		http.DefaultClient,
-//		"http://127.0.0.1:8080",
-//		// This triggers an error during initialization, so each call will short circuit returning an error.
-//		triple.WithSendCompression("invalid"),
-//	)
-//	validateExpectedError := func(t *testing.T, err error) {
-//		t.Helper()
-//		assert.NotNil(t, err)
-//		var connectErr *triple.Error
-//		assert.True(t, errors.As(err, &connectErr))
-//		assert.Equal(t, connectErr.Message(), `unknown compression "invalid"`)
-//	}
-//
-//	t.Run("unary", func(t *testing.T) {
-//		t.Parallel()
-//		_, err := client.Ping(context.Background(), triple.NewRequest(&pingv1.PingRequest{}))
-//		validateExpectedError(t, err)
-//	})
-//
-//	t.Run("bidi", func(t *testing.T) {
-//		t.Parallel()
-//		bidiStream, err := client.CumSum(context.Background())
-//		validateExpectedError(t, err)
-//		err = bidiStream.Send(&pingv1.CumSumRequest{})
-//		validateExpectedError(t, err)
-//	})
-//
-//	t.Run("client_stream", func(t *testing.T) {
-//		t.Parallel()
-//		clientStream, err := client.Sum(context.Background())
-//		validateExpectedError(t, err)
-//		err = clientStream.Send(&pingv1.SumRequest{})
-//		validateExpectedError(t, err)
-//	})
-//
-//	t.Run("server_stream", func(t *testing.T) {
-//		t.Parallel()
-//		_, err := client.CountUp(context.Background(), triple.NewRequest(&pingv1.CountUpRequest{Number: 3}))
-//		validateExpectedError(t, err)
-//	})
-//}
-//
-//func TestClientPeer(t *testing.T) {
-//	t.Parallel()
-//	mux := http.NewServeMux()
-//	mux.Handle(pingv1connect.NewPingServiceHandler(pingServer{}))
-//	server := httptest.NewUnstartedServer(mux)
-//	server.EnableHTTP2 = true
-//	server.StartTLS()
-//	t.Cleanup(server.Close)
-//
-//	run := func(t *testing.T, opts ...triple.ClientOption) {
-//		t.Helper()
-//		client := pingv1connect.NewPingServiceClient(
-//			server.Client(),
-//			server.URL,
-//			triple.WithClientOptions(opts...),
-//			triple.WithInterceptors(&assertPeerInterceptor{t}),
-//		)
-//		ctx := context.Background()
-//		// unary
-//		_, err := client.Ping(ctx, triple.NewRequest[pingv1.PingRequest](nil))
-//		assert.Nil(t, err)
-//		text := strings.Repeat(".", 256)
-//		r, err := client.Ping(ctx, triple.NewRequest(&pingv1.PingRequest{Text: text}))
-//		assert.Nil(t, err)
-//		assert.Equal(t, r.Msg.Text, text)
-//		// client streaming
-//		clientStream, err := client.Sum(ctx)
-//		assert.Nil(t, err)
-//		t.Cleanup(func() {
-//			_, closeErr := clientStream.CloseAndReceive()
-//			assert.Nil(t, closeErr)
-//		})
-//		assert.NotZero(t, clientStream.Peer().Addr)
-//		assert.NotZero(t, clientStream.Peer().Protocol)
-//		err = clientStream.Send(&pingv1.SumRequest{})
-//		assert.Nil(t, err)
-//		// server streaming
-//		serverStream, err := client.CountUp(ctx, triple.NewRequest(&pingv1.CountUpRequest{}))
-//		t.Cleanup(func() {
-//			assert.Nil(t, serverStream.Close())
-//		})
-//		assert.Nil(t, err)
-//		// bidi streaming
-//		bidiStream, err := client.CumSum(ctx)
-//		assert.Nil(t, err)
-//		t.Cleanup(func() {
-//			assert.Nil(t, bidiStream.CloseRequest())
-//			assert.Nil(t, bidiStream.CloseResponse())
-//		})
-//		assert.NotZero(t, bidiStream.Peer().Addr)
-//		assert.NotZero(t, bidiStream.Peer().Protocol)
-//		err = bidiStream.Send(&pingv1.CumSumRequest{})
-//		assert.Nil(t, err)
-//	}
-//
-//	t.Run("connect", func(t *testing.T) {
-//		t.Parallel()
-//		run(t)
-//	})
-//	t.Run("connect+get", func(t *testing.T) {
-//		t.Parallel()
-//		run(t,
-//			triple.WithHTTPGet(),
-//			triple.WithSendGzip(),
-//		)
-//	})
-//	t.Run("grpc", func(t *testing.T) {
-//		t.Parallel()
-//		run(t, triple.WithGRPC())
-//	})
-//	t.Run("grpcweb", func(t *testing.T) {
-//		t.Parallel()
-//		run(t, triple.WithGRPCWeb())
-//	})
-//}
-//
-//type assertPeerInterceptor struct {
-//	tb testing.TB
-//}
-//
-//func (a *assertPeerInterceptor) WrapUnary(next triple.UnaryFunc) triple.UnaryFunc {
-//	return func(ctx context.Context, req triple.AnyRequest) (triple.AnyResponse, error) {
-//		assert.NotZero(a.tb, req.Peer().Addr)
-//		assert.NotZero(a.tb, req.Peer().Protocol)
-//		return next(ctx, req)
-//	}
-//}
-//
-//func (a *assertPeerInterceptor) WrapStreamingClient(next triple.StreamingClientFunc) triple.StreamingClientFunc {
-//	return func(ctx context.Context, spec triple.Spec) triple.StreamingClientConn {
-//		conn := next(ctx, spec)
-//		assert.NotZero(a.tb, conn.Peer().Addr)
-//		assert.NotZero(a.tb, conn.Peer().Protocol)
-//		assert.NotZero(a.tb, conn.Spec())
-//		return conn
-//	}
-//}
-//
-//func (a *assertPeerInterceptor) WrapStreamingHandler(next triple.StreamingHandlerFunc) triple.StreamingHandlerFunc {
-//	return func(ctx context.Context, conn triple.StreamingHandlerConn) error {
-//		assert.NotZero(a.tb, conn.Peer().Addr)
-//		assert.NotZero(a.tb, conn.Peer().Protocol)
-//		assert.NotZero(a.tb, conn.Spec())
-//		return next(ctx, conn)
-//	}
-//}
+import (
+	"context"
+	"errors"
+	"net/http"
+	"net/http/httptest"
+	"strings"
+	"testing"
+
+	triple "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/assert"
+	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1"
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1/pingv1connect"
+)
+
+func TestNewClient_InitFailure(t *testing.T) {
+	t.Parallel()
+	client := pingv1connect.NewPingServiceClient(
+		http.DefaultClient,
+		"http://127.0.0.1:8080",
+		// This triggers an error during initialization, so each call will short circuit returning an error.
+		triple.WithSendCompression("invalid"),
+	)
+	validateExpectedError := func(t *testing.T, err error) {
+		t.Helper()
+		assert.NotNil(t, err)
+		var tripleErr *triple.Error
+		assert.True(t, errors.As(err, &tripleErr))
+		assert.Equal(t, tripleErr.Message(), `unknown compression "invalid"`)
+	}
+
+	t.Run("unary", func(t *testing.T) {
+		t.Parallel()
+		err := client.Ping(context.Background(), triple.NewRequest(&pingv1.PingRequest{}), triple.NewResponse(&pingv1.PingResponse{}))
+		validateExpectedError(t, err)
+	})
+}
+
+func TestClientPeer(t *testing.T) {
+	t.Parallel()
+	mux := http.NewServeMux()
+	mux.Handle(pingv1connect.NewPingServiceHandler(pingServer{}))
+	server := httptest.NewUnstartedServer(mux)
+	server.EnableHTTP2 = true
+	server.StartTLS()
+	t.Cleanup(server.Close)
+
+	run := func(t *testing.T, opts ...triple.ClientOption) {
+		t.Helper()
+		client := pingv1connect.NewPingServiceClient(
+			server.Client(),
+			server.URL,
+			triple.WithClientOptions(opts...),
+			triple.WithInterceptors(&assertPeerInterceptor{t}),
+		)
+		ctx := context.Background()
+		// unary
+		var message *pingv1.PingRequest
+		err := client.Ping(ctx, triple.NewRequest(message), triple.NewResponse(&pingv1.PingResponse{}))
+		assert.Nil(t, err)
+		text := strings.Repeat(".", 256)
+		msg := &pingv1.PingResponse{}
+		err = client.Ping(ctx, triple.NewRequest(&pingv1.PingRequest{Text: text}), triple.NewResponse(msg))
+		assert.Nil(t, err)
+		assert.Equal(t, msg.Text, text)
+		////client streaming
+		//clientStream, err := client.Sum(ctx)
+		//assert.Nil(t, err)
+		//t.Cleanup(func() {
+		//	closeErr := clientStream.CloseAndReceive(triple.NewResponse(&pingv1.SumResponse{}))
+		//	assert.Nil(t, closeErr)
+		//})
+		//assert.NotZero(t, clientStream.Peer().Addr)
+		//assert.NotZero(t, clientStream.Peer().Protocol)
+		//err = clientStream.Send(&pingv1.SumRequest{})
+		//assert.Nil(t, err)
+		////server streaming
+		//serverStream, err := client.CountUp(ctx, triple.NewRequest(&pingv1.CountUpRequest{}))
+		//t.Cleanup(func() {
+		//	assert.Nil(t, serverStream.Close())
+		//})
+		//assert.Nil(t, err)
+		//// bidi streaming
+		//bidiStream, err := client.CumSum(ctx)
+		//assert.Nil(t, err)
+		//t.Cleanup(func() {
+		//	assert.Nil(t, bidiStream.CloseRequest())
+		//	assert.Nil(t, bidiStream.CloseResponse())
+		//})
+		//assert.NotZero(t, bidiStream.Peer().Addr)
+		//assert.NotZero(t, bidiStream.Peer().Protocol)
+		//err = bidiStream.Send(&pingv1.CumSumRequest{})
+		//assert.Nil(t, err)
+	}
+
+	t.Run("triple", func(t *testing.T) {
+		t.Parallel()
+		run(t)
+	})
+	t.Run("grpc", func(t *testing.T) {
+		t.Parallel()
+		run(t, triple.WithGRPC())
+	})
+}
+
+type assertPeerInterceptor struct {
+	tb testing.TB
+}
+
+func (a *assertPeerInterceptor) WrapUnaryHandler(next triple.UnaryHandlerFunc) triple.UnaryHandlerFunc {
+	return func(ctx context.Context, req triple.AnyRequest) (triple.AnyResponse, error) {
+		assert.NotZero(a.tb, req.Peer().Addr)
+		assert.NotZero(a.tb, req.Peer().Protocol)
+		return next(ctx, req)
+	}
+}
+
+func (a *assertPeerInterceptor) WrapUnary(next triple.UnaryFunc) triple.UnaryFunc {
+	return func(ctx context.Context, req triple.AnyRequest, res triple.AnyResponse) error {
+		assert.NotZero(a.tb, req.Peer().Addr)
+		assert.NotZero(a.tb, req.Peer().Protocol)
+		return next(ctx, req, res)
+	}
+}
+
+func (a *assertPeerInterceptor) WrapStreamingClient(next triple.StreamingClientFunc) triple.StreamingClientFunc {
+	return func(ctx context.Context, spec triple.Spec) triple.StreamingClientConn {
+		conn := next(ctx, spec)
+		assert.NotZero(a.tb, conn.Peer().Addr)
+		assert.NotZero(a.tb, conn.Peer().Protocol)
+		assert.NotZero(a.tb, conn.Spec())
+		return conn
+	}
+}
+
+func (a *assertPeerInterceptor) WrapStreamingHandler(next triple.StreamingHandlerFunc) triple.StreamingHandlerFunc {
+	return func(ctx context.Context, conn triple.StreamingHandlerConn) error {
+		assert.NotZero(a.tb, conn.Peer().Addr)
+		assert.NotZero(a.tb, conn.Peer().Protocol)
+		assert.NotZero(a.tb, conn.Spec())
+		return next(ctx, conn)
+	}
+}
diff --git a/protocol/triple/triple_protocol/client_get_fallback_test.go b/protocol/triple/triple_protocol/client_get_fallback_test.go
deleted file mode 100644
index 22e333b..0000000
--- a/protocol/triple/triple_protocol/client_get_fallback_test.go
+++ /dev/null
@@ -1,62 +0,0 @@
-// // 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
-
-//
-//import (
-//	"context"
-//	"net/http"
-//	"net/http/httptest"
-//	"strings"
-//	"testing"
-//
-//	"dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/assert"
-//	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/proto/connect/ping/v1"
-//)
-//
-//func TestClientUnaryGetFallback(t *testing.T) {
-//	t.Parallel()
-//	mux := http.NewServeMux()
-//	mux.Handle("/connect.ping.v1.PingService/Ping", NewUnaryHandler(
-//		"/connect.ping.v1.PingService/Ping",
-//		func(ctx context.Context, r *Request[pingv1.PingRequest]) (*Response[pingv1.PingResponse], error) {
-//			return NewResponse(&pingv1.PingResponse{
-//				Number: r.Msg.Number,
-//				Text:   r.Msg.Text,
-//			}), nil
-//		},
-//		WithIdempotency(IdempotencyNoSideEffects),
-//	))
-//	server := httptest.NewUnstartedServer(mux)
-//	server.EnableHTTP2 = true
-//	server.StartTLS()
-//	t.Cleanup(server.Close)
-//
-//	client := NewClient[pingv1.PingRequest, pingv1.PingResponse](
-//		server.Client(),
-//		server.URL+"/connect.ping.v1.PingService/Ping",
-//		WithHTTPGet(),
-//		withHTTPGetMaxURLSize(1, true),
-//		WithSendGzip(),
-//	)
-//	ctx := context.Background()
-//
-//	_, err := client.CallUnary(ctx, NewRequest[pingv1.PingRequest](nil))
-//	assert.Nil(t, err)
-//
-//	text := strings.Repeat(".", 256)
-//	r, err := client.CallUnary(ctx, NewRequest(&pingv1.PingRequest{Text: text}))
-//	assert.Nil(t, err)
-//	assert.Equal(t, r.Msg.Text, text)
-//}
diff --git a/protocol/triple/triple_protocol/client_stream_test.go b/protocol/triple/triple_protocol/client_stream_test.go
index 506e91f..f68395e 100644
--- a/protocol/triple/triple_protocol/client_stream_test.go
+++ b/protocol/triple/triple_protocol/client_stream_test.go
@@ -1,106 +1,103 @@
-// // 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.
+// 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
 
-//
-//import (
-//	"errors"
-//	"fmt"
-//	"net/http"
-//	"testing"
-//
-//	"dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/assert"
-//	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/proto/connect/ping/v1"
-//)
-//
-//func TestClientStreamForClient_NoPanics(t *testing.T) {
-//	t.Parallel()
-//	initErr := errors.New("client init failure")
-//	clientStream := &ClientStreamForClient[pingv1.PingRequest, pingv1.PingResponse]{err: initErr}
-//	assert.ErrorIs(t, clientStream.Send(&pingv1.PingRequest{}), initErr)
-//	verifyHeaders(t, clientStream.RequestHeader())
-//	res, err := clientStream.CloseAndReceive()
-//	assert.Nil(t, res)
-//	assert.ErrorIs(t, err, initErr)
-//	conn, err := clientStream.Conn()
-//	assert.NotNil(t, err)
-//	assert.Nil(t, conn)
-//}
-//
-//func TestServerStreamForClient_NoPanics(t *testing.T) {
-//	t.Parallel()
-//	initErr := errors.New("client init failure")
-//	serverStream := &ServerStreamForClient[pingv1.PingResponse]{constructErr: initErr}
-//	assert.ErrorIs(t, serverStream.Err(), initErr)
-//	assert.ErrorIs(t, serverStream.Close(), initErr)
-//	assert.NotNil(t, serverStream.Msg())
-//	assert.False(t, serverStream.Receive())
-//	verifyHeaders(t, serverStream.ResponseHeader())
-//	verifyHeaders(t, serverStream.ResponseTrailer())
-//	conn, err := serverStream.Conn()
-//	assert.NotNil(t, err)
-//	assert.Nil(t, conn)
-//}
-//
-//func TestServerStreamForClient(t *testing.T) {
-//	t.Parallel()
-//	stream := &ServerStreamForClient[pingv1.PingResponse]{conn: &nopStreamingClientConn{}}
-//	// Ensure that each call to Receive allocates a new message. This helps
-//	// vtprotobuf, which doesn't automatically zero messages before unmarshaling
-//	// (see https://github.com/bufbuild/connect-go/issues/345), and it's also
-//	// less error-prone for users.
-//	assert.True(t, stream.Receive())
-//	first := fmt.Sprintf("%p", stream.Msg())
-//	assert.True(t, stream.Receive())
-//	second := fmt.Sprintf("%p", stream.Msg())
-//	assert.NotEqual(t, first, second)
-//	conn, err := stream.Conn()
-//	assert.Nil(t, err)
-//	assert.NotNil(t, conn)
-//}
-//
-//func TestBidiStreamForClient_NoPanics(t *testing.T) {
-//	t.Parallel()
-//	initErr := errors.New("client init failure")
-//	bidiStream := &BidiStreamForClient[pingv1.CumSumRequest, pingv1.CumSumResponse]{err: initErr}
-//	res, err := bidiStream.Receive()
-//	assert.Nil(t, res)
-//	assert.ErrorIs(t, err, initErr)
-//	verifyHeaders(t, bidiStream.RequestHeader())
-//	verifyHeaders(t, bidiStream.ResponseHeader())
-//	verifyHeaders(t, bidiStream.ResponseTrailer())
-//	assert.ErrorIs(t, bidiStream.Send(&pingv1.CumSumRequest{}), initErr)
-//	assert.ErrorIs(t, bidiStream.CloseRequest(), initErr)
-//	assert.ErrorIs(t, bidiStream.CloseResponse(), initErr)
-//	conn, err := bidiStream.Conn()
-//	assert.NotNil(t, err)
-//	assert.Nil(t, conn)
-//}
-//
-//func verifyHeaders(t *testing.T, headers http.Header) {
-//	t.Helper()
-//	assert.Equal(t, headers, http.Header{})
-//
-//	// Verify set/del don't panic
-//	headers.Set("a", "b")
-//	headers.Del("a")
-//}
-//
-//type nopStreamingClientConn struct {
-//	StreamingClientConn
-//}
-//
-//func (c *nopStreamingClientConn) Receive(msg any) error {
-//	return nil
-//}
+import (
+	"errors"
+	"fmt"
+	"net/http"
+	"testing"
+
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/assert"
+	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1"
+)
+
+func TestClientStreamForClient_NoPanics(t *testing.T) {
+	t.Parallel()
+	initErr := errors.New("client init failure")
+	clientStream := &ClientStreamForClient{err: initErr}
+	assert.ErrorIs(t, clientStream.Send(&pingv1.PingRequest{}), initErr)
+	verifyHeaders(t, clientStream.RequestHeader())
+	res := NewResponse(&pingv1.PingResponse{})
+	err := clientStream.CloseAndReceive(res)
+	assert.ErrorIs(t, err, initErr)
+	conn, err := clientStream.Conn()
+	assert.NotNil(t, err)
+	assert.Nil(t, conn)
+}
+
+func TestServerStreamForClient_NoPanics(t *testing.T) {
+	t.Parallel()
+	initErr := errors.New("client init failure")
+	serverStream := &ServerStreamForClient{constructErr: initErr}
+	assert.ErrorIs(t, serverStream.Err(), initErr)
+	assert.ErrorIs(t, serverStream.Close(), initErr)
+	assert.Nil(t, serverStream.Msg())
+	assert.False(t, serverStream.Receive(NewResponse(&pingv1.PingResponse{})))
+	verifyHeaders(t, serverStream.ResponseHeader())
+	verifyHeaders(t, serverStream.ResponseTrailer())
+	conn, err := serverStream.Conn()
+	assert.NotNil(t, err)
+	assert.Nil(t, conn)
+}
+
+func TestServerStreamForClient(t *testing.T) {
+	t.Parallel()
+	stream := &ServerStreamForClient{conn: &nopStreamingClientConn{}}
+	res := NewResponse(&pingv1.PingResponse{})
+	assert.True(t, stream.Receive(res))
+	first := fmt.Sprintf("%p", stream.Msg())
+	res1 := NewResponse(&pingv1.PingResponse{})
+	assert.True(t, stream.Receive(res1))
+	second := fmt.Sprintf("%p", stream.Msg())
+	assert.NotEqual(t, first, second)
+	conn, err := stream.Conn()
+	assert.Nil(t, err)
+	assert.NotNil(t, conn)
+}
+
+func TestBidiStreamForClient_NoPanics(t *testing.T) {
+	t.Parallel()
+	initErr := errors.New("client init failure")
+	bidiStream := &BidiStreamForClient{err: initErr}
+	res := NewResponse(&pingv1.CumSumResponse{})
+	err := bidiStream.Receive(res)
+	assert.ErrorIs(t, err, initErr)
+	verifyHeaders(t, bidiStream.RequestHeader())
+	verifyHeaders(t, bidiStream.ResponseHeader())
+	verifyHeaders(t, bidiStream.ResponseTrailer())
+	assert.ErrorIs(t, bidiStream.Send(&pingv1.CumSumRequest{}), initErr)
+	assert.ErrorIs(t, bidiStream.CloseRequest(), initErr)
+	assert.ErrorIs(t, bidiStream.CloseResponse(), initErr)
+	conn, err := bidiStream.Conn()
+	assert.NotNil(t, err)
+	assert.Nil(t, conn)
+}
+
+func verifyHeaders(t *testing.T, headers http.Header) {
+	t.Helper()
+	assert.Equal(t, headers, http.Header{})
+
+	// Verify set/del don't panic
+	headers.Set("a", "b")
+	headers.Del("a")
+}
+
+type nopStreamingClientConn struct {
+	StreamingClientConn
+}
+
+func (c *nopStreamingClientConn) Receive(msg any) error {
+	return nil
+}
diff --git a/protocol/triple/triple_protocol/code_test.go b/protocol/triple/triple_protocol/code_test.go
index 89c8ca4..2273bd3 100644
--- a/protocol/triple/triple_protocol/code_test.go
+++ b/protocol/triple/triple_protocol/code_test.go
@@ -18,10 +18,8 @@
 	"strconv"
 	"strings"
 	"testing"
-)
 
-import (
-	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/assert"
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/assert"
 )
 
 func TestCode(t *testing.T) {
diff --git a/protocol/triple/triple_protocol/codec.go b/protocol/triple/triple_protocol/codec.go
index e3ba583..ef749ac 100644
--- a/protocol/triple/triple_protocol/codec.go
+++ b/protocol/triple/triple_protocol/codec.go
@@ -220,7 +220,7 @@
 
 func errNotProto(message any) error {
 	if _, ok := message.(protoiface.MessageV1); ok {
-		return fmt.Errorf("%T uses github.com/golang/protobuf, but connect-go only supports google.golang.org/protobuf: see https://go.dev/blog/protobuf-apiv2", message)
+		return fmt.Errorf("%T uses github.com/golang/protobuf, but triple only supports google.golang.org/protobuf: see https://go.dev/blog/protobuf-apiv2", message)
 	}
 	return fmt.Errorf("%T doesn't implement proto.Message", message)
 }
diff --git a/protocol/triple/triple_protocol/codec_test.go b/protocol/triple/triple_protocol/codec_test.go
index 6793d16..d505f24 100644
--- a/protocol/triple/triple_protocol/codec_test.go
+++ b/protocol/triple/triple_protocol/codec_test.go
@@ -1,112 +1,111 @@
-// // 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.
+// 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
 
-//
-//import (
-//	"bytes"
-//	"strings"
-//	"testing"
-//	"testing/quick"
-//
-//	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/assert"
-//	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/proto/connect/ping/v1"
-//	"google.golang.org/protobuf/proto"
-//	"google.golang.org/protobuf/types/known/emptypb"
-//	"google.golang.org/protobuf/types/known/structpb"
-//)
-//
-//func convertMapToInterface(stringMap map[string]string) map[string]interface{} {
-//	interfaceMap := make(map[string]interface{})
-//	for key, value := range stringMap {
-//		interfaceMap[key] = value
-//	}
-//	return interfaceMap
-//}
-//
-//func TestCodecRoundTrips(t *testing.T) {
-//	t.Parallel()
-//	makeRoundtrip := func(codec Codec) func(string, int64) bool {
-//		return func(text string, number int64) bool {
-//			got := pingv1.PingRequest{}
-//			want := pingv1.PingRequest{Text: text, Number: number}
-//			data, err := codec.Marshal(&want)
-//			if err != nil {
-//				t.Fatal(err)
-//			}
-//			err = codec.Unmarshal(data, &got)
-//			if err != nil {
-//				t.Fatal(err)
-//			}
-//			return proto.Equal(&got, &want)
-//		}
-//	}
-//	if err := quick.Check(makeRoundtrip(&protoBinaryCodec{}), nil /* config */); err != nil {
-//		t.Error(err)
-//	}
-//	if err := quick.Check(makeRoundtrip(&protoJSONCodec{}), nil /* config */); err != nil {
-//		t.Error(err)
-//	}
-//}
-//
-//func TestStableCodec(t *testing.T) {
-//	t.Parallel()
-//	makeRoundtrip := func(codec stableCodec) func(map[string]string) bool {
-//		return func(input map[string]string) bool {
-//			initialProto, err := structpb.NewStruct(convertMapToInterface(input))
-//			if err != nil {
-//				t.Fatal(err)
-//			}
-//			want, err := codec.MarshalStable(initialProto)
-//			if err != nil {
-//				t.Fatal(err)
-//			}
-//			for i := 0; i < 10; i++ {
-//				roundtripProto := &structpb.Struct{}
-//				err = codec.Unmarshal(want, roundtripProto)
-//				if err != nil {
-//					t.Fatal(err)
-//				}
-//				got, err := codec.MarshalStable(roundtripProto)
-//				if err != nil {
-//					t.Fatal(err)
-//				}
-//				if !bytes.Equal(got, want) {
-//					return false
-//				}
-//			}
-//			return true
-//		}
-//	}
-//	if err := quick.Check(makeRoundtrip(&protoBinaryCodec{}), nil /* config */); err != nil {
-//		t.Error(err)
-//	}
-//	if err := quick.Check(makeRoundtrip(&protoJSONCodec{}), nil /* config */); err != nil {
-//		t.Error(err)
-//	}
-//}
-//
-//func TestJSONCodec(t *testing.T) {
-//	t.Parallel()
-//
-//	var empty emptypb.Empty
-//	codec := &protoJSONCodec{name: "json"}
-//	err := codec.Unmarshal([]byte{}, &empty)
-//	assert.NotNil(t, err)
-//	assert.True(
-//		t,
-//		strings.Contains(err.Error(), "valid JSON"),
-//		assert.Sprintf(`error message should explain that "" is not a valid JSON object`),
-//	)
-//}
+import (
+	"bytes"
+	"strings"
+	"testing"
+	"testing/quick"
+
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/assert"
+	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1"
+	"google.golang.org/protobuf/proto"
+	"google.golang.org/protobuf/types/known/emptypb"
+	"google.golang.org/protobuf/types/known/structpb"
+)
+
+func convertMapToInterface(stringMap map[string]string) map[string]interface{} {
+	interfaceMap := make(map[string]interface{})
+	for key, value := range stringMap {
+		interfaceMap[key] = value
+	}
+	return interfaceMap
+}
+
+func TestCodecRoundTrips(t *testing.T) {
+	t.Parallel()
+	makeRoundtrip := func(codec Codec) func(string, int64) bool {
+		return func(text string, number int64) bool {
+			got := pingv1.PingRequest{}
+			want := pingv1.PingRequest{Text: text, Number: number}
+			data, err := codec.Marshal(&want)
+			if err != nil {
+				t.Fatal(err)
+			}
+			err = codec.Unmarshal(data, &got)
+			if err != nil {
+				t.Fatal(err)
+			}
+			return proto.Equal(&got, &want)
+		}
+	}
+	if err := quick.Check(makeRoundtrip(&protoBinaryCodec{}), nil /* config */); err != nil {
+		t.Error(err)
+	}
+	if err := quick.Check(makeRoundtrip(&protoJSONCodec{}), nil /* config */); err != nil {
+		t.Error(err)
+	}
+}
+
+func TestStableCodec(t *testing.T) {
+	t.Parallel()
+	makeRoundtrip := func(codec stableCodec) func(map[string]string) bool {
+		return func(input map[string]string) bool {
+			initialProto, err := structpb.NewStruct(convertMapToInterface(input))
+			if err != nil {
+				t.Fatal(err)
+			}
+			want, err := codec.MarshalStable(initialProto)
+			if err != nil {
+				t.Fatal(err)
+			}
+			for i := 0; i < 10; i++ {
+				roundtripProto := &structpb.Struct{}
+				err = codec.Unmarshal(want, roundtripProto)
+				if err != nil {
+					t.Fatal(err)
+				}
+				got, err := codec.MarshalStable(roundtripProto)
+				if err != nil {
+					t.Fatal(err)
+				}
+				if !bytes.Equal(got, want) {
+					return false
+				}
+			}
+			return true
+		}
+	}
+	if err := quick.Check(makeRoundtrip(&protoBinaryCodec{}), nil /* config */); err != nil {
+		t.Error(err)
+	}
+	if err := quick.Check(makeRoundtrip(&protoJSONCodec{}), nil /* config */); err != nil {
+		t.Error(err)
+	}
+}
+
+func TestJSONCodec(t *testing.T) {
+	t.Parallel()
+
+	var empty emptypb.Empty
+	codec := &protoJSONCodec{name: "json"}
+	err := codec.Unmarshal([]byte{}, &empty)
+	assert.NotNil(t, err)
+	assert.True(
+		t,
+		strings.Contains(err.Error(), "valid JSON"),
+		assert.Sprintf(`error message should explain that "" is not a valid JSON object`),
+	)
+}
diff --git a/protocol/triple/triple_protocol/compression_test.go b/protocol/triple/triple_protocol/compression_test.go
index c905a53..21c33f8 100644
--- a/protocol/triple/triple_protocol/compression_test.go
+++ b/protocol/triple/triple_protocol/compression_test.go
@@ -1,163 +1,162 @@
-// // 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.
+// 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
 
-//
-//import (
-//	"context"
-//	"net/http"
-//	"net/http/httptest"
-//	"testing"
-//
-//	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/assert"
-//	"google.golang.org/protobuf/types/known/emptypb"
-//)
-//
-//func TestAcceptEncodingOrdering(t *testing.T) {
-//	t.Parallel()
-//	const (
-//		compressionBrotli = "br"
-//		expect            = compressionGzip + "," + compressionBrotli
-//	)
-//
-//	withFakeBrotli, ok := withGzip().(*compressionOption)
-//	assert.True(t, ok)
-//	withFakeBrotli.Name = compressionBrotli
-//
-//	var called bool
-//	verify := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-//		got := r.Header.Get(connectUnaryHeaderAcceptCompression)
-//		assert.Equal(t, got, expect)
-//		w.WriteHeader(http.StatusOK)
-//		called = true
-//	})
-//	server := httptest.NewServer(verify)
-//	defer server.Close()
-//
-//	client := NewClient[emptypb.Empty, emptypb.Empty](
-//		server.Client(),
-//		server.URL,
-//		withFakeBrotli,
-//		withGzip(),
-//	)
-//	_, _ = client.CallUnary(context.Background(), NewRequest(&emptypb.Empty{}))
-//	assert.True(t, called)
-//}
-//
-//func TestClientCompressionOptionTest(t *testing.T) {
-//	t.Parallel()
-//	const testURL = "http://foo.bar.com/service/method"
-//
-//	checkPools := func(t *testing.T, config *clientConfig) {
-//		t.Helper()
-//		assert.Equal(t, len(config.CompressionNames), len(config.CompressionPools))
-//		for _, name := range config.CompressionNames {
-//			pool := config.CompressionPools[name]
-//			assert.NotNil(t, pool)
-//		}
-//	}
-//	dummyDecompressCtor := func() Decompressor { return nil }
-//	dummyCompressCtor := func() Compressor { return nil }
-//
-//	t.Run("defaults", func(t *testing.T) {
-//		t.Parallel()
-//		config, err := newClientConfig(testURL, nil)
-//		assert.Nil(t, err)
-//		assert.Equal(t, config.CompressionNames, []string{compressionGzip})
-//		checkPools(t, config)
-//	})
-//	t.Run("WithAcceptCompression", func(t *testing.T) {
-//		t.Parallel()
-//		opts := []ClientOption{WithAcceptCompression("foo", dummyDecompressCtor, dummyCompressCtor)}
-//		config, err := newClientConfig(testURL, opts)
-//		assert.Nil(t, err)
-//		assert.Equal(t, config.CompressionNames, []string{compressionGzip, "foo"})
-//		checkPools(t, config)
-//	})
-//	t.Run("WithAcceptCompression-empty-name-noop", func(t *testing.T) {
-//		t.Parallel()
-//		opts := []ClientOption{WithAcceptCompression("", dummyDecompressCtor, dummyCompressCtor)}
-//		config, err := newClientConfig(testURL, opts)
-//		assert.Nil(t, err)
-//		assert.Equal(t, config.CompressionNames, []string{compressionGzip})
-//		checkPools(t, config)
-//	})
-//	t.Run("WithAcceptCompression-nil-ctors-noop", func(t *testing.T) {
-//		t.Parallel()
-//		opts := []ClientOption{WithAcceptCompression("foo", nil, nil)}
-//		config, err := newClientConfig(testURL, opts)
-//		assert.Nil(t, err)
-//		assert.Equal(t, config.CompressionNames, []string{compressionGzip})
-//		checkPools(t, config)
-//	})
-//	t.Run("WithAcceptCompression-nil-ctors-unregisters", func(t *testing.T) {
-//		t.Parallel()
-//		opts := []ClientOption{WithAcceptCompression("gzip", nil, nil)}
-//		config, err := newClientConfig(testURL, opts)
-//		assert.Nil(t, err)
-//		assert.Equal(t, config.CompressionNames, nil)
-//		checkPools(t, config)
-//	})
-//}
-//
-//func TestHandlerCompressionOptionTest(t *testing.T) {
-//	t.Parallel()
-//	const testProc = "/service/method"
-//
-//	checkPools := func(t *testing.T, config *handlerConfig) {
-//		t.Helper()
-//		assert.Equal(t, len(config.CompressionNames), len(config.CompressionPools))
-//		for _, name := range config.CompressionNames {
-//			pool := config.CompressionPools[name]
-//			assert.NotNil(t, pool)
-//		}
-//	}
-//	dummyDecompressCtor := func() Decompressor { return nil }
-//	dummyCompressCtor := func() Compressor { return nil }
-//
-//	t.Run("defaults", func(t *testing.T) {
-//		t.Parallel()
-//		config := newHandlerConfig(testProc, nil)
-//		assert.Equal(t, config.CompressionNames, []string{compressionGzip})
-//		checkPools(t, config)
-//	})
-//	t.Run("WithCompression", func(t *testing.T) {
-//		t.Parallel()
-//		opts := []HandlerOption{WithCompression("foo", dummyDecompressCtor, dummyCompressCtor)}
-//		config := newHandlerConfig(testProc, opts)
-//		assert.Equal(t, config.CompressionNames, []string{compressionGzip, "foo"})
-//		checkPools(t, config)
-//	})
-//	t.Run("WithCompression-empty-name-noop", func(t *testing.T) {
-//		t.Parallel()
-//		opts := []HandlerOption{WithCompression("", dummyDecompressCtor, dummyCompressCtor)}
-//		config := newHandlerConfig(testProc, opts)
-//		assert.Equal(t, config.CompressionNames, []string{compressionGzip})
-//		checkPools(t, config)
-//	})
-//	t.Run("WithCompression-nil-ctors-noop", func(t *testing.T) {
-//		t.Parallel()
-//		opts := []HandlerOption{WithCompression("foo", nil, nil)}
-//		config := newHandlerConfig(testProc, opts)
-//		assert.Equal(t, config.CompressionNames, []string{compressionGzip})
-//		checkPools(t, config)
-//	})
-//	t.Run("WithCompression-nil-ctors-unregisters", func(t *testing.T) {
-//		t.Parallel()
-//		opts := []HandlerOption{WithCompression("gzip", nil, nil)}
-//		config := newHandlerConfig(testProc, opts)
-//		assert.Equal(t, config.CompressionNames, nil)
-//		checkPools(t, config)
-//	})
-//}
+import (
+	"context"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/assert"
+	"google.golang.org/protobuf/types/known/emptypb"
+)
+
+func TestAcceptEncodingOrdering(t *testing.T) {
+	t.Parallel()
+	const (
+		compressionBrotli = "br"
+		expect            = compressionGzip + "," + compressionBrotli
+	)
+
+	withFakeBrotli, ok := withGzip().(*compressionOption)
+	assert.True(t, ok)
+	withFakeBrotli.Name = compressionBrotli
+
+	var called bool
+	verify := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		got := r.Header.Get(tripleUnaryHeaderAcceptCompression)
+		assert.Equal(t, got, expect)
+		w.WriteHeader(http.StatusOK)
+		called = true
+	})
+	server := httptest.NewServer(verify)
+	defer server.Close()
+
+	client := NewClient(
+		server.Client(),
+		server.URL,
+		withFakeBrotli,
+		withGzip(),
+	)
+	_ = client.CallUnary(context.Background(), NewRequest(&emptypb.Empty{}), NewResponse(&emptypb.Empty{}))
+	assert.True(t, called)
+}
+
+func TestClientCompressionOptionTest(t *testing.T) {
+	t.Parallel()
+	const testURL = "http://foo.bar.com/service/method"
+
+	checkPools := func(t *testing.T, config *clientConfig) {
+		t.Helper()
+		assert.Equal(t, len(config.CompressionNames), len(config.CompressionPools))
+		for _, name := range config.CompressionNames {
+			pool := config.CompressionPools[name]
+			assert.NotNil(t, pool)
+		}
+	}
+	dummyDecompressCtor := func() Decompressor { return nil }
+	dummyCompressCtor := func() Compressor { return nil }
+
+	t.Run("defaults", func(t *testing.T) {
+		t.Parallel()
+		config, err := newClientConfig(testURL, nil)
+		assert.Nil(t, err)
+		assert.Equal(t, config.CompressionNames, []string{compressionGzip})
+		checkPools(t, config)
+	})
+	t.Run("WithAcceptCompression", func(t *testing.T) {
+		t.Parallel()
+		opts := []ClientOption{WithAcceptCompression("foo", dummyDecompressCtor, dummyCompressCtor)}
+		config, err := newClientConfig(testURL, opts)
+		assert.Nil(t, err)
+		assert.Equal(t, config.CompressionNames, []string{compressionGzip, "foo"})
+		checkPools(t, config)
+	})
+	t.Run("WithAcceptCompression-empty-name-noop", func(t *testing.T) {
+		t.Parallel()
+		opts := []ClientOption{WithAcceptCompression("", dummyDecompressCtor, dummyCompressCtor)}
+		config, err := newClientConfig(testURL, opts)
+		assert.Nil(t, err)
+		assert.Equal(t, config.CompressionNames, []string{compressionGzip})
+		checkPools(t, config)
+	})
+	t.Run("WithAcceptCompression-nil-ctors-noop", func(t *testing.T) {
+		t.Parallel()
+		opts := []ClientOption{WithAcceptCompression("foo", nil, nil)}
+		config, err := newClientConfig(testURL, opts)
+		assert.Nil(t, err)
+		assert.Equal(t, config.CompressionNames, []string{compressionGzip})
+		checkPools(t, config)
+	})
+	t.Run("WithAcceptCompression-nil-ctors-unregisters", func(t *testing.T) {
+		t.Parallel()
+		opts := []ClientOption{WithAcceptCompression("gzip", nil, nil)}
+		config, err := newClientConfig(testURL, opts)
+		assert.Nil(t, err)
+		assert.Equal(t, config.CompressionNames, []string(nil))
+		checkPools(t, config)
+	})
+}
+
+func TestHandlerCompressionOptionTest(t *testing.T) {
+	t.Parallel()
+	const testProc = "/service/method"
+
+	checkPools := func(t *testing.T, config *handlerConfig) {
+		t.Helper()
+		assert.Equal(t, len(config.CompressionNames), len(config.CompressionPools))
+		for _, name := range config.CompressionNames {
+			pool := config.CompressionPools[name]
+			assert.NotNil(t, pool)
+		}
+	}
+	dummyDecompressCtor := func() Decompressor { return nil }
+	dummyCompressCtor := func() Compressor { return nil }
+
+	t.Run("defaults", func(t *testing.T) {
+		t.Parallel()
+		config := newHandlerConfig(testProc, nil)
+		assert.Equal(t, config.CompressionNames, []string{compressionGzip})
+		checkPools(t, config)
+	})
+	t.Run("WithCompression", func(t *testing.T) {
+		t.Parallel()
+		opts := []HandlerOption{WithCompression("foo", dummyDecompressCtor, dummyCompressCtor)}
+		config := newHandlerConfig(testProc, opts)
+		assert.Equal(t, config.CompressionNames, []string{compressionGzip, "foo"})
+		checkPools(t, config)
+	})
+	t.Run("WithCompression-empty-name-noop", func(t *testing.T) {
+		t.Parallel()
+		opts := []HandlerOption{WithCompression("", dummyDecompressCtor, dummyCompressCtor)}
+		config := newHandlerConfig(testProc, opts)
+		assert.Equal(t, config.CompressionNames, []string{compressionGzip})
+		checkPools(t, config)
+	})
+	t.Run("WithCompression-nil-ctors-noop", func(t *testing.T) {
+		t.Parallel()
+		opts := []HandlerOption{WithCompression("foo", nil, nil)}
+		config := newHandlerConfig(testProc, opts)
+		assert.Equal(t, config.CompressionNames, []string{compressionGzip})
+		checkPools(t, config)
+	})
+	t.Run("WithCompression-nil-ctors-unregisters", func(t *testing.T) {
+		t.Parallel()
+		opts := []HandlerOption{WithCompression("gzip", nil, nil)}
+		config := newHandlerConfig(testProc, opts)
+		assert.Equal(t, config.CompressionNames, []string(nil))
+		checkPools(t, config)
+	})
+}
diff --git a/protocol/triple/triple_protocol/connect_ext_test.go b/protocol/triple/triple_protocol/connect_ext_test.go
index 9f8a7a3..8e4cd90 100644
--- a/protocol/triple/triple_protocol/connect_ext_test.go
+++ b/protocol/triple/triple_protocol/connect_ext_test.go
@@ -1,454 +1,451 @@
-// // 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.
+// 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 (
-//	"bytes"
-//	"compress/flate"
-//	"compress/gzip"
-//	"context"
-//	"encoding/binary"
-//	"errors"
-//	"fmt"
-//	"io"
-//	"math"
-//	"math/rand"
-//	"net/http"
-//	"net/http/httptest"
-//	"strings"
-//	"sync"
-//	"testing"
-//	"time"
-//
-//	"dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/assert"
-//	"dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/proto/connect/import/v1/importv1connect"
-//	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/proto/connect/ping/v1"
-//	"dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/proto/connect/ping/v1/pingv1connect"
-//	"google.golang.org/protobuf/proto"
-//	"google.golang.org/protobuf/reflect/protoregistry"
-//)
-//
-//const errorMessage = "oh no"
-//
-//// The ping server implementation used in the tests returns errors if the
-//// client doesn't set a header, and the server sets headers and trailers on the
-//// response.
-//const (
-//	headerValue                 = "some header value"
-//	trailerValue                = "some trailer value"
-//	clientHeader                = "Connect-Client-Header"
-//	handlerHeader               = "Connect-Handler-Header"
-//	handlerTrailer              = "Connect-Handler-Trailer"
-//	clientMiddlewareErrorHeader = "Connect-Trigger-HTTP-Error"
-//)
-//
-//func TestServer(t *testing.T) {
-//	t.Parallel()
-//	testPing := func(t *testing.T, client pingv1connect.PingServiceClient) { //nolint:thelper
-//		t.Run("ping", func(t *testing.T) {
-//			num := int64(42)
-//			request := triple.NewRequest(&pingv1.PingRequest{Number: num})
-//			request.Header().Set(clientHeader, headerValue)
-//			expect := &pingv1.PingResponse{Number: num}
-//			response, err := client.Ping(context.Background(), request)
-//			assert.Nil(t, err)
-//			assert.Equal(t, response.Msg, expect)
-//			assert.Equal(t, response.Header().Values(handlerHeader), []string{headerValue})
-//			assert.Equal(t, response.Trailer().Values(handlerTrailer), []string{trailerValue})
-//		})
-//		t.Run("zero_ping", func(t *testing.T) {
-//			request := triple.NewRequest(&pingv1.PingRequest{})
-//			request.Header().Set(clientHeader, headerValue)
-//			response, err := client.Ping(context.Background(), request)
-//			assert.Nil(t, err)
-//			var expect pingv1.PingResponse
-//			assert.Equal(t, response.Msg, &expect)
-//			assert.Equal(t, response.Header().Values(handlerHeader), []string{headerValue})
-//			assert.Equal(t, response.Trailer().Values(handlerTrailer), []string{trailerValue})
-//		})
-//		t.Run("large_ping", func(t *testing.T) {
-//			// Using a large payload splits the request and response over multiple
-//			// packets, ensuring that we're managing HTTP readers and writers
-//			// correctly.
-//			if testing.Short() {
-//				t.Skipf("skipping %s test in short mode", t.Name())
-//			}
-//			hellos := strings.Repeat("hello", 1024*1024) // ~5mb
-//			request := triple.NewRequest(&pingv1.PingRequest{Text: hellos})
-//			request.Header().Set(clientHeader, headerValue)
-//			response, err := client.Ping(context.Background(), request)
-//			assert.Nil(t, err)
-//			assert.Equal(t, response.Msg.Text, hellos)
-//			assert.Equal(t, response.Header().Values(handlerHeader), []string{headerValue})
-//			assert.Equal(t, response.Trailer().Values(handlerTrailer), []string{trailerValue})
-//		})
-//		t.Run("ping_error", func(t *testing.T) {
-//			_, err := client.Ping(
-//				context.Background(),
-//				triple.NewRequest(&pingv1.PingRequest{}),
-//			)
-//			assert.Equal(t, triple.CodeOf(err), triple.CodeInvalidArgument)
-//		})
-//		t.Run("ping_timeout", func(t *testing.T) {
-//			ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(-time.Second))
-//			defer cancel()
-//			request := triple.NewRequest(&pingv1.PingRequest{})
-//			request.Header().Set(clientHeader, headerValue)
-//			_, err := client.Ping(ctx, request)
-//			assert.Equal(t, triple.CodeOf(err), triple.CodeDeadlineExceeded)
-//		})
-//	}
-//	testSum := func(t *testing.T, client pingv1connect.PingServiceClient) { //nolint:thelper
-//		t.Run("sum", func(t *testing.T) {
-//			const (
-//				upTo   = 10
-//				expect = 55 // 1+10 + 2+9 + ... + 5+6 = 55
-//			)
-//			stream, err := client.Sum(context.Background())
-//			assert.Nil(t, err)
-//			stream.RequestHeader().Set(clientHeader, headerValue)
-//			for i := int64(1); i <= upTo; i++ {
-//				err := stream.Send(&pingv1.SumRequest{Number: i})
-//				assert.Nil(t, err, assert.Sprintf("send %d", i))
-//			}
-//			response, err := stream.CloseAndReceive()
-//			assert.Nil(t, err)
-//			assert.Equal(t, response.Msg.Sum, expect)
-//			assert.Equal(t, response.Header().Values(handlerHeader), []string{headerValue})
-//			assert.Equal(t, response.Trailer().Values(handlerTrailer), []string{trailerValue})
-//		})
-//		t.Run("sum_error", func(t *testing.T) {
-//			stream, err := client.Sum(context.Background())
-//			assert.Nil(t, err)
-//			if err := stream.Send(&pingv1.SumRequest{Number: 1}); err != nil {
-//				assert.ErrorIs(t, err, io.EOF)
-//				assert.Equal(t, triple.CodeOf(err), triple.CodeUnknown)
-//			}
-//			_, err = stream.CloseAndReceive()
-//			assert.Equal(t, triple.CodeOf(err), triple.CodeInvalidArgument)
-//		})
-//		t.Run("sum_close_and_receive_without_send", func(t *testing.T) {
-//			stream, err := client.Sum(context.Background())
-//			assert.Nil(t, err)
-//			stream.RequestHeader().Set(clientHeader, headerValue)
-//			got, err := stream.CloseAndReceive()
-//			assert.Nil(t, err)
-//			assert.Equal(t, got.Msg, &pingv1.SumResponse{}) // receive header only stream
-//			assert.Equal(t, got.Header().Values(handlerHeader), []string{headerValue})
-//		})
-//	}
-//	testCountUp := func(t *testing.T, client pingv1connect.PingServiceClient) { //nolint:thelper
-//		t.Run("count_up", func(t *testing.T) {
-//			const upTo = 5
-//			got := make([]int64, 0, upTo)
-//			expect := make([]int64, 0, upTo)
-//			for i := 1; i <= upTo; i++ {
-//				expect = append(expect, int64(i))
-//			}
-//			request := triple.NewRequest(&pingv1.CountUpRequest{Number: upTo})
-//			request.Header().Set(clientHeader, headerValue)
-//			stream, err := client.CountUp(context.Background(), request)
-//			assert.Nil(t, err)
-//			for stream.Receive() {
-//				got = append(got, stream.Msg().Number)
-//			}
-//			assert.Nil(t, stream.Err())
-//			assert.Nil(t, stream.Close())
-//			assert.Equal(t, got, expect)
-//		})
-//		t.Run("count_up_error", func(t *testing.T) {
-//			stream, err := client.CountUp(
-//				context.Background(),
-//				triple.NewRequest(&pingv1.CountUpRequest{Number: 1}),
-//			)
-//			assert.Nil(t, err)
-//			for stream.Receive() {
-//				t.Fatalf("expected error, shouldn't receive any messages")
-//			}
-//			assert.Equal(
-//				t,
-//				triple.CodeOf(stream.Err()),
-//				triple.CodeInvalidArgument,
-//			)
-//		})
-//		t.Run("count_up_timeout", func(t *testing.T) {
-//			ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(-time.Second))
-//			defer cancel()
-//			_, err := client.CountUp(ctx, triple.NewRequest(&pingv1.CountUpRequest{Number: 1}))
-//			assert.NotNil(t, err)
-//			assert.Equal(t, triple.CodeOf(err), triple.CodeDeadlineExceeded)
-//		})
-//	}
-//	testCumSum := func(t *testing.T, client pingv1connect.PingServiceClient, expectSuccess bool) { //nolint:thelper
-//		t.Run("cumsum", func(t *testing.T) {
-//			send := []int64{3, 5, 1}
-//			expect := []int64{3, 8, 9}
-//			var got []int64
-//			stream, err := client.CumSum(context.Background())
-//			assert.Nil(t, err)
-//			stream.RequestHeader().Set(clientHeader, headerValue)
-//			if !expectSuccess { // server doesn't support HTTP/2
-//				failNoHTTP2(t, stream)
-//				return
-//			}
-//			var wg sync.WaitGroup
-//			wg.Add(2)
-//			go func() {
-//				defer wg.Done()
-//				for i, n := range send {
-//					err := stream.Send(&pingv1.CumSumRequest{Number: n})
-//					assert.Nil(t, err, assert.Sprintf("send error #%d", i))
-//				}
-//				assert.Nil(t, stream.CloseRequest())
-//			}()
-//			go func() {
-//				defer wg.Done()
-//				for {
-//					msg, err := stream.Receive()
-//					if errors.Is(err, io.EOF) {
-//						break
-//					}
-//					assert.Nil(t, err)
-//					got = append(got, msg.Sum)
-//				}
-//				assert.Nil(t, stream.CloseResponse())
-//			}()
-//			wg.Wait()
-//			assert.Equal(t, got, expect)
-//			assert.Equal(t, stream.ResponseHeader().Values(handlerHeader), []string{headerValue})
-//			assert.Equal(t, stream.ResponseTrailer().Values(handlerTrailer), []string{trailerValue})
-//		})
-//		t.Run("cumsum_error", func(t *testing.T) {
-//			stream, err := client.CumSum(context.Background())
-//			assert.Nil(t, err)
-//			if !expectSuccess { // server doesn't support HTTP/2
-//				failNoHTTP2(t, stream)
-//				return
-//			}
-//			if err := stream.Send(&pingv1.CumSumRequest{Number: 42}); err != nil {
-//				assert.ErrorIs(t, err, io.EOF)
-//				assert.Equal(t, triple.CodeOf(err), triple.CodeUnknown)
-//			}
-//			// We didn't send the headers the server expects, so we should now get an
-//			// error.
-//			_, err = stream.Receive()
-//			assert.Equal(t, triple.CodeOf(err), triple.CodeInvalidArgument)
-//			assert.True(t, triple.IsWireError(err))
-//		})
-//		t.Run("cumsum_empty_stream", func(t *testing.T) {
-//			stream, err := client.CumSum(context.Background())
-//			assert.Nil(t, err)
-//			stream.RequestHeader().Set(clientHeader, headerValue)
-//			if !expectSuccess { // server doesn't support HTTP/2
-//				failNoHTTP2(t, stream)
-//				return
-//			}
-//			// Deliberately closing with calling Send to test the behavior of Receive.
-//			// This test case is based on the grpc interop tests.
-//			assert.Nil(t, stream.CloseRequest())
-//			response, err := stream.Receive()
-//			assert.Nil(t, response)
-//			assert.True(t, errors.Is(err, io.EOF))
-//			assert.False(t, triple.IsWireError(err))
-//			assert.Nil(t, stream.CloseResponse()) // clean-up the stream
-//		})
-//		t.Run("cumsum_cancel_after_first_response", func(t *testing.T) {
-//			ctx, cancel := context.WithCancel(context.Background())
-//			stream, err := client.CumSum(ctx)
-//			assert.Nil(t, err)
-//			stream.RequestHeader().Set(clientHeader, headerValue)
-//			if !expectSuccess { // server doesn't support HTTP/2
-//				failNoHTTP2(t, stream)
-//				cancel()
-//				return
-//			}
-//			var got []int64
-//			expect := []int64{42}
-//			if err := stream.Send(&pingv1.CumSumRequest{Number: 42}); err != nil {
-//				assert.ErrorIs(t, err, io.EOF)
-//				assert.Equal(t, triple.CodeOf(err), triple.CodeUnknown)
-//			}
-//			msg, err := stream.Receive()
-//			assert.Nil(t, err)
-//			got = append(got, msg.Sum)
-//			cancel()
-//			_, err = stream.Receive()
-//			assert.Equal(t, triple.CodeOf(err), triple.CodeCanceled)
-//			assert.Equal(t, got, expect)
-//			assert.False(t, triple.IsWireError(err))
-//		})
-//		t.Run("cumsum_cancel_before_send", func(t *testing.T) {
-//			ctx, cancel := context.WithCancel(context.Background())
-//			stream, err := client.CumSum(ctx)
-//			assert.Nil(t, err)
-//			stream.RequestHeader().Set(clientHeader, headerValue)
-//			assert.Nil(t, stream.Send(&pingv1.CumSumRequest{Number: 8}))
-//			cancel()
-//			// On a subsequent send, ensure that we are still catching context
-//			// cancellations.
-//			err = stream.Send(&pingv1.CumSumRequest{Number: 19})
-//			assert.Equal(t, triple.CodeOf(err), triple.CodeCanceled, assert.Sprintf("%v", err))
-//			assert.False(t, triple.IsWireError(err))
-//		})
-//	}
-//	testErrors := func(t *testing.T, client pingv1connect.PingServiceClient) { //nolint:thelper
-//		assertIsHTTPMiddlewareError := func(tb testing.TB, err error) {
-//			tb.Helper()
-//			assert.NotNil(tb, err)
-//			var connectErr *triple.Error
-//			assert.True(tb, errors.As(err, &connectErr))
-//			expect := newHTTPMiddlewareError()
-//			assert.Equal(tb, connectErr.Code(), expect.Code())
-//			assert.Equal(tb, connectErr.Message(), expect.Message())
-//			for k, v := range expect.Meta() {
-//				assert.Equal(tb, connectErr.Meta().Values(k), v)
-//			}
-//			assert.Equal(tb, len(connectErr.Details()), len(expect.Details()))
-//		}
-//		t.Run("errors", func(t *testing.T) {
-//			request := triple.NewRequest(&pingv1.FailRequest{
-//				Code: int32(triple.CodeResourceExhausted),
-//			})
-//			request.Header().Set(clientHeader, headerValue)
-//
-//			response, err := client.Fail(context.Background(), request)
-//			assert.Nil(t, response)
-//			assert.NotNil(t, err)
-//			var connectErr *triple.Error
-//			ok := errors.As(err, &connectErr)
-//			assert.True(t, ok, assert.Sprintf("conversion to *connect.Error"))
-//			assert.True(t, triple.IsWireError(err))
-//			assert.Equal(t, connectErr.Code(), triple.CodeResourceExhausted)
-//			assert.Equal(t, connectErr.Error(), "resource_exhausted: "+errorMessage)
-//			assert.Zero(t, connectErr.Details())
-//			assert.Equal(t, connectErr.Meta().Values(handlerHeader), []string{headerValue})
-//			assert.Equal(t, connectErr.Meta().Values(handlerTrailer), []string{trailerValue})
-//		})
-//		t.Run("middleware_errors_unary", func(t *testing.T) {
-//			request := triple.NewRequest(&pingv1.PingRequest{})
-//			request.Header().Set(clientMiddlewareErrorHeader, headerValue)
-//			_, err := client.Ping(context.Background(), request)
-//			assertIsHTTPMiddlewareError(t, err)
-//		})
-//		t.Run("middleware_errors_streaming", func(t *testing.T) {
-//			request := triple.NewRequest(&pingv1.CountUpRequest{Number: 10})
-//			request.Header().Set(clientMiddlewareErrorHeader, headerValue)
-//			stream, err := client.CountUp(context.Background(), request)
-//			assert.Nil(t, err)
-//			assert.False(t, stream.Receive())
-//			assertIsHTTPMiddlewareError(t, stream.Err())
-//		})
-//	}
-//	testMatrix := func(t *testing.T, server *httptest.Server, bidi bool) { //nolint:thelper
-//		run := func(t *testing.T, opts ...triple.ClientOption) {
-//			t.Helper()
-//			client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, opts...)
-//			testPing(t, client)
-//			testSum(t, client)
-//			testCountUp(t, client)
-//			testCumSum(t, client, bidi)
-//			testErrors(t, client)
-//		}
-//		t.Run("connect", func(t *testing.T) {
-//			t.Run("proto", func(t *testing.T) {
-//				run(t)
-//			})
-//			t.Run("proto_gzip", func(t *testing.T) {
-//				run(t, triple.WithSendGzip())
-//			})
-//			t.Run("json_gzip", func(t *testing.T) {
-//				run(
-//					t,
-//					triple.WithProtoJSON(),
-//					triple.WithSendGzip(),
-//				)
-//			})
-//		})
-//		t.Run("grpc", func(t *testing.T) {
-//			t.Run("proto", func(t *testing.T) {
-//				run(t, triple.WithGRPC())
-//			})
-//			t.Run("proto_gzip", func(t *testing.T) {
-//				run(t, triple.WithGRPC(), triple.WithSendGzip())
-//			})
-//			t.Run("json_gzip", func(t *testing.T) {
-//				run(
-//					t,
-//					triple.WithGRPC(),
-//					triple.WithProtoJSON(),
-//					triple.WithSendGzip(),
-//				)
-//			})
-//		})
-//		t.Run("grpcweb", func(t *testing.T) {
-//			t.Run("proto", func(t *testing.T) {
-//				run(t, triple.WithGRPCWeb())
-//			})
-//			t.Run("proto_gzip", func(t *testing.T) {
-//				run(t, triple.WithGRPCWeb(), triple.WithSendGzip())
-//			})
-//			t.Run("json_gzip", func(t *testing.T) {
-//				run(
-//					t,
-//					triple.WithGRPCWeb(),
-//					triple.WithProtoJSON(),
-//					triple.WithSendGzip(),
-//				)
-//			})
-//		})
-//	}
-//
-//	mux := http.NewServeMux()
-//	pingRoute, pingHandler := pingv1connect.NewPingServiceHandler(
-//		pingServer{checkMetadata: true},
-//	)
-//	errorWriter := triple.NewErrorWriter()
-//	// Add some net/http middleware to the ping service so we can also exercise ErrorWriter.
-//	mux.Handle(pingRoute, http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
-//		if request.Header.Get(clientMiddlewareErrorHeader) != "" {
-//			defer request.Body.Close()
-//			if _, err := io.Copy(io.Discard, request.Body); err != nil {
-//				t.Errorf("drain request body: %v", err)
-//			}
-//			if !errorWriter.IsSupported(request) {
-//				t.Errorf("ErrorWriter doesn't support Content-Type %q", request.Header.Get("Content-Type"))
-//			}
-//			if err := errorWriter.Write(response, request, newHTTPMiddlewareError()); err != nil {
-//				t.Errorf("send RPC error from HTTP middleware: %v", err)
-//			}
-//			return
-//		}
-//		pingHandler.ServeHTTP(response, request)
-//	}))
-//
-//	t.Run("http1", func(t *testing.T) {
-//		t.Parallel()
-//		server := httptest.NewServer(mux)
-//		defer server.Close()
-//		testMatrix(t, server, false /* bidi */)
-//	})
-//	t.Run("http2", func(t *testing.T) {
-//		t.Parallel()
-//		server := httptest.NewUnstartedServer(mux)
-//		server.EnableHTTP2 = true
-//		server.StartTLS()
-//		defer server.Close()
-//		testMatrix(t, server, true /* bidi */)
-//	})
-//}
-//
+import (
+	"bytes"
+	"compress/flate"
+	"compress/gzip"
+	"context"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"io"
+	"math"
+	"net/http"
+	"net/http/httptest"
+	"strings"
+	"testing"
+	"time"
+
+	triple "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
+
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/assert"
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/import/v1/importv1connect"
+	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1"
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1/pingv1connect"
+	"google.golang.org/protobuf/proto"
+	"google.golang.org/protobuf/reflect/protoregistry"
+)
+
+const errorMessage = "oh no"
+
+// The ping server implementation used in the tests returns errors if the
+// client doesn't set a header, and the server sets headers and trailers on the
+// response.
+const (
+	headerValue                 = "some header value"
+	trailerValue                = "some trailer value"
+	clientHeader                = "Connect-Client-Header"
+	handlerHeader               = "Connect-Handler-Header"
+	handlerTrailer              = "Connect-Handler-Trailer"
+	clientMiddlewareErrorHeader = "Connect-Trigger-HTTP-Error"
+)
+
+func TestServer(t *testing.T) {
+	t.Parallel()
+	testPing := func(t *testing.T, client pingv1connect.PingServiceClient) { //nolint:thelper
+		t.Run("ping", func(t *testing.T) {
+			num := int64(42)
+			request := triple.NewRequest(&pingv1.PingRequest{Number: num})
+			request.Header().Set(clientHeader, headerValue)
+			expect := &pingv1.PingResponse{Number: num}
+			msg := &pingv1.PingResponse{}
+			response := triple.NewResponse(msg)
+			err := client.Ping(context.Background(), request, response)
+			assert.Nil(t, err)
+			assert.Equal(t, response.Msg.(*pingv1.PingResponse), expect)
+			assert.Equal(t, response.Header().Values(handlerHeader), []string{headerValue})
+			assert.Equal(t, response.Trailer().Values(handlerTrailer), []string{trailerValue})
+		})
+		t.Run("zero_ping", func(t *testing.T) {
+			request := triple.NewRequest(&pingv1.PingRequest{})
+			request.Header().Set(clientHeader, headerValue)
+			msg := &pingv1.PingResponse{}
+			response := triple.NewResponse(msg)
+			err := client.Ping(context.Background(), request, response)
+			assert.Nil(t, err)
+			var expect pingv1.PingResponse
+			assert.Equal(t, msg, &expect)
+			assert.Equal(t, response.Header().Values(handlerHeader), []string{headerValue})
+			assert.Equal(t, response.Trailer().Values(handlerTrailer), []string{trailerValue})
+		})
+		t.Run("large_ping", func(t *testing.T) {
+			// Using a large payload splits the request and response over multiple
+			// packets, ensuring that we're managing HTTP readers and writers
+			// correctly.
+			if testing.Short() {
+				t.Skipf("skipping %s test in short mode", t.Name())
+			}
+			hellos := strings.Repeat("hello", 1024*1024) // ~5mb
+			request := triple.NewRequest(&pingv1.PingRequest{Text: hellos})
+			request.Header().Set(clientHeader, headerValue)
+			msg := &pingv1.PingResponse{}
+			response := triple.NewResponse(msg)
+			err := client.Ping(context.Background(), request, response)
+			assert.Nil(t, err)
+			assert.Equal(t, msg.Text, hellos)
+			assert.Equal(t, response.Header().Values(handlerHeader), []string{headerValue})
+			assert.Equal(t, response.Trailer().Values(handlerTrailer), []string{trailerValue})
+		})
+		t.Run("ping_error", func(t *testing.T) {
+			err := client.Ping(
+				context.Background(),
+				triple.NewRequest(&pingv1.PingRequest{}),
+				triple.NewResponse(&pingv1.PingResponse{}),
+			)
+			assert.Equal(t, triple.CodeOf(err), triple.CodeInvalidArgument)
+		})
+		t.Run("ping_timeout", func(t *testing.T) {
+			ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(-time.Second))
+			defer cancel()
+			request := triple.NewRequest(&pingv1.PingRequest{})
+			request.Header().Set(clientHeader, headerValue)
+			err := client.Ping(ctx, request, triple.NewResponse(&pingv1.PingResponse{}))
+			assert.Equal(t, triple.CodeOf(err), triple.CodeDeadlineExceeded)
+		})
+	}
+	//testSum := func(t *testing.T, client pingv1connect.PingServiceClient) { //nolint:thelper
+	//	t.Run("sum", func(t *testing.T) {
+	//		const (
+	//			upTo   = 10
+	//			expect = 55 // 1+10 + 2+9 + ... + 5+6 = 55
+	//		)
+	//		stream, err := client.Sum(context.Background())
+	//		assert.Nil(t, err)
+	//		stream.RequestHeader().Set(clientHeader, headerValue)
+	//		for i := int64(1); i <= upTo; i++ {
+	//			err := stream.Send(&pingv1.SumRequest{Number: i})
+	//			assert.Nil(t, err, assert.Sprintf("send %d", i))
+	//		}
+	//		msg := &pingv1.SumResponse{}
+	//		response := triple.NewResponse(msg)
+	//		err = stream.CloseAndReceive(response)
+	//		assert.Nil(t, err)
+	//		assert.Equal(t, msg.Sum, expect)
+	//		assert.Equal(t, response.Header().Values(handlerHeader), []string{headerValue})
+	//		assert.Equal(t, response.Trailer().Values(handlerTrailer), []string{trailerValue})
+	//	})
+	//	t.Run("sum_error", func(t *testing.T) {
+	//		stream, err := client.Sum(context.Background())
+	//		assert.Nil(t, err)
+	//		if err := stream.Send(&pingv1.SumRequest{Number: 1}); err != nil {
+	//			assert.ErrorIs(t, err, io.EOF)
+	//			assert.Equal(t, triple.CodeOf(err), triple.CodeUnknown)
+	//		}
+	//		err = stream.CloseAndReceive(triple.NewResponse(&pingv1.SumResponse{}))
+	//		assert.Equal(t, triple.CodeOf(err), triple.CodeInvalidArgument)
+	//	})
+	//	t.Run("sum_close_and_receive_without_send", func(t *testing.T) {
+	//		stream, err := client.Sum(context.Background())
+	//		assert.Nil(t, err)
+	//		stream.RequestHeader().Set(clientHeader, headerValue)
+	//		msg := &pingv1.SumResponse{}
+	//		got := triple.NewResponse(msg)
+	//		err = stream.CloseAndReceive(got)
+	//		assert.Nil(t, err)
+	//		assert.Equal(t, msg, &pingv1.SumResponse{}) // receive header only stream
+	//		assert.Equal(t, got.Header().Values(handlerHeader), []string{headerValue})
+	//	})
+	//}
+	//testCountUp := func(t *testing.T, client pingv1connect.PingServiceClient) { //nolint:thelper
+	//	t.Run("count_up", func(t *testing.T) {
+	//		const upTo = 5
+	//		got := make([]int64, 0, upTo)
+	//		expect := make([]int64, 0, upTo)
+	//		for i := 1; i <= upTo; i++ {
+	//			expect = append(expect, int64(i))
+	//		}
+	//		request := triple.NewRequest(&pingv1.CountUpRequest{Number: upTo})
+	//		request.Header().Set(clientHeader, headerValue)
+	//		stream, err := client.CountUp(context.Background(), request)
+	//		assert.Nil(t, err)
+	//		for stream.Receive(&pingv1.CountUpResponse{}) {
+	//			msg := stream.Msg().(pingv1.CountUpResponse)
+	//			got = append(got, msg.Number)
+	//		}
+	//		assert.Nil(t, stream.Err())
+	//		assert.Nil(t, stream.Close())
+	//		assert.Equal(t, got, expect)
+	//	})
+	//	t.Run("count_up_error", func(t *testing.T) {
+	//		stream, err := client.CountUp(
+	//			context.Background(),
+	//			triple.NewRequest(&pingv1.CountUpRequest{Number: 1}),
+	//		)
+	//		assert.Nil(t, err)
+	//		for stream.Receive(&pingv1.CountUpResponse{}) {
+	//			t.Fatalf("expected error, shouldn't receive any messages")
+	//		}
+	//		assert.Equal(
+	//			t,
+	//			triple.CodeOf(stream.Err()),
+	//			triple.CodeInvalidArgument,
+	//		)
+	//	})
+	//	t.Run("count_up_timeout", func(t *testing.T) {
+	//		ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(-time.Second))
+	//		defer cancel()
+	//		_, err := client.CountUp(ctx, triple.NewRequest(&pingv1.CountUpRequest{Number: 1}))
+	//		assert.NotNil(t, err)
+	//		assert.Equal(t, triple.CodeOf(err), triple.CodeDeadlineExceeded)
+	//	})
+	//}
+	//testCumSum := func(t *testing.T, client pingv1connect.PingServiceClient, expectSuccess bool) { //nolint:thelper
+	//	t.Run("cumsum", func(t *testing.T) {
+	//		send := []int64{3, 5, 1}
+	//		expect := []int64{3, 8, 9}
+	//		var got []int64
+	//		stream, err := client.CumSum(context.Background())
+	//		assert.Nil(t, err)
+	//		stream.RequestHeader().Set(clientHeader, headerValue)
+	//		if !expectSuccess { // server doesn't support HTTP/2
+	//			failNoHTTP2(t, stream)
+	//			return
+	//		}
+	//		var wg sync.WaitGroup
+	//		wg.Add(2)
+	//		go func() {
+	//			defer wg.Done()
+	//			for i, n := range send {
+	//				err := stream.Send(&pingv1.CumSumRequest{Number: n})
+	//				assert.Nil(t, err, assert.Sprintf("send error #%d", i))
+	//			}
+	//			assert.Nil(t, stream.CloseRequest())
+	//		}()
+	//		go func() {
+	//			defer wg.Done()
+	//			for {
+	//				msg := &pingv1.CumSumResponse{}
+	//				err := stream.Receive(msg)
+	//				if errors.Is(err, io.EOF) {
+	//					break
+	//				}
+	//				assert.Nil(t, err)
+	//				got = append(got, msg.Sum)
+	//			}
+	//			assert.Nil(t, stream.CloseResponse())
+	//		}()
+	//		wg.Wait()
+	//		assert.Equal(t, got, expect)
+	//		assert.Equal(t, stream.ResponseHeader().Values(handlerHeader), []string{headerValue})
+	//		assert.Equal(t, stream.ResponseTrailer().Values(handlerTrailer), []string{trailerValue})
+	//	})
+	//	t.Run("cumsum_error", func(t *testing.T) {
+	//		stream, err := client.CumSum(context.Background())
+	//		assert.Nil(t, err)
+	//		if !expectSuccess { // server doesn't support HTTP/2
+	//			failNoHTTP2(t, stream)
+	//			return
+	//		}
+	//		if err := stream.Send(&pingv1.CumSumRequest{Number: 42}); err != nil {
+	//			assert.ErrorIs(t, err, io.EOF)
+	//			assert.Equal(t, triple.CodeOf(err), triple.CodeUnknown)
+	//		}
+	//		// We didn't send the headers the server expects, so we should now get an
+	//		// error.
+	//		err = stream.Receive(&pingv1.CumSumResponse{})
+	//		assert.Equal(t, triple.CodeOf(err), triple.CodeInvalidArgument)
+	//		assert.True(t, triple.IsWireError(err))
+	//	})
+	//	t.Run("cumsum_empty_stream", func(t *testing.T) {
+	//		stream, err := client.CumSum(context.Background())
+	//		assert.Nil(t, err)
+	//		stream.RequestHeader().Set(clientHeader, headerValue)
+	//		if !expectSuccess { // server doesn't support HTTP/2
+	//			failNoHTTP2(t, stream)
+	//			return
+	//		}
+	//		// Deliberately closing with calling Send to test the behavior of Receive.
+	//		// This test case is based on the grpc interop tests.
+	//		assert.Nil(t, stream.CloseRequest())
+	//		response := &pingv1.CumSumResponse{}
+	//		err = stream.Receive(response)
+	//		assert.True(t, errors.Is(err, io.EOF))
+	//		assert.False(t, triple.IsWireError(err))
+	//		assert.Nil(t, stream.CloseResponse()) // clean-up the stream
+	//	})
+	//	t.Run("cumsum_cancel_after_first_response", func(t *testing.T) {
+	//		ctx, cancel := context.WithCancel(context.Background())
+	//		stream, err := client.CumSum(ctx)
+	//		assert.Nil(t, err)
+	//		stream.RequestHeader().Set(clientHeader, headerValue)
+	//		if !expectSuccess { // server doesn't support HTTP/2
+	//			failNoHTTP2(t, stream)
+	//			cancel()
+	//			return
+	//		}
+	//		var got []int64
+	//		expect := []int64{42}
+	//		if err := stream.Send(&pingv1.CumSumRequest{Number: 42}); err != nil {
+	//			assert.ErrorIs(t, err, io.EOF)
+	//			assert.Equal(t, triple.CodeOf(err), triple.CodeUnknown)
+	//		}
+	//		msg := &pingv1.CumSumResponse{}
+	//		err = stream.Receive(msg)
+	//		assert.Nil(t, err)
+	//		got = append(got, msg.Sum)
+	//		cancel()
+	//		err = stream.Receive(&pingv1.CumSumResponse{})
+	//		assert.Equal(t, triple.CodeOf(err), triple.CodeCanceled)
+	//		assert.Equal(t, got, expect)
+	//		assert.False(t, triple.IsWireError(err))
+	//	})
+	//	t.Run("cumsum_cancel_before_send", func(t *testing.T) {
+	//		ctx, cancel := context.WithCancel(context.Background())
+	//		stream, err := client.CumSum(ctx)
+	//		assert.Nil(t, err)
+	//		stream.RequestHeader().Set(clientHeader, headerValue)
+	//		assert.Nil(t, stream.Send(&pingv1.CumSumRequest{Number: 8}))
+	//		cancel()
+	//		// On a subsequent send, ensure that we are still catching context
+	//		// cancellations.
+	//		err = stream.Send(&pingv1.CumSumRequest{Number: 19})
+	//		assert.Equal(t, triple.CodeOf(err), triple.CodeCanceled, assert.Sprintf("%v", err))
+	//		assert.False(t, triple.IsWireError(err))
+	//	})
+	//}
+	testErrors := func(t *testing.T, client pingv1connect.PingServiceClient) { //nolint:thelper
+		assertIsHTTPMiddlewareError := func(tb testing.TB, err error) {
+			tb.Helper()
+			assert.NotNil(tb, err)
+			var tripleErr *triple.Error
+			assert.True(tb, errors.As(err, &tripleErr))
+			expect := newHTTPMiddlewareError()
+			assert.Equal(tb, tripleErr.Code(), expect.Code())
+			assert.Equal(tb, tripleErr.Message(), expect.Message())
+			for k, v := range expect.Meta() {
+				assert.Equal(tb, tripleErr.Meta().Values(k), v)
+			}
+			assert.Equal(tb, len(tripleErr.Details()), len(expect.Details()))
+		}
+		t.Run("errors", func(t *testing.T) {
+			request := triple.NewRequest(&pingv1.FailRequest{
+				Code: int32(triple.CodeResourceExhausted),
+			})
+			request.Header().Set(clientHeader, headerValue)
+			response := triple.NewResponse(&pingv1.FailResponse{})
+			err := client.Fail(context.Background(), request, response)
+			assert.NotNil(t, err)
+			var tripleErr *triple.Error
+			ok := errors.As(err, &tripleErr)
+			assert.True(t, ok, assert.Sprintf("conversion to *triple.Error"))
+			assert.True(t, triple.IsWireError(err))
+			assert.Equal(t, tripleErr.Code(), triple.CodeResourceExhausted)
+			assert.Equal(t, tripleErr.Error(), "resource_exhausted: "+errorMessage)
+			assert.Zero(t, tripleErr.Details())
+			assert.Equal(t, tripleErr.Meta().Values(handlerHeader), []string{headerValue})
+			assert.Equal(t, tripleErr.Meta().Values(handlerTrailer), []string{trailerValue})
+		})
+		t.Run("middleware_errors_unary", func(t *testing.T) {
+			request := triple.NewRequest(&pingv1.PingRequest{})
+			request.Header().Set(clientMiddlewareErrorHeader, headerValue)
+			res := triple.NewResponse(&pingv1.PingResponse{})
+			err := client.Ping(context.Background(), request, res)
+			assertIsHTTPMiddlewareError(t, err)
+		})
+		//t.Run("middleware_errors_streaming", func(t *testing.T) {
+		//	request := triple.NewRequest(&pingv1.CountUpRequest{Number: 10})
+		//	request.Header().Set(clientMiddlewareErrorHeader, headerValue)
+		//	stream, err := client.CountUp(context.Background(), request)
+		//	assert.Nil(t, err)
+		//	assert.False(t, stream.Receive(&pingv1.CountUpResponse{}))
+		//	assertIsHTTPMiddlewareError(t, stream.Err())
+		//})
+	}
+	testMatrix := func(t *testing.T, server *httptest.Server, bidi bool) { //nolint:thelper
+		run := func(t *testing.T, opts ...triple.ClientOption) {
+			t.Helper()
+			client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, opts...)
+			testPing(t, client)
+			// testSum(t, client)
+			// testCountUp(t, client)
+			// testCumSum(t, client, bidi)
+			testErrors(t, client)
+		}
+		t.Run("triple", func(t *testing.T) {
+			t.Run("proto", func(t *testing.T) {
+				run(t)
+			})
+			t.Run("proto_gzip", func(t *testing.T) {
+				run(t, triple.WithSendGzip())
+			})
+			t.Run("json_gzip", func(t *testing.T) {
+				run(
+					t,
+					triple.WithProtoJSON(),
+					triple.WithSendGzip(),
+				)
+			})
+		})
+		t.Run("grpc", func(t *testing.T) {
+			t.Run("proto", func(t *testing.T) {
+				run(t, triple.WithGRPC())
+			})
+			t.Run("proto_gzip", func(t *testing.T) {
+				run(t, triple.WithGRPC(), triple.WithSendGzip())
+			})
+			t.Run("json_gzip", func(t *testing.T) {
+				run(
+					t,
+					triple.WithGRPC(),
+					triple.WithProtoJSON(),
+					triple.WithSendGzip(),
+				)
+			})
+		})
+	}
+
+	mux := http.NewServeMux()
+	pingRoute, pingHandler := pingv1connect.NewPingServiceHandler(
+		pingServer{checkMetadata: true},
+	)
+	errorWriter := triple.NewErrorWriter()
+	// Add some net/http middleware to the ping service so we can also exercise ErrorWriter.
+	mux.Handle(pingRoute, http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
+		if request.Header.Get(clientMiddlewareErrorHeader) != "" {
+			defer request.Body.Close()
+			if _, err := io.Copy(io.Discard, request.Body); err != nil {
+				t.Errorf("drain request body: %v", err)
+			}
+			if !errorWriter.IsSupported(request) {
+				t.Errorf("ErrorWriter doesn't support Content-Type %q", request.Header.Get("Content-Type"))
+			}
+			if err := errorWriter.Write(response, request, newHTTPMiddlewareError()); err != nil {
+				t.Errorf("send RPC error from HTTP middleware: %v", err)
+			}
+			return
+		}
+		pingHandler.ServeHTTP(response, request)
+	}))
+
+	t.Run("http1", func(t *testing.T) {
+		t.Parallel()
+		server := httptest.NewServer(mux)
+		defer server.Close()
+		testMatrix(t, server, false /* bidi */)
+	})
+	t.Run("http2", func(t *testing.T) {
+		t.Parallel()
+		server := httptest.NewUnstartedServer(mux)
+		server.EnableHTTP2 = true
+		server.StartTLS()
+		defer server.Close()
+		testMatrix(t, server, true /* bidi */)
+	})
+}
+
 //func TestConcurrentStreams(t *testing.T) {
 //	if testing.Short() {
 //		t.Skipf("skipping %s test in short mode", t.Name())
@@ -478,7 +475,8 @@
 //					t.Errorf("failed to send request: %v", err)
 //					break
 //				}
-//				resp, err := sum.Receive()
+//				resp := &pingv1.CumSumResponse{}
+//				err := sum.Receive(resp)
 //				if err != nil {
 //					t.Errorf("failed to receive from stream: %v", err)
 //					break
@@ -499,61 +497,63 @@
 //	start.Done()
 //	done.Wait()
 //}
-//
-//func TestHeaderBasic(t *testing.T) {
-//	t.Parallel()
-//	const (
-//		key  = "Test-Key"
-//		cval = "client value"
-//		hval = "client value"
-//	)
-//
-//	pingServer := &pluggablePingServer{
-//		ping: func(ctx context.Context, request *triple.Request[pingv1.PingRequest]) (*triple.Response[pingv1.PingResponse], error) {
-//			assert.Equal(t, request.Header().Get(key), cval)
-//			response := triple.NewResponse(&pingv1.PingResponse{})
-//			response.Header().Set(key, hval)
-//			return response, nil
-//		},
-//	}
-//	mux := http.NewServeMux()
-//	mux.Handle(pingv1connect.NewPingServiceHandler(pingServer))
-//	server := httptest.NewServer(mux)
-//	defer server.Close()
-//
-//	client := pingv1connect.NewPingServiceClient(server.Client(), server.URL)
-//	request := triple.NewRequest(&pingv1.PingRequest{})
-//	request.Header().Set(key, cval)
-//	response, err := client.Ping(context.Background(), request)
-//	assert.Nil(t, err)
-//	assert.Equal(t, response.Header().Get(key), hval)
-//}
-//
-//func TestTimeoutParsing(t *testing.T) {
-//	t.Parallel()
-//	const timeout = 10 * time.Minute
-//	pingServer := &pluggablePingServer{
-//		ping: func(ctx context.Context, request *triple.Request[pingv1.PingRequest]) (*triple.Response[pingv1.PingResponse], error) {
-//			deadline, ok := ctx.Deadline()
-//			assert.True(t, ok)
-//			remaining := time.Until(deadline)
-//			assert.True(t, remaining > 0)
-//			assert.True(t, remaining <= timeout)
-//			return triple.NewResponse(&pingv1.PingResponse{}), nil
-//		},
-//	}
-//	mux := http.NewServeMux()
-//	mux.Handle(pingv1connect.NewPingServiceHandler(pingServer))
-//	server := httptest.NewServer(mux)
-//	defer server.Close()
-//
-//	ctx, cancel := context.WithTimeout(context.Background(), timeout)
-//	defer cancel()
-//	client := pingv1connect.NewPingServiceClient(server.Client(), server.URL)
-//	_, err := client.Ping(ctx, triple.NewRequest(&pingv1.PingRequest{}))
-//	assert.Nil(t, err)
-//}
-//
+
+func TestHeaderBasic(t *testing.T) {
+	t.Parallel()
+	const (
+		key  = "Test-Key"
+		cval = "client value"
+		hval = "client value"
+	)
+
+	pingServer := &pluggablePingServer{
+		ping: func(ctx context.Context, request *triple.Request) (*triple.Response, error) {
+			assert.Equal(t, request.Header().Get(key), cval)
+			response := triple.NewResponse(&pingv1.PingResponse{})
+			response.Header().Set(key, hval)
+			return response, nil
+		},
+	}
+	mux := http.NewServeMux()
+	mux.Handle(pingv1connect.NewPingServiceHandler(pingServer))
+	server := httptest.NewServer(mux)
+	defer server.Close()
+
+	client := pingv1connect.NewPingServiceClient(server.Client(), server.URL)
+	request := triple.NewRequest(&pingv1.PingRequest{})
+	request.Header().Set(key, cval)
+	response := triple.NewResponse(&pingv1.PingResponse{})
+	err := client.Ping(context.Background(), request, response)
+	assert.Nil(t, err)
+	assert.Equal(t, response.Header().Get(key), hval)
+}
+
+func TestTimeoutParsing(t *testing.T) {
+	t.Parallel()
+	const timeout = 10 * time.Minute
+	pingServer := &pluggablePingServer{
+		ping: func(ctx context.Context, request *triple.Request) (*triple.Response, error) {
+			deadline, ok := ctx.Deadline()
+			assert.True(t, ok)
+			remaining := time.Until(deadline)
+			assert.True(t, remaining > 0)
+			assert.True(t, remaining <= timeout)
+			return triple.NewResponse(&pingv1.PingResponse{}), nil
+		},
+	}
+	mux := http.NewServeMux()
+	mux.Handle(pingv1connect.NewPingServiceHandler(pingServer))
+	server := httptest.NewServer(mux)
+	defer server.Close()
+
+	ctx, cancel := context.WithTimeout(context.Background(), timeout)
+	defer cancel()
+	client := pingv1connect.NewPingServiceClient(server.Client(), server.URL)
+	response := triple.NewResponse(&pingv1.PingResponse{})
+	err := client.Ping(ctx, triple.NewRequest(&pingv1.PingRequest{}), response)
+	assert.Nil(t, err)
+}
+
 //func TestFailCodec(t *testing.T) {
 //	t.Parallel()
 //	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
@@ -566,12 +566,12 @@
 //	)
 //	stream, _ := client.CumSum(context.Background())
 //	err := stream.Send(&pingv1.CumSumRequest{})
-//	var connectErr *triple.Error
+//	var tripleErr *triple.Error
 //	assert.NotNil(t, err)
-//	assert.True(t, errors.As(err, &connectErr))
-//	assert.Equal(t, connectErr.Code(), triple.CodeInternal)
+//	assert.True(t, errors.As(err, &tripleErr))
+//	assert.Equal(t, tripleErr.Code(), triple.CodeInternal)
 //}
-//
+
 //func TestContextError(t *testing.T) {
 //	t.Parallel()
 //	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
@@ -586,146 +586,148 @@
 //	stream, err := client.CumSum(ctx)
 //	assert.Nil(t, err)
 //	err = stream.Send(nil)
-//	var connectErr *triple.Error
+//	var tripleErr *triple.Error
 //	assert.NotNil(t, err)
-//	assert.True(t, errors.As(err, &connectErr))
-//	assert.Equal(t, connectErr.Code(), triple.CodeCanceled)
+//	assert.True(t, errors.As(err, &tripleErr))
+//	assert.Equal(t, tripleErr.Code(), triple.CodeCanceled)
 //	assert.False(t, triple.IsWireError(err))
 //}
-//
-//func TestGRPCMarshalStatusError(t *testing.T) {
-//	t.Parallel()
-//
-//	mux := http.NewServeMux()
-//	mux.Handle(pingv1connect.NewPingServiceHandler(
-//		pingServer{},
-//		triple.WithCodec(failCodec{}),
-//	))
-//	server := httptest.NewUnstartedServer(mux)
-//	server.EnableHTTP2 = true
-//	server.StartTLS()
-//	defer server.Close()
-//
-//	assertInternalError := func(tb testing.TB, opts ...triple.ClientOption) {
-//		tb.Helper()
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, opts...)
-//		request := triple.NewRequest(&pingv1.FailRequest{Code: int32(triple.CodeResourceExhausted)})
-//		_, err := client.Fail(context.Background(), request)
-//		tb.Log(err)
-//		assert.NotNil(t, err)
-//		var connectErr *triple.Error
-//		ok := errors.As(err, &connectErr)
-//		assert.True(t, ok)
-//		assert.Equal(t, connectErr.Code(), triple.CodeInternal)
-//		assert.True(
-//			t,
-//			strings.HasSuffix(connectErr.Message(), ": boom"),
-//		)
-//	}
-//
-//	// Only applies to gRPC protocols, where we're marshaling the Status protobuf
-//	// message to binary.
-//	assertInternalError(t, triple.WithGRPC())
-//	assertInternalError(t, triple.WithGRPCWeb())
-//}
-//
-//func TestGRPCMissingTrailersError(t *testing.T) {
-//	t.Parallel()
-//
-//	trimTrailers := func(handler http.Handler) http.Handler {
-//		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-//			r.Header.Del("Te")
-//			handler.ServeHTTP(&trimTrailerWriter{w: w}, r)
-//		})
-//	}
-//
-//	mux := http.NewServeMux()
-//	mux.Handle(pingv1connect.NewPingServiceHandler(
-//		pingServer{checkMetadata: true},
-//	))
-//	server := httptest.NewUnstartedServer(trimTrailers(mux))
-//	server.EnableHTTP2 = true
-//	server.StartTLS()
-//	t.Cleanup(server.Close)
-//	client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithGRPC())
-//
-//	assertErrorNoTrailers := func(t *testing.T, err error) {
-//		t.Helper()
-//		assert.NotNil(t, err)
-//		var connectErr *triple.Error
-//		ok := errors.As(err, &connectErr)
-//		assert.True(t, ok)
-//		assert.Equal(t, connectErr.Code(), triple.CodeInternal)
-//		assert.True(
-//			t,
-//			strings.HasSuffix(connectErr.Message(), "gRPC protocol error: no Grpc-Status trailer"),
-//		)
-//	}
-//
-//	assertNilOrEOF := func(t *testing.T, err error) {
-//		t.Helper()
-//		if err != nil {
-//			assert.ErrorIs(t, err, io.EOF)
-//		}
-//	}
-//
-//	t.Run("ping", func(t *testing.T) {
-//		t.Parallel()
-//		request := triple.NewRequest(&pingv1.PingRequest{Number: 1, Text: "foobar"})
-//		_, err := client.Ping(context.Background(), request)
-//		assertErrorNoTrailers(t, err)
-//	})
-//	t.Run("sum", func(t *testing.T) {
-//		t.Parallel()
-//		stream, err := client.Sum(context.Background())
-//		assert.Nil(t, err)
-//		err = stream.Send(&pingv1.SumRequest{Number: 1})
-//		assertNilOrEOF(t, err)
-//		_, err = stream.CloseAndReceive()
-//		assertErrorNoTrailers(t, err)
-//	})
-//	t.Run("count_up", func(t *testing.T) {
-//		t.Parallel()
-//		stream, err := client.CountUp(context.Background(), triple.NewRequest(&pingv1.CountUpRequest{Number: 10}))
-//		assert.Nil(t, err)
-//		assert.False(t, stream.Receive())
-//		assertErrorNoTrailers(t, stream.Err())
-//	})
-//	t.Run("cumsum", func(t *testing.T) {
-//		t.Parallel()
-//		stream, err := client.CumSum(context.Background())
-//		assert.Nil(t, err)
-//		assertNilOrEOF(t, stream.Send(&pingv1.CumSumRequest{Number: 10}))
-//		_, err = stream.Receive()
-//		assertErrorNoTrailers(t, err)
-//		assert.Nil(t, stream.CloseResponse())
-//	})
-//	t.Run("cumsum_empty_stream", func(t *testing.T) {
-//		t.Parallel()
-//		stream, err := client.CumSum(context.Background())
-//		assert.Nil(t, err)
-//		assert.Nil(t, stream.CloseRequest())
-//		response, err := stream.Receive()
-//		assert.Nil(t, response)
-//		assertErrorNoTrailers(t, err)
-//		assert.Nil(t, stream.CloseResponse())
-//	})
-//}
-//
-//func TestUnavailableIfHostInvalid(t *testing.T) {
-//	t.Parallel()
-//	client := pingv1connect.NewPingServiceClient(
-//		http.DefaultClient,
-//		"https://api.invalid/",
-//	)
-//	_, err := client.Ping(
-//		context.Background(),
-//		triple.NewRequest(&pingv1.PingRequest{}),
-//	)
-//	assert.NotNil(t, err)
-//	assert.Equal(t, triple.CodeOf(err), triple.CodeUnavailable)
-//}
-//
+
+func TestGRPCMarshalStatusError(t *testing.T) {
+	t.Parallel()
+
+	mux := http.NewServeMux()
+	mux.Handle(pingv1connect.NewPingServiceHandler(
+		pingServer{},
+		triple.WithCodec(failCodec{}),
+	))
+	server := httptest.NewUnstartedServer(mux)
+	server.EnableHTTP2 = true
+	server.StartTLS()
+	defer server.Close()
+
+	assertInternalError := func(tb testing.TB, opts ...triple.ClientOption) {
+		tb.Helper()
+		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, opts...)
+		request := triple.NewRequest(&pingv1.FailRequest{Code: int32(triple.CodeResourceExhausted)})
+		res := triple.NewResponse(&pingv1.FailResponse{})
+		err := client.Fail(context.Background(), request, res)
+		tb.Log(err)
+		assert.NotNil(t, err)
+		var tripleErr *triple.Error
+		ok := errors.As(err, &tripleErr)
+		assert.True(t, ok)
+		assert.Equal(t, tripleErr.Code(), triple.CodeInternal)
+		assert.True(
+			t,
+			strings.HasSuffix(tripleErr.Message(), ": boom"),
+		)
+	}
+
+	// Only applies to gRPC protocols, where we're marshaling the Status protobuf
+	// message to binary.
+	assertInternalError(t, triple.WithGRPC())
+}
+
+func TestGRPCMissingTrailersError(t *testing.T) {
+	t.Parallel()
+
+	trimTrailers := func(handler http.Handler) http.Handler {
+		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+			r.Header.Del("Te")
+			handler.ServeHTTP(&trimTrailerWriter{w: w}, r)
+		})
+	}
+
+	mux := http.NewServeMux()
+	mux.Handle(pingv1connect.NewPingServiceHandler(
+		pingServer{checkMetadata: true},
+	))
+	server := httptest.NewUnstartedServer(trimTrailers(mux))
+	server.EnableHTTP2 = true
+	server.StartTLS()
+	t.Cleanup(server.Close)
+	client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithGRPC())
+
+	assertErrorNoTrailers := func(t *testing.T, err error) {
+		t.Helper()
+		assert.NotNil(t, err)
+		var tripleErr *triple.Error
+		ok := errors.As(err, &tripleErr)
+		assert.True(t, ok)
+		assert.Equal(t, tripleErr.Code(), triple.CodeInternal)
+		assert.True(
+			t,
+			strings.HasSuffix(tripleErr.Message(), "gRPC protocol error: no Grpc-Status trailer"),
+		)
+	}
+
+	//assertNilOrEOF := func(t *testing.T, err error) {
+	//	t.Helper()
+	//	if err != nil {
+	//		assert.ErrorIs(t, err, io.EOF)
+	//	}
+	//}
+
+	t.Run("ping", func(t *testing.T) {
+		t.Parallel()
+		request := triple.NewRequest(&pingv1.PingRequest{Number: 1, Text: "foobar"})
+		res := triple.NewResponse(&pingv1.PingResponse{})
+		err := client.Ping(context.Background(), request, res)
+		assertErrorNoTrailers(t, err)
+	})
+	//t.Run("sum", func(t *testing.T) {
+	//	t.Parallel()
+	//	stream, err := client.Sum(context.Background())
+	//	assert.Nil(t, err)
+	//	err = stream.Send(&pingv1.SumRequest{Number: 1})
+	//	assertNilOrEOF(t, err)
+	//	res := triple.NewResponse(&pingv1.SumResponse{})
+	//	err = stream.CloseAndReceive(res)
+	//	assertErrorNoTrailers(t, err)
+	//})
+	//t.Run("count_up", func(t *testing.T) {
+	//	t.Parallel()
+	//	stream, err := client.CountUp(context.Background(), triple.NewRequest(&pingv1.CountUpRequest{Number: 10}))
+	//	assert.Nil(t, err)
+	//	assert.False(t, stream.Receive(&pingv1.CountUpResponse{}))
+	//	assertErrorNoTrailers(t, stream.Err())
+	//})
+	//t.Run("cumsum", func(t *testing.T) {
+	//	t.Parallel()
+	//	stream, err := client.CumSum(context.Background())
+	//	assert.Nil(t, err)
+	//	assertNilOrEOF(t, stream.Send(&pingv1.CumSumRequest{Number: 10}))
+	//	err = stream.Receive(&pingv1.CumSumResponse{})
+	//	assertErrorNoTrailers(t, err)
+	//	assert.Nil(t, stream.CloseResponse())
+	//})
+	//t.Run("cumsum_empty_stream", func(t *testing.T) {
+	//	t.Parallel()
+	//	stream, err := client.CumSum(context.Background())
+	//	assert.Nil(t, err)
+	//	assert.Nil(t, stream.CloseRequest())
+	//	err = stream.Receive(&pingv1.CumSumResponse{})
+	//	assertErrorNoTrailers(t, err)
+	//	assert.Nil(t, stream.CloseResponse())
+	//})
+}
+
+func TestUnavailableIfHostInvalid(t *testing.T) {
+	t.Parallel()
+	client := pingv1connect.NewPingServiceClient(
+		http.DefaultClient,
+		"https://api.invalid/",
+	)
+	err := client.Ping(
+		context.Background(),
+		triple.NewRequest(&pingv1.PingRequest{}),
+		triple.NewResponse(&pingv1.PingResponse{}),
+	)
+	assert.NotNil(t, err)
+	assert.Equal(t, triple.CodeOf(err), triple.CodeUnavailable)
+}
+
 //func TestBidiRequiresHTTP2(t *testing.T) {
 //	t.Parallel()
 //	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -742,190 +744,193 @@
 //	assert.Nil(t, err)
 //	assert.Nil(t, stream.Send(&pingv1.CumSumRequest{}))
 //	assert.Nil(t, stream.CloseRequest())
-//	_, err = stream.Receive()
+//	err = stream.Receive(&pingv1.CumSumResponse{})
 //	assert.NotNil(t, err)
-//	var connectErr *triple.Error
-//	assert.True(t, errors.As(err, &connectErr))
-//	assert.Equal(t, connectErr.Code(), triple.CodeUnimplemented)
+//	var tripleErr *triple.Error
+//	assert.True(t, errors.As(err, &tripleErr))
+//	assert.Equal(t, tripleErr.Code(), triple.CodeUnimplemented)
 //	assert.True(
 //		t,
-//		strings.HasSuffix(connectErr.Message(), ": bidi streams require at least HTTP/2"),
+//		strings.HasSuffix(tripleErr.Message(), ": bidi streams require at least HTTP/2"),
 //	)
 //}
-//
-//func TestCompressMinBytesClient(t *testing.T) {
-//	t.Parallel()
-//	assertContentType := func(tb testing.TB, text, expect string) {
-//		tb.Helper()
-//		mux := http.NewServeMux()
-//		mux.Handle("/", http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
-//			assert.Equal(tb, request.Header.Get("Content-Encoding"), expect)
-//		}))
-//		server := httptest.NewServer(mux)
-//		tb.Cleanup(server.Close)
-//		_, err := pingv1connect.NewPingServiceClient(
-//			server.Client(),
-//			server.URL,
-//			triple.WithSendGzip(),
-//			triple.WithCompressMinBytes(8),
-//		).Ping(context.Background(), triple.NewRequest(&pingv1.PingRequest{Text: text}))
-//		assert.Nil(tb, err)
-//	}
-//	t.Run("request_uncompressed", func(t *testing.T) {
-//		t.Parallel()
-//		assertContentType(t, "ping", "")
-//	})
-//	t.Run("request_compressed", func(t *testing.T) {
-//		t.Parallel()
-//		assertContentType(t, "pingping", "gzip")
-//	})
-//
-//	t.Run("request_uncompressed", func(t *testing.T) {
-//		t.Parallel()
-//		assertContentType(t, "ping", "")
-//	})
-//	t.Run("request_compressed", func(t *testing.T) {
-//		t.Parallel()
-//		assertContentType(t, strings.Repeat("ping", 2), "gzip")
-//	})
-//}
-//
-//func TestCompressMinBytes(t *testing.T) {
-//	t.Parallel()
-//	mux := http.NewServeMux()
-//	mux.Handle(pingv1connect.NewPingServiceHandler(
-//		pingServer{},
-//		triple.WithCompressMinBytes(8),
-//	))
-//	server := httptest.NewServer(mux)
-//	t.Cleanup(func() {
-//		server.Close()
-//	})
-//	client := server.Client()
-//
-//	getPingResponse := func(t *testing.T, pingText string) *http.Response {
-//		t.Helper()
-//		request := &pingv1.PingRequest{Text: pingText}
-//		requestBytes, err := proto.Marshal(request)
-//		assert.Nil(t, err)
-//		req, err := http.NewRequestWithContext(
-//			context.Background(),
-//			http.MethodPost,
-//			server.URL+"/"+pingv1connect.PingServiceName+"/Ping",
-//			bytes.NewReader(requestBytes),
-//		)
-//		assert.Nil(t, err)
-//		req.Header.Set("Content-Type", "application/proto")
-//		response, err := client.Do(req)
-//		assert.Nil(t, err)
-//		t.Cleanup(func() {
-//			assert.Nil(t, response.Body.Close())
-//		})
-//		return response
-//	}
-//
-//	t.Run("response_uncompressed", func(t *testing.T) {
-//		t.Parallel()
-//		assert.False(t, getPingResponse(t, "ping").Uncompressed) //nolint:bodyclose
-//	})
-//
-//	t.Run("response_compressed", func(t *testing.T) {
-//		t.Parallel()
-//		assert.True(t, getPingResponse(t, strings.Repeat("ping", 2)).Uncompressed) //nolint:bodyclose
-//	})
-//}
-//
-//func TestCustomCompression(t *testing.T) {
-//	t.Parallel()
-//	mux := http.NewServeMux()
-//	compressionName := "deflate"
-//	decompressor := func() triple.Decompressor {
-//		// Need to instantiate with a reader - before decompressing Reset(io.Reader) is called
-//		return newDeflateReader(strings.NewReader(""))
-//	}
-//	compressor := func() triple.Compressor {
-//		w, err := flate.NewWriter(&strings.Builder{}, flate.DefaultCompression)
-//		if err != nil {
-//			t.Fatalf("failed to create flate writer: %v", err)
-//		}
-//		return w
-//	}
-//	mux.Handle(pingv1connect.NewPingServiceHandler(
-//		pingServer{},
-//		triple.WithCompression(compressionName, decompressor, compressor),
-//	))
-//	server := httptest.NewServer(mux)
-//	defer server.Close()
-//
-//	client := pingv1connect.NewPingServiceClient(server.Client(),
-//		server.URL,
-//		triple.WithAcceptCompression(compressionName, decompressor, compressor),
-//		triple.WithSendCompression(compressionName),
-//	)
-//	request := &pingv1.PingRequest{Text: "testing 1..2..3.."}
-//	response, err := client.Ping(context.Background(), triple.NewRequest(request))
-//	assert.Nil(t, err)
-//	assert.Equal(t, response.Msg, &pingv1.PingResponse{Text: request.Text})
-//}
-//
-//func TestClientWithoutGzipSupport(t *testing.T) {
-//	// See https://github.com/bufbuild/connect-go/pull/349 for why we want to
-//	// support this. TL;DR is that Microsoft's dapr sidecar can't handle
-//	// asymmetric compression.
-//	t.Parallel()
-//	mux := http.NewServeMux()
-//	mux.Handle(pingv1connect.NewPingServiceHandler(pingServer{}))
-//	server := httptest.NewServer(mux)
-//	defer server.Close()
-//
-//	client := pingv1connect.NewPingServiceClient(server.Client(),
-//		server.URL,
-//		triple.WithAcceptCompression("gzip", nil, nil),
-//		triple.WithSendGzip(),
-//	)
-//	request := &pingv1.PingRequest{Text: "gzip me!"}
-//	_, err := client.Ping(context.Background(), triple.NewRequest(request))
-//	assert.NotNil(t, err)
-//	assert.Equal(t, triple.CodeOf(err), triple.CodeUnknown)
-//	assert.True(t, strings.Contains(err.Error(), "unknown compression"))
-//}
-//
-//func TestInvalidHeaderTimeout(t *testing.T) {
-//	t.Parallel()
-//	mux := http.NewServeMux()
-//	mux.Handle(pingv1connect.NewPingServiceHandler(pingServer{}))
-//	server := httptest.NewServer(mux)
-//	t.Cleanup(func() {
-//		server.Close()
-//	})
-//	getPingResponseWithTimeout := func(t *testing.T, timeout string) *http.Response {
-//		t.Helper()
-//		request, err := http.NewRequestWithContext(
-//			context.Background(),
-//			http.MethodPost,
-//			server.URL+"/"+pingv1connect.PingServiceName+"/Ping",
-//			strings.NewReader("{}"),
-//		)
-//		assert.Nil(t, err)
-//		request.Header.Set("Content-Type", "application/json")
-//		request.Header.Set("Connect-Timeout-Ms", timeout)
-//		response, err := server.Client().Do(request)
-//		assert.Nil(t, err)
-//		t.Cleanup(func() {
-//			assert.Nil(t, response.Body.Close())
-//		})
-//		return response
-//	}
-//	t.Run("timeout_non_numeric", func(t *testing.T) {
-//		t.Parallel()
-//		assert.Equal(t, getPingResponseWithTimeout(t, "10s").StatusCode, http.StatusBadRequest) //nolint:bodyclose
-//	})
-//	t.Run("timeout_out_of_range", func(t *testing.T) {
-//		t.Parallel()
-//		assert.Equal(t, getPingResponseWithTimeout(t, "12345678901").StatusCode, http.StatusBadRequest) //nolint:bodyclose
-//	})
-//}
-//
+
+func TestCompressMinBytesClient(t *testing.T) {
+	t.Parallel()
+	assertContentType := func(tb testing.TB, text, expect string) {
+		tb.Helper()
+		mux := http.NewServeMux()
+		mux.Handle("/", http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
+			assert.Equal(tb, request.Header.Get("Content-Encoding"), expect)
+		}))
+		server := httptest.NewServer(mux)
+		tb.Cleanup(server.Close)
+		err := pingv1connect.NewPingServiceClient(
+			server.Client(),
+			server.URL,
+			triple.WithSendGzip(),
+			triple.WithCompressMinBytes(8),
+		).Ping(context.Background(), triple.NewRequest(&pingv1.PingRequest{Text: text}), triple.NewResponse(&pingv1.PingResponse{}))
+		assert.Nil(tb, err)
+	}
+	t.Run("request_uncompressed", func(t *testing.T) {
+		t.Parallel()
+		assertContentType(t, "ping", "")
+	})
+	t.Run("request_compressed", func(t *testing.T) {
+		t.Parallel()
+		assertContentType(t, "pingping", "gzip")
+	})
+
+	t.Run("request_uncompressed", func(t *testing.T) {
+		t.Parallel()
+		assertContentType(t, "ping", "")
+	})
+	t.Run("request_compressed", func(t *testing.T) {
+		t.Parallel()
+		assertContentType(t, strings.Repeat("ping", 2), "gzip")
+	})
+}
+
+func TestCompressMinBytes(t *testing.T) {
+	t.Parallel()
+	mux := http.NewServeMux()
+	mux.Handle(pingv1connect.NewPingServiceHandler(
+		pingServer{},
+		triple.WithCompressMinBytes(8),
+	))
+	server := httptest.NewServer(mux)
+	t.Cleanup(func() {
+		server.Close()
+	})
+	client := server.Client()
+
+	getPingResponse := func(t *testing.T, pingText string) *http.Response {
+		t.Helper()
+		request := &pingv1.PingRequest{Text: pingText}
+		requestBytes, err := proto.Marshal(request)
+		assert.Nil(t, err)
+		req, err := http.NewRequestWithContext(
+			context.Background(),
+			http.MethodPost,
+			server.URL+"/"+pingv1connect.PingServiceName+"/Ping",
+			bytes.NewReader(requestBytes),
+		)
+		assert.Nil(t, err)
+		req.Header.Set("Content-Type", "application/proto")
+		response, err := client.Do(req)
+		assert.Nil(t, err)
+		t.Cleanup(func() {
+			assert.Nil(t, response.Body.Close())
+		})
+		return response
+	}
+
+	t.Run("response_uncompressed", func(t *testing.T) {
+		t.Parallel()
+		assert.False(t, getPingResponse(t, "ping").Uncompressed) //nolint:bodyclose
+	})
+
+	t.Run("response_compressed", func(t *testing.T) {
+		t.Parallel()
+		assert.True(t, getPingResponse(t, strings.Repeat("ping", 2)).Uncompressed) //nolint:bodyclose
+	})
+}
+
+func TestCustomCompression(t *testing.T) {
+	t.Parallel()
+	mux := http.NewServeMux()
+	compressionName := "deflate"
+	decompressor := func() triple.Decompressor {
+		// Need to instantiate with a reader - before decompressing Reset(io.Reader) is called
+		return newDeflateReader(strings.NewReader(""))
+	}
+	compressor := func() triple.Compressor {
+		w, err := flate.NewWriter(&strings.Builder{}, flate.DefaultCompression)
+		if err != nil {
+			t.Fatalf("failed to create flate writer: %v", err)
+		}
+		return w
+	}
+	mux.Handle(pingv1connect.NewPingServiceHandler(
+		pingServer{},
+		triple.WithCompression(compressionName, decompressor, compressor),
+	))
+	server := httptest.NewServer(mux)
+	defer server.Close()
+
+	client := pingv1connect.NewPingServiceClient(server.Client(),
+		server.URL,
+		triple.WithAcceptCompression(compressionName, decompressor, compressor),
+		triple.WithSendCompression(compressionName),
+	)
+	request := &pingv1.PingRequest{Text: "testing 1..2..3.."}
+	msg := &pingv1.PingResponse{}
+	response := triple.NewResponse(msg)
+	err := client.Ping(context.Background(), triple.NewRequest(request), response)
+	assert.Nil(t, err)
+	assert.Equal(t, msg, &pingv1.PingResponse{Text: request.Text})
+}
+
+func TestClientWithoutGzipSupport(t *testing.T) {
+	// See https://github.com/bufbuild/connect-go/pull/349 for why we want to
+	// support this. TL;DR is that Microsoft's dapr sidecar can't handle
+	// asymmetric compression.
+	t.Parallel()
+	mux := http.NewServeMux()
+	mux.Handle(pingv1connect.NewPingServiceHandler(pingServer{}))
+	server := httptest.NewServer(mux)
+	defer server.Close()
+
+	client := pingv1connect.NewPingServiceClient(server.Client(),
+		server.URL,
+		triple.WithAcceptCompression("gzip", nil, nil),
+		triple.WithSendGzip(),
+	)
+	request := &pingv1.PingRequest{Text: "gzip me!"}
+	err := client.Ping(context.Background(), triple.NewRequest(request), triple.NewResponse(&pingv1.PingResponse{}))
+	assert.NotNil(t, err)
+	assert.Equal(t, triple.CodeOf(err), triple.CodeUnknown)
+	assert.True(t, strings.Contains(err.Error(), "unknown compression"))
+}
+
+func TestInvalidHeaderTimeout(t *testing.T) {
+	t.Parallel()
+	mux := http.NewServeMux()
+	mux.Handle(pingv1connect.NewPingServiceHandler(pingServer{}))
+	server := httptest.NewServer(mux)
+	t.Cleanup(func() {
+		server.Close()
+	})
+	getPingResponseWithTimeout := func(t *testing.T, timeout string) *http.Response {
+		t.Helper()
+		request, err := http.NewRequestWithContext(
+			context.Background(),
+			http.MethodPost,
+			server.URL+"/"+pingv1connect.PingServiceName+"/Ping",
+			strings.NewReader("{}"),
+		)
+		assert.Nil(t, err)
+		request.Header.Set("Content-Type", "application/json")
+		request.Header.Set("Triple-Timeout-Ms", timeout)
+		response, err := server.Client().Do(request)
+		assert.Nil(t, err)
+		t.Cleanup(func() {
+			assert.Nil(t, response.Body.Close())
+		})
+		return response
+	}
+	t.Run("timeout_non_numeric", func(t *testing.T) {
+		t.Parallel()
+		assert.Equal(t, getPingResponseWithTimeout(t, "10s").StatusCode, http.StatusBadRequest) //nolint:bodyclose
+	})
+	t.Run("timeout_out_of_range", func(t *testing.T) {
+		t.Parallel()
+		assert.Equal(t, getPingResponseWithTimeout(t, "12345678901").StatusCode, http.StatusBadRequest) //nolint:bodyclose
+	})
+}
+
+//修改了判断的逻辑,无法判断类型了
 //func TestInterceptorReturnsWrongType(t *testing.T) {
 //	t.Parallel()
 //	mux := http.NewServeMux()
@@ -933,514 +938,454 @@
 //	server := httptest.NewServer(mux)
 //	defer server.Close()
 //	client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithInterceptors(triple.UnaryInterceptorFunc(func(next triple.UnaryFunc) triple.UnaryFunc {
-//		return func(ctx context.Context, request triple.AnyRequest) (triple.AnyResponse, error) {
-//			if _, err := next(ctx, request); err != nil {
-//				return nil, err
+//		return func(ctx context.Context, request triple.AnyRequest, response triple.AnyResponse) error {
+//			if err := next(ctx, request, response); err != nil {
+//				return err
 //			}
-//			return triple.NewResponse(&pingv1.CumSumResponse{
-//				Sum: 1,
-//			}), nil
+//			return nil
 //		}
 //	})))
-//	_, err := client.Ping(context.Background(), triple.NewRequest(&pingv1.PingRequest{Text: "hello!"}))
+//	err := client.Ping(context.Background(), triple.NewRequest(&pingv1.PingRequest{Text: "hello!"}), triple.NewResponse(&pingv1.PingResponse{}))
 //	assert.NotNil(t, err)
-//	var connectErr *triple.Error
-//	assert.True(t, errors.As(err, &connectErr))
-//	assert.Equal(t, connectErr.Code(), triple.CodeInternal)
-//	assert.True(t, strings.Contains(connectErr.Message(), "unexpected client response type"))
+//	var tripleErr *triple.Error
+//	assert.True(t, errors.As(err, &tripleErr))
+//	assert.Equal(t, tripleErr.Code(), triple.CodeInternal)
+//	assert.True(t, strings.Contains(tripleErr.Message(), "unexpected client response type"))
 //}
-//
-//func TestHandlerWithReadMaxBytes(t *testing.T) {
-//	t.Parallel()
-//	mux := http.NewServeMux()
-//	readMaxBytes := 1024
-//	mux.Handle(pingv1connect.NewPingServiceHandler(
-//		pingServer{},
-//		triple.WithReadMaxBytes(readMaxBytes),
-//	))
-//	readMaxBytesMatrix := func(t *testing.T, client pingv1connect.PingServiceClient, compressed bool) {
-//		t.Helper()
-//		t.Run("equal_read_max", func(t *testing.T) {
-//			t.Parallel()
-//			// Serializes to exactly readMaxBytes (1024) - no errors expected
-//			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("a", 1021)}
-//			assert.Equal(t, proto.Size(pingRequest), readMaxBytes)
-//			_, err := client.Ping(context.Background(), triple.NewRequest(pingRequest))
-//			assert.Nil(t, err)
-//		})
-//		t.Run("read_max_plus_one", func(t *testing.T) {
-//			t.Parallel()
-//			// Serializes to readMaxBytes+1 (1025) - expect invalid argument.
-//			// This will be over the limit after decompression but under with compression.
-//			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("a", 1022)}
-//			if compressed {
-//				compressedSize := gzipCompressedSize(t, pingRequest)
-//				assert.True(t, compressedSize < readMaxBytes, assert.Sprintf("expected compressed size %d < %d", compressedSize, readMaxBytes))
-//			}
-//			_, err := client.Ping(context.Background(), triple.NewRequest(pingRequest))
-//			assert.NotNil(t, err, assert.Sprintf("expected non-nil error for large message"))
-//			assert.Equal(t, triple.CodeOf(err), triple.CodeResourceExhausted)
-//			assert.True(t, strings.HasSuffix(err.Error(), fmt.Sprintf("message size %d is larger than configured max %d", proto.Size(pingRequest), readMaxBytes)))
-//		})
-//		t.Run("read_max_large", func(t *testing.T) {
-//			t.Parallel()
-//			if testing.Short() {
-//				t.Skipf("skipping %s test in short mode", t.Name())
-//			}
-//			// Serializes to much larger than readMaxBytes (5 MiB)
-//			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("abcde", 1024*1024)}
-//			expectedSize := proto.Size(pingRequest)
-//			// With gzip request compression, the error should indicate the envelope size (before decompression) is too large.
-//			if compressed {
-//				expectedSize = gzipCompressedSize(t, pingRequest)
-//				assert.True(t, expectedSize > readMaxBytes, assert.Sprintf("expected compressed size %d > %d", expectedSize, readMaxBytes))
-//			}
-//			_, err := client.Ping(context.Background(), triple.NewRequest(pingRequest))
-//			assert.NotNil(t, err, assert.Sprintf("expected non-nil error for large message"))
-//			assert.Equal(t, triple.CodeOf(err), triple.CodeResourceExhausted)
-//			assert.Equal(t, err.Error(), fmt.Sprintf("resource_exhausted: message size %d is larger than configured max %d", expectedSize, readMaxBytes))
-//		})
-//	}
-//	newHTTP2Server := func(t *testing.T) *httptest.Server {
-//		t.Helper()
-//		server := httptest.NewUnstartedServer(mux)
-//		server.EnableHTTP2 = true
-//		server.StartTLS()
-//		t.Cleanup(server.Close)
-//		return server
-//	}
-//	t.Run("connect", func(t *testing.T) {
-//		t.Parallel()
-//		server := newHTTP2Server(t)
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL)
-//		readMaxBytesMatrix(t, client, false)
-//	})
-//	t.Run("connect_gzip", func(t *testing.T) {
-//		t.Parallel()
-//		server := newHTTP2Server(t)
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithSendGzip())
-//		readMaxBytesMatrix(t, client, true)
-//	})
-//	t.Run("grpc", func(t *testing.T) {
-//		t.Parallel()
-//		server := newHTTP2Server(t)
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithGRPC())
-//		readMaxBytesMatrix(t, client, false)
-//	})
-//	t.Run("grpc_gzip", func(t *testing.T) {
-//		t.Parallel()
-//		server := newHTTP2Server(t)
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithGRPC(), triple.WithSendGzip())
-//		readMaxBytesMatrix(t, client, true)
-//	})
-//	t.Run("grpcweb", func(t *testing.T) {
-//		t.Parallel()
-//		server := newHTTP2Server(t)
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithGRPCWeb())
-//		readMaxBytesMatrix(t, client, false)
-//	})
-//	t.Run("grpcweb_gzip", func(t *testing.T) {
-//		t.Parallel()
-//		server := newHTTP2Server(t)
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithGRPCWeb(), triple.WithSendGzip())
-//		readMaxBytesMatrix(t, client, true)
-//	})
-//}
-//
-//func TestHandlerWithHTTPMaxBytes(t *testing.T) {
-//	// This is similar to Connect's own ReadMaxBytes option, but applied to the
-//	// whole stream using the stdlib's http.MaxBytesHandler.
-//	t.Parallel()
-//	const readMaxBytes = 128
-//	mux := http.NewServeMux()
-//	pingRoute, pingHandler := pingv1connect.NewPingServiceHandler(pingServer{})
-//	mux.Handle(pingRoute, http.MaxBytesHandler(pingHandler, readMaxBytes))
-//	run := func(t *testing.T, client pingv1connect.PingServiceClient, compressed bool) {
-//		t.Helper()
-//		t.Run("below_read_max", func(t *testing.T) {
-//			t.Parallel()
-//			_, err := client.Ping(context.Background(), triple.NewRequest(&pingv1.PingRequest{}))
-//			assert.Nil(t, err)
-//		})
-//		t.Run("just_above_max", func(t *testing.T) {
-//			t.Parallel()
-//			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("a", readMaxBytes*10)}
-//			_, err := client.Ping(context.Background(), triple.NewRequest(pingRequest))
-//			if compressed {
-//				compressedSize := gzipCompressedSize(t, pingRequest)
-//				assert.True(t, compressedSize < readMaxBytes, assert.Sprintf("expected compressed size %d < %d", compressedSize, readMaxBytes))
-//				assert.Nil(t, err)
-//				return
-//			}
-//			assert.NotNil(t, err, assert.Sprintf("expected non-nil error for large message"))
-//			assert.Equal(t, triple.CodeOf(err), triple.CodeResourceExhausted)
-//		})
-//		t.Run("read_max_large", func(t *testing.T) {
-//			t.Parallel()
-//			if testing.Short() {
-//				t.Skipf("skipping %s test in short mode", t.Name())
-//			}
-//			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("abcde", 1024*1024)}
-//			if compressed {
-//				expectedSize := gzipCompressedSize(t, pingRequest)
-//				assert.True(t, expectedSize > readMaxBytes, assert.Sprintf("expected compressed size %d > %d", expectedSize, readMaxBytes))
-//			}
-//			_, err := client.Ping(context.Background(), triple.NewRequest(pingRequest))
-//			assert.NotNil(t, err, assert.Sprintf("expected non-nil error for large message"))
-//			assert.Equal(t, triple.CodeOf(err), triple.CodeResourceExhausted)
-//		})
-//	}
-//	newHTTP2Server := func(t *testing.T) *httptest.Server {
-//		t.Helper()
-//		server := httptest.NewUnstartedServer(mux)
-//		server.EnableHTTP2 = true
-//		server.StartTLS()
-//		t.Cleanup(server.Close)
-//		return server
-//	}
-//	t.Run("connect", func(t *testing.T) {
-//		t.Parallel()
-//		server := newHTTP2Server(t)
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL)
-//		run(t, client, false)
-//	})
-//	t.Run("connect_gzip", func(t *testing.T) {
-//		t.Parallel()
-//		server := newHTTP2Server(t)
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithSendGzip())
-//		run(t, client, true)
-//	})
-//	t.Run("grpc", func(t *testing.T) {
-//		t.Parallel()
-//		server := newHTTP2Server(t)
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithGRPC())
-//		run(t, client, false)
-//	})
-//	t.Run("grpc_gzip", func(t *testing.T) {
-//		t.Parallel()
-//		server := newHTTP2Server(t)
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithGRPC(), triple.WithSendGzip())
-//		run(t, client, true)
-//	})
-//	t.Run("grpcweb", func(t *testing.T) {
-//		t.Parallel()
-//		server := newHTTP2Server(t)
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithGRPCWeb())
-//		run(t, client, false)
-//	})
-//	t.Run("grpcweb_gzip", func(t *testing.T) {
-//		t.Parallel()
-//		server := newHTTP2Server(t)
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithGRPCWeb(), triple.WithSendGzip())
-//		run(t, client, true)
-//	})
-//}
-//
-//func TestClientWithReadMaxBytes(t *testing.T) {
-//	t.Parallel()
-//	createServer := func(tb testing.TB, enableCompression bool) *httptest.Server {
-//		tb.Helper()
-//		mux := http.NewServeMux()
-//		var compressionOption triple.HandlerOption
-//		if enableCompression {
-//			compressionOption = triple.WithCompressMinBytes(1)
-//		} else {
-//			compressionOption = triple.WithCompressMinBytes(math.MaxInt)
-//		}
-//		mux.Handle(pingv1connect.NewPingServiceHandler(pingServer{}, compressionOption))
-//		server := httptest.NewUnstartedServer(mux)
-//		server.EnableHTTP2 = true
-//		server.StartTLS()
-//		tb.Cleanup(server.Close)
-//		return server
-//	}
-//	serverUncompressed := createServer(t, false)
-//	serverCompressed := createServer(t, true)
-//	readMaxBytes := 1024
-//	readMaxBytesMatrix := func(t *testing.T, client pingv1connect.PingServiceClient, compressed bool) {
-//		t.Helper()
-//		t.Run("equal_read_max", func(t *testing.T) {
-//			t.Parallel()
-//			// Serializes to exactly readMaxBytes (1024) - no errors expected
-//			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("a", 1021)}
-//			assert.Equal(t, proto.Size(pingRequest), readMaxBytes)
-//			_, err := client.Ping(context.Background(), triple.NewRequest(pingRequest))
-//			assert.Nil(t, err)
-//		})
-//		t.Run("read_max_plus_one", func(t *testing.T) {
-//			t.Parallel()
-//			// Serializes to readMaxBytes+1 (1025) - expect resource exhausted.
-//			// This will be over the limit after decompression but under with compression.
-//			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("a", 1022)}
-//			_, err := client.Ping(context.Background(), triple.NewRequest(pingRequest))
-//			assert.NotNil(t, err, assert.Sprintf("expected non-nil error for large message"))
-//			assert.Equal(t, triple.CodeOf(err), triple.CodeResourceExhausted)
-//			assert.True(t, strings.HasSuffix(err.Error(), fmt.Sprintf("message size %d is larger than configured max %d", proto.Size(pingRequest), readMaxBytes)))
-//		})
-//		t.Run("read_max_large", func(t *testing.T) {
-//			t.Parallel()
-//			if testing.Short() {
-//				t.Skipf("skipping %s test in short mode", t.Name())
-//			}
-//			// Serializes to much larger than readMaxBytes (5 MiB)
-//			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("abcde", 1024*1024)}
-//			expectedSize := proto.Size(pingRequest)
-//			// With gzip response compression, the error should indicate the envelope size (before decompression) is too large.
-//			if compressed {
-//				expectedSize = gzipCompressedSize(t, pingRequest)
-//				assert.True(t, expectedSize > readMaxBytes, assert.Sprintf("expected compressed size %d > %d", expectedSize, readMaxBytes))
-//			}
-//			assert.True(t, expectedSize > readMaxBytes, assert.Sprintf("expected compressed size %d > %d", expectedSize, readMaxBytes))
-//			_, err := client.Ping(context.Background(), triple.NewRequest(pingRequest))
-//			assert.NotNil(t, err, assert.Sprintf("expected non-nil error for large message"))
-//			assert.Equal(t, triple.CodeOf(err), triple.CodeResourceExhausted)
-//			assert.Equal(t, err.Error(), fmt.Sprintf("resource_exhausted: message size %d is larger than configured max %d", expectedSize, readMaxBytes))
-//		})
-//	}
-//	t.Run("connect", func(t *testing.T) {
-//		t.Parallel()
-//		client := pingv1connect.NewPingServiceClient(serverUncompressed.Client(), serverUncompressed.URL, triple.WithReadMaxBytes(readMaxBytes))
-//		readMaxBytesMatrix(t, client, false)
-//	})
-//	t.Run("connect_gzip", func(t *testing.T) {
-//		t.Parallel()
-//		client := pingv1connect.NewPingServiceClient(serverCompressed.Client(), serverCompressed.URL, triple.WithReadMaxBytes(readMaxBytes))
-//		readMaxBytesMatrix(t, client, true)
-//	})
-//	t.Run("grpc", func(t *testing.T) {
-//		t.Parallel()
-//		client := pingv1connect.NewPingServiceClient(serverUncompressed.Client(), serverUncompressed.URL, triple.WithReadMaxBytes(readMaxBytes), triple.WithGRPC())
-//		readMaxBytesMatrix(t, client, false)
-//	})
-//	t.Run("grpc_gzip", func(t *testing.T) {
-//		t.Parallel()
-//		client := pingv1connect.NewPingServiceClient(serverCompressed.Client(), serverCompressed.URL, triple.WithReadMaxBytes(readMaxBytes), triple.WithGRPC())
-//		readMaxBytesMatrix(t, client, true)
-//	})
-//	t.Run("grpcweb", func(t *testing.T) {
-//		t.Parallel()
-//		client := pingv1connect.NewPingServiceClient(serverUncompressed.Client(), serverUncompressed.URL, triple.WithReadMaxBytes(readMaxBytes), triple.WithGRPCWeb())
-//		readMaxBytesMatrix(t, client, false)
-//	})
-//	t.Run("grpcweb_gzip", func(t *testing.T) {
-//		t.Parallel()
-//		client := pingv1connect.NewPingServiceClient(serverCompressed.Client(), serverCompressed.URL, triple.WithReadMaxBytes(readMaxBytes), triple.WithGRPCWeb())
-//		readMaxBytesMatrix(t, client, true)
-//	})
-//}
-//
-//func TestHandlerWithSendMaxBytes(t *testing.T) {
-//	t.Parallel()
-//	sendMaxBytes := 1024
-//	sendMaxBytesMatrix := func(t *testing.T, client pingv1connect.PingServiceClient, compressed bool) {
-//		t.Helper()
-//		t.Run("equal_send_max", func(t *testing.T) {
-//			t.Parallel()
-//			// Serializes to exactly sendMaxBytes (1024) - no errors expected
-//			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("a", 1021)}
-//			assert.Equal(t, proto.Size(pingRequest), sendMaxBytes)
-//			_, err := client.Ping(context.Background(), triple.NewRequest(pingRequest))
-//			assert.Nil(t, err)
-//		})
-//		t.Run("send_max_plus_one", func(t *testing.T) {
-//			t.Parallel()
-//			// Serializes to sendMaxBytes+1 (1025) - expect invalid argument.
-//			// This will be over the limit after decompression but under with compression.
-//			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("a", 1022)}
-//			if compressed {
-//				compressedSize := gzipCompressedSize(t, pingRequest)
-//				assert.True(t, compressedSize < sendMaxBytes, assert.Sprintf("expected compressed size %d < %d", compressedSize, sendMaxBytes))
-//			}
-//			_, err := client.Ping(context.Background(), triple.NewRequest(pingRequest))
-//			if compressed {
-//				assert.Nil(t, err)
-//			} else {
-//				assert.NotNil(t, err, assert.Sprintf("expected non-nil error for large message"))
-//				assert.Equal(t, triple.CodeOf(err), triple.CodeResourceExhausted)
-//				assert.True(t, strings.HasSuffix(err.Error(), fmt.Sprintf("message size %d exceeds sendMaxBytes %d", proto.Size(pingRequest), sendMaxBytes)))
-//			}
-//		})
-//		t.Run("send_max_large", func(t *testing.T) {
-//			t.Parallel()
-//			if testing.Short() {
-//				t.Skipf("skipping %s test in short mode", t.Name())
-//			}
-//			// Serializes to much larger than sendMaxBytes (5 MiB)
-//			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("abcde", 1024*1024)}
-//			expectedSize := proto.Size(pingRequest)
-//			// With gzip request compression, the error should indicate the envelope size (before decompression) is too large.
-//			if compressed {
-//				expectedSize = gzipCompressedSize(t, pingRequest)
-//				assert.True(t, expectedSize > sendMaxBytes, assert.Sprintf("expected compressed size %d > %d", expectedSize, sendMaxBytes))
-//			}
-//			_, err := client.Ping(context.Background(), triple.NewRequest(pingRequest))
-//			assert.NotNil(t, err, assert.Sprintf("expected non-nil error for large message"))
-//			assert.Equal(t, triple.CodeOf(err), triple.CodeResourceExhausted)
-//			if compressed {
-//				assert.Equal(t, err.Error(), fmt.Sprintf("resource_exhausted: compressed message size %d exceeds sendMaxBytes %d", expectedSize, sendMaxBytes))
-//			} else {
-//				assert.Equal(t, err.Error(), fmt.Sprintf("resource_exhausted: message size %d exceeds sendMaxBytes %d", expectedSize, sendMaxBytes))
-//			}
-//		})
-//	}
-//	newHTTP2Server := func(t *testing.T, compressed bool, sendMaxBytes int) *httptest.Server {
-//		t.Helper()
-//		mux := http.NewServeMux()
-//		options := []triple.HandlerOption{triple.WithSendMaxBytes(sendMaxBytes)}
-//		if compressed {
-//			options = append(options, triple.WithCompressMinBytes(1))
-//		} else {
-//			options = append(options, triple.WithCompressMinBytes(math.MaxInt))
-//		}
-//		mux.Handle(pingv1connect.NewPingServiceHandler(
-//			pingServer{},
-//			options...,
-//		))
-//		server := httptest.NewUnstartedServer(mux)
-//		server.EnableHTTP2 = true
-//		server.StartTLS()
-//		t.Cleanup(server.Close)
-//		return server
-//	}
-//	t.Run("connect", func(t *testing.T) {
-//		t.Parallel()
-//		server := newHTTP2Server(t, false, sendMaxBytes)
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL)
-//		sendMaxBytesMatrix(t, client, false)
-//	})
-//	t.Run("connect_gzip", func(t *testing.T) {
-//		t.Parallel()
-//		server := newHTTP2Server(t, true, sendMaxBytes)
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL)
-//		sendMaxBytesMatrix(t, client, true)
-//	})
-//	t.Run("grpc", func(t *testing.T) {
-//		t.Parallel()
-//		server := newHTTP2Server(t, false, sendMaxBytes)
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithGRPC())
-//		sendMaxBytesMatrix(t, client, false)
-//	})
-//	t.Run("grpc_gzip", func(t *testing.T) {
-//		t.Parallel()
-//		server := newHTTP2Server(t, true, sendMaxBytes)
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithGRPC())
-//		sendMaxBytesMatrix(t, client, true)
-//	})
-//	t.Run("grpcweb", func(t *testing.T) {
-//		t.Parallel()
-//		server := newHTTP2Server(t, false, sendMaxBytes)
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithGRPCWeb())
-//		sendMaxBytesMatrix(t, client, false)
-//	})
-//	t.Run("grpcweb_gzip", func(t *testing.T) {
-//		t.Parallel()
-//		server := newHTTP2Server(t, true, sendMaxBytes)
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithGRPCWeb())
-//		sendMaxBytesMatrix(t, client, true)
-//	})
-//}
-//
-//func TestClientWithSendMaxBytes(t *testing.T) {
-//	t.Parallel()
-//	mux := http.NewServeMux()
-//	mux.Handle(pingv1connect.NewPingServiceHandler(pingServer{}))
-//	server := httptest.NewUnstartedServer(mux)
-//	server.EnableHTTP2 = true
-//	server.StartTLS()
-//	t.Cleanup(server.Close)
-//	sendMaxBytesMatrix := func(t *testing.T, client pingv1connect.PingServiceClient, sendMaxBytes int, compressed bool) {
-//		t.Helper()
-//		t.Run("equal_send_max", func(t *testing.T) {
-//			t.Parallel()
-//			// Serializes to exactly sendMaxBytes (1024) - no errors expected
-//			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("a", 1021)}
-//			assert.Equal(t, proto.Size(pingRequest), sendMaxBytes)
-//			_, err := client.Ping(context.Background(), triple.NewRequest(pingRequest))
-//			assert.Nil(t, err)
-//		})
-//		t.Run("send_max_plus_one", func(t *testing.T) {
-//			t.Parallel()
-//			// Serializes to sendMaxBytes+1 (1025) - expect resource exhausted.
-//			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("a", 1022)}
-//			assert.Equal(t, proto.Size(pingRequest), sendMaxBytes+1)
-//			_, err := client.Ping(context.Background(), triple.NewRequest(pingRequest))
-//			if compressed {
-//				assert.True(t, gzipCompressedSize(t, pingRequest) < sendMaxBytes)
-//				assert.Nil(t, err, assert.Sprintf("expected nil error for compressed message < sendMaxBytes"))
-//			} else {
-//				assert.NotNil(t, err, assert.Sprintf("expected non-nil error for large message"))
-//				assert.Equal(t, triple.CodeOf(err), triple.CodeResourceExhausted)
-//				assert.True(t, strings.HasSuffix(err.Error(), fmt.Sprintf("message size %d exceeds sendMaxBytes %d", proto.Size(pingRequest), sendMaxBytes)))
-//			}
-//		})
-//		t.Run("send_max_large", func(t *testing.T) {
-//			t.Parallel()
-//			if testing.Short() {
-//				t.Skipf("skipping %s test in short mode", t.Name())
-//			}
-//			// Serializes to much larger than sendMaxBytes (5 MiB)
-//			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("abcde", 1024*1024)}
-//			expectedSize := proto.Size(pingRequest)
-//			// With gzip response compression, the error should indicate the envelope size (before decompression) is too large.
-//			if compressed {
-//				expectedSize = gzipCompressedSize(t, pingRequest)
-//			}
-//			assert.True(t, expectedSize > sendMaxBytes)
-//			_, err := client.Ping(context.Background(), triple.NewRequest(pingRequest))
-//			assert.NotNil(t, err, assert.Sprintf("expected non-nil error for large message"))
-//			assert.Equal(t, triple.CodeOf(err), triple.CodeResourceExhausted)
-//			if compressed {
-//				assert.Equal(t, err.Error(), fmt.Sprintf("resource_exhausted: compressed message size %d exceeds sendMaxBytes %d", expectedSize, sendMaxBytes))
-//			} else {
-//				assert.Equal(t, err.Error(), fmt.Sprintf("resource_exhausted: message size %d exceeds sendMaxBytes %d", expectedSize, sendMaxBytes))
-//			}
-//		})
-//	}
-//	t.Run("connect", func(t *testing.T) {
-//		t.Parallel()
-//		sendMaxBytes := 1024
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithSendMaxBytes(sendMaxBytes))
-//		sendMaxBytesMatrix(t, client, sendMaxBytes, false)
-//	})
-//	t.Run("connect_gzip", func(t *testing.T) {
-//		t.Parallel()
-//		sendMaxBytes := 1024
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithSendMaxBytes(sendMaxBytes), triple.WithSendGzip())
-//		sendMaxBytesMatrix(t, client, sendMaxBytes, true)
-//	})
-//	t.Run("grpc", func(t *testing.T) {
-//		t.Parallel()
-//		sendMaxBytes := 1024
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithSendMaxBytes(sendMaxBytes), triple.WithGRPC())
-//		sendMaxBytesMatrix(t, client, sendMaxBytes, false)
-//	})
-//	t.Run("grpc_gzip", func(t *testing.T) {
-//		t.Parallel()
-//		sendMaxBytes := 1024
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithSendMaxBytes(sendMaxBytes), triple.WithGRPC(), triple.WithSendGzip())
-//		sendMaxBytesMatrix(t, client, sendMaxBytes, true)
-//	})
-//	t.Run("grpcweb", func(t *testing.T) {
-//		t.Parallel()
-//		sendMaxBytes := 1024
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithSendMaxBytes(sendMaxBytes), triple.WithGRPCWeb())
-//		sendMaxBytesMatrix(t, client, sendMaxBytes, false)
-//	})
-//	t.Run("grpcweb_gzip", func(t *testing.T) {
-//		t.Parallel()
-//		sendMaxBytes := 1024
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithSendMaxBytes(sendMaxBytes), triple.WithGRPCWeb(), triple.WithSendGzip())
-//		sendMaxBytesMatrix(t, client, sendMaxBytes, true)
-//	})
-//}
-//
+
+func TestHandlerWithReadMaxBytes(t *testing.T) {
+	t.Parallel()
+	mux := http.NewServeMux()
+	readMaxBytes := 1024
+	mux.Handle(pingv1connect.NewPingServiceHandler(
+		pingServer{},
+		triple.WithReadMaxBytes(readMaxBytes),
+	))
+	readMaxBytesMatrix := func(t *testing.T, client pingv1connect.PingServiceClient, compressed bool) {
+		t.Helper()
+		t.Run("equal_read_max", func(t *testing.T) {
+			t.Parallel()
+			// Serializes to exactly readMaxBytes (1024) - no errors expected
+			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("a", 1021)}
+			assert.Equal(t, proto.Size(pingRequest), readMaxBytes)
+			err := client.Ping(context.Background(), triple.NewRequest(pingRequest), triple.NewResponse(&pingv1.PingResponse{}))
+			assert.Nil(t, err)
+		})
+		t.Run("read_max_plus_one", func(t *testing.T) {
+			t.Parallel()
+			// Serializes to readMaxBytes+1 (1025) - expect invalid argument.
+			// This will be over the limit after decompression but under with compression.
+			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("a", 1022)}
+			if compressed {
+				compressedSize := gzipCompressedSize(t, pingRequest)
+				assert.True(t, compressedSize < readMaxBytes, assert.Sprintf("expected compressed size %d < %d", compressedSize, readMaxBytes))
+			}
+			err := client.Ping(context.Background(), triple.NewRequest(pingRequest), triple.NewResponse(&pingv1.PingResponse{}))
+			assert.NotNil(t, err, assert.Sprintf("expected non-nil error for large message"))
+			assert.Equal(t, triple.CodeOf(err), triple.CodeResourceExhausted)
+			assert.True(t, strings.HasSuffix(err.Error(), fmt.Sprintf("message size %d is larger than configured max %d", proto.Size(pingRequest), readMaxBytes)))
+		})
+		t.Run("read_max_large", func(t *testing.T) {
+			t.Parallel()
+			if testing.Short() {
+				t.Skipf("skipping %s test in short mode", t.Name())
+			}
+			// Serializes to much larger than readMaxBytes (5 MiB)
+			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("abcde", 1024*1024)}
+			expectedSize := proto.Size(pingRequest)
+			// With gzip request compression, the error should indicate the envelope size (before decompression) is too large.
+			if compressed {
+				expectedSize = gzipCompressedSize(t, pingRequest)
+				assert.True(t, expectedSize > readMaxBytes, assert.Sprintf("expected compressed size %d > %d", expectedSize, readMaxBytes))
+			}
+			err := client.Ping(context.Background(), triple.NewRequest(pingRequest), triple.NewResponse(&pingv1.PingResponse{}))
+			assert.NotNil(t, err, assert.Sprintf("expected non-nil error for large message"))
+			assert.Equal(t, triple.CodeOf(err), triple.CodeResourceExhausted)
+			assert.Equal(t, err.Error(), fmt.Sprintf("resource_exhausted: message size %d is larger than configured max %d", expectedSize, readMaxBytes))
+		})
+	}
+	newHTTP2Server := func(t *testing.T) *httptest.Server {
+		t.Helper()
+		server := httptest.NewUnstartedServer(mux)
+		server.EnableHTTP2 = true
+		server.StartTLS()
+		t.Cleanup(server.Close)
+		return server
+	}
+	t.Run("triple", func(t *testing.T) {
+		t.Parallel()
+		server := newHTTP2Server(t)
+		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL)
+		readMaxBytesMatrix(t, client, false)
+	})
+	t.Run("connect_gzip", func(t *testing.T) {
+		t.Parallel()
+		server := newHTTP2Server(t)
+		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithSendGzip())
+		readMaxBytesMatrix(t, client, true)
+	})
+	t.Run("grpc", func(t *testing.T) {
+		t.Parallel()
+		server := newHTTP2Server(t)
+		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithGRPC())
+		readMaxBytesMatrix(t, client, false)
+	})
+	t.Run("grpc_gzip", func(t *testing.T) {
+		t.Parallel()
+		server := newHTTP2Server(t)
+		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithGRPC(), triple.WithSendGzip())
+		readMaxBytesMatrix(t, client, true)
+	})
+}
+
+func TestHandlerWithHTTPMaxBytes(t *testing.T) {
+	// This is similar to Connect's own ReadMaxBytes option, but applied to the
+	// whole stream using the stdlib's http.MaxBytesHandler.
+	t.Parallel()
+	const readMaxBytes = 128
+	mux := http.NewServeMux()
+	pingRoute, pingHandler := pingv1connect.NewPingServiceHandler(pingServer{})
+	mux.Handle(pingRoute, http.MaxBytesHandler(pingHandler, readMaxBytes))
+	run := func(t *testing.T, client pingv1connect.PingServiceClient, compressed bool) {
+		t.Helper()
+		t.Run("below_read_max", func(t *testing.T) {
+			t.Parallel()
+			err := client.Ping(context.Background(), triple.NewRequest(&pingv1.PingRequest{}), triple.NewResponse(&pingv1.PingResponse{}))
+			assert.Nil(t, err)
+		})
+		t.Run("just_above_max", func(t *testing.T) {
+			t.Parallel()
+			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("a", readMaxBytes*10)}
+			err := client.Ping(context.Background(), triple.NewRequest(pingRequest), triple.NewResponse(&pingv1.PingResponse{}))
+			if compressed {
+				compressedSize := gzipCompressedSize(t, pingRequest)
+				assert.True(t, compressedSize < readMaxBytes, assert.Sprintf("expected compressed size %d < %d", compressedSize, readMaxBytes))
+				assert.Nil(t, err)
+				return
+			}
+			assert.NotNil(t, err, assert.Sprintf("expected non-nil error for large message"))
+			assert.Equal(t, triple.CodeOf(err), triple.CodeResourceExhausted)
+		})
+		t.Run("read_max_large", func(t *testing.T) {
+			t.Parallel()
+			if testing.Short() {
+				t.Skipf("skipping %s test in short mode", t.Name())
+			}
+			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("abcde", 1024*1024)}
+			if compressed {
+				expectedSize := gzipCompressedSize(t, pingRequest)
+				assert.True(t, expectedSize > readMaxBytes, assert.Sprintf("expected compressed size %d > %d", expectedSize, readMaxBytes))
+			}
+			err := client.Ping(context.Background(), triple.NewRequest(pingRequest), triple.NewResponse(&pingv1.PingResponse{}))
+			assert.NotNil(t, err, assert.Sprintf("expected non-nil error for large message"))
+			assert.Equal(t, triple.CodeOf(err), triple.CodeResourceExhausted)
+		})
+	}
+	newHTTP2Server := func(t *testing.T) *httptest.Server {
+		t.Helper()
+		server := httptest.NewUnstartedServer(mux)
+		server.EnableHTTP2 = true
+		server.StartTLS()
+		t.Cleanup(server.Close)
+		return server
+	}
+	t.Run("triple", func(t *testing.T) {
+		t.Parallel()
+		server := newHTTP2Server(t)
+		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL)
+		run(t, client, false)
+	})
+	t.Run("connect_gzip", func(t *testing.T) {
+		t.Parallel()
+		server := newHTTP2Server(t)
+		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithSendGzip())
+		run(t, client, true)
+	})
+	t.Run("grpc", func(t *testing.T) {
+		t.Parallel()
+		server := newHTTP2Server(t)
+		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithGRPC())
+		run(t, client, false)
+	})
+	t.Run("grpc_gzip", func(t *testing.T) {
+		t.Parallel()
+		server := newHTTP2Server(t)
+		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithGRPC(), triple.WithSendGzip())
+		run(t, client, true)
+	})
+}
+
+func TestClientWithReadMaxBytes(t *testing.T) {
+	t.Parallel()
+	createServer := func(tb testing.TB, enableCompression bool) *httptest.Server {
+		tb.Helper()
+		mux := http.NewServeMux()
+		var compressionOption triple.HandlerOption
+		if enableCompression {
+			compressionOption = triple.WithCompressMinBytes(1)
+		} else {
+			compressionOption = triple.WithCompressMinBytes(math.MaxInt)
+		}
+		mux.Handle(pingv1connect.NewPingServiceHandler(pingServer{}, compressionOption))
+		server := httptest.NewUnstartedServer(mux)
+		server.EnableHTTP2 = true
+		server.StartTLS()
+		tb.Cleanup(server.Close)
+		return server
+	}
+	serverUncompressed := createServer(t, false)
+	serverCompressed := createServer(t, true)
+	readMaxBytes := 1024
+	readMaxBytesMatrix := func(t *testing.T, client pingv1connect.PingServiceClient, compressed bool) {
+		t.Helper()
+		t.Run("equal_read_max", func(t *testing.T) {
+			t.Parallel()
+			// Serializes to exactly readMaxBytes (1024) - no errors expected
+			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("a", 1021)}
+			assert.Equal(t, proto.Size(pingRequest), readMaxBytes)
+			err := client.Ping(context.Background(), triple.NewRequest(pingRequest), triple.NewResponse(&pingv1.PingResponse{}))
+			assert.Nil(t, err)
+		})
+		t.Run("read_max_plus_one", func(t *testing.T) {
+			t.Parallel()
+			// Serializes to readMaxBytes+1 (1025) - expect resource exhausted.
+			// This will be over the limit after decompression but under with compression.
+			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("a", 1022)}
+			err := client.Ping(context.Background(), triple.NewRequest(pingRequest), triple.NewResponse(&pingv1.PingResponse{}))
+			assert.NotNil(t, err, assert.Sprintf("expected non-nil error for large message"))
+			assert.Equal(t, triple.CodeOf(err), triple.CodeResourceExhausted)
+			assert.True(t, strings.HasSuffix(err.Error(), fmt.Sprintf("message size %d is larger than configured max %d", proto.Size(pingRequest), readMaxBytes)))
+		})
+		t.Run("read_max_large", func(t *testing.T) {
+			t.Parallel()
+			if testing.Short() {
+				t.Skipf("skipping %s test in short mode", t.Name())
+			}
+			// Serializes to much larger than readMaxBytes (5 MiB)
+			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("abcde", 1024*1024)}
+			expectedSize := proto.Size(pingRequest)
+			// With gzip response compression, the error should indicate the envelope size (before decompression) is too large.
+			if compressed {
+				expectedSize = gzipCompressedSize(t, pingRequest)
+				assert.True(t, expectedSize > readMaxBytes, assert.Sprintf("expected compressed size %d > %d", expectedSize, readMaxBytes))
+			}
+			assert.True(t, expectedSize > readMaxBytes, assert.Sprintf("expected compressed size %d > %d", expectedSize, readMaxBytes))
+			err := client.Ping(context.Background(), triple.NewRequest(pingRequest), triple.NewResponse(&pingv1.PingResponse{}))
+			assert.NotNil(t, err, assert.Sprintf("expected non-nil error for large message"))
+			assert.Equal(t, triple.CodeOf(err), triple.CodeResourceExhausted)
+			assert.Equal(t, err.Error(), fmt.Sprintf("resource_exhausted: message size %d is larger than configured max %d", expectedSize, readMaxBytes))
+		})
+	}
+	t.Run("triple", func(t *testing.T) {
+		t.Parallel()
+		client := pingv1connect.NewPingServiceClient(serverUncompressed.Client(), serverUncompressed.URL, triple.WithReadMaxBytes(readMaxBytes))
+		readMaxBytesMatrix(t, client, false)
+	})
+	t.Run("connect_gzip", func(t *testing.T) {
+		t.Parallel()
+		client := pingv1connect.NewPingServiceClient(serverCompressed.Client(), serverCompressed.URL, triple.WithReadMaxBytes(readMaxBytes))
+		readMaxBytesMatrix(t, client, true)
+	})
+	t.Run("grpc", func(t *testing.T) {
+		t.Parallel()
+		client := pingv1connect.NewPingServiceClient(serverUncompressed.Client(), serverUncompressed.URL, triple.WithReadMaxBytes(readMaxBytes), triple.WithGRPC())
+		readMaxBytesMatrix(t, client, false)
+	})
+	t.Run("grpc_gzip", func(t *testing.T) {
+		t.Parallel()
+		client := pingv1connect.NewPingServiceClient(serverCompressed.Client(), serverCompressed.URL, triple.WithReadMaxBytes(readMaxBytes), triple.WithGRPC())
+		readMaxBytesMatrix(t, client, true)
+	})
+}
+
+func TestHandlerWithSendMaxBytes(t *testing.T) {
+	t.Parallel()
+	sendMaxBytes := 1024
+	sendMaxBytesMatrix := func(t *testing.T, client pingv1connect.PingServiceClient, compressed bool) {
+		t.Helper()
+		t.Run("equal_send_max", func(t *testing.T) {
+			t.Parallel()
+			// Serializes to exactly sendMaxBytes (1024) - no errors expected
+			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("a", 1021)}
+			assert.Equal(t, proto.Size(pingRequest), sendMaxBytes)
+			err := client.Ping(context.Background(), triple.NewRequest(pingRequest), triple.NewResponse(&pingv1.PingResponse{}))
+			assert.Nil(t, err)
+		})
+		t.Run("send_max_plus_one", func(t *testing.T) {
+			t.Parallel()
+			// Serializes to sendMaxBytes+1 (1025) - expect invalid argument.
+			// This will be over the limit after decompression but under with compression.
+			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("a", 1022)}
+			if compressed {
+				compressedSize := gzipCompressedSize(t, pingRequest)
+				assert.True(t, compressedSize < sendMaxBytes, assert.Sprintf("expected compressed size %d < %d", compressedSize, sendMaxBytes))
+			}
+			err := client.Ping(context.Background(), triple.NewRequest(pingRequest), triple.NewResponse(&pingv1.PingResponse{}))
+			if compressed {
+				assert.Nil(t, err)
+			} else {
+				assert.NotNil(t, err, assert.Sprintf("expected non-nil error for large message"))
+				assert.Equal(t, triple.CodeOf(err), triple.CodeResourceExhausted)
+				assert.True(t, strings.HasSuffix(err.Error(), fmt.Sprintf("message size %d exceeds sendMaxBytes %d", proto.Size(pingRequest), sendMaxBytes)))
+			}
+		})
+		t.Run("send_max_large", func(t *testing.T) {
+			t.Parallel()
+			if testing.Short() {
+				t.Skipf("skipping %s test in short mode", t.Name())
+			}
+			// Serializes to much larger than sendMaxBytes (5 MiB)
+			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("abcde", 1024*1024)}
+			expectedSize := proto.Size(pingRequest)
+			// With gzip request compression, the error should indicate the envelope size (before decompression) is too large.
+			if compressed {
+				expectedSize = gzipCompressedSize(t, pingRequest)
+				assert.True(t, expectedSize > sendMaxBytes, assert.Sprintf("expected compressed size %d > %d", expectedSize, sendMaxBytes))
+			}
+			err := client.Ping(context.Background(), triple.NewRequest(pingRequest), triple.NewResponse(&pingv1.PingResponse{}))
+			assert.NotNil(t, err, assert.Sprintf("expected non-nil error for large message"))
+			assert.Equal(t, triple.CodeOf(err), triple.CodeResourceExhausted)
+			if compressed {
+				assert.Equal(t, err.Error(), fmt.Sprintf("resource_exhausted: compressed message size %d exceeds sendMaxBytes %d", expectedSize, sendMaxBytes))
+			} else {
+				assert.Equal(t, err.Error(), fmt.Sprintf("resource_exhausted: message size %d exceeds sendMaxBytes %d", expectedSize, sendMaxBytes))
+			}
+		})
+	}
+	newHTTP2Server := func(t *testing.T, compressed bool, sendMaxBytes int) *httptest.Server {
+		t.Helper()
+		mux := http.NewServeMux()
+		options := []triple.HandlerOption{triple.WithSendMaxBytes(sendMaxBytes)}
+		if compressed {
+			options = append(options, triple.WithCompressMinBytes(1))
+		} else {
+			options = append(options, triple.WithCompressMinBytes(math.MaxInt))
+		}
+		mux.Handle(pingv1connect.NewPingServiceHandler(
+			pingServer{},
+			options...,
+		))
+		server := httptest.NewUnstartedServer(mux)
+		server.EnableHTTP2 = true
+		server.StartTLS()
+		t.Cleanup(server.Close)
+		return server
+	}
+	t.Run("triple", func(t *testing.T) {
+		t.Parallel()
+		server := newHTTP2Server(t, false, sendMaxBytes)
+		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL)
+		sendMaxBytesMatrix(t, client, false)
+	})
+	t.Run("connect_gzip", func(t *testing.T) {
+		t.Parallel()
+		server := newHTTP2Server(t, true, sendMaxBytes)
+		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL)
+		sendMaxBytesMatrix(t, client, true)
+	})
+	t.Run("grpc", func(t *testing.T) {
+		t.Parallel()
+		server := newHTTP2Server(t, false, sendMaxBytes)
+		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithGRPC())
+		sendMaxBytesMatrix(t, client, false)
+	})
+	t.Run("grpc_gzip", func(t *testing.T) {
+		t.Parallel()
+		server := newHTTP2Server(t, true, sendMaxBytes)
+		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithGRPC())
+		sendMaxBytesMatrix(t, client, true)
+	})
+}
+
+func TestClientWithSendMaxBytes(t *testing.T) {
+	t.Parallel()
+	mux := http.NewServeMux()
+	mux.Handle(pingv1connect.NewPingServiceHandler(pingServer{}))
+	server := httptest.NewUnstartedServer(mux)
+	server.EnableHTTP2 = true
+	server.StartTLS()
+	t.Cleanup(server.Close)
+	sendMaxBytesMatrix := func(t *testing.T, client pingv1connect.PingServiceClient, sendMaxBytes int, compressed bool) {
+		t.Helper()
+		t.Run("equal_send_max", func(t *testing.T) {
+			t.Parallel()
+			// Serializes to exactly sendMaxBytes (1024) - no errors expected
+			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("a", 1021)}
+			assert.Equal(t, proto.Size(pingRequest), sendMaxBytes)
+			err := client.Ping(context.Background(), triple.NewRequest(pingRequest), triple.NewResponse(&pingv1.PingResponse{}))
+			assert.Nil(t, err)
+		})
+		t.Run("send_max_plus_one", func(t *testing.T) {
+			t.Parallel()
+			// Serializes to sendMaxBytes+1 (1025) - expect resource exhausted.
+			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("a", 1022)}
+			assert.Equal(t, proto.Size(pingRequest), sendMaxBytes+1)
+			err := client.Ping(context.Background(), triple.NewRequest(pingRequest), triple.NewResponse(&pingv1.PingResponse{}))
+			if compressed {
+				assert.True(t, gzipCompressedSize(t, pingRequest) < sendMaxBytes)
+				assert.Nil(t, err, assert.Sprintf("expected nil error for compressed message < sendMaxBytes"))
+			} else {
+				assert.NotNil(t, err, assert.Sprintf("expected non-nil error for large message"))
+				assert.Equal(t, triple.CodeOf(err), triple.CodeResourceExhausted)
+				assert.True(t, strings.HasSuffix(err.Error(), fmt.Sprintf("message size %d exceeds sendMaxBytes %d", proto.Size(pingRequest), sendMaxBytes)))
+			}
+		})
+		t.Run("send_max_large", func(t *testing.T) {
+			t.Parallel()
+			if testing.Short() {
+				t.Skipf("skipping %s test in short mode", t.Name())
+			}
+			// Serializes to much larger than sendMaxBytes (5 MiB)
+			pingRequest := &pingv1.PingRequest{Text: strings.Repeat("abcde", 1024*1024)}
+			expectedSize := proto.Size(pingRequest)
+			// With gzip response compression, the error should indicate the envelope size (before decompression) is too large.
+			if compressed {
+				expectedSize = gzipCompressedSize(t, pingRequest)
+			}
+			assert.True(t, expectedSize > sendMaxBytes)
+			err := client.Ping(context.Background(), triple.NewRequest(pingRequest), triple.NewResponse(&pingv1.PingResponse{}))
+			assert.NotNil(t, err, assert.Sprintf("expected non-nil error for large message"))
+			assert.Equal(t, triple.CodeOf(err), triple.CodeResourceExhausted)
+			if compressed {
+				assert.Equal(t, err.Error(), fmt.Sprintf("resource_exhausted: compressed message size %d exceeds sendMaxBytes %d", expectedSize, sendMaxBytes))
+			} else {
+				assert.Equal(t, err.Error(), fmt.Sprintf("resource_exhausted: message size %d exceeds sendMaxBytes %d", expectedSize, sendMaxBytes))
+			}
+		})
+	}
+	t.Run("triple", func(t *testing.T) {
+		t.Parallel()
+		sendMaxBytes := 1024
+		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithSendMaxBytes(sendMaxBytes))
+		sendMaxBytesMatrix(t, client, sendMaxBytes, false)
+	})
+	t.Run("connect_gzip", func(t *testing.T) {
+		t.Parallel()
+		sendMaxBytes := 1024
+		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithSendMaxBytes(sendMaxBytes), triple.WithSendGzip())
+		sendMaxBytesMatrix(t, client, sendMaxBytes, true)
+	})
+	t.Run("grpc", func(t *testing.T) {
+		t.Parallel()
+		sendMaxBytes := 1024
+		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithSendMaxBytes(sendMaxBytes), triple.WithGRPC())
+		sendMaxBytesMatrix(t, client, sendMaxBytes, false)
+	})
+	t.Run("grpc_gzip", func(t *testing.T) {
+		t.Parallel()
+		sendMaxBytes := 1024
+		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithSendMaxBytes(sendMaxBytes), triple.WithGRPC(), triple.WithSendGzip())
+		sendMaxBytesMatrix(t, client, sendMaxBytes, true)
+	})
+}
+
 //func TestBidiStreamServerSendsFirstMessage(t *testing.T) {
 //	t.Parallel()
 //	run := func(t *testing.T, opts ...triple.ClientOption) {
 //		t.Helper()
 //		headersSent := make(chan struct{})
 //		pingServer := &pluggablePingServer{
-//			cumSum: func(ctx context.Context, stream *triple.BidiStream[pingv1.CumSumRequest, pingv1.CumSumResponse]) error {
+//			cumSum: func(ctx context.Context, stream *triple.BidiStream) error {
 //				close(headersSent)
 //				return nil
 //			},
@@ -1471,7 +1416,7 @@
 //		case <-headersSent:
 //		}
 //	}
-//	t.Run("connect", func(t *testing.T) {
+//	t.Run("triple", func(t *testing.T) {
 //		t.Parallel()
 //		run(t)
 //	})
@@ -1479,324 +1424,322 @@
 //		t.Parallel()
 //		run(t, triple.WithGRPC())
 //	})
-//	t.Run("grpcweb", func(t *testing.T) {
-//		t.Parallel()
-//		run(t, triple.WithGRPCWeb())
-//	})
 //}
-//
+
 //func TestStreamForServer(t *testing.T) {
-//	t.Parallel()
-//	newPingServer := func(pingServer pingv1connect.PingServiceHandler) (pingv1connect.PingServiceClient, *httptest.Server) {
-//		mux := http.NewServeMux()
-//		mux.Handle(pingv1connect.NewPingServiceHandler(pingServer))
-//		server := httptest.NewUnstartedServer(mux)
-//		server.EnableHTTP2 = true
-//		server.StartTLS()
-//		client := pingv1connect.NewPingServiceClient(
-//			server.Client(),
-//			server.URL,
-//		)
-//		return client, server
-//	}
-//	t.Run("not-proto-message", func(t *testing.T) {
-//		t.Parallel()
-//		client, server := newPingServer(&pluggablePingServer{
-//			cumSum: func(ctx context.Context, stream *triple.BidiStream[pingv1.CumSumRequest, pingv1.CumSumResponse]) error {
-//				return stream.Conn().Send("foobar")
-//			},
-//		})
-//		t.Cleanup(server.Close)
-//		stream, err := client.CumSum(context.Background())
-//		assert.Nil(t, err)
-//		assert.Nil(t, stream.Send(nil))
-//		_, err = stream.Receive()
-//		assert.NotNil(t, err)
-//		assert.Equal(t, triple.CodeOf(err), triple.CodeInternal)
-//		assert.Nil(t, stream.CloseRequest())
-//	})
-//	t.Run("nil-message", func(t *testing.T) {
-//		t.Parallel()
-//		client, server := newPingServer(&pluggablePingServer{
-//			cumSum: func(ctx context.Context, stream *triple.BidiStream[pingv1.CumSumRequest, pingv1.CumSumResponse]) error {
-//				return stream.Send(nil)
-//			},
-//		})
-//		t.Cleanup(server.Close)
-//		stream, err := client.CumSum(context.Background())
-//		assert.Nil(t, err)
-//		assert.Nil(t, stream.Send(nil))
-//		_, err = stream.Receive()
-//		assert.NotNil(t, err)
-//		assert.Equal(t, triple.CodeOf(err), triple.CodeUnknown)
-//		assert.Nil(t, stream.CloseRequest())
-//	})
-//	t.Run("get-spec", func(t *testing.T) {
-//		t.Parallel()
-//		client, server := newPingServer(&pluggablePingServer{
-//			cumSum: func(ctx context.Context, stream *triple.BidiStream[pingv1.CumSumRequest, pingv1.CumSumResponse]) error {
-//				assert.Equal(t, stream.Spec().StreamType, triple.StreamTypeBidi)
-//				assert.Equal(t, stream.Spec().Procedure, pingv1connect.PingServiceCumSumProcedure)
-//				assert.False(t, stream.Spec().IsClient)
-//				return nil
-//			},
-//		})
-//		t.Cleanup(server.Close)
-//		stream, err := client.CumSum(context.Background())
-//		assert.Nil(t, err)
-//		assert.Nil(t, stream.Send(nil))
-//		assert.Nil(t, stream.CloseRequest())
-//	})
-//	t.Run("server-stream", func(t *testing.T) {
-//		t.Parallel()
-//		client, server := newPingServer(&pluggablePingServer{
-//			countUp: func(ctx context.Context, req *triple.Request[pingv1.CountUpRequest], stream *triple.ServerStream[pingv1.CountUpResponse]) error {
-//				assert.Equal(t, stream.Conn().Spec().StreamType, triple.StreamTypeServer)
-//				assert.Equal(t, stream.Conn().Spec().Procedure, pingv1connect.PingServiceCountUpProcedure)
-//				assert.False(t, stream.Conn().Spec().IsClient)
-//				assert.Nil(t, stream.Send(&pingv1.CountUpResponse{Number: 1}))
-//				return nil
-//			},
-//		})
-//		t.Cleanup(server.Close)
-//		stream, err := client.CountUp(context.Background(), triple.NewRequest(&pingv1.CountUpRequest{}))
-//		assert.Nil(t, err)
-//		assert.NotNil(t, stream)
-//		assert.Nil(t, stream.Close())
-//	})
-//	t.Run("server-stream-send", func(t *testing.T) {
-//		t.Parallel()
-//		client, server := newPingServer(&pluggablePingServer{
-//			countUp: func(ctx context.Context, req *triple.Request[pingv1.CountUpRequest], stream *triple.ServerStream[pingv1.CountUpResponse]) error {
-//				assert.Nil(t, stream.Send(&pingv1.CountUpResponse{Number: 1}))
-//				return nil
-//			},
-//		})
-//		t.Cleanup(server.Close)
-//		stream, err := client.CountUp(context.Background(), triple.NewRequest(&pingv1.CountUpRequest{}))
-//		assert.Nil(t, err)
-//		assert.True(t, stream.Receive())
-//		msg := stream.Msg()
-//		assert.NotNil(t, msg)
-//		assert.Equal(t, msg.Number, 1)
-//		assert.Nil(t, stream.Close())
-//	})
-//	t.Run("server-stream-send-nil", func(t *testing.T) {
-//		t.Parallel()
-//		client, server := newPingServer(&pluggablePingServer{
-//			countUp: func(ctx context.Context, req *triple.Request[pingv1.CountUpRequest], stream *triple.ServerStream[pingv1.CountUpResponse]) error {
-//				stream.ResponseHeader().Set("foo", "bar")
-//				stream.ResponseTrailer().Set("bas", "blah")
-//				assert.Nil(t, stream.Send(nil))
-//				return nil
-//			},
-//		})
-//		t.Cleanup(server.Close)
-//		stream, err := client.CountUp(context.Background(), triple.NewRequest(&pingv1.CountUpRequest{}))
-//		assert.Nil(t, err)
-//		assert.False(t, stream.Receive())
-//		headers := stream.ResponseHeader()
-//		assert.NotNil(t, headers)
-//		assert.Equal(t, headers.Get("foo"), "bar")
-//		trailers := stream.ResponseTrailer()
-//		assert.NotNil(t, trailers)
-//		assert.Equal(t, trailers.Get("bas"), "blah")
-//		assert.Nil(t, stream.Close())
-//	})
-//	t.Run("client-stream", func(t *testing.T) {
-//		t.Parallel()
-//		client, server := newPingServer(&pluggablePingServer{
-//			sum: func(ctx context.Context, stream *triple.ClientStream[pingv1.SumRequest]) (*triple.Response[pingv1.SumResponse], error) {
-//				assert.Equal(t, stream.Spec().StreamType, triple.StreamTypeClient)
-//				assert.Equal(t, stream.Spec().Procedure, pingv1connect.PingServiceSumProcedure)
-//				assert.False(t, stream.Spec().IsClient)
-//				assert.True(t, stream.Receive())
-//				msg := stream.Msg()
-//				assert.NotNil(t, msg)
-//				assert.Equal(t, msg.Number, 1)
-//				return triple.NewResponse(&pingv1.SumResponse{Sum: 1}), nil
-//			},
-//		})
-//		t.Cleanup(server.Close)
-//		stream, err := client.Sum(context.Background())
-//		assert.Nil(t, err)
-//		assert.Nil(t, stream.Send(&pingv1.SumRequest{Number: 1}))
-//		res, err := stream.CloseAndReceive()
-//		assert.Nil(t, err)
-//		assert.NotNil(t, res)
-//		assert.Equal(t, res.Msg.Sum, 1)
-//	})
-//	t.Run("client-stream-conn", func(t *testing.T) {
-//		t.Parallel()
-//		client, server := newPingServer(&pluggablePingServer{
-//			sum: func(ctx context.Context, stream *triple.ClientStream[pingv1.SumRequest]) (*triple.Response[pingv1.SumResponse], error) {
-//				assert.NotNil(t, stream.Conn().Send("not-proto"))
-//				return triple.NewResponse(&pingv1.SumResponse{}), nil
-//			},
-//		})
-//		t.Cleanup(server.Close)
-//		stream, err := client.Sum(context.Background())
-//		assert.Nil(t, err)
-//		assert.Nil(t, stream.Send(&pingv1.SumRequest{Number: 1}))
-//		res, err := stream.CloseAndReceive()
-//		assert.Nil(t, err)
-//		assert.NotNil(t, res)
-//	})
-//	t.Run("client-stream-send-msg", func(t *testing.T) {
-//		t.Parallel()
-//		client, server := newPingServer(&pluggablePingServer{
-//			sum: func(ctx context.Context, stream *triple.ClientStream[pingv1.SumRequest]) (*triple.Response[pingv1.SumResponse], error) {
-//				assert.Nil(t, stream.Conn().Send(&pingv1.SumResponse{Sum: 2}))
-//				return triple.NewResponse(&pingv1.SumResponse{}), nil
-//			},
-//		})
-//		t.Cleanup(server.Close)
-//		stream, err := client.Sum(context.Background())
-//		assert.Nil(t, err)
-//		assert.Nil(t, stream.Send(&pingv1.SumRequest{Number: 1}))
-//		res, err := stream.CloseAndReceive()
-//		assert.NotNil(t, err)
-//		assert.Equal(t, triple.CodeOf(err), triple.CodeUnknown)
-//		assert.Nil(t, res)
-//	})
-//}
-//
-//func TestConnectHTTPErrorCodes(t *testing.T) {
-//	t.Parallel()
-//	checkHTTPStatus := func(t *testing.T, connectCode triple.Code, wantHttpStatus int) {
-//		t.Helper()
-//		mux := http.NewServeMux()
-//		pluggableServer := &pluggablePingServer{
-//			ping: func(_ context.Context, _ *triple.Request[pingv1.PingRequest]) (*triple.Response[pingv1.PingResponse], error) {
-//				return nil, triple.NewError(connectCode, errors.New("error"))
-//			},
-//		}
-//		mux.Handle(pingv1connect.NewPingServiceHandler(pluggableServer))
-//		server := httptest.NewServer(mux)
-//		t.Cleanup(server.Close)
-//		req, err := http.NewRequestWithContext(
-//			context.Background(),
-//			http.MethodPost,
-//			server.URL+"/"+pingv1connect.PingServiceName+"/Ping",
-//			strings.NewReader("{}"),
-//		)
-//		assert.Nil(t, err)
-//		req.Header.Set("Content-Type", "application/json")
-//		resp, err := server.Client().Do(req)
-//		assert.Nil(t, err)
-//		defer resp.Body.Close()
-//		assert.Equal(t, wantHttpStatus, resp.StatusCode)
-//		connectClient := pingv1connect.NewPingServiceClient(server.Client(), server.URL)
-//		connectResp, err := connectClient.Ping(context.Background(), triple.NewRequest(&pingv1.PingRequest{}))
-//		assert.NotNil(t, err)
-//		assert.Nil(t, connectResp)
-//	}
-//	t.Run("CodeCanceled-408", func(t *testing.T) {
-//		t.Parallel()
-//		checkHTTPStatus(t, triple.CodeCanceled, 408)
-//	})
-//	t.Run("CodeUnknown-500", func(t *testing.T) {
-//		t.Parallel()
-//		checkHTTPStatus(t, triple.CodeUnknown, 500)
-//	})
-//	t.Run("CodeInvalidArgument-400", func(t *testing.T) {
-//		t.Parallel()
-//		checkHTTPStatus(t, triple.CodeInvalidArgument, 400)
-//	})
-//	t.Run("CodeDeadlineExceeded-408", func(t *testing.T) {
-//		t.Parallel()
-//		checkHTTPStatus(t, triple.CodeDeadlineExceeded, 408)
-//	})
-//	t.Run("CodeNotFound-404", func(t *testing.T) {
-//		t.Parallel()
-//		checkHTTPStatus(t, triple.CodeNotFound, 404)
-//	})
-//	t.Run("CodeAlreadyExists-409", func(t *testing.T) {
-//		t.Parallel()
-//		checkHTTPStatus(t, triple.CodeAlreadyExists, 409)
-//	})
-//	t.Run("CodePermissionDenied-403", func(t *testing.T) {
-//		t.Parallel()
-//		checkHTTPStatus(t, triple.CodePermissionDenied, 403)
-//	})
-//	t.Run("CodeResourceExhausted-429", func(t *testing.T) {
-//		t.Parallel()
-//		checkHTTPStatus(t, triple.CodeResourceExhausted, 429)
-//	})
-//	t.Run("CodeFailedPrecondition-412", func(t *testing.T) {
-//		t.Parallel()
-//		checkHTTPStatus(t, triple.CodeFailedPrecondition, 412)
-//	})
-//	t.Run("CodeAborted-409", func(t *testing.T) {
-//		t.Parallel()
-//		checkHTTPStatus(t, triple.CodeAborted, 409)
-//	})
-//	t.Run("CodeOutOfRange-400", func(t *testing.T) {
-//		t.Parallel()
-//		checkHTTPStatus(t, triple.CodeOutOfRange, 400)
-//	})
-//	t.Run("CodeUnimplemented-404", func(t *testing.T) {
-//		t.Parallel()
-//		checkHTTPStatus(t, triple.CodeUnimplemented, 404)
-//	})
-//	t.Run("CodeInternal-500", func(t *testing.T) {
-//		t.Parallel()
-//		checkHTTPStatus(t, triple.CodeInternal, 500)
-//	})
-//	t.Run("CodeUnavailable-503", func(t *testing.T) {
-//		t.Parallel()
-//		checkHTTPStatus(t, triple.CodeUnavailable, 503)
-//	})
-//	t.Run("CodeDataLoss-500", func(t *testing.T) {
-//		t.Parallel()
-//		checkHTTPStatus(t, triple.CodeDataLoss, 500)
-//	})
-//	t.Run("CodeUnauthenticated-401", func(t *testing.T) {
-//		t.Parallel()
-//		checkHTTPStatus(t, triple.CodeUnauthenticated, 401)
-//	})
-//	t.Run("100-500", func(t *testing.T) {
-//		t.Parallel()
-//		checkHTTPStatus(t, 100, 500)
-//	})
-//	t.Run("0-500", func(t *testing.T) {
-//		t.Parallel()
-//		checkHTTPStatus(t, 0, 500)
-//	})
-//}
-//
-//func TestFailCompression(t *testing.T) {
-//	t.Parallel()
+//t.Parallel()
+//newPingServer := func(pingServer pingv1connect.PingServiceHandler) (pingv1connect.PingServiceClient, *httptest.Server) {
 //	mux := http.NewServeMux()
-//	compressorName := "fail"
-//	compressor := func() triple.Compressor { return failCompressor{} }
-//	decompressor := func() triple.Decompressor { return failDecompressor{} }
-//	mux.Handle(
-//		pingv1connect.NewPingServiceHandler(
-//			pingServer{},
-//			triple.WithCompression(compressorName, decompressor, compressor),
-//		),
-//	)
+//	mux.Handle(pingv1connect.NewPingServiceHandler(pingServer))
 //	server := httptest.NewUnstartedServer(mux)
 //	server.EnableHTTP2 = true
 //	server.StartTLS()
-//	t.Cleanup(server.Close)
-//	pingclient := pingv1connect.NewPingServiceClient(
+//	client := pingv1connect.NewPingServiceClient(
 //		server.Client(),
 //		server.URL,
-//		triple.WithAcceptCompression(compressorName, decompressor, compressor),
-//		triple.WithSendCompression(compressorName),
 //	)
-//	_, err := pingclient.Ping(
-//		context.Background(),
-//		triple.NewRequest(&pingv1.PingRequest{
-//			Text: "ping",
-//		}),
-//	)
+//	return client, server
+//}
+//t.Run("not-proto-message", func(t *testing.T) {
+//	t.Parallel()
+//	client, server := newPingServer(&pluggablePingServer{
+//		cumSum: func(ctx context.Context, stream *triple.BidiStream) error {
+//			return stream.Conn().Send("foobar")
+//		},
+//	})
+//	t.Cleanup(server.Close)
+//	stream, err := client.CumSum(context.Background())
+//	assert.Nil(t, err)
+//	assert.Nil(t, stream.Send(nil))
+//	err = stream.Receive(&pingv1.CumSumResponse{})
 //	assert.NotNil(t, err)
 //	assert.Equal(t, triple.CodeOf(err), triple.CodeInternal)
+//	assert.Nil(t, stream.CloseRequest())
+//})
+//t.Run("nil-message", func(t *testing.T) {
+//	t.Parallel()
+//	client, server := newPingServer(&pluggablePingServer{
+//		cumSum: func(ctx context.Context, stream *triple.BidiStream) error {
+//			return stream.Send(nil)
+//		},
+//	})
+//	t.Cleanup(server.Close)
+//	stream, err := client.CumSum(context.Background())
+//	assert.Nil(t, err)
+//	assert.Nil(t, stream.Send(nil))
+//	err = stream.Receive(&pingv1.CumSumResponse{})
+//	assert.NotNil(t, err)
+//	assert.Equal(t, triple.CodeOf(err), triple.CodeUnknown)
+//	assert.Nil(t, stream.CloseRequest())
+//})
+//t.Run("get-spec", func(t *testing.T) {
+//	t.Parallel()
+//	client, server := newPingServer(&pluggablePingServer{
+//		cumSum: func(ctx context.Context, stream *triple.BidiStream) error {
+//			assert.Equal(t, stream.Spec().StreamType, triple.StreamTypeBidi)
+//			assert.Equal(t, stream.Spec().Procedure, pingv1connect.PingServiceCumSumProcedure)
+//			assert.False(t, stream.Spec().IsClient)
+//			return nil
+//		},
+//	})
+//	t.Cleanup(server.Close)
+//	stream, err := client.CumSum(context.Background())
+//	assert.Nil(t, err)
+//	assert.Nil(t, stream.Send(nil))
+//	assert.Nil(t, stream.CloseRequest())
+//})
+//t.Run("server-stream", func(t *testing.T) {
+//	t.Parallel()
+//	client, server := newPingServer(&pluggablePingServer{
+//		countUp: func(ctx context.Context, req *triple.Request, stream *triple.ServerStream) error {
+//			assert.Equal(t, stream.Conn().Spec().StreamType, triple.StreamTypeServer)
+//			assert.Equal(t, stream.Conn().Spec().Procedure, pingv1connect.PingServiceCountUpProcedure)
+//			assert.False(t, stream.Conn().Spec().IsClient)
+//			assert.Nil(t, stream.Send(&pingv1.CountUpResponse{Number: 1}))
+//			return nil
+//		},
+//	})
+//	t.Cleanup(server.Close)
+//	stream, err := client.CountUp(context.Background(), triple.NewRequest(&pingv1.CountUpRequest{}))
+//	assert.Nil(t, err)
+//	assert.NotNil(t, stream)
+//	assert.Nil(t, stream.Close())
+//})
+//t.Run("server-stream-send", func(t *testing.T) {
+//	t.Parallel()
+//	client, server := newPingServer(&pluggablePingServer{
+//		countUp: func(ctx context.Context, req *triple.Request, stream *triple.ServerStream) error {
+//			assert.Nil(t, stream.Send(&pingv1.CountUpResponse{Number: 1}))
+//			return nil
+//		},
+//	})
+//	t.Cleanup(server.Close)
+//	stream, err := client.CountUp(context.Background(), triple.NewRequest(&pingv1.CountUpRequest{}))
+//	assert.Nil(t, err)
+//	assert.True(t, stream.Receive(&pingv1.CountUpResponse{}))
+//	msg := stream.Msg().(pingv1.CountUpResponse)
+//	assert.NotNil(t, msg)
+//	assert.Equal(t, msg.Number, 1)
+//	assert.Nil(t, stream.Close())
+//})
+//t.Run("server-stream-send-nil", func(t *testing.T) {
+//	t.Parallel()
+//	client, server := newPingServer(&pluggablePingServer{
+//		countUp: func(ctx context.Context, req *triple.Request, stream *triple.ServerStream) error {
+//			stream.ResponseHeader().Set("foo", "bar")
+//			stream.ResponseTrailer().Set("bas", "blah")
+//			assert.Nil(t, stream.Send(nil))
+//			return nil
+//		},
+//	})
+//	t.Cleanup(server.Close)
+//	stream, err := client.CountUp(context.Background(), triple.NewRequest(&pingv1.CountUpRequest{}))
+//	assert.Nil(t, err)
+//	assert.False(t, stream.Receive(&pingv1.CountUpResponse{}))
+//	headers := stream.ResponseHeader()
+//	assert.NotNil(t, headers)
+//	assert.Equal(t, headers.Get("foo"), "bar")
+//	trailers := stream.ResponseTrailer()
+//	assert.NotNil(t, trailers)
+//	assert.Equal(t, trailers.Get("bas"), "blah")
+//	assert.Nil(t, stream.Close())
+//})
+//t.Run("client-stream", func(t *testing.T) {
+//	t.Parallel()
+//	client, server := newPingServer(&pluggablePingServer{
+//		sum: func(ctx context.Context, stream *triple.ClientStream) (*triple.Response, error) {
+//			assert.Equal(t, stream.Spec().StreamType, triple.StreamTypeClient)
+//			assert.Equal(t, stream.Spec().Procedure, pingv1connect.PingServiceSumProcedure)
+//			assert.False(t, stream.Spec().IsClient)
+//			assert.True(t, stream.Receive(&pingv1.SumRequest{}))
+//			msg := stream.Msg().(pingv1.SumRequest)
+//			assert.NotNil(t, msg)
+//			assert.Equal(t, msg.Number, 1)
+//			return triple.NewResponse(&pingv1.SumResponse{Sum: 1}), nil
+//		},
+//	})
+//	t.Cleanup(server.Close)
+//	stream, err := client.Sum(context.Background())
+//	assert.Nil(t, err)
+//	assert.Nil(t, stream.Send(&pingv1.SumRequest{Number: 1}))
+//	msg := &pingv1.SumResponse{}
+//	res := triple.NewResponse(msg)
+//	err = stream.CloseAndReceive(res)
+//	assert.Nil(t, err)
+//	assert.NotNil(t, res)
+//	assert.Equal(t, msg.Sum, 1)
+//})
+//t.Run("client-stream-conn", func(t *testing.T) {
+//	t.Parallel()
+//	client, server := newPingServer(&pluggablePingServer{
+//		sum: func(ctx context.Context, stream *triple.ClientStream) (*triple.Response, error) {
+//			assert.NotNil(t, stream.Conn().Send("not-proto"))
+//			return triple.NewResponse(&pingv1.SumResponse{}), nil
+//		},
+//	})
+//	t.Cleanup(server.Close)
+//	stream, err := client.Sum(context.Background())
+//	assert.Nil(t, err)
+//	assert.Nil(t, stream.Send(&pingv1.SumRequest{Number: 1}))
+//	res := triple.NewResponse(&pingv1.SumResponse{})
+//	err = stream.CloseAndReceive(res)
+//	assert.Nil(t, err)
+//})
+//t.Run("client-stream-send-msg", func(t *testing.T) {
+//	t.Parallel()
+//	client, server := newPingServer(&pluggablePingServer{
+//		sum: func(ctx context.Context, stream *triple.ClientStream) (*triple.Response, error) {
+//			assert.Nil(t, stream.Conn().Send(&pingv1.SumResponse{Sum: 2}))
+//			return triple.NewResponse(&pingv1.SumResponse{}), nil
+//		},
+//	})
+//	t.Cleanup(server.Close)
+//	stream, err := client.Sum(context.Background())
+//	assert.Nil(t, err)
+//	assert.Nil(t, stream.Send(&pingv1.SumRequest{Number: 1}))
+//	res := triple.NewResponse(&pingv1.SumResponse{})
+//	err = stream.CloseAndReceive(res)
+//	assert.NotNil(t, err)
+//	assert.Equal(t, triple.CodeOf(err), triple.CodeUnknown)
+//})
 //}
-//
+
+func TestConnectHTTPErrorCodes(t *testing.T) {
+	t.Parallel()
+	checkHTTPStatus := func(t *testing.T, connectCode triple.Code, wantHttpStatus int) {
+		t.Helper()
+		mux := http.NewServeMux()
+		pluggableServer := &pluggablePingServer{
+			ping: func(_ context.Context, _ *triple.Request) (*triple.Response, error) {
+				return nil, triple.NewError(connectCode, errors.New("error"))
+			},
+		}
+		mux.Handle(pingv1connect.NewPingServiceHandler(pluggableServer))
+		server := httptest.NewServer(mux)
+		t.Cleanup(server.Close)
+		req, err := http.NewRequestWithContext(
+			context.Background(),
+			http.MethodPost,
+			server.URL+"/"+pingv1connect.PingServiceName+"/Ping",
+			strings.NewReader("{}"),
+		)
+		assert.Nil(t, err)
+		req.Header.Set("Content-Type", "application/json")
+		resp, err := server.Client().Do(req)
+		assert.Nil(t, err)
+		defer resp.Body.Close()
+		assert.Equal(t, wantHttpStatus, resp.StatusCode)
+		connectClient := pingv1connect.NewPingServiceClient(server.Client(), server.URL)
+		err = connectClient.Ping(context.Background(), triple.NewRequest(&pingv1.PingRequest{}), triple.NewResponse(&pingv1.PingResponse{}))
+		assert.NotNil(t, err)
+	}
+	t.Run("CodeCanceled-408", func(t *testing.T) {
+		t.Parallel()
+		checkHTTPStatus(t, triple.CodeCanceled, 408)
+	})
+	t.Run("CodeUnknown-500", func(t *testing.T) {
+		t.Parallel()
+		checkHTTPStatus(t, triple.CodeUnknown, 500)
+	})
+	t.Run("CodeInvalidArgument-400", func(t *testing.T) {
+		t.Parallel()
+		checkHTTPStatus(t, triple.CodeInvalidArgument, 400)
+	})
+	t.Run("CodeDeadlineExceeded-408", func(t *testing.T) {
+		t.Parallel()
+		checkHTTPStatus(t, triple.CodeDeadlineExceeded, 408)
+	})
+	t.Run("CodeNotFound-404", func(t *testing.T) {
+		t.Parallel()
+		checkHTTPStatus(t, triple.CodeNotFound, 404)
+	})
+	t.Run("CodeAlreadyExists-409", func(t *testing.T) {
+		t.Parallel()
+		checkHTTPStatus(t, triple.CodeAlreadyExists, 409)
+	})
+	t.Run("CodePermissionDenied-403", func(t *testing.T) {
+		t.Parallel()
+		checkHTTPStatus(t, triple.CodePermissionDenied, 403)
+	})
+	t.Run("CodeResourceExhausted-429", func(t *testing.T) {
+		t.Parallel()
+		checkHTTPStatus(t, triple.CodeResourceExhausted, 429)
+	})
+	t.Run("CodeFailedPrecondition-412", func(t *testing.T) {
+		t.Parallel()
+		checkHTTPStatus(t, triple.CodeFailedPrecondition, 412)
+	})
+	t.Run("CodeAborted-409", func(t *testing.T) {
+		t.Parallel()
+		checkHTTPStatus(t, triple.CodeAborted, 409)
+	})
+	t.Run("CodeOutOfRange-400", func(t *testing.T) {
+		t.Parallel()
+		checkHTTPStatus(t, triple.CodeOutOfRange, 400)
+	})
+	t.Run("CodeUnimplemented-404", func(t *testing.T) {
+		t.Parallel()
+		checkHTTPStatus(t, triple.CodeUnimplemented, 404)
+	})
+	t.Run("CodeInternal-500", func(t *testing.T) {
+		t.Parallel()
+		checkHTTPStatus(t, triple.CodeInternal, 500)
+	})
+	t.Run("CodeUnavailable-503", func(t *testing.T) {
+		t.Parallel()
+		checkHTTPStatus(t, triple.CodeUnavailable, 503)
+	})
+	t.Run("CodeDataLoss-500", func(t *testing.T) {
+		t.Parallel()
+		checkHTTPStatus(t, triple.CodeDataLoss, 500)
+	})
+	t.Run("CodeUnauthenticated-401", func(t *testing.T) {
+		t.Parallel()
+		checkHTTPStatus(t, triple.CodeUnauthenticated, 401)
+	})
+	t.Run("100-500", func(t *testing.T) {
+		t.Parallel()
+		checkHTTPStatus(t, 100, 500)
+	})
+	t.Run("0-500", func(t *testing.T) {
+		t.Parallel()
+		checkHTTPStatus(t, 0, 500)
+	})
+}
+
+func TestFailCompression(t *testing.T) {
+	t.Parallel()
+	mux := http.NewServeMux()
+	compressorName := "fail"
+	compressor := func() triple.Compressor { return failCompressor{} }
+	decompressor := func() triple.Decompressor { return failDecompressor{} }
+	mux.Handle(
+		pingv1connect.NewPingServiceHandler(
+			pingServer{},
+			triple.WithCompression(compressorName, decompressor, compressor),
+		),
+	)
+	server := httptest.NewUnstartedServer(mux)
+	server.EnableHTTP2 = true
+	server.StartTLS()
+	t.Cleanup(server.Close)
+	pingclient := pingv1connect.NewPingServiceClient(
+		server.Client(),
+		server.URL,
+		triple.WithAcceptCompression(compressorName, decompressor, compressor),
+		triple.WithSendCompression(compressorName),
+	)
+	err := pingclient.Ping(
+		context.Background(),
+		triple.NewRequest(&pingv1.PingRequest{
+			Text: "ping",
+		}),
+		triple.NewResponse(&pingv1.PingResponse{}),
+	)
+	assert.NotNil(t, err)
+	assert.Equal(t, triple.CodeOf(err), triple.CodeInternal)
+}
+
 //func TestUnflushableResponseWriter(t *testing.T) {
 //	t.Parallel()
 //	assertIsFlusherErr := func(t *testing.T, err error) {
@@ -1824,9 +1767,8 @@
 //		name    string
 //		options []triple.ClientOption
 //	}{
-//		{"connect", nil},
+//		{"triple", nil},
 //		{"grpc", []triple.ClientOption{triple.WithGRPC()}},
-//		{"grpcweb", []triple.ClientOption{triple.WithGRPCWeb()}},
 //	}
 //	for _, tt := range tests {
 //		tt := tt
@@ -1841,52 +1783,52 @@
 //				assertIsFlusherErr(t, err)
 //				return
 //			}
-//			assert.False(t, stream.Receive())
+//			assert.False(t, stream.Receive(&pingv1.CountUpResponse{}))
 //			assertIsFlusherErr(t, stream.Err())
 //		})
 //	}
 //}
-//
-//func TestGRPCErrorMetadataIsTrailersOnly(t *testing.T) {
-//	t.Parallel()
-//	mux := http.NewServeMux()
-//	mux.Handle(pingv1connect.NewPingServiceHandler(pingServer{}))
-//	server := httptest.NewUnstartedServer(mux)
-//	server.EnableHTTP2 = true
-//	server.StartTLS()
-//	t.Cleanup(server.Close)
-//
-//	protoBytes, err := proto.Marshal(&pingv1.FailRequest{Code: int32(triple.CodeInternal)})
-//	assert.Nil(t, err)
-//	// Manually construct a gRPC prefix. Data is uncompressed, so the first byte
-//	// is 0. Set the last 4 bytes to the message length.
-//	var prefix [5]byte
-//	binary.BigEndian.PutUint32(prefix[1:5], uint32(len(protoBytes)))
-//	body := append(prefix[:], protoBytes...)
-//	// Manually send off a gRPC request.
-//	req, err := http.NewRequestWithContext(
-//		context.Background(),
-//		http.MethodPost,
-//		server.URL+pingv1connect.PingServiceFailProcedure,
-//		bytes.NewReader(body),
-//	)
-//	assert.Nil(t, err)
-//	req.Header.Set("Content-Type", "application/grpc")
-//	res, err := server.Client().Do(req)
-//	assert.Nil(t, err)
-//	assert.Equal(t, res.StatusCode, http.StatusOK)
-//	assert.Equal(t, res.Header.Get("Content-Type"), "application/grpc")
-//	// pingServer.Fail adds handlerHeader and handlerTrailer to the error
-//	// metadata. The gRPC protocol should send all error metadata as trailers.
-//	assert.Zero(t, res.Header.Get(handlerHeader))
-//	assert.Zero(t, res.Header.Get(handlerTrailer))
-//	_, err = io.Copy(io.Discard, res.Body)
-//	assert.Nil(t, err)
-//	assert.Nil(t, res.Body.Close())
-//	assert.NotZero(t, res.Trailer.Get(handlerHeader))
-//	assert.NotZero(t, res.Trailer.Get(handlerTrailer))
-//}
-//
+
+func TestGRPCErrorMetadataIsTrailersOnly(t *testing.T) {
+	t.Parallel()
+	mux := http.NewServeMux()
+	mux.Handle(pingv1connect.NewPingServiceHandler(pingServer{}))
+	server := httptest.NewUnstartedServer(mux)
+	server.EnableHTTP2 = true
+	server.StartTLS()
+	t.Cleanup(server.Close)
+
+	protoBytes, err := proto.Marshal(&pingv1.FailRequest{Code: int32(triple.CodeInternal)})
+	assert.Nil(t, err)
+	// Manually construct a gRPC prefix. Data is uncompressed, so the first byte
+	// is 0. Set the last 4 bytes to the message length.
+	var prefix [5]byte
+	binary.BigEndian.PutUint32(prefix[1:5], uint32(len(protoBytes)))
+	body := append(prefix[:], protoBytes...)
+	// Manually send off a gRPC request.
+	req, err := http.NewRequestWithContext(
+		context.Background(),
+		http.MethodPost,
+		server.URL+pingv1connect.PingServiceFailProcedure,
+		bytes.NewReader(body),
+	)
+	assert.Nil(t, err)
+	req.Header.Set("Content-Type", "application/grpc")
+	res, err := server.Client().Do(req)
+	assert.Nil(t, err)
+	assert.Equal(t, res.StatusCode, http.StatusOK)
+	assert.Equal(t, res.Header.Get("Content-Type"), "application/grpc")
+	// pingServer.Fail adds handlerHeader and handlerTrailer to the error
+	// metadata. The gRPC protocol should send all error metadata as trailers.
+	assert.Zero(t, res.Header.Get(handlerHeader))
+	assert.Zero(t, res.Header.Get(handlerTrailer))
+	_, err = io.Copy(io.Discard, res.Body)
+	assert.Nil(t, err)
+	assert.Nil(t, res.Body.Close())
+	assert.NotZero(t, res.Trailer.Get(handlerHeader))
+	assert.NotZero(t, res.Trailer.Get(handlerTrailer))
+}
+
 //func TestConnectProtocolHeaderSentByDefault(t *testing.T) {
 //	t.Parallel()
 //	mux := http.NewServeMux()
@@ -1897,86 +1839,86 @@
 //	t.Cleanup(server.Close)
 //
 //	client := pingv1connect.NewPingServiceClient(server.Client(), server.URL)
-//	_, err := client.Ping(context.Background(), triple.NewRequest(&pingv1.PingRequest{}))
+//	err := client.Ping(context.Background(), triple.NewRequest(&pingv1.PingRequest{}), triple.NewResponse(&pingv1.PingResponse{}))
 //	assert.Nil(t, err)
 //
 //	stream, err := client.CumSum(context.Background())
 //	assert.Nil(t, err)
 //	assert.Nil(t, stream.Send(&pingv1.CumSumRequest{}))
-//	_, err = stream.Receive()
+//	err = stream.Receive(&pingv1.CumSumResponse{})
 //	assert.Nil(t, err)
 //	assert.Nil(t, stream.CloseRequest())
 //	assert.Nil(t, stream.CloseResponse())
 //}
-//
-//func TestConnectProtocolHeaderRequired(t *testing.T) {
-//	t.Parallel()
-//	mux := http.NewServeMux()
-//	mux.Handle(pingv1connect.NewPingServiceHandler(
-//		pingServer{},
-//		triple.WithRequireConnectProtocolHeader(),
-//	))
-//	server := httptest.NewServer(mux)
-//	t.Cleanup(server.Close)
-//
-//	tests := []struct {
-//		headers http.Header
-//	}{
-//		{http.Header{}},
-//		{http.Header{"Connect-Protocol-Version": []string{"0"}}},
-//	}
-//	for _, tcase := range tests {
-//		req, err := http.NewRequestWithContext(
-//			context.Background(),
-//			http.MethodPost,
-//			server.URL+"/"+pingv1connect.PingServiceName+"/Ping",
-//			strings.NewReader("{}"),
-//		)
-//		assert.Nil(t, err)
-//		req.Header.Set("Content-Type", "application/json")
-//		for k, v := range tcase.headers {
-//			req.Header[k] = v
-//		}
-//		response, err := server.Client().Do(req)
-//		assert.Nil(t, err)
-//		assert.Nil(t, response.Body.Close())
-//		assert.Equal(t, response.StatusCode, http.StatusBadRequest)
-//	}
-//}
-//
-//func TestAllowCustomUserAgent(t *testing.T) {
-//	t.Parallel()
-//
-//	const customAgent = "custom"
-//	mux := http.NewServeMux()
-//	mux.Handle(pingv1connect.NewPingServiceHandler(&pluggablePingServer{
-//		ping: func(_ context.Context, req *triple.Request[pingv1.PingRequest]) (*triple.Response[pingv1.PingResponse], error) {
-//			agent := req.Header().Get("User-Agent")
-//			assert.Equal(t, agent, customAgent)
-//			return triple.NewResponse(&pingv1.PingResponse{Number: req.Msg.Number}), nil
-//		},
-//	}))
-//	server := httptest.NewServer(mux)
-//	t.Cleanup(server.Close)
-//
-//	// If the user has set a User-Agent, we shouldn't clobber it.
-//	tests := []struct {
-//		protocol string
-//		opts     []triple.ClientOption
-//	}{
-//		{"connect", nil},
-//		{"grpc", []triple.ClientOption{triple.WithGRPC()}},
-//		{"grpcweb", []triple.ClientOption{triple.WithGRPCWeb()}},
-//	}
-//	for _, testCase := range tests {
-//		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, testCase.opts...)
-//		req := triple.NewRequest(&pingv1.PingRequest{Number: 42})
-//		req.Header().Set("User-Agent", customAgent)
-//		_, err := client.Ping(context.Background(), req)
-//		assert.Nil(t, err)
-//	}
-//}
-//
+
+func TestConnectProtocolHeaderRequired(t *testing.T) {
+	t.Parallel()
+	mux := http.NewServeMux()
+	mux.Handle(pingv1connect.NewPingServiceHandler(
+		pingServer{},
+		triple.WithRequireConnectProtocolHeader(),
+	))
+	server := httptest.NewServer(mux)
+	t.Cleanup(server.Close)
+
+	tests := []struct {
+		headers http.Header
+	}{
+		{http.Header{}},
+		{http.Header{"Connect-Protocol-Version": []string{"0"}}},
+	}
+	for _, tcase := range tests {
+		req, err := http.NewRequestWithContext(
+			context.Background(),
+			http.MethodPost,
+			server.URL+"/"+pingv1connect.PingServiceName+"/Ping",
+			strings.NewReader("{}"),
+		)
+		assert.Nil(t, err)
+		req.Header.Set("Content-Type", "application/json")
+		for k, v := range tcase.headers {
+			req.Header[k] = v
+		}
+		response, err := server.Client().Do(req)
+		assert.Nil(t, err)
+		assert.Nil(t, response.Body.Close())
+		assert.Equal(t, response.StatusCode, http.StatusBadRequest)
+	}
+}
+
+func TestAllowCustomUserAgent(t *testing.T) {
+	t.Parallel()
+
+	const customAgent = "custom"
+	mux := http.NewServeMux()
+	mux.Handle(pingv1connect.NewPingServiceHandler(&pluggablePingServer{
+		ping: func(_ context.Context, req *triple.Request) (*triple.Response, error) {
+			agent := req.Header().Get("User-Agent")
+			assert.Equal(t, agent, customAgent)
+			msg := req.Msg.(*pingv1.PingRequest)
+			return triple.NewResponse(&pingv1.PingResponse{Number: msg.Number}), nil
+		},
+	}))
+	server := httptest.NewServer(mux)
+	t.Cleanup(server.Close)
+
+	// If the user has set a User-Agent, we shouldn't clobber it.
+	tests := []struct {
+		protocol string
+		opts     []triple.ClientOption
+	}{
+		{"triple", nil},
+		{"grpc", []triple.ClientOption{triple.WithGRPC()}},
+	}
+	for _, testCase := range tests {
+		client := pingv1connect.NewPingServiceClient(server.Client(), server.URL, testCase.opts...)
+		req := triple.NewRequest(&pingv1.PingRequest{Number: 42})
+		req.Header().Set("User-Agent", customAgent)
+		err := client.Ping(context.Background(), req, triple.NewResponse(&pingv1.PingResponse{}))
+		assert.Nil(t, err)
+	}
+}
+
 //func TestBidiOverHTTP1(t *testing.T) {
 //	t.Parallel()
 //	mux := http.NewServeMux()
@@ -1993,14 +1935,14 @@
 //	if err := stream.Send(&pingv1.CumSumRequest{Number: 2}); err != nil {
 //		assert.ErrorIs(t, err, io.EOF)
 //	}
-//	_, err = stream.Receive()
+//	err = stream.Receive(&pingv1.CumSumResponse{})
 //	assert.NotNil(t, err)
 //	assert.Equal(t, triple.CodeOf(err), triple.CodeUnknown)
 //	assert.Equal(t, err.Error(), "unknown: HTTP status 505 HTTP Version Not Supported")
 //	assert.Nil(t, stream.CloseRequest())
 //	assert.Nil(t, stream.CloseResponse())
 //}
-//
+
 //func TestHandlerReturnsNilResponse(t *testing.T) {
 //	// When user-written handlers return nil responses _and_ nil errors, ensure
 //	// that the resulting panic includes at least the name of the procedure.
@@ -2021,10 +1963,10 @@
 //
 //	mux := http.NewServeMux()
 //	mux.Handle(pingv1connect.NewPingServiceHandler(&pluggablePingServer{
-//		ping: func(ctx context.Context, req *triple.Request[pingv1.PingRequest]) (*triple.Response[pingv1.PingResponse], error) {
+//		ping: func(ctx context.Context, req *triple.Request) (*triple.Response, error) {
 //			return nil, nil //nolint: nilnil
 //		},
-//		sum: func(ctx context.Context, req *triple.ClientStream[pingv1.SumRequest]) (*triple.Response[pingv1.SumResponse], error) {
+//		sum: func(ctx context.Context, req *triple.ClientStream) (*triple.Response, error) {
 //			return nil, nil //nolint: nilnil
 //		},
 //	}, triple.WithRecover(recoverPanic)))
@@ -2032,192 +1974,194 @@
 //	t.Cleanup(server.Close)
 //	client := pingv1connect.NewPingServiceClient(server.Client(), server.URL)
 //
-//	_, err := client.Ping(context.Background(), triple.NewRequest(&pingv1.PingRequest{}))
+//	err := client.Ping(context.Background(), triple.NewRequest(&pingv1.PingRequest{}), triple.NewResponse(&pingv1.PingResponse{}))
 //	assert.NotNil(t, err)
 //	assert.Equal(t, triple.CodeOf(err), triple.CodeInternal)
 //
 //	stream, err := client.Sum(context.Background())
 //	assert.Nil(t, err)
-//	_, err = stream.CloseAndReceive()
+//	err = stream.CloseAndReceive(triple.NewResponse(&pingv1.SumResponse{}))
 //	assert.NotNil(t, err)
 //	assert.Equal(t, triple.CodeOf(err), triple.CodeInternal)
 //
 //	assert.Equal(t, panics, 2)
 //}
-//
-//// TestBlankImportCodeGeneration tests that services.connect.go is generated with
-//// blank import statements to services.pb.go so that the service's Descriptor is
-//// available in the global proto registry.
-//func TestBlankImportCodeGeneration(t *testing.T) {
-//	t.Parallel()
-//	desc, err := protoregistry.GlobalFiles.FindDescriptorByName(importv1connect.ImportServiceName)
-//	assert.Nil(t, err)
-//	assert.NotNil(t, desc)
-//}
-//
-//type unflushableWriter struct {
-//	w http.ResponseWriter
-//}
-//
-//func (w *unflushableWriter) Header() http.Header         { return w.w.Header() }
-//func (w *unflushableWriter) Write(b []byte) (int, error) { return w.w.Write(b) }
-//func (w *unflushableWriter) WriteHeader(code int)        { w.w.WriteHeader(code) }
-//
-//func gzipCompressedSize(tb testing.TB, message proto.Message) int {
-//	tb.Helper()
-//	uncompressed, err := proto.Marshal(message)
-//	assert.Nil(tb, err)
-//	var buf bytes.Buffer
-//	gzipWriter := gzip.NewWriter(&buf)
-//	_, err = gzipWriter.Write(uncompressed)
-//	assert.Nil(tb, err)
-//	assert.Nil(tb, gzipWriter.Close())
-//	return buf.Len()
-//}
-//
-//type failCodec struct{}
-//
-//func (c failCodec) Name() string {
-//	return "proto"
-//}
-//
-//func (c failCodec) Marshal(message any) ([]byte, error) {
-//	return nil, errors.New("boom")
-//}
-//
-//func (c failCodec) Unmarshal(data []byte, message any) error {
-//	protoMessage, ok := message.(proto.Message)
-//	if !ok {
-//		return fmt.Errorf("not protobuf: %T", message)
-//	}
-//	return proto.Unmarshal(data, protoMessage)
-//}
-//
-//type pluggablePingServer struct {
-//	pingv1connect.UnimplementedPingServiceHandler
-//
-//	ping    func(context.Context, *triple.Request[pingv1.PingRequest]) (*triple.Response[pingv1.PingResponse], error)
-//	sum     func(context.Context, *triple.ClientStream[pingv1.SumRequest]) (*triple.Response[pingv1.SumResponse], error)
-//	countUp func(context.Context, *triple.Request[pingv1.CountUpRequest], *triple.ServerStream[pingv1.CountUpResponse]) error
-//	cumSum  func(context.Context, *triple.BidiStream[pingv1.CumSumRequest, pingv1.CumSumResponse]) error
-//}
-//
-//func (p *pluggablePingServer) Ping(
-//	ctx context.Context,
-//	request *triple.Request[pingv1.PingRequest],
-//) (*triple.Response[pingv1.PingResponse], error) {
-//	return p.ping(ctx, request)
-//}
-//
-//func (p *pluggablePingServer) Sum(
-//	ctx context.Context,
-//	stream *triple.ClientStream[pingv1.SumRequest],
-//) (*triple.Response[pingv1.SumResponse], error) {
-//	return p.sum(ctx, stream)
-//}
-//
-//func (p *pluggablePingServer) CountUp(
-//	ctx context.Context,
-//	req *triple.Request[pingv1.CountUpRequest],
-//	stream *triple.ServerStream[pingv1.CountUpResponse],
-//) error {
-//	return p.countUp(ctx, req, stream)
-//}
-//
-//func (p *pluggablePingServer) CumSum(
-//	ctx context.Context,
-//	stream *triple.BidiStream[pingv1.CumSumRequest, pingv1.CumSumResponse],
-//) error {
-//	return p.cumSum(ctx, stream)
-//}
-//
-//func failNoHTTP2(tb testing.TB, stream *triple.BidiStreamForClient[pingv1.CumSumRequest, pingv1.CumSumResponse]) {
-//	tb.Helper()
-//	if err := stream.Send(&pingv1.CumSumRequest{}); err != nil {
-//		assert.ErrorIs(tb, err, io.EOF)
-//		assert.Equal(tb, triple.CodeOf(err), triple.CodeUnknown)
-//	}
-//	assert.Nil(tb, stream.CloseRequest())
-//	_, err := stream.Receive()
-//	assert.NotNil(tb, err) // should be 505
-//	assert.True(
-//		tb,
-//		strings.Contains(err.Error(), "HTTP status 505"),
-//		assert.Sprintf("expected 505, got %v", err),
-//	)
-//	assert.Nil(tb, stream.CloseResponse())
-//}
-//
-//func expectClientHeader(check bool, req triple.AnyRequest) error {
-//	if !check {
-//		return nil
-//	}
-//	if err := expectMetadata(req.Header(), "header", clientHeader, headerValue); err != nil {
-//		return err
-//	}
-//	return nil
-//}
-//
-//func expectMetadata(meta http.Header, metaType, key, value string) error {
-//	if got := meta.Get(key); got != value {
-//		return triple.NewError(triple.CodeInvalidArgument, fmt.Errorf(
-//			"%s %q: got %q, expected %q",
-//			metaType,
-//			key,
-//			got,
-//			value,
-//		))
-//	}
-//	return nil
-//}
-//
-//type pingServer struct {
-//	pingv1connect.UnimplementedPingServiceHandler
-//
-//	checkMetadata bool
-//}
-//
-//func (p pingServer) Ping(ctx context.Context, request *triple.Request[pingv1.PingRequest]) (*triple.Response[pingv1.PingResponse], error) {
-//	if err := expectClientHeader(p.checkMetadata, request); err != nil {
-//		return nil, err
-//	}
-//	if request.Peer().Addr == "" {
-//		return nil, triple.NewError(triple.CodeInternal, errors.New("no peer address"))
-//	}
-//	if request.Peer().Protocol == "" {
-//		return nil, triple.NewError(triple.CodeInternal, errors.New("no peer protocol"))
-//	}
-//	response := triple.NewResponse(
-//		&pingv1.PingResponse{
-//			Number: request.Msg.Number,
-//			Text:   request.Msg.Text,
-//		},
-//	)
-//	response.Header().Set(handlerHeader, headerValue)
-//	response.Trailer().Set(handlerTrailer, trailerValue)
-//	return response, nil
-//}
-//
-//func (p pingServer) Fail(ctx context.Context, request *triple.Request[pingv1.FailRequest]) (*triple.Response[pingv1.FailResponse], error) {
-//	if err := expectClientHeader(p.checkMetadata, request); err != nil {
-//		return nil, err
-//	}
-//	if request.Peer().Addr == "" {
-//		return nil, triple.NewError(triple.CodeInternal, errors.New("no peer address"))
-//	}
-//	if request.Peer().Protocol == "" {
-//		return nil, triple.NewError(triple.CodeInternal, errors.New("no peer protocol"))
-//	}
-//	err := triple.NewError(triple.Code(request.Msg.Code), errors.New(errorMessage))
-//	err.Meta().Set(handlerHeader, headerValue)
-//	err.Meta().Set(handlerTrailer, trailerValue)
-//	return nil, err
-//}
-//
+
+// TestBlankImportCodeGeneration tests that services.triple.go is generated with
+// blank import statements to services.pb.go so that the service's Descriptor is
+// available in the global proto registry.
+func TestBlankImportCodeGeneration(t *testing.T) {
+	t.Parallel()
+	desc, err := protoregistry.GlobalFiles.FindDescriptorByName(importv1connect.ImportServiceName)
+	assert.Nil(t, err)
+	assert.NotNil(t, desc)
+}
+
+type unflushableWriter struct {
+	w http.ResponseWriter
+}
+
+func (w *unflushableWriter) Header() http.Header         { return w.w.Header() }
+func (w *unflushableWriter) Write(b []byte) (int, error) { return w.w.Write(b) }
+func (w *unflushableWriter) WriteHeader(code int)        { w.w.WriteHeader(code) }
+
+func gzipCompressedSize(tb testing.TB, message proto.Message) int {
+	tb.Helper()
+	uncompressed, err := proto.Marshal(message)
+	assert.Nil(tb, err)
+	var buf bytes.Buffer
+	gzipWriter := gzip.NewWriter(&buf)
+	_, err = gzipWriter.Write(uncompressed)
+	assert.Nil(tb, err)
+	assert.Nil(tb, gzipWriter.Close())
+	return buf.Len()
+}
+
+type failCodec struct{}
+
+func (c failCodec) Name() string {
+	return "proto"
+}
+
+func (c failCodec) Marshal(message any) ([]byte, error) {
+	return nil, errors.New("boom")
+}
+
+func (c failCodec) Unmarshal(data []byte, message any) error {
+	protoMessage, ok := message.(proto.Message)
+	if !ok {
+		return fmt.Errorf("not protobuf: %T", message)
+	}
+	return proto.Unmarshal(data, protoMessage)
+}
+
+type pluggablePingServer struct {
+	pingv1connect.UnimplementedPingServiceHandler
+
+	ping    func(context.Context, *triple.Request) (*triple.Response, error)
+	sum     func(context.Context, *triple.ClientStream) (*triple.Response, error)
+	countUp func(context.Context, *triple.Request, *triple.ServerStream) error
+	cumSum  func(context.Context, *triple.BidiStream) error
+}
+
+func (p *pluggablePingServer) Ping(
+	ctx context.Context,
+	request *triple.Request,
+) (*triple.Response, error) {
+	return p.ping(ctx, request)
+}
+
+func (p *pluggablePingServer) Sum(
+	ctx context.Context,
+	stream *triple.ClientStream,
+) (*triple.Response, error) {
+	return p.sum(ctx, stream)
+}
+
+func (p *pluggablePingServer) CountUp(
+	ctx context.Context,
+	req *triple.Request,
+	stream *triple.ServerStream,
+) error {
+	return p.countUp(ctx, req, stream)
+}
+
+func (p *pluggablePingServer) CumSum(
+	ctx context.Context,
+	stream *triple.BidiStream,
+) error {
+	return p.cumSum(ctx, stream)
+}
+
+func failNoHTTP2(tb testing.TB, stream *triple.BidiStreamForClient) {
+	tb.Helper()
+	if err := stream.Send(&pingv1.CumSumRequest{}); err != nil {
+		assert.ErrorIs(tb, err, io.EOF)
+		assert.Equal(tb, triple.CodeOf(err), triple.CodeUnknown)
+	}
+	assert.Nil(tb, stream.CloseRequest())
+	err := stream.Receive(&pingv1.CumSumResponse{})
+	assert.NotNil(tb, err) // should be 505
+	assert.True(
+		tb,
+		strings.Contains(err.Error(), "HTTP status 505"),
+		assert.Sprintf("expected 505, got %v", err),
+	)
+	assert.Nil(tb, stream.CloseResponse())
+}
+
+func expectClientHeader(check bool, req triple.AnyRequest) error {
+	if !check {
+		return nil
+	}
+	if err := expectMetadata(req.Header(), "header", clientHeader, headerValue); err != nil {
+		return err
+	}
+	return nil
+}
+
+func expectMetadata(meta http.Header, metaType, key, value string) error {
+	if got := meta.Get(key); got != value {
+		return triple.NewError(triple.CodeInvalidArgument, fmt.Errorf(
+			"%s %q: got %q, expected %q",
+			metaType,
+			key,
+			got,
+			value,
+		))
+	}
+	return nil
+}
+
+type pingServer struct {
+	pingv1connect.UnimplementedPingServiceHandler
+
+	checkMetadata bool
+}
+
+func (p pingServer) Ping(ctx context.Context, request *triple.Request) (*triple.Response, error) {
+	if err := expectClientHeader(p.checkMetadata, request); err != nil {
+		return nil, err
+	}
+	if request.Peer().Addr == "" {
+		return nil, triple.NewError(triple.CodeInternal, errors.New("no peer address"))
+	}
+	if request.Peer().Protocol == "" {
+		return nil, triple.NewError(triple.CodeInternal, errors.New("no peer protocol"))
+	}
+	msg := request.Msg.(*pingv1.PingRequest)
+	response := triple.NewResponse(
+		&pingv1.PingResponse{
+			Number: msg.Number,
+			Text:   msg.Text,
+		},
+	)
+	response.Header().Set(handlerHeader, headerValue)
+	response.Trailer().Set(handlerTrailer, trailerValue)
+	return response, nil
+}
+
+func (p pingServer) Fail(ctx context.Context, request *triple.Request) (*triple.Response, error) {
+	if err := expectClientHeader(p.checkMetadata, request); err != nil {
+		return nil, err
+	}
+	if request.Peer().Addr == "" {
+		return nil, triple.NewError(triple.CodeInternal, errors.New("no peer address"))
+	}
+	if request.Peer().Protocol == "" {
+		return nil, triple.NewError(triple.CodeInternal, errors.New("no peer protocol"))
+	}
+	msg := request.Msg.(*pingv1.FailRequest)
+	err := triple.NewError(triple.Code(msg.Code), errors.New(errorMessage))
+	err.Meta().Set(handlerHeader, headerValue)
+	err.Meta().Set(handlerTrailer, trailerValue)
+	return nil, err
+}
+
 //func (p pingServer) Sum(
 //	ctx context.Context,
-//	stream *triple.ClientStream[pingv1.SumRequest],
-//) (*triple.Response[pingv1.SumResponse], error) {
+//	stream *triple.ClientStream,
+//) (*triple.Response, error) {
 //	if p.checkMetadata {
 //		if err := expectMetadata(stream.RequestHeader(), "header", clientHeader, headerValue); err != nil {
 //			return nil, err
@@ -2230,8 +2174,10 @@
 //		return nil, triple.NewError(triple.CodeInternal, errors.New("no peer protocol"))
 //	}
 //	var sum int64
-//	for stream.Receive() {
-//		sum += stream.Msg().Number
+//
+//	for stream.Receive(&pingv1.SumRequest{}) {
+//		msg := stream.Msg().(*pingv1.SumRequest)
+//		sum += msg.Number
 //	}
 //	if stream.Err() != nil {
 //		return nil, stream.Err()
@@ -2241,11 +2187,11 @@
 //	response.Trailer().Set(handlerTrailer, trailerValue)
 //	return response, nil
 //}
-//
+
 //func (p pingServer) CountUp(
 //	ctx context.Context,
-//	request *triple.Request[pingv1.CountUpRequest],
-//	stream *triple.ServerStream[pingv1.CountUpResponse],
+//	request *triple.Request,
+//	stream *triple.ServerStream,
 //) error {
 //	if err := expectClientHeader(p.checkMetadata, request); err != nil {
 //		return err
@@ -2256,25 +2202,26 @@
 //	if request.Peer().Protocol == "" {
 //		return triple.NewError(triple.CodeInternal, errors.New("no peer protocol"))
 //	}
-//	if request.Msg.Number <= 0 {
+//	msg := request.Msg.(*pingv1.CountUpRequest)
+//	if msg.Number <= 0 {
 //		return triple.NewError(triple.CodeInvalidArgument, fmt.Errorf(
 //			"number must be positive: got %v",
-//			request.Msg.Number,
+//			msg.Number,
 //		))
 //	}
 //	stream.ResponseHeader().Set(handlerHeader, headerValue)
 //	stream.ResponseTrailer().Set(handlerTrailer, trailerValue)
-//	for i := int64(1); i <= request.Msg.Number; i++ {
+//	for i := int64(1); i <= msg.Number; i++ {
 //		if err := stream.Send(&pingv1.CountUpResponse{Number: i}); err != nil {
 //			return err
 //		}
 //	}
 //	return nil
 //}
-//
+
 //func (p pingServer) CumSum(
 //	ctx context.Context,
-//	stream *triple.BidiStream[pingv1.CumSumRequest, pingv1.CumSumResponse],
+//	stream *triple.BidiStream,
 //) error {
 //	var sum int64
 //	if p.checkMetadata {
@@ -2291,7 +2238,8 @@
 //	stream.ResponseHeader().Set(handlerHeader, headerValue)
 //	stream.ResponseTrailer().Set(handlerTrailer, trailerValue)
 //	for {
-//		msg, err := stream.Receive()
+//		msg := &pingv1.CumSumRequest{}
+//		err := stream.Receive(msg)
 //		if errors.Is(err, io.EOF) {
 //			return nil
 //		} else if err != nil {
@@ -2303,90 +2251,90 @@
 //		}
 //	}
 //}
-//
-//type deflateReader struct {
-//	r io.ReadCloser
-//}
-//
-//func newDeflateReader(r io.Reader) *deflateReader {
-//	return &deflateReader{r: flate.NewReader(r)}
-//}
-//
-//func (d *deflateReader) Read(p []byte) (int, error) {
-//	return d.r.Read(p)
-//}
-//
-//func (d *deflateReader) Close() error {
-//	return d.r.Close()
-//}
-//
-//func (d *deflateReader) Reset(reader io.Reader) error {
-//	if resetter, ok := d.r.(flate.Resetter); ok {
-//		return resetter.Reset(reader, nil)
-//	}
-//	return fmt.Errorf("flate reader should implement flate.Resetter")
-//}
-//
-//var _ triple.Decompressor = (*deflateReader)(nil)
-//
-//type trimTrailerWriter struct {
-//	w http.ResponseWriter
-//}
-//
-//func (l *trimTrailerWriter) Header() http.Header {
-//	return l.w.Header()
-//}
-//
-//// Write writes b to underlying writer and counts written size.
-//func (l *trimTrailerWriter) Write(b []byte) (int, error) {
-//	l.removeTrailers()
-//	return l.w.Write(b)
-//}
-//
-//// WriteHeader writes s to underlying writer and retains the status.
-//func (l *trimTrailerWriter) WriteHeader(s int) {
-//	l.removeTrailers()
-//	l.w.WriteHeader(s)
-//}
-//
-//// Flush implements http.Flusher.
-//func (l *trimTrailerWriter) Flush() {
-//	l.removeTrailers()
-//	if f, ok := l.w.(http.Flusher); ok {
-//		f.Flush()
-//	}
-//}
-//
-//func (l *trimTrailerWriter) removeTrailers() {
-//	for _, v := range l.w.Header().Values("Trailer") {
-//		l.w.Header().Del(v)
-//	}
-//	l.w.Header().Del("Trailer")
-//	for k := range l.w.Header() {
-//		if strings.HasPrefix(k, http.TrailerPrefix) {
-//			l.w.Header().Del(k)
-//		}
-//	}
-//}
-//
-//func newHTTPMiddlewareError() *triple.Error {
-//	err := triple.NewError(triple.CodeResourceExhausted, errors.New("error from HTTP middleware"))
-//	err.Meta().Set("Middleware-Foo", "bar")
-//	return err
-//}
-//
-//type failDecompressor struct {
-//	triple.Decompressor
-//}
-//
-//type failCompressor struct{}
-//
-//func (failCompressor) Write([]byte) (int, error) {
-//	return 0, errors.New("failCompressor")
-//}
-//
-//func (failCompressor) Close() error {
-//	return errors.New("failCompressor")
-//}
-//
-//func (failCompressor) Reset(io.Writer) {}
+
+type deflateReader struct {
+	r io.ReadCloser
+}
+
+func newDeflateReader(r io.Reader) *deflateReader {
+	return &deflateReader{r: flate.NewReader(r)}
+}
+
+func (d *deflateReader) Read(p []byte) (int, error) {
+	return d.r.Read(p)
+}
+
+func (d *deflateReader) Close() error {
+	return d.r.Close()
+}
+
+func (d *deflateReader) Reset(reader io.Reader) error {
+	if resetter, ok := d.r.(flate.Resetter); ok {
+		return resetter.Reset(reader, nil)
+	}
+	return fmt.Errorf("flate reader should implement flate.Resetter")
+}
+
+var _ triple.Decompressor = (*deflateReader)(nil)
+
+type trimTrailerWriter struct {
+	w http.ResponseWriter
+}
+
+func (l *trimTrailerWriter) Header() http.Header {
+	return l.w.Header()
+}
+
+// Write writes b to underlying writer and counts written size.
+func (l *trimTrailerWriter) Write(b []byte) (int, error) {
+	l.removeTrailers()
+	return l.w.Write(b)
+}
+
+// WriteHeader writes s to underlying writer and retains the status.
+func (l *trimTrailerWriter) WriteHeader(s int) {
+	l.removeTrailers()
+	l.w.WriteHeader(s)
+}
+
+// Flush implements http.Flusher.
+func (l *trimTrailerWriter) Flush() {
+	l.removeTrailers()
+	if f, ok := l.w.(http.Flusher); ok {
+		f.Flush()
+	}
+}
+
+func (l *trimTrailerWriter) removeTrailers() {
+	for _, v := range l.w.Header().Values("Trailer") {
+		l.w.Header().Del(v)
+	}
+	l.w.Header().Del("Trailer")
+	for k := range l.w.Header() {
+		if strings.HasPrefix(k, http.TrailerPrefix) {
+			l.w.Header().Del(k)
+		}
+	}
+}
+
+func newHTTPMiddlewareError() *triple.Error {
+	err := triple.NewError(triple.CodeResourceExhausted, errors.New("error from HTTP middleware"))
+	err.Meta().Set("Middleware-Foo", "bar")
+	return err
+}
+
+type failDecompressor struct {
+	triple.Decompressor
+}
+
+type failCompressor struct{}
+
+func (failCompressor) Write([]byte) (int, error) {
+	return 0, errors.New("failCompressor")
+}
+
+func (failCompressor) Close() error {
+	return errors.New("failCompressor")
+}
+
+func (failCompressor) Reset(io.Writer) {}
diff --git a/protocol/triple/triple_protocol/duplex_http_call.go b/protocol/triple/triple_protocol/duplex_http_call.go
index 21ab2e0..9f5e6ed 100644
--- a/protocol/triple/triple_protocol/duplex_http_call.go
+++ b/protocol/triple/triple_protocol/duplex_http_call.go
@@ -123,7 +123,7 @@
 	// safe to close the write side of the pipe while net/http is reading from
 	// it.
 	//
-	// Because connect also supports some RPC types over HTTP/1.1, we need to be
+	// Because triple also supports some RPC types over HTTP/1.1, we need to be
 	// careful how we expose this method to users. HTTP/1.1 doesn't support
 	// bidirectional streaming - the write side of the stream (aka request body)
 	// must be closed before we start reading the response or we'll just block
diff --git a/protocol/triple/triple_protocol/error.go b/protocol/triple/triple_protocol/error.go
index af537c6..cd167ba 100644
--- a/protocol/triple/triple_protocol/error.go
+++ b/protocol/triple/triple_protocol/error.go
@@ -99,7 +99,7 @@
 //
 // Service implementations and interceptors should return errors that can be
 // cast to an [*Error] (using the standard library's [errors.As]). If the returned
-// error can't be cast to an [*Error], connect will use [CodeUnknown] and the
+// error can't be cast to an [*Error], triple will use [CodeUnknown] and the
 // returned error's message.
 //
 // Error details are an optional mechanism for servers, interceptors, and
@@ -223,7 +223,7 @@
 	return NewError(c, fmt.Errorf(template, args...))
 }
 
-// asError uses errors.As to unwrap any error and look for a connect *Error.
+// asError uses errors.As to unwrap any error and look for a triple *Error.
 func asError(err error) (*Error, bool) {
 	var connectErr *Error
 	ok := errors.As(err, &connectErr)
@@ -292,7 +292,7 @@
 }
 
 // wrapIfLikelyWithGRPCNotUsedError adds a wrapping error that has a message
-// telling the caller that they likely forgot to use connect.WithGRPC().
+// telling the caller that they likely forgot to use triple.WithGRPC().
 //
 // This happens when running a gRPC-only server.
 // This is fragile and may break over time, and this should be considered a best-effort.
@@ -309,7 +309,7 @@
 	if errString := err.Error(); strings.HasPrefix(errString, `Post "`) &&
 		strings.Contains(errString, `http2: Transport: cannot retry err`) &&
 		strings.HasSuffix(errString, `after Request.Body was written; define Request.GetBody to avoid this error`) {
-		return fmt.Errorf("possible missing connect.WithGPRC() client option when talking to gRPC server, see %s: %w", commonErrorsURL, err)
+		return fmt.Errorf("possible missing triple.WithGPRC() client option when talking to gRPC server, see %s: %w", commonErrorsURL, err)
 	}
 	return err
 }
diff --git a/protocol/triple/triple_protocol/error_test.go b/protocol/triple/triple_protocol/error_test.go
index 6ee04c3..2dad699 100644
--- a/protocol/triple/triple_protocol/error_test.go
+++ b/protocol/triple/triple_protocol/error_test.go
@@ -20,6 +20,8 @@
 	"strings"
 	"testing"
 	"time"
+
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/assert"
 )
 
 import (
@@ -29,10 +31,6 @@
 	"google.golang.org/protobuf/types/known/emptypb"
 )
 
-import (
-	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/assert"
-)
-
 func TestErrorNilUnderlying(t *testing.T) {
 	t.Parallel()
 	err := NewError(CodeUnknown, nil)
@@ -68,9 +66,9 @@
 		"another: %w",
 		NewError(CodeUnavailable, errors.New("foo")),
 	)
-	connectErr, ok := asError(err)
+	tripleErr, ok := asError(err)
 	assert.True(t, ok)
-	assert.Equal(t, connectErr.Code(), CodeUnavailable)
+	assert.Equal(t, tripleErr.Code(), CodeUnavailable)
 }
 
 func TestCodeOf(t *testing.T) {
@@ -88,11 +86,11 @@
 	second := durationpb.New(time.Second)
 	detail, err := NewErrorDetail(second)
 	assert.Nil(t, err)
-	connectErr := NewError(CodeUnknown, errors.New("error with details"))
-	assert.Zero(t, connectErr.Details())
-	connectErr.AddDetail(detail)
-	assert.Equal(t, len(connectErr.Details()), 1)
-	unmarshaled, err := connectErr.Details()[0].Value()
+	tripleErr := NewError(CodeUnknown, errors.New("error with details"))
+	assert.Zero(t, tripleErr.Details())
+	tripleErr.AddDetail(detail)
+	assert.Equal(t, len(tripleErr.Details()), 1)
+	unmarshaled, err := tripleErr.Details()[0].Value()
 	assert.Nil(t, err)
 	assert.Equal(t, unmarshaled, proto.Message(second))
 	secondBin, err := proto.Marshal(second)
@@ -109,7 +107,7 @@
 	assert.True(t, errors.Is(err, err))
 	// Our errors should have the same semantics. Note that we'd need to extend
 	// the ErrorDetail interface to support value equality.
-	connectErr := NewError(CodeUnavailable, err)
-	assert.False(t, errors.Is(connectErr, NewError(CodeUnavailable, err)))
-	assert.True(t, errors.Is(connectErr, connectErr))
+	tripleErr := NewError(CodeUnavailable, err)
+	assert.False(t, errors.Is(tripleErr, NewError(CodeUnavailable, err)))
+	assert.True(t, errors.Is(tripleErr, tripleErr))
 }
diff --git a/protocol/triple/triple_protocol/error_writer.go b/protocol/triple/triple_protocol/error_writer.go
index 9f420a4..b9aedef 100644
--- a/protocol/triple/triple_protocol/error_writer.go
+++ b/protocol/triple/triple_protocol/error_writer.go
@@ -107,8 +107,8 @@
 }
 
 func (w *ErrorWriter) writeConnectUnary(response http.ResponseWriter, err error) error {
-	if connectErr, ok := asError(err); ok {
-		mergeHeaders(response.Header(), connectErr.meta)
+	if tripleErr, ok := asError(err); ok {
+		mergeHeaders(response.Header(), tripleErr.meta)
 	}
 	response.WriteHeader(tripleCodeToHTTP(CodeOf(err)))
 	data, marshalErr := json.Marshal(newTripleWireError(err))
diff --git a/protocol/triple/triple_protocol/example_init_test.go b/protocol/triple/triple_protocol/example_init_test.go
index cbb0ab3..4823861 100644
--- a/protocol/triple/triple_protocol/example_init_test.go
+++ b/protocol/triple/triple_protocol/example_init_test.go
@@ -1,144 +1,143 @@
-// // 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.
+// 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.
 //
-//import (
-//	"context"
-//	"errors"
-//	"net"
-//	"net/http"
-//	"net/http/httptest"
-//	"sync"
-//
-//	"dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/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" }
+// 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" }
diff --git a/protocol/triple/triple_protocol/handler.go b/protocol/triple/triple_protocol/handler.go
index 2593389..4f39483 100644
--- a/protocol/triple/triple_protocol/handler.go
+++ b/protocol/triple/triple_protocol/handler.go
@@ -55,7 +55,7 @@
 		if res == nil && err == nil {
 			// This is going to panic during serialization. Debugging is much easier
 			// if we panic here instead, so we can include the procedure name.
-			panic(fmt.Sprintf("%s returned nil *connect.Response and nil error", procedure)) //nolint: forbidigo
+			panic(fmt.Sprintf("%s returned nil *triple.Response and nil error", procedure)) //nolint: forbidigo
 		}
 		return res, err
 	})
@@ -69,7 +69,7 @@
 	// Given a stream, how should we call the unary function?
 	implementation := func(ctx context.Context, conn StreamingHandlerConn) error {
 		req := reqInitFunc()
-		if err := conn.Receive(&req); err != nil {
+		if err := conn.Receive(req); err != nil {
 			return err
 		}
 		// wrap the specific msg
@@ -116,7 +116,7 @@
 			if res == nil {
 				// This is going to panic during serialization. Debugging is much easier
 				// if we panic here instead, so we can include the procedure name.
-				panic(fmt.Sprintf("%s returned nil *connect.Response and nil error", procedure)) //nolint: forbidigo
+				panic(fmt.Sprintf("%s returned nil *triple.Response and nil error", procedure)) //nolint: forbidigo
 			}
 			mergeHeaders(conn.ResponseHeader(), res.header)
 			mergeHeaders(conn.ResponseTrailer(), res.trailer)
diff --git a/protocol/triple/triple_protocol/handler_example_test.go b/protocol/triple/triple_protocol/handler_example_test.go
index 461e085..65e5c4b 100644
--- a/protocol/triple/triple_protocol/handler_example_test.go
+++ b/protocol/triple/triple_protocol/handler_example_test.go
@@ -1,68 +1,69 @@
-// // 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.
+// 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"
-//	"net/http"
-//
-//	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/proto/connect/ping/v1"
-//	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/proto/connect/ping/v1/pingv1connect"
-//)
-//
-//// ExamplePingServer implements some trivial business logic. The Protobuf
-//// definition for this API is in proto/connect/ping/v1/ping.proto.
-//type ExamplePingServer struct {
-//	pingv1connect.UnimplementedPingServiceHandler
-//}
-//
-//// Ping implements pingv1connect.PingServiceHandler.
-//func (*ExamplePingServer) Ping(
-//	_ context.Context,
-//	request *pingv1.PingRequest,
-//) (*pingv1.PingResponse, error) {
-//	return &pingv1.PingResponse{
-//		Number: request.Number,
-//		Text:   request.Text,
-//	}, nil
-//}
-//
-//func Example_handler() {
-//	// protoc-gen-connect-go generates constructors that return plain net/http
-//	// Handlers, so they're compatible with most Go HTTP routers and middleware
-//	// (for example, net/http's StripPrefix). Each handler automatically supports
-//	// the Connect, gRPC, and gRPC-Web protocols.
-//	mux := http.NewServeMux()
-//	mux.Handle(
-//		pingv1connect.NewPingServiceHandler(
-//			&ExamplePingServer{}, // our business logic
-//		),
-//	)
-//	// You can serve gRPC's health and server reflection APIs using
-//	// github.com/bufbuild/connect-grpchealth-go and
-//	// github.com/bufbuild/connect-grpcreflect-go.
-//	_ = http.ListenAndServeTLS(
-//		"localhost:8080",
-//		"internal/testdata/server.crt",
-//		"internal/testdata/server.key",
-//		mux,
-//	)
-//	// To serve HTTP/2 requests without TLS (as many gRPC clients expect), import
-//	// golang.org/x/net/http2/h2c and golang.org/x/net/http2 and change to:
-//	// _ = http.ListenAndServe(
-//	// 	"localhost:8080",
-//	// 	h2c.NewHandler(mux, &http2.Server{}),
-//	// )
-//}
+import (
+	"context"
+	"net/http"
+
+	triple "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
+	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1"
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1/pingv1connect"
+)
+
+// ExamplePingServer implements some trivial business logic. The Protobuf
+// definition for this API is in proto/triple/ping/v1/ping.proto.
+type ExamplePingServer struct {
+	pingv1connect.UnimplementedPingServiceHandler
+}
+
+// Ping implements pingv1connect.PingServiceHandler.
+func (*ExamplePingServer) Ping(
+	_ context.Context,
+	request *triple.Request,
+) (*triple.Response, error) {
+	msg := request.Msg.(*pingv1.PingRequest)
+	return triple.NewResponse(&pingv1.PingResponse{
+		Number: msg.Number,
+		Text:   msg.Text,
+	}), nil
+}
+
+func Example_handler() {
+	// protoc-gen-triple-go generates constructors that return plain net/http
+	// Handlers, so they're compatible with most Go HTTP routers and middleware
+	// (for example, net/http's StripPrefix). Each handler automatically supports
+	// the Connect, gRPC, and gRPC-Web protocols.
+	mux := http.NewServeMux()
+	mux.Handle(
+		pingv1connect.NewPingServiceHandler(
+			&ExamplePingServer{}, // our business logic
+		),
+	)
+	// You can serve gRPC's health and server reflection APIs using
+	// github.com/bufbuild/triple-grpchealth-go and
+	// github.com/bufbuild/triple-grpcreflect-go.
+	_ = http.ListenAndServeTLS(
+		"localhost:8080",
+		"internal/testdata/server.crt",
+		"internal/testdata/server.key",
+		mux,
+	)
+	// To serve HTTP/2 requests without TLS (as many gRPC clients expect), import
+	// golang.org/x/net/http2/h2c and golang.org/x/net/http2 and change to:
+	// _ = http.ListenAndServe(
+	// 	"localhost:8080",
+	// 	h2c.NewHandler(mux, &http2.Server{}),
+	// )
+}
diff --git a/protocol/triple/triple_protocol/handler_ext_test.go b/protocol/triple/triple_protocol/handler_ext_test.go
index 905705e..5435a90 100644
--- a/protocol/triple/triple_protocol/handler_ext_test.go
+++ b/protocol/triple/triple_protocol/handler_ext_test.go
@@ -1,200 +1,198 @@
-// // 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.
+// 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"
-//	"encoding/json"
-//	"net/http"
-//	"net/http/httptest"
-//	"strings"
-//	"testing"
-//
-//	"dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/assert"
-//	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/proto/connect/ping/v1"
-//	"dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/proto/connect/ping/v1/pingv1connect"
-//)
-//
-//func TestHandler_ServeHTTP(t *testing.T) {
-//	t.Parallel()
-//	mux := http.NewServeMux()
-//	mux.Handle(pingv1connect.NewPingServiceHandler(
-//		successPingServer{},
-//	))
-//	const pingProcedure = "/" + pingv1connect.PingServiceName + "/Ping"
-//	const sumProcedure = "/" + pingv1connect.PingServiceName + "/Sum"
-//	server := httptest.NewServer(mux)
-//	client := server.Client()
-//	t.Cleanup(func() {
-//		server.Close()
-//	})
-//
-//	t.Run("get_method_no_encoding", func(t *testing.T) {
-//		t.Parallel()
-//		request, err := http.NewRequestWithContext(
-//			context.Background(),
-//			http.MethodGet,
-//			server.URL+pingProcedure,
-//			strings.NewReader(""),
-//		)
-//		assert.Nil(t, err)
-//		resp, err := client.Do(request)
-//		assert.Nil(t, err)
-//		defer resp.Body.Close()
-//		assert.Equal(t, resp.StatusCode, http.StatusUnsupportedMediaType)
-//	})
-//
-//	t.Run("get_method_bad_encoding", func(t *testing.T) {
-//		t.Parallel()
-//		request, err := http.NewRequestWithContext(
-//			context.Background(),
-//			http.MethodGet,
-//			server.URL+pingProcedure+`?encoding=unk&message={}`,
-//			strings.NewReader(""),
-//		)
-//		assert.Nil(t, err)
-//		resp, err := client.Do(request)
-//		assert.Nil(t, err)
-//		defer resp.Body.Close()
-//		assert.Equal(t, resp.StatusCode, http.StatusUnsupportedMediaType)
-//	})
-//
-//	t.Run("idempotent_get_method", func(t *testing.T) {
-//		t.Parallel()
-//		request, err := http.NewRequestWithContext(
-//			context.Background(),
-//			http.MethodGet,
-//			server.URL+pingProcedure+`?encoding=json&message={}`,
-//			strings.NewReader(""),
-//		)
-//		assert.Nil(t, err)
-//		resp, err := client.Do(request)
-//		assert.Nil(t, err)
-//		defer resp.Body.Close()
-//		assert.Equal(t, resp.StatusCode, http.StatusOK)
-//	})
-//
-//	t.Run("method_not_allowed", func(t *testing.T) {
-//		t.Parallel()
-//		request, err := http.NewRequestWithContext(
-//			context.Background(),
-//			http.MethodGet,
-//			server.URL+sumProcedure,
-//			strings.NewReader(""),
-//		)
-//		assert.Nil(t, err)
-//		resp, err := client.Do(request)
-//		assert.Nil(t, err)
-//		defer resp.Body.Close()
-//		assert.Equal(t, resp.StatusCode, http.StatusMethodNotAllowed)
-//		assert.Equal(t, resp.Header.Get("Allow"), http.MethodPost)
-//	})
-//
-//	t.Run("unsupported_content_type", func(t *testing.T) {
-//		t.Parallel()
-//		request, err := http.NewRequestWithContext(
-//			context.Background(),
-//			http.MethodPost,
-//			server.URL+pingProcedure,
-//			strings.NewReader("{}"),
-//		)
-//		assert.Nil(t, err)
-//		request.Header.Set("Content-Type", "application/x-custom-json")
-//		resp, err := client.Do(request)
-//		assert.Nil(t, err)
-//		defer resp.Body.Close()
-//		assert.Equal(t, resp.StatusCode, http.StatusUnsupportedMediaType)
-//		assert.Equal(t, resp.Header.Get("Accept-Post"), strings.Join([]string{
-//			"application/grpc",
-//			"application/grpc+json",
-//			"application/grpc+json; charset=utf-8",
-//			"application/grpc+proto",
-//			"application/grpc-web",
-//			"application/grpc-web+json",
-//			"application/grpc-web+json; charset=utf-8",
-//			"application/grpc-web+proto",
-//			"application/json",
-//			"application/json; charset=utf-8",
-//			"application/proto",
-//		}, ", "))
-//	})
-//
-//	t.Run("charset_in_content_type_header", func(t *testing.T) {
-//		t.Parallel()
-//		req, err := http.NewRequestWithContext(
-//			context.Background(),
-//			http.MethodPost,
-//			server.URL+pingProcedure,
-//			strings.NewReader("{}"),
-//		)
-//		assert.Nil(t, err)
-//		req.Header.Set("Content-Type", "application/json;Charset=Utf-8")
-//		resp, err := client.Do(req)
-//		assert.Nil(t, err)
-//		defer resp.Body.Close()
-//		assert.Equal(t, resp.StatusCode, http.StatusOK)
-//	})
-//
-//	t.Run("unsupported_charset", func(t *testing.T) {
-//		t.Parallel()
-//		req, err := http.NewRequestWithContext(
-//			context.Background(),
-//			http.MethodPost,
-//			server.URL+pingProcedure,
-//			strings.NewReader("{}"),
-//		)
-//		assert.Nil(t, err)
-//		req.Header.Set("Content-Type", "application/json; charset=shift-jis")
-//		resp, err := client.Do(req)
-//		assert.Nil(t, err)
-//		defer resp.Body.Close()
-//		assert.Equal(t, resp.StatusCode, http.StatusUnsupportedMediaType)
-//	})
-//
-//	t.Run("unsupported_content_encoding", func(t *testing.T) {
-//		t.Parallel()
-//		req, err := http.NewRequestWithContext(
-//			context.Background(),
-//			http.MethodPost,
-//			server.URL+pingProcedure,
-//			strings.NewReader("{}"),
-//		)
-//		assert.Nil(t, err)
-//		req.Header.Set("Content-Type", "application/json")
-//		req.Header.Set("Content-Encoding", "invalid")
-//		resp, err := client.Do(req)
-//		assert.Nil(t, err)
-//		defer resp.Body.Close()
-//		assert.Equal(t, resp.StatusCode, http.StatusNotFound)
-//
-//		type errorMessage struct {
-//			Code    string `json:"code,omitempty"`
-//			Message string `json:"message,omitempty"`
-//		}
-//		var message errorMessage
-//		err = json.NewDecoder(resp.Body).Decode(&message)
-//		assert.Nil(t, err)
-//		assert.Equal(t, message.Message, `unknown compression "invalid": supported encodings are gzip`)
-//		assert.Equal(t, message.Code, triple.CodeUnimplemented.String())
-//	})
-//}
-//
-//type successPingServer struct {
-//	pingv1connect.UnimplementedPingServiceHandler
-//}
-//
-//func (successPingServer) Ping(context.Context, *triple.Request[pingv1.PingRequest]) (*triple.Response[pingv1.PingResponse], error) {
-//	return &triple.Response[pingv1.PingResponse]{}, nil
-//}
+import (
+	"context"
+	"encoding/json"
+	"net/http"
+	"net/http/httptest"
+	"strings"
+	"testing"
+
+	triple "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
+
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/assert"
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1/pingv1connect"
+)
+
+func TestHandler_ServeHTTP(t *testing.T) {
+	t.Parallel()
+	mux := http.NewServeMux()
+	mux.Handle(pingv1connect.NewPingServiceHandler(
+		successPingServer{},
+	))
+	const pingProcedure = "/" + pingv1connect.PingServiceName + "/Ping"
+	const sumProcedure = "/" + pingv1connect.PingServiceName + "/Sum"
+	server := httptest.NewServer(mux)
+	client := server.Client()
+	t.Cleanup(func() {
+		server.Close()
+	})
+
+	t.Run("get_method_no_encoding", func(t *testing.T) {
+		t.Parallel()
+		request, err := http.NewRequestWithContext(
+			context.Background(),
+			http.MethodPost,
+			server.URL+pingProcedure,
+			strings.NewReader(""),
+		)
+		assert.Nil(t, err)
+		resp, err := client.Do(request)
+		assert.Nil(t, err)
+		defer resp.Body.Close()
+		assert.Equal(t, resp.StatusCode, http.StatusUnsupportedMediaType)
+	})
+
+	t.Run("get_method_bad_encoding", func(t *testing.T) {
+		t.Parallel()
+		request, err := http.NewRequestWithContext(
+			context.Background(),
+			http.MethodPost,
+			server.URL+pingProcedure+`?encoding=unk&message={}`,
+			strings.NewReader(""),
+		)
+		assert.Nil(t, err)
+		resp, err := client.Do(request)
+		assert.Nil(t, err)
+		defer resp.Body.Close()
+		assert.Equal(t, resp.StatusCode, http.StatusUnsupportedMediaType)
+	})
+
+	//triple并不支持POST
+	//t.Run("idempotent_get_method", func(t *testing.T) {
+	//	t.Parallel()
+	//	request, err := http.NewRequestWithContext(
+	//		context.Background(),
+	//		http.MethodPost,
+	//		server.URL+pingProcedure+`?encoding=json&message={}`,
+	//		strings.NewReader(""),
+	//	)
+	//	assert.Nil(t, err)
+	//	resp, err := client.Do(request)
+	//	assert.Nil(t, err)
+	//	defer resp.Body.Close()
+	//	assert.Equal(t, resp.StatusCode, http.StatusOK)
+	//})
+
+	//不支持流式调用
+	//t.Run("method_not_allowed", func(t *testing.T) {
+	//	t.Parallel()
+	//	request, err := http.NewRequestWithContext(
+	//		context.Background(),
+	//		http.MethodGet,
+	//		server.URL+sumProcedure,
+	//		strings.NewReader(""),
+	//	)
+	//	assert.Nil(t, err)
+	//	resp, err := client.Do(request)
+	//	assert.Nil(t, err)
+	//	defer resp.Body.Close()
+	//	assert.Equal(t, resp.StatusCode, http.StatusMethodNotAllowed)
+	//	assert.Equal(t, resp.Header.Get("Allow"), http.MethodPost)
+	//})
+
+	t.Run("unsupported_content_type", func(t *testing.T) {
+		t.Parallel()
+		request, err := http.NewRequestWithContext(
+			context.Background(),
+			http.MethodPost,
+			server.URL+pingProcedure,
+			strings.NewReader("{}"),
+		)
+		assert.Nil(t, err)
+		request.Header.Set("Content-Type", "application/x-custom-json")
+		resp, err := client.Do(request)
+		assert.Nil(t, err)
+		defer resp.Body.Close()
+		assert.Equal(t, resp.StatusCode, http.StatusUnsupportedMediaType)
+		assert.Equal(t, resp.Header.Get("Accept-Post"), strings.Join([]string{
+			"application/grpc",
+			"application/grpc+json",
+			"application/grpc+json; charset=utf-8",
+			"application/grpc+proto",
+			"application/json",
+			"application/json; charset=utf-8",
+			"application/proto",
+		}, ", "))
+	})
+
+	t.Run("charset_in_content_type_header", func(t *testing.T) {
+		t.Parallel()
+		req, err := http.NewRequestWithContext(
+			context.Background(),
+			http.MethodPost,
+			server.URL+pingProcedure,
+			strings.NewReader("{}"),
+		)
+		assert.Nil(t, err)
+		req.Header.Set("Content-Type", "application/json;Charset=Utf-8")
+		resp, err := client.Do(req)
+		assert.Nil(t, err)
+		defer resp.Body.Close()
+		assert.Equal(t, resp.StatusCode, http.StatusOK)
+	})
+
+	t.Run("unsupported_charset", func(t *testing.T) {
+		t.Parallel()
+		req, err := http.NewRequestWithContext(
+			context.Background(),
+			http.MethodPost,
+			server.URL+pingProcedure,
+			strings.NewReader("{}"),
+		)
+		assert.Nil(t, err)
+		req.Header.Set("Content-Type", "application/json; charset=shift-jis")
+		resp, err := client.Do(req)
+		assert.Nil(t, err)
+		defer resp.Body.Close()
+		assert.Equal(t, resp.StatusCode, http.StatusUnsupportedMediaType)
+	})
+
+	t.Run("unsupported_content_encoding", func(t *testing.T) {
+		t.Parallel()
+		req, err := http.NewRequestWithContext(
+			context.Background(),
+			http.MethodPost,
+			server.URL+pingProcedure,
+			strings.NewReader("{}"),
+		)
+		assert.Nil(t, err)
+		req.Header.Set("Content-Type", "application/json")
+		req.Header.Set("Content-Encoding", "invalid")
+		resp, err := client.Do(req)
+		assert.Nil(t, err)
+		defer resp.Body.Close()
+		assert.Equal(t, resp.StatusCode, http.StatusNotFound)
+
+		type errorMessage struct {
+			Code    string `json:"code,omitempty"`
+			Message string `json:"message,omitempty"`
+		}
+		var message errorMessage
+		err = json.NewDecoder(resp.Body).Decode(&message)
+		assert.Nil(t, err)
+		assert.Equal(t, message.Message, `unknown compression "invalid": supported encodings are gzip`)
+		assert.Equal(t, message.Code, triple.CodeUnimplemented.String())
+	})
+}
+
+type successPingServer struct {
+	pingv1connect.UnimplementedPingServiceHandler
+}
+
+func (successPingServer) Ping(context.Context, *triple.Request) (*triple.Response, error) {
+	return &triple.Response{}, nil
+}
diff --git a/protocol/triple/triple_protocol/handler_stream_test.go b/protocol/triple/triple_protocol/handler_stream_test.go
index ccf1b3d..2178457 100644
--- a/protocol/triple/triple_protocol/handler_stream_test.go
+++ b/protocol/triple/triple_protocol/handler_stream_test.go
@@ -1,44 +1,36 @@
-// // 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.
+// 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
 
-//
-//import (
-//	"fmt"
-//	"testing"
-//
-//	"dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/assert"
-//	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/proto/connect/ping/v1"
-//)
-//
+//是否需要另行分配???---》handler_stream 63
 //func TestClientStreamIterator(t *testing.T) {
 //	t.Parallel()
 //	// The server's view of a client streaming RPC is an iterator. For safety,
 //	// and to match grpc-go's behavior, we should allocate a new message for each
 //	// iteration.
-//	stream := &ClientStream[pingv1.PingRequest]{conn: &nopStreamingHandlerConn{}}
-//	assert.True(t, stream.Receive())
+//	stream := &ClientStream{conn: &nopStreamingHandlerConn{}}
+//	assert.True(t, stream.Receive(nil))
 //	first := fmt.Sprintf("%p", stream.Msg())
-//	assert.True(t, stream.Receive())
+//	assert.True(t, stream.Receive(nil))
 //	second := fmt.Sprintf("%p", stream.Msg())
 //	assert.NotEqual(t, first, second, assert.Sprintf("should allocate a new message for each iteration"))
 //}
-//
-//type nopStreamingHandlerConn struct {
-//	StreamingHandlerConn
-//}
-//
-//func (nopStreamingHandlerConn) Receive(msg any) error {
-//	return nil
-//}
+
+type nopStreamingHandlerConn struct {
+	StreamingHandlerConn
+}
+
+func (nopStreamingHandlerConn) Receive(msg any) error {
+	return nil
+}
diff --git a/protocol/triple/triple_protocol/header_test.go b/protocol/triple/triple_protocol/header_test.go
index 73ba299..7ab4828 100644
--- a/protocol/triple/triple_protocol/header_test.go
+++ b/protocol/triple/triple_protocol/header_test.go
@@ -19,10 +19,8 @@
 	"net/http"
 	"testing"
 	"testing/quick"
-)
 
-import (
-	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/assert"
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/assert"
 )
 
 func TestBinaryEncodingQuick(t *testing.T) {
diff --git a/protocol/triple/triple_protocol/idempotency_level.go b/protocol/triple/triple_protocol/idempotency_level.go
index e1d3a67..50f86a5 100644
--- a/protocol/triple/triple_protocol/idempotency_level.go
+++ b/protocol/triple/triple_protocol/idempotency_level.go
@@ -4,14 +4,13 @@
 // 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
+//	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
 
 import (
diff --git a/protocol/triple/triple_protocol/interceptor_example_test.go b/protocol/triple/triple_protocol/interceptor_example_test.go
index f43d6fe..53ac348 100644
--- a/protocol/triple/triple_protocol/interceptor_example_test.go
+++ b/protocol/triple/triple_protocol/interceptor_example_test.go
@@ -1,97 +1,97 @@
-// // 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.
+// 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"
-//	connect "dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect"
-//	"log"
-//	"os"
-//
-//	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/proto/connect/ping/v1"
-//	"dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/proto/connect/ping/v1/pingv1connect"
-//)
-//
-//func ExampleUnaryInterceptorFunc() {
-//	logger := log.New(os.Stdout, "" /* prefix */, 0 /* flags */)
-//	loggingInterceptor := connect.UnaryInterceptorFunc(
-//		func(next connect.UnaryFunc) connect.UnaryFunc {
-//			return connect.UnaryFunc(func(ctx context.Context, request connect.AnyRequest) (connect.AnyResponse, error) {
-//				logger.Println("calling:", request.Spec().Procedure)
-//				logger.Println("request:", request.Any())
-//				response, err := next(ctx, request)
-//				if err != nil {
-//					logger.Println("error:", err)
-//				} else {
-//					logger.Println("response:", response.Any())
-//				}
-//				return response, err
-//			})
-//		},
-//	)
-//	client := pingv1connect.NewPingServiceClient(
-//		examplePingServer.Client(),
-//		examplePingServer.URL(),
-//		connect.WithInterceptors(loggingInterceptor),
-//	)
-//	if _, err := client.Ping(context.Background(), connect.NewRequest(&pingv1.PingRequest{Number: 42})); err != nil {
-//		logger.Println("error:", err)
-//		return
-//	}
-//
-//	// Output:
-//	// calling: /connect.ping.v1.PingService/Ping
-//	// request: number:42
-//	// response: number:42
-//}
-//
-//func ExampleWithInterceptors() {
-//	logger := log.New(os.Stdout, "" /* prefix */, 0 /* flags */)
-//	outer := connect.UnaryInterceptorFunc(
-//		func(next connect.UnaryFunc) connect.UnaryFunc {
-//			return connect.UnaryFunc(func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {
-//				logger.Println("outer interceptor: before call")
-//				res, err := next(ctx, req)
-//				logger.Println("outer interceptor: after call")
-//				return res, err
-//			})
-//		},
-//	)
-//	inner := connect.UnaryInterceptorFunc(
-//		func(next connect.UnaryFunc) connect.UnaryFunc {
-//			return connect.UnaryFunc(func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {
-//				logger.Println("inner interceptor: before call")
-//				res, err := next(ctx, req)
-//				logger.Println("inner interceptor: after call")
-//				return res, err
-//			})
-//		},
-//	)
-//	client := pingv1connect.NewPingServiceClient(
-//		examplePingServer.Client(),
-//		examplePingServer.URL(),
-//		connect.WithInterceptors(outer, inner),
-//	)
-//	if _, err := client.Ping(context.Background(), connect.NewRequest(&pingv1.PingRequest{})); err != nil {
-//		logger.Println("error:", err)
-//		return
-//	}
-//
-//	// Output:
-//	// outer interceptor: before call
-//	// inner interceptor: before call
-//	// inner interceptor: after call
-//	// outer interceptor: after call
-//}
+import (
+	"context"
+	"log"
+	"os"
+
+	triple "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
+
+	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1"
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1/pingv1connect"
+)
+
+func ExampleUnaryInterceptorFunc() {
+	logger := log.New(os.Stdout, "" /* prefix */, 0 /* flags */)
+	loggingInterceptor := triple.UnaryInterceptorFunc(
+		func(next triple.UnaryFunc) triple.UnaryFunc {
+			return triple.UnaryFunc(func(ctx context.Context, request triple.AnyRequest, response triple.AnyResponse) error {
+				logger.Println("calling:", request.Spec().Procedure)
+				logger.Println("request:", request.Any())
+				err := next(ctx, request, response)
+				if err != nil {
+					logger.Println("error:", err)
+				} else {
+					logger.Println("response:", response.Any())
+				}
+				return err
+			})
+		},
+	)
+	client := pingv1connect.NewPingServiceClient(
+		examplePingServer.Client(),
+		examplePingServer.URL(),
+		triple.WithInterceptors(loggingInterceptor),
+	)
+	if err := client.Ping(context.Background(), triple.NewRequest(&pingv1.PingRequest{Number: 42}), triple.NewResponse(&pingv1.PingResponse{})); err != nil {
+		logger.Println("error:", err)
+		return
+	}
+
+	// Output:
+	// calling: /connect.ping.v1.PingService/Ping
+	// request: number:42
+	// response: number:42
+}
+
+func ExampleWithInterceptors() {
+	logger := log.New(os.Stdout, "" /* prefix */, 0 /* flags */)
+	outer := triple.UnaryInterceptorFunc(
+		func(next triple.UnaryFunc) triple.UnaryFunc {
+			return triple.UnaryFunc(func(ctx context.Context, req triple.AnyRequest, res triple.AnyResponse) error {
+				logger.Println("outer interceptor: before call")
+				err := next(ctx, req, res)
+				logger.Println("outer interceptor: after call")
+				return err
+			})
+		},
+	)
+	inner := triple.UnaryInterceptorFunc(
+		func(next triple.UnaryFunc) triple.UnaryFunc {
+			return triple.UnaryFunc(func(ctx context.Context, req triple.AnyRequest, res triple.AnyResponse) error {
+				logger.Println("inner interceptor: before call")
+				err := next(ctx, req, res)
+				logger.Println("inner interceptor: after call")
+				return err
+			})
+		},
+	)
+	client := pingv1connect.NewPingServiceClient(
+		examplePingServer.Client(),
+		examplePingServer.URL(),
+		triple.WithInterceptors(outer, inner),
+	)
+	if err := client.Ping(context.Background(), triple.NewRequest(&pingv1.PingRequest{}), triple.NewResponse(&pingv1.PingResponse{})); err != nil {
+		logger.Println("error:", err)
+		return
+	}
+
+	// Output:
+	// outer interceptor: before call
+	// inner interceptor: before call
+	// inner interceptor: after call
+	// outer interceptor: after call
+}
diff --git a/protocol/triple/triple_protocol/interceptor_ext_test.go b/protocol/triple/triple_protocol/interceptor_ext_test.go
index 03f8a1a..3ae14f6 100644
--- a/protocol/triple/triple_protocol/interceptor_ext_test.go
+++ b/protocol/triple/triple_protocol/interceptor_ext_test.go
@@ -1,270 +1,283 @@
-// // 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.
+// 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"
-//	"net/http"
-//	"net/http/httptest"
-//	"testing"
-//
-//	"dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/assert"
-//	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/proto/connect/ping/v1"
-//	"dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/proto/connect/ping/v1/pingv1connect"
-//)
-//
-//func TestOnionOrderingEndToEnd(t *testing.T) {
-//	t.Parallel()
-//	// Helper function: returns a function that asserts that there's some value
-//	// set for header "expect", and adds a value for header "add".
-//	newInspector := func(expect, add string) func(triple.Spec, http.Header) {
-//		return func(spec triple.Spec, header http.Header) {
-//			if expect != "" {
-//				assert.NotZero(
-//					t,
-//					header.Get(expect),
-//					assert.Sprintf(
-//						"%s (IsClient %v): header %q missing: %v",
-//						spec.Procedure,
-//						spec.IsClient,
-//						expect,
-//						header,
-//					),
-//				)
-//			}
-//			header.Set(add, "v")
-//		}
-//	}
-//	// Helper function: asserts that there's a value present for header keys
-//	// "one", "two", "three", and "four".
-//	assertAllPresent := func(spec triple.Spec, header http.Header) {
-//		for _, key := range []string{"one", "two", "three", "four"} {
-//			assert.NotZero(
-//				t,
-//				header.Get(key),
-//				assert.Sprintf(
-//					"%s (IsClient %v): checking all headers, %q missing: %v",
-//					spec.Procedure,
-//					spec.IsClient,
-//					key,
-//					header,
-//				),
-//			)
-//		}
-//	}
-//
-//	// The client and handler interceptor onions are the meat of the test. The
-//	// order of interceptor execution must be the same for unary and streaming
-//	// procedures.
-//	//
-//	// Requests should fall through the client onion from top to bottom, traverse
-//	// the network, and then fall through the handler onion from top to bottom.
-//	// Responses should climb up the handler onion, traverse the network, and
-//	// then climb up the client onion.
-//	//
-//	// The request and response sides of this onion are numbered to make the
-//	// intended order clear.
-//	clientOnion := triple.WithInterceptors(
-//		newHeaderInterceptor(
-//			// 1 (start). request: should see protocol-related headers
-//			func(_ triple.Spec, h http.Header) {
-//				assert.NotZero(t, h.Get("Content-Type"))
-//			},
-//			// 12 (end). response: check "one"-"four"
-//			assertAllPresent,
-//		),
-//		newHeaderInterceptor(
-//			newInspector("", "one"),       // 2. request: add header "one"
-//			newInspector("three", "four"), // 11. response: check "three", add "four"
-//		),
-//		newHeaderInterceptor(
-//			newInspector("one", "two"),   // 3. request: check "one", add "two"
-//			newInspector("two", "three"), // 10. response: check "two", add "three"
-//		),
-//	)
-//	handlerOnion := triple.WithInterceptors(
-//		newHeaderInterceptor(
-//			newInspector("two", "three"), // 4. request: check "two", add "three"
-//			newInspector("one", "two"),   // 9. response: check "one", add "two"
-//		),
-//		newHeaderInterceptor(
-//			newInspector("three", "four"), // 5. request: check "three", add "four"
-//			newInspector("", "one"),       // 8. response: add "one"
-//		),
-//		newHeaderInterceptor(
-//			assertAllPresent, // 6. request: check "one"-"four"
-//			nil,              // 7. response: no-op
-//		),
-//	)
-//
-//	mux := http.NewServeMux()
-//	mux.Handle(
-//		pingv1connect.NewPingServiceHandler(
-//			pingServer{},
-//			handlerOnion,
-//		),
-//	)
-//	server := httptest.NewServer(mux)
-//	defer server.Close()
-//
-//	client := pingv1connect.NewPingServiceClient(
-//		server.Client(),
-//		server.URL,
-//		clientOnion,
-//	)
-//
-//	_, err := client.Ping(context.Background(), triple.NewRequest(&pingv1.PingRequest{Number: 10}))
-//	assert.Nil(t, err)
-//
-//	responses, err := client.CountUp(context.Background(), triple.NewRequest(&pingv1.CountUpRequest{Number: 10}))
-//	assert.Nil(t, err)
-//	var sum int64
-//	for responses.Receive() {
-//		sum += responses.Msg().Number
-//	}
-//	assert.Equal(t, sum, 55)
-//	assert.Nil(t, responses.Close())
-//}
-//
+import (
+	"context"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	triple "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
+
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/assert"
+	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1"
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1/pingv1connect"
+)
+
+func TestOnionOrderingEndToEnd(t *testing.T) {
+	t.Parallel()
+	// Helper function: returns a function that asserts that there's some value
+	// set for header "expect", and adds a value for header "add".
+	newInspector := func(expect, add string) func(triple.Spec, http.Header) {
+		return func(spec triple.Spec, header http.Header) {
+			if expect != "" {
+				assert.NotZero(
+					t,
+					header.Get(expect),
+					assert.Sprintf(
+						"%s (IsClient %v): header %q missing: %v",
+						spec.Procedure,
+						spec.IsClient,
+						expect,
+						header,
+					),
+				)
+			}
+			header.Set(add, "v")
+		}
+	}
+	// Helper function: asserts that there's a value present for header keys
+	// "one", "two", "three", and "four".
+	assertAllPresent := func(spec triple.Spec, header http.Header) {
+		for _, key := range []string{"one", "two", "three", "four"} {
+			assert.NotZero(
+				t,
+				header.Get(key),
+				assert.Sprintf(
+					"%s (IsClient %v): checking all headers, %q missing: %v",
+					spec.Procedure,
+					spec.IsClient,
+					key,
+					header,
+				),
+			)
+		}
+	}
+
+	// The client and handler interceptor onions are the meat of the test. The
+	// order of interceptor execution must be the same for unary and streaming
+	// procedures.
+	//
+	// Requests should fall through the client onion from top to bottom, traverse
+	// the network, and then fall through the handler onion from top to bottom.
+	// Responses should climb up the handler onion, traverse the network, and
+	// then climb up the client onion.
+	//
+	// The request and response sides of this onion are numbered to make the
+	// intended order clear.
+	clientOnion := triple.WithInterceptors(
+		newHeaderInterceptor(
+			// 1 (start). request: should see protocol-related headers
+			func(_ triple.Spec, h http.Header) {
+				assert.NotZero(t, h.Get("Content-Type"))
+			},
+			// 12 (end). response: check "one"-"four"
+			assertAllPresent,
+		),
+		newHeaderInterceptor(
+			newInspector("", "one"),       // 2. request: add header "one"
+			newInspector("three", "four"), // 11. response: check "three", add "four"
+		),
+		newHeaderInterceptor(
+			newInspector("one", "two"),   // 3. request: check "one", add "two"
+			newInspector("two", "three"), // 10. response: check "two", add "three"
+		),
+	)
+	handlerOnion := triple.WithInterceptors(
+		newHeaderInterceptor(
+			newInspector("two", "three"), // 4. request: check "two", add "three"
+			newInspector("one", "two"),   // 9. response: check "one", add "two"
+		),
+		newHeaderInterceptor(
+			newInspector("three", "four"), // 5. request: check "three", add "four"
+			newInspector("", "one"),       // 8. response: add "one"
+		),
+		newHeaderInterceptor(
+			assertAllPresent, // 6. request: check "one"-"four"
+			nil,              // 7. response: no-op
+		),
+	)
+
+	mux := http.NewServeMux()
+	mux.Handle(
+		pingv1connect.NewPingServiceHandler(
+			pingServer{},
+			handlerOnion,
+		),
+	)
+	server := httptest.NewServer(mux)
+	defer server.Close()
+
+	client := pingv1connect.NewPingServiceClient(
+		server.Client(),
+		server.URL,
+		clientOnion,
+	)
+
+	err := client.Ping(context.Background(), triple.NewRequest(&pingv1.PingRequest{Number: 10}), triple.NewResponse(&pingv1.PingResponse{}))
+	assert.Nil(t, err)
+
+	//responses, err := client.CountUp(context.Background(), triple.NewRequest(&pingv1.CountUpRequest{Number: 10}))
+	//assert.Nil(t, err)
+	//var sum int64
+	//for responses.Receive(&pingv1.CountUpResponse{}) {
+	//	msg := responses.Msg().(pingv1.CountUpResponse)
+	//	sum += msg.Number
+	//}
+	//assert.Equal(t, sum, 55)
+	//assert.Nil(t, responses.Close())
+}
+
 //func TestEmptyUnaryInterceptorFunc(t *testing.T) {
 //	t.Parallel()
 //	mux := http.NewServeMux()
 //	interceptor := triple.UnaryInterceptorFunc(func(next triple.UnaryFunc) triple.UnaryFunc {
-//		return func(ctx context.Context, request triple.AnyRequest) (triple.AnyResponse, error) {
-//			return next(ctx, request)
+//		return func(ctx context.Context, request triple.AnyRequest, response triple.AnyResponse) error {
+//			return next(ctx, request, response)
 //		}
 //	})
 //	mux.Handle(pingv1connect.NewPingServiceHandler(pingServer{}, triple.WithInterceptors(interceptor)))
 //	server := httptest.NewServer(mux)
 //	t.Cleanup(server.Close)
 //	connectClient := pingv1connect.NewPingServiceClient(server.Client(), server.URL, triple.WithInterceptors(interceptor))
-//	_, err := connectClient.Ping(context.Background(), triple.NewRequest(&pingv1.PingRequest{}))
+//	err := connectClient.Ping(context.Background(), triple.NewRequest(&pingv1.PingRequest{}), triple.NewResponse(&pingv1.PingResponse{}))
 //	assert.Nil(t, err)
 //	sumStream, err := connectClient.Sum(context.Background())
 //	assert.Nil(t, err)
 //	assert.Nil(t, sumStream.Send(&pingv1.SumRequest{Number: 1}))
-//	resp, err := sumStream.CloseAndReceive()
+//	err = sumStream.CloseAndReceive(triple.NewResponse(&pingv1.SumResponse{}))
 //	assert.Nil(t, err)
-//	assert.NotNil(t, resp)
 //	countUpStream, err := connectClient.CountUp(context.Background(), triple.NewRequest(&pingv1.CountUpRequest{}))
 //	assert.Nil(t, err)
-//	for countUpStream.Receive() {
+//	for countUpStream.Receive(&pingv1.CountUpResponse{}) {
 //		assert.NotNil(t, countUpStream.Msg())
 //	}
 //	assert.Nil(t, countUpStream.Close())
 //}
+
+// headerInterceptor makes it easier to write interceptors that inspect or
+// mutate HTTP headers. It applies the same logic to unary and streaming
+// procedures, wrapping the send or receive side of the stream as appropriate.
 //
-//// headerInterceptor makes it easier to write interceptors that inspect or
-//// mutate HTTP headers. It applies the same logic to unary and streaming
-//// procedures, wrapping the send or receive side of the stream as appropriate.
-////
-//// It's useful as a testing harness to make sure that we're chaining
-//// interceptors in the correct order.
-//type headerInterceptor struct {
-//	inspectRequestHeader  func(triple.Spec, http.Header)
-//	inspectResponseHeader func(triple.Spec, http.Header)
-//}
-//
-//// newHeaderInterceptor constructs a headerInterceptor. Nil function pointers
-//// are treated as no-ops.
-//func newHeaderInterceptor(
-//	inspectRequestHeader func(triple.Spec, http.Header),
-//	inspectResponseHeader func(triple.Spec, http.Header),
-//) *headerInterceptor {
-//	interceptor := headerInterceptor{
-//		inspectRequestHeader:  inspectRequestHeader,
-//		inspectResponseHeader: inspectResponseHeader,
-//	}
-//	if interceptor.inspectRequestHeader == nil {
-//		interceptor.inspectRequestHeader = func(_ triple.Spec, _ http.Header) {}
-//	}
-//	if interceptor.inspectResponseHeader == nil {
-//		interceptor.inspectResponseHeader = func(_ triple.Spec, _ http.Header) {}
-//	}
-//	return &interceptor
-//}
-//
-//func (h *headerInterceptor) WrapUnary(next triple.UnaryFunc) triple.UnaryFunc {
-//	return func(ctx context.Context, req triple.AnyRequest) (triple.AnyResponse, error) {
-//		h.inspectRequestHeader(req.Spec(), req.Header())
-//		res, err := next(ctx, req)
-//		if err != nil {
-//			return nil, err
-//		}
-//		h.inspectResponseHeader(req.Spec(), res.Header())
-//		return res, nil
-//	}
-//}
-//
-//func (h *headerInterceptor) WrapStreamingClient(next triple.StreamingClientFunc) triple.StreamingClientFunc {
-//	return func(ctx context.Context, spec triple.Spec) triple.StreamingClientConn {
-//		return &headerInspectingClientConn{
-//			StreamingClientConn:   next(ctx, spec),
-//			inspectRequestHeader:  h.inspectRequestHeader,
-//			inspectResponseHeader: h.inspectResponseHeader,
-//		}
-//	}
-//}
-//
-//func (h *headerInterceptor) WrapStreamingHandler(next triple.StreamingHandlerFunc) triple.StreamingHandlerFunc {
-//	return func(ctx context.Context, conn triple.StreamingHandlerConn) error {
-//		h.inspectRequestHeader(conn.Spec(), conn.RequestHeader())
-//		return next(ctx, &headerInspectingHandlerConn{
-//			StreamingHandlerConn:  conn,
-//			inspectResponseHeader: h.inspectResponseHeader,
-//		})
-//	}
-//}
-//
-//type headerInspectingHandlerConn struct {
-//	triple.StreamingHandlerConn
-//
-//	inspectedResponse     bool
-//	inspectResponseHeader func(triple.Spec, http.Header)
-//}
-//
-//func (hc *headerInspectingHandlerConn) Send(msg any) error {
-//	if !hc.inspectedResponse {
-//		hc.inspectResponseHeader(hc.Spec(), hc.ResponseHeader())
-//		hc.inspectedResponse = true
-//	}
-//	return hc.StreamingHandlerConn.Send(msg)
-//}
-//
-//type headerInspectingClientConn struct {
-//	triple.StreamingClientConn
-//
-//	inspectedRequest      bool
-//	inspectRequestHeader  func(triple.Spec, http.Header)
-//	inspectedResponse     bool
-//	inspectResponseHeader func(triple.Spec, http.Header)
-//}
-//
-//func (cc *headerInspectingClientConn) Send(msg any) error {
-//	if !cc.inspectedRequest {
-//		cc.inspectRequestHeader(cc.Spec(), cc.RequestHeader())
-//		cc.inspectedRequest = true
-//	}
-//	return cc.StreamingClientConn.Send(msg)
-//}
-//
-//func (cc *headerInspectingClientConn) Receive(msg any) error {
-//	err := cc.StreamingClientConn.Receive(msg)
-//	if !cc.inspectedResponse {
-//		cc.inspectResponseHeader(cc.Spec(), cc.ResponseHeader())
-//		cc.inspectedResponse = true
-//	}
-//	return err
-//}
+// It's useful as a testing harness to make sure that we're chaining
+// interceptors in the correct order.
+type headerInterceptor struct {
+	inspectRequestHeader  func(triple.Spec, http.Header)
+	inspectResponseHeader func(triple.Spec, http.Header)
+}
+
+// newHeaderInterceptor constructs a headerInterceptor. Nil function pointers
+// are treated as no-ops.
+func newHeaderInterceptor(
+	inspectRequestHeader func(triple.Spec, http.Header),
+	inspectResponseHeader func(triple.Spec, http.Header),
+) *headerInterceptor {
+	interceptor := headerInterceptor{
+		inspectRequestHeader:  inspectRequestHeader,
+		inspectResponseHeader: inspectResponseHeader,
+	}
+	if interceptor.inspectRequestHeader == nil {
+		interceptor.inspectRequestHeader = func(_ triple.Spec, _ http.Header) {}
+	}
+	if interceptor.inspectResponseHeader == nil {
+		interceptor.inspectResponseHeader = func(_ triple.Spec, _ http.Header) {}
+	}
+	return &interceptor
+}
+
+func (h *headerInterceptor) WrapUnaryHandler(next triple.UnaryHandlerFunc) triple.UnaryHandlerFunc {
+	return func(ctx context.Context, request triple.AnyRequest) (triple.AnyResponse, error) {
+		h.inspectRequestHeader(request.Spec(), request.Header())
+		response, err := next(ctx, request)
+		if err != nil {
+			return nil, err
+		}
+		h.inspectResponseHeader(request.Spec(), response.Header())
+		return response, nil
+	}
+}
+
+func (h *headerInterceptor) WrapUnary(next triple.UnaryFunc) triple.UnaryFunc {
+	return func(ctx context.Context, req triple.AnyRequest, res triple.AnyResponse) error {
+		h.inspectRequestHeader(req.Spec(), req.Header())
+		err := next(ctx, req, res)
+		if err != nil {
+			return err
+		}
+		h.inspectResponseHeader(req.Spec(), res.Header())
+		return nil
+	}
+}
+
+func (h *headerInterceptor) WrapStreamingClient(next triple.StreamingClientFunc) triple.StreamingClientFunc {
+	return func(ctx context.Context, spec triple.Spec) triple.StreamingClientConn {
+		return &headerInspectingClientConn{
+			StreamingClientConn:   next(ctx, spec),
+			inspectRequestHeader:  h.inspectRequestHeader,
+			inspectResponseHeader: h.inspectResponseHeader,
+		}
+	}
+}
+
+func (h *headerInterceptor) WrapStreamingHandler(next triple.StreamingHandlerFunc) triple.StreamingHandlerFunc {
+	return func(ctx context.Context, conn triple.StreamingHandlerConn) error {
+		h.inspectRequestHeader(conn.Spec(), conn.RequestHeader())
+		return next(ctx, &headerInspectingHandlerConn{
+			StreamingHandlerConn:  conn,
+			inspectResponseHeader: h.inspectResponseHeader,
+		})
+	}
+}
+
+type headerInspectingHandlerConn struct {
+	triple.StreamingHandlerConn
+
+	inspectedResponse     bool
+	inspectResponseHeader func(triple.Spec, http.Header)
+}
+
+func (hc *headerInspectingHandlerConn) Send(msg any) error {
+	if !hc.inspectedResponse {
+		hc.inspectResponseHeader(hc.Spec(), hc.ResponseHeader())
+		hc.inspectedResponse = true
+	}
+	return hc.StreamingHandlerConn.Send(msg)
+}
+
+type headerInspectingClientConn struct {
+	triple.StreamingClientConn
+
+	inspectedRequest      bool
+	inspectRequestHeader  func(triple.Spec, http.Header)
+	inspectedResponse     bool
+	inspectResponseHeader func(triple.Spec, http.Header)
+}
+
+func (cc *headerInspectingClientConn) Send(msg any) error {
+	if !cc.inspectedRequest {
+		cc.inspectRequestHeader(cc.Spec(), cc.RequestHeader())
+		cc.inspectedRequest = true
+	}
+	return cc.StreamingClientConn.Send(msg)
+}
+
+func (cc *headerInspectingClientConn) Receive(msg any) error {
+	err := cc.StreamingClientConn.Receive(msg)
+	if !cc.inspectedResponse {
+		cc.inspectResponseHeader(cc.Spec(), cc.ResponseHeader())
+		cc.inspectedResponse = true
+	}
+	return err
+}
diff --git a/protocol/triple/triple_protocol/assert/assert.go b/protocol/triple/triple_protocol/internal/assert/assert.go
similarity index 84%
rename from protocol/triple/triple_protocol/assert/assert.go
rename to protocol/triple/triple_protocol/internal/assert/assert.go
index a1717c8..05dac87 100644
--- a/protocol/triple/triple_protocol/assert/assert.go
+++ b/protocol/triple/triple_protocol/internal/assert/assert.go
@@ -8,13 +8,13 @@
 //
 // 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.
+// WITHOUT WARRANTIES OR CONDITIONS OF interface{} KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
 // Package assert is a minimal assert package using generics.
 //
-// This prevents connect from needing additional dependencies.
+// This prevents triple from needing additional dependencies.
 package assert
 
 import (
@@ -28,12 +28,11 @@
 
 import (
 	"github.com/google/go-cmp/cmp"
-
 	"google.golang.org/protobuf/testing/protocmp"
 )
 
 // Equal asserts that two values are equal.
-func Equal[T any](tb testing.TB, got, want T, options ...Option) bool {
+func Equal(tb testing.TB, got, want interface{}, options ...Option) bool {
 	tb.Helper()
 	if cmpEqual(got, want) {
 		return true
@@ -43,7 +42,7 @@
 }
 
 // NotEqual asserts that two values aren't equal.
-func NotEqual[T any](tb testing.TB, got, want T, options ...Option) bool {
+func NotEqual(tb testing.TB, got, want interface{}, options ...Option) bool {
 	tb.Helper()
 	if !cmpEqual(got, want) {
 		return true
@@ -53,7 +52,7 @@
 }
 
 // Nil asserts that the value is nil.
-func Nil(tb testing.TB, got any, options ...Option) bool {
+func Nil(tb testing.TB, got interface{}, options ...Option) bool {
 	tb.Helper()
 	if isNil(got) {
 		return true
@@ -63,7 +62,7 @@
 }
 
 // NotNil asserts that the value isn't nil.
-func NotNil(tb testing.TB, got any, options ...Option) bool {
+func NotNil(tb testing.TB, got interface{}, options ...Option) bool {
 	tb.Helper()
 	if !isNil(got) {
 		return true
@@ -73,9 +72,10 @@
 }
 
 // Zero asserts that the value is its type's zero value.
-func Zero[T any](tb testing.TB, got T, options ...Option) bool {
+func Zero(tb testing.TB, got interface{}, options ...Option) bool {
 	tb.Helper()
-	var want T
+	typ := reflect.TypeOf(got)
+	want := reflect.Zero(typ).Interface()
 	if cmpEqual(got, want) {
 		return true
 	}
@@ -84,9 +84,9 @@
 }
 
 // NotZero asserts that the value is non-zero.
-func NotZero[T any](tb testing.TB, got T, options ...Option) bool {
+func NotZero(tb testing.TB, got interface{}, options ...Option) bool {
 	tb.Helper()
-	var want T
+	var want interface{}
 	if !cmpEqual(got, want) {
 		return true
 	}
@@ -162,7 +162,7 @@
 // are passed directly to fmt.Sprintf for formatting.
 //
 // If Sprintf is passed multiple times, only the last message is used.
-func Sprintf(template string, args ...any) Option {
+func Sprintf(template string, args ...interface{}) Option {
 	return &sprintfOption{fmt.Sprintf(template, args...)}
 }
 
@@ -174,7 +174,7 @@
 	return o.msg
 }
 
-func report(tb testing.TB, got, want any, desc string, showWant bool, options ...Option) {
+func report(tb testing.TB, got, want interface{}, desc string, showWant bool, options ...Option) {
 	tb.Helper()
 	buffer := &bytes.Buffer{}
 	if len(options) > 0 {
@@ -189,7 +189,7 @@
 	tb.Fatal(buffer.String())
 }
 
-func isNil(got any) bool {
+func isNil(got interface{}) bool {
 	// Simple case, true only when the user directly passes a literal nil.
 	if got == nil {
 		return true
@@ -207,6 +207,6 @@
 	}
 }
 
-func cmpEqual(got, want any) bool {
+func cmpEqual(got, want interface{}) bool {
 	return cmp.Equal(got, want, protocmp.Transform())
 }
diff --git a/protocol/triple/triple_protocol/assert/assert_test.go b/protocol/triple/triple_protocol/internal/assert/assert_test.go
similarity index 100%
rename from protocol/triple/triple_protocol/assert/assert_test.go
rename to protocol/triple/triple_protocol/internal/assert/assert_test.go
diff --git a/protocol/triple/triple_protocol/internal/gen/proto/connect/collide/v1/collide.pb.go b/protocol/triple/triple_protocol/internal/gen/proto/connect/collide/v1/collide.pb.go
new file mode 100644
index 0000000..a16907d
--- /dev/null
+++ b/protocol/triple/triple_protocol/internal/gen/proto/connect/collide/v1/collide.pb.go
@@ -0,0 +1,223 @@
+// 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.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.30.0
+// 	protoc        (unknown)
+// source: proto/triple/collide/v1/collide.proto
+
+package collidev1
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type ImportRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *ImportRequest) Reset() {
+	*x = ImportRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_connect_collide_v1_collide_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ImportRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ImportRequest) ProtoMessage() {}
+
+func (x *ImportRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_connect_collide_v1_collide_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ImportRequest.ProtoReflect.Descriptor instead.
+func (*ImportRequest) Descriptor() ([]byte, []int) {
+	return file_proto_connect_collide_v1_collide_proto_rawDescGZIP(), []int{0}
+}
+
+type ImportResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *ImportResponse) Reset() {
+	*x = ImportResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_connect_collide_v1_collide_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ImportResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ImportResponse) ProtoMessage() {}
+
+func (x *ImportResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_connect_collide_v1_collide_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ImportResponse.ProtoReflect.Descriptor instead.
+func (*ImportResponse) Descriptor() ([]byte, []int) {
+	return file_proto_connect_collide_v1_collide_proto_rawDescGZIP(), []int{1}
+}
+
+var File_proto_connect_collide_v1_collide_proto protoreflect.FileDescriptor
+
+var file_proto_connect_collide_v1_collide_proto_rawDesc = []byte{
+	0x0a, 0x26, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x2f,
+	0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6c, 0x6c, 0x69,
+	0x64, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
+	0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x22, 0x0f, 0x0a, 0x0d,
+	0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x10, 0x0a,
+	0x0e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32,
+	0x63, 0x0a, 0x0e, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
+	0x65, 0x12, 0x51, 0x0a, 0x06, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x21, 0x2e, 0x63, 0x6f,
+	0x6e, 0x6e, 0x65, 0x63, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x2e, 0x76, 0x31,
+	0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22,
+	0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65,
+	0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x22, 0x00, 0x42, 0xf3, 0x01, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x6e,
+	0x6e, 0x65, 0x63, 0x74, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x42,
+	0x0c, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a,
+	0x61, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x61, 0x63,
+	0x68, 0x65, 0x2f, 0x64, 0x75, 0x62, 0x62, 0x6f, 0x2d, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x74, 0x72, 0x69, 0x70, 0x6c, 0x65, 0x2f, 0x74, 0x72, 0x69, 0x70,
+	0x6c, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x2f, 0x63, 0x6f,
+	0x6c, 0x6c, 0x69, 0x64, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65,
+	0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x43, 0x58, 0xaa, 0x02, 0x12, 0x43, 0x6f, 0x6e, 0x6e, 0x65,
+	0x63, 0x74, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x12,
+	0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x5c, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x5c,
+	0x56, 0x31, 0xe2, 0x02, 0x1e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x5c, 0x43, 0x6f, 0x6c,
+	0x6c, 0x69, 0x64, 0x65, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64,
+	0x61, 0x74, 0x61, 0xea, 0x02, 0x14, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x3a, 0x3a, 0x43,
+	0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x33,
+}
+
+var (
+	file_proto_connect_collide_v1_collide_proto_rawDescOnce sync.Once
+	file_proto_connect_collide_v1_collide_proto_rawDescData = file_proto_connect_collide_v1_collide_proto_rawDesc
+)
+
+func file_proto_connect_collide_v1_collide_proto_rawDescGZIP() []byte {
+	file_proto_connect_collide_v1_collide_proto_rawDescOnce.Do(func() {
+		file_proto_connect_collide_v1_collide_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_connect_collide_v1_collide_proto_rawDescData)
+	})
+	return file_proto_connect_collide_v1_collide_proto_rawDescData
+}
+
+var file_proto_connect_collide_v1_collide_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_proto_connect_collide_v1_collide_proto_goTypes = []interface{}{
+	(*ImportRequest)(nil),  // 0: triple.collide.v1.ImportRequest
+	(*ImportResponse)(nil), // 1: triple.collide.v1.ImportResponse
+}
+var file_proto_connect_collide_v1_collide_proto_depIdxs = []int32{
+	0, // 0: triple.collide.v1.CollideService.Import:input_type -> triple.collide.v1.ImportRequest
+	1, // 1: triple.collide.v1.CollideService.Import:output_type -> triple.collide.v1.ImportResponse
+	1, // [1:2] is the sub-list for method output_type
+	0, // [0:1] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_proto_connect_collide_v1_collide_proto_init() }
+func file_proto_connect_collide_v1_collide_proto_init() {
+	if File_proto_connect_collide_v1_collide_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_proto_connect_collide_v1_collide_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ImportRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_proto_connect_collide_v1_collide_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ImportResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_proto_connect_collide_v1_collide_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_proto_connect_collide_v1_collide_proto_goTypes,
+		DependencyIndexes: file_proto_connect_collide_v1_collide_proto_depIdxs,
+		MessageInfos:      file_proto_connect_collide_v1_collide_proto_msgTypes,
+	}.Build()
+	File_proto_connect_collide_v1_collide_proto = out.File
+	file_proto_connect_collide_v1_collide_proto_rawDesc = nil
+	file_proto_connect_collide_v1_collide_proto_goTypes = nil
+	file_proto_connect_collide_v1_collide_proto_depIdxs = nil
+}
diff --git a/protocol/triple/triple_protocol/internal/gen/proto/connect/import/v1/import.pb.go b/protocol/triple/triple_protocol/internal/gen/proto/connect/import/v1/import.pb.go
new file mode 100644
index 0000000..a644683
--- /dev/null
+++ b/protocol/triple/triple_protocol/internal/gen/proto/connect/import/v1/import.pb.go
@@ -0,0 +1,92 @@
+// 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.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.30.0
+// 	protoc        (unknown)
+// source: proto/triple/import/v1/import.proto
+
+package importv1
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+var File_proto_connect_import_v1_import_proto protoreflect.FileDescriptor
+
+var file_proto_connect_import_v1_import_proto_rawDesc = []byte{
+	0x0a, 0x24, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x2f,
+	0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74,
+	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x11, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x2e,
+	0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x76, 0x31, 0x32, 0x0f, 0x0a, 0x0d, 0x49, 0x6d, 0x70,
+	0x6f, 0x72, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x42, 0xeb, 0x01, 0x0a, 0x15, 0x63,
+	0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x2e, 0x69, 0x6d, 0x70, 0x6f, 0x72,
+	0x74, 0x2e, 0x76, 0x31, 0x42, 0x0b, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x74,
+	0x6f, 0x50, 0x01, 0x5a, 0x5f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+	0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2f, 0x64, 0x75, 0x62, 0x62, 0x6f, 0x2d, 0x67, 0x6f, 0x2f,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x74, 0x72, 0x69, 0x70, 0x6c, 0x65, 0x2f,
+	0x74, 0x72, 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f,
+	0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
+	0x74, 0x2f, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x69, 0x6d, 0x70, 0x6f,
+	0x72, 0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x49, 0x58, 0xaa, 0x02, 0x11, 0x43, 0x6f, 0x6e,
+	0x6e, 0x65, 0x63, 0x74, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02,
+	0x11, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x5c, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x5c,
+	0x56, 0x31, 0xe2, 0x02, 0x1d, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x5c, 0x49, 0x6d, 0x70,
+	0x6f, 0x72, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61,
+	0x74, 0x61, 0xea, 0x02, 0x13, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x3a, 0x3a, 0x49, 0x6d,
+	0x70, 0x6f, 0x72, 0x74, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var file_proto_connect_import_v1_import_proto_goTypes = []interface{}{}
+var file_proto_connect_import_v1_import_proto_depIdxs = []int32{
+	0, // [0:0] is the sub-list for method output_type
+	0, // [0:0] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_proto_connect_import_v1_import_proto_init() }
+func file_proto_connect_import_v1_import_proto_init() {
+	if File_proto_connect_import_v1_import_proto != nil {
+		return
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_proto_connect_import_v1_import_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   0,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_proto_connect_import_v1_import_proto_goTypes,
+		DependencyIndexes: file_proto_connect_import_v1_import_proto_depIdxs,
+	}.Build()
+	File_proto_connect_import_v1_import_proto = out.File
+	file_proto_connect_import_v1_import_proto_rawDesc = nil
+	file_proto_connect_import_v1_import_proto_goTypes = nil
+	file_proto_connect_import_v1_import_proto_depIdxs = nil
+}
diff --git a/protocol/triple/triple_protocol/internal/gen/proto/connect/import/v1/importv1connect/import.connect.go b/protocol/triple/triple_protocol/internal/gen/proto/connect/import/v1/importv1connect/import.connect.go
new file mode 100644
index 0000000..12d7d81
--- /dev/null
+++ b/protocol/triple/triple_protocol/internal/gen/proto/connect/import/v1/importv1connect/import.connect.go
@@ -0,0 +1,78 @@
+// 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.
+
+// Code generated by protoc-gen-connect-go. DO NOT EDIT.
+//
+// Source: connect/import/v1/import.proto
+
+package importv1connect
+
+import (
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
+	_ "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/import/v1"
+	http "net/http"
+	strings "strings"
+)
+
+// This is a compile-time assertion to ensure that this generated file and the connect package are
+// compatible. If you get a compiler error that this constant is not defined, this code was
+// generated with a version of connect newer than the one compiled into your binary. You can fix the
+// problem by either regenerating this code with an older version of connect or updating the connect
+// version compiled into your binary.
+
+const (
+	// ImportServiceName is the fully-qualified name of the ImportService service.
+	ImportServiceName = "connect.import.v1.ImportService"
+)
+
+// ImportServiceClient is a client for the connect.import.v1.ImportService service.
+type ImportServiceClient interface {
+}
+
+// NewImportServiceClient constructs a client for the connect.import.v1.ImportService service. By
+// default, it uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses,
+// and sends uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the
+// connect.WithGRPC() or connect.WithGRPCWeb() options.
+//
+// The URL supplied here should be the base URL for the Connect or gRPC server (for example,
+// http://api.acme.com or https://acme.com/grpc).
+func NewImportServiceClient(httpClient triple_protocol.HTTPClient, baseURL string, opts ...triple_protocol.ClientOption) ImportServiceClient {
+	baseURL = strings.TrimRight(baseURL, "/")
+	return &importServiceClient{}
+}
+
+// importServiceClient implements ImportServiceClient.
+type importServiceClient struct {
+}
+
+// ImportServiceHandler is an implementation of the connect.import.v1.ImportService service.
+type ImportServiceHandler interface {
+}
+
+// NewImportServiceHandler builds an HTTP handler from the service implementation. It returns the
+// path on which to mount the handler and the handler itself.
+//
+// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf
+// and JSON codecs. They also support gzip compression.
+func NewImportServiceHandler(svc ImportServiceHandler, opts ...triple_protocol.HandlerOption) (string, http.Handler) {
+	return "/connect.import.v1.ImportService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		switch r.URL.Path {
+		default:
+			http.NotFound(w, r)
+		}
+	})
+}
+
+// UnimplementedImportServiceHandler returns CodeUnimplemented from all methods.
+type UnimplementedImportServiceHandler struct{}
diff --git a/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1/ping.pb.go b/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1/ping.pb.go
new file mode 100644
index 0000000..9f9b717
--- /dev/null
+++ b/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1/ping.pb.go
@@ -0,0 +1,781 @@
+// 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.
+
+// The canonical location for this file is
+// https://github.com/bufbuild/connect-go/blob/main/internal/proto/connect/ping/v1/ping.proto.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.30.0
+// 	protoc        (unknown)
+// source: proto/triple/ping/v1/ping.proto
+
+// The triple.ping.v1 package contains an echo service designed to test the
+// triple-go implementation.
+
+package pingv1
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type PingRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Number int64  `protobuf:"varint,1,opt,name=number,proto3" json:"number,omitempty"`
+	Text   string `protobuf:"bytes,2,opt,name=text,proto3" json:"text,omitempty"`
+}
+
+func (x *PingRequest) Reset() {
+	*x = PingRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_connect_ping_v1_ping_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *PingRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PingRequest) ProtoMessage() {}
+
+func (x *PingRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_connect_ping_v1_ping_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PingRequest.ProtoReflect.Descriptor instead.
+func (*PingRequest) Descriptor() ([]byte, []int) {
+	return file_proto_connect_ping_v1_ping_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *PingRequest) GetNumber() int64 {
+	if x != nil {
+		return x.Number
+	}
+	return 0
+}
+
+func (x *PingRequest) GetText() string {
+	if x != nil {
+		return x.Text
+	}
+	return ""
+}
+
+type PingResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Number int64  `protobuf:"varint,1,opt,name=number,proto3" json:"number,omitempty"`
+	Text   string `protobuf:"bytes,2,opt,name=text,proto3" json:"text,omitempty"`
+}
+
+func (x *PingResponse) Reset() {
+	*x = PingResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_connect_ping_v1_ping_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *PingResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PingResponse) ProtoMessage() {}
+
+func (x *PingResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_connect_ping_v1_ping_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PingResponse.ProtoReflect.Descriptor instead.
+func (*PingResponse) Descriptor() ([]byte, []int) {
+	return file_proto_connect_ping_v1_ping_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *PingResponse) GetNumber() int64 {
+	if x != nil {
+		return x.Number
+	}
+	return 0
+}
+
+func (x *PingResponse) GetText() string {
+	if x != nil {
+		return x.Text
+	}
+	return ""
+}
+
+type FailRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Code int32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
+}
+
+func (x *FailRequest) Reset() {
+	*x = FailRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_connect_ping_v1_ping_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *FailRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FailRequest) ProtoMessage() {}
+
+func (x *FailRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_connect_ping_v1_ping_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use FailRequest.ProtoReflect.Descriptor instead.
+func (*FailRequest) Descriptor() ([]byte, []int) {
+	return file_proto_connect_ping_v1_ping_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *FailRequest) GetCode() int32 {
+	if x != nil {
+		return x.Code
+	}
+	return 0
+}
+
+type FailResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *FailResponse) Reset() {
+	*x = FailResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_connect_ping_v1_ping_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *FailResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FailResponse) ProtoMessage() {}
+
+func (x *FailResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_connect_ping_v1_ping_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use FailResponse.ProtoReflect.Descriptor instead.
+func (*FailResponse) Descriptor() ([]byte, []int) {
+	return file_proto_connect_ping_v1_ping_proto_rawDescGZIP(), []int{3}
+}
+
+type SumRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Number int64 `protobuf:"varint,1,opt,name=number,proto3" json:"number,omitempty"`
+}
+
+func (x *SumRequest) Reset() {
+	*x = SumRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_connect_ping_v1_ping_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SumRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SumRequest) ProtoMessage() {}
+
+func (x *SumRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_connect_ping_v1_ping_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SumRequest.ProtoReflect.Descriptor instead.
+func (*SumRequest) Descriptor() ([]byte, []int) {
+	return file_proto_connect_ping_v1_ping_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *SumRequest) GetNumber() int64 {
+	if x != nil {
+		return x.Number
+	}
+	return 0
+}
+
+type SumResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Sum int64 `protobuf:"varint,1,opt,name=sum,proto3" json:"sum,omitempty"`
+}
+
+func (x *SumResponse) Reset() {
+	*x = SumResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_connect_ping_v1_ping_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SumResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SumResponse) ProtoMessage() {}
+
+func (x *SumResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_connect_ping_v1_ping_proto_msgTypes[5]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SumResponse.ProtoReflect.Descriptor instead.
+func (*SumResponse) Descriptor() ([]byte, []int) {
+	return file_proto_connect_ping_v1_ping_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *SumResponse) GetSum() int64 {
+	if x != nil {
+		return x.Sum
+	}
+	return 0
+}
+
+type CountUpRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Number int64 `protobuf:"varint,1,opt,name=number,proto3" json:"number,omitempty"`
+}
+
+func (x *CountUpRequest) Reset() {
+	*x = CountUpRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_connect_ping_v1_ping_proto_msgTypes[6]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CountUpRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CountUpRequest) ProtoMessage() {}
+
+func (x *CountUpRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_connect_ping_v1_ping_proto_msgTypes[6]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CountUpRequest.ProtoReflect.Descriptor instead.
+func (*CountUpRequest) Descriptor() ([]byte, []int) {
+	return file_proto_connect_ping_v1_ping_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *CountUpRequest) GetNumber() int64 {
+	if x != nil {
+		return x.Number
+	}
+	return 0
+}
+
+type CountUpResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Number int64 `protobuf:"varint,1,opt,name=number,proto3" json:"number,omitempty"`
+}
+
+func (x *CountUpResponse) Reset() {
+	*x = CountUpResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_connect_ping_v1_ping_proto_msgTypes[7]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CountUpResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CountUpResponse) ProtoMessage() {}
+
+func (x *CountUpResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_connect_ping_v1_ping_proto_msgTypes[7]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CountUpResponse.ProtoReflect.Descriptor instead.
+func (*CountUpResponse) Descriptor() ([]byte, []int) {
+	return file_proto_connect_ping_v1_ping_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *CountUpResponse) GetNumber() int64 {
+	if x != nil {
+		return x.Number
+	}
+	return 0
+}
+
+type CumSumRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Number int64 `protobuf:"varint,1,opt,name=number,proto3" json:"number,omitempty"`
+}
+
+func (x *CumSumRequest) Reset() {
+	*x = CumSumRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_connect_ping_v1_ping_proto_msgTypes[8]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CumSumRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CumSumRequest) ProtoMessage() {}
+
+func (x *CumSumRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_connect_ping_v1_ping_proto_msgTypes[8]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CumSumRequest.ProtoReflect.Descriptor instead.
+func (*CumSumRequest) Descriptor() ([]byte, []int) {
+	return file_proto_connect_ping_v1_ping_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *CumSumRequest) GetNumber() int64 {
+	if x != nil {
+		return x.Number
+	}
+	return 0
+}
+
+type CumSumResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Sum int64 `protobuf:"varint,1,opt,name=sum,proto3" json:"sum,omitempty"`
+}
+
+func (x *CumSumResponse) Reset() {
+	*x = CumSumResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_connect_ping_v1_ping_proto_msgTypes[9]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CumSumResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CumSumResponse) ProtoMessage() {}
+
+func (x *CumSumResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_connect_ping_v1_ping_proto_msgTypes[9]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CumSumResponse.ProtoReflect.Descriptor instead.
+func (*CumSumResponse) Descriptor() ([]byte, []int) {
+	return file_proto_connect_ping_v1_ping_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *CumSumResponse) GetSum() int64 {
+	if x != nil {
+		return x.Sum
+	}
+	return 0
+}
+
+var File_proto_connect_ping_v1_ping_proto protoreflect.FileDescriptor
+
+var file_proto_connect_ping_v1_ping_proto_rawDesc = []byte{
+	0x0a, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x2f,
+	0x70, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x69, 0x6e, 0x67, 0x2e, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x12, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x2e, 0x70, 0x69, 0x6e, 0x67,
+	0x2e, 0x76, 0x31, 0x22, 0x39, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x03, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65,
+	0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x22, 0x3a,
+	0x0a, 0x0c, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16,
+	0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06,
+	0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x22, 0x21, 0x0a, 0x0b, 0x46, 0x61,
+	0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64,
+	0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x0e, 0x0a,
+	0x0c, 0x46, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x0a,
+	0x0a, 0x53, 0x75, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6e,
+	0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6e, 0x75, 0x6d,
+	0x62, 0x65, 0x72, 0x22, 0x1f, 0x0a, 0x0b, 0x53, 0x75, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x75, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52,
+	0x03, 0x73, 0x75, 0x6d, 0x22, 0x28, 0x0a, 0x0e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x55, 0x70, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x29,
+	0x0a, 0x0f, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x55, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+	0x65, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x03, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x27, 0x0a, 0x0d, 0x43, 0x75, 0x6d,
+	0x53, 0x75, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75,
+	0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62,
+	0x65, 0x72, 0x22, 0x22, 0x0a, 0x0e, 0x43, 0x75, 0x6d, 0x53, 0x75, 0x6d, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x75, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x03, 0x52, 0x03, 0x73, 0x75, 0x6d, 0x32, 0x87, 0x03, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x53,
+	0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x48, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x1c,
+	0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x2e, 0x70, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31,
+	0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x63,
+	0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x2e, 0x70, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x50,
+	0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x90, 0x02, 0x01,
+	0x12, 0x45, 0x0a, 0x04, 0x46, 0x61, 0x69, 0x6c, 0x12, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65,
+	0x63, 0x74, 0x2e, 0x70, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
+	0x2e, 0x70, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73,
+	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x03, 0x53, 0x75, 0x6d, 0x12, 0x1b,
+	0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x2e, 0x70, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31,
+	0x2e, 0x53, 0x75, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x63, 0x6f,
+	0x6e, 0x6e, 0x65, 0x63, 0x74, 0x2e, 0x70, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75,
+	0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x12, 0x50, 0x0a,
+	0x07, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x55, 0x70, 0x12, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65,
+	0x63, 0x74, 0x2e, 0x70, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74,
+	0x55, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x63, 0x6f, 0x6e, 0x6e,
+	0x65, 0x63, 0x74, 0x2e, 0x70, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x75, 0x6e,
+	0x74, 0x55, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12,
+	0x4f, 0x0a, 0x06, 0x43, 0x75, 0x6d, 0x53, 0x75, 0x6d, 0x12, 0x1e, 0x2e, 0x63, 0x6f, 0x6e, 0x6e,
+	0x65, 0x63, 0x74, 0x2e, 0x70, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, 0x6d, 0x53,
+	0x75, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x6e,
+	0x65, 0x63, 0x74, 0x2e, 0x70, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x75, 0x6d, 0x53,
+	0x75, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01,
+	0x42, 0xdb, 0x01, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
+	0x2e, 0x70, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x42, 0x09, 0x50, 0x69, 0x6e, 0x67, 0x50, 0x72,
+	0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x5b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
+	0x6d, 0x2f, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2f, 0x64, 0x75, 0x62, 0x62, 0x6f, 0x2d, 0x67,
+	0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x74, 0x72, 0x69, 0x70, 0x6c,
+	0x65, 0x2f, 0x74, 0x72, 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
+	0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6e, 0x6e,
+	0x65, 0x63, 0x74, 0x2f, 0x70, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x31, 0x3b, 0x70, 0x69, 0x6e, 0x67,
+	0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x50, 0x58, 0xaa, 0x02, 0x0f, 0x43, 0x6f, 0x6e, 0x6e, 0x65,
+	0x63, 0x74, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0f, 0x43, 0x6f, 0x6e,
+	0x6e, 0x65, 0x63, 0x74, 0x5c, 0x50, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1b, 0x43,
+	0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x5c, 0x50, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x31, 0x5c, 0x47,
+	0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x11, 0x43, 0x6f, 0x6e,
+	0x6e, 0x65, 0x63, 0x74, 0x3a, 0x3a, 0x50, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_proto_connect_ping_v1_ping_proto_rawDescOnce sync.Once
+	file_proto_connect_ping_v1_ping_proto_rawDescData = file_proto_connect_ping_v1_ping_proto_rawDesc
+)
+
+func file_proto_connect_ping_v1_ping_proto_rawDescGZIP() []byte {
+	file_proto_connect_ping_v1_ping_proto_rawDescOnce.Do(func() {
+		file_proto_connect_ping_v1_ping_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_connect_ping_v1_ping_proto_rawDescData)
+	})
+	return file_proto_connect_ping_v1_ping_proto_rawDescData
+}
+
+var file_proto_connect_ping_v1_ping_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
+var file_proto_connect_ping_v1_ping_proto_goTypes = []interface{}{
+	(*PingRequest)(nil),     // 0: triple.ping.v1.PingRequest
+	(*PingResponse)(nil),    // 1: triple.ping.v1.PingResponse
+	(*FailRequest)(nil),     // 2: triple.ping.v1.FailRequest
+	(*FailResponse)(nil),    // 3: triple.ping.v1.FailResponse
+	(*SumRequest)(nil),      // 4: triple.ping.v1.SumRequest
+	(*SumResponse)(nil),     // 5: triple.ping.v1.SumResponse
+	(*CountUpRequest)(nil),  // 6: triple.ping.v1.CountUpRequest
+	(*CountUpResponse)(nil), // 7: triple.ping.v1.CountUpResponse
+	(*CumSumRequest)(nil),   // 8: triple.ping.v1.CumSumRequest
+	(*CumSumResponse)(nil),  // 9: triple.ping.v1.CumSumResponse
+}
+var file_proto_connect_ping_v1_ping_proto_depIdxs = []int32{
+	0, // 0: triple.ping.v1.PingService.Ping:input_type -> triple.ping.v1.PingRequest
+	2, // 1: triple.ping.v1.PingService.Fail:input_type -> triple.ping.v1.FailRequest
+	4, // 2: triple.ping.v1.PingService.Sum:input_type -> triple.ping.v1.SumRequest
+	6, // 3: triple.ping.v1.PingService.CountUp:input_type -> triple.ping.v1.CountUpRequest
+	8, // 4: triple.ping.v1.PingService.CumSum:input_type -> triple.ping.v1.CumSumRequest
+	1, // 5: triple.ping.v1.PingService.Ping:output_type -> triple.ping.v1.PingResponse
+	3, // 6: triple.ping.v1.PingService.Fail:output_type -> triple.ping.v1.FailResponse
+	5, // 7: triple.ping.v1.PingService.Sum:output_type -> triple.ping.v1.SumResponse
+	7, // 8: triple.ping.v1.PingService.CountUp:output_type -> triple.ping.v1.CountUpResponse
+	9, // 9: triple.ping.v1.PingService.CumSum:output_type -> triple.ping.v1.CumSumResponse
+	5, // [5:10] is the sub-list for method output_type
+	0, // [0:5] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_proto_connect_ping_v1_ping_proto_init() }
+func file_proto_connect_ping_v1_ping_proto_init() {
+	if File_proto_connect_ping_v1_ping_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_proto_connect_ping_v1_ping_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*PingRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_proto_connect_ping_v1_ping_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*PingResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_proto_connect_ping_v1_ping_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*FailRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_proto_connect_ping_v1_ping_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*FailResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_proto_connect_ping_v1_ping_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SumRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_proto_connect_ping_v1_ping_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SumResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_proto_connect_ping_v1_ping_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CountUpRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_proto_connect_ping_v1_ping_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CountUpResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_proto_connect_ping_v1_ping_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CumSumRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_proto_connect_ping_v1_ping_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CumSumResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_proto_connect_ping_v1_ping_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   10,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_proto_connect_ping_v1_ping_proto_goTypes,
+		DependencyIndexes: file_proto_connect_ping_v1_ping_proto_depIdxs,
+		MessageInfos:      file_proto_connect_ping_v1_ping_proto_msgTypes,
+	}.Build()
+	File_proto_connect_ping_v1_ping_proto = out.File
+	file_proto_connect_ping_v1_ping_proto_rawDesc = nil
+	file_proto_connect_ping_v1_ping_proto_goTypes = nil
+	file_proto_connect_ping_v1_ping_proto_depIdxs = nil
+}
diff --git a/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1/pingv1connect/ping.connect.go b/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1/pingv1connect/ping.connect.go
new file mode 100644
index 0000000..02babd8
--- /dev/null
+++ b/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1/pingv1connect/ping.connect.go
@@ -0,0 +1,240 @@
+// 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.
+
+// The canonical location for this file is
+// https://github.com/bufbuild/connect-go/blob/main/internal/proto/connect/ping/v1/ping.proto.
+
+// Code generated by protoc-gen-connect-go. DO NOT EDIT.
+//
+// Source: connect/ping/v1/ping.proto
+
+// The connect.ping.v1 package contains an echo service designed to test the
+// connect-go implementation.
+package pingv1connect
+
+import (
+	context "context"
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
+	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1"
+	errors "errors"
+	http "net/http"
+	strings "strings"
+)
+
+const (
+	// PingServiceName is the fully-qualified name of the PingService service.
+	PingServiceName = "connect.ping.v1.PingService"
+)
+
+// These constants are the fully-qualified names of the RPCs defined in this package. They're
+// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route.
+//
+// Note that these are different from the fully-qualified method names used by
+// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to
+// reflection-formatted method names, remove the leading slash and convert the remaining slash to a
+// period.
+const (
+	// PingServicePingProcedure is the fully-qualified name of the PingService's Ping RPC.
+	PingServicePingProcedure = "/connect.ping.v1.PingService/Ping"
+	// PingServiceFailProcedure is the fully-qualified name of the PingService's Fail RPC.
+	PingServiceFailProcedure = "/connect.ping.v1.PingService/Fail"
+	//// PingServiceSumProcedure is the fully-qualified name of the PingService's Sum RPC.
+	//PingServiceSumProcedure = "/connect.ping.v1.PingService/Sum"
+	//// PingServiceCountUpProcedure is the fully-qualified name of the PingService's CountUp RPC.
+	//PingServiceCountUpProcedure = "/connect.ping.v1.PingService/CountUp"
+	//// PingServiceCumSumProcedure is the fully-qualified name of the PingService's CumSum RPC.
+	//PingServiceCumSumProcedure = "/connect.ping.v1.PingService/CumSum"
+)
+
+// PingServiceClient is a client for the connect.ping.v1.PingService service.
+type PingServiceClient interface {
+	// Ping sends a ping to the server to determine if it's reachable.
+	Ping(context.Context, *triple_protocol.Request, *triple_protocol.Response) error
+	// Fail always fails.
+	Fail(context.Context, *triple_protocol.Request, *triple_protocol.Response) error
+	//// Sum calculates the sum of the numbers sent on the stream.
+	//Sum(context.Context) (*triple_protocol.ClientStreamForClient,error)
+	//// CountUp returns a stream of the numbers up to the given request.
+	//CountUp(context.Context, *triple_protocol.Request) (*triple_protocol.ServerStreamForClient, error)
+	//// CumSum determines the cumulative sum of all the numbers sent on the stream.
+	//CumSum(context.Context) (*triple_protocol.BidiStreamForClient,error)
+}
+
+// NewPingServiceClient constructs a client for the connect.ping.v1.PingService service. By default,
+// it uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, and
+// sends uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the connect.WithGRPC()
+// or connect.WithGRPCWeb() options.
+//
+// The URL supplied here should be the base URL for the Connect or gRPC server (for example,
+// http://api.acme.com or https://acme.com/grpc).
+func NewPingServiceClient(httpClient triple_protocol.HTTPClient, baseURL string, opts ...triple_protocol.ClientOption) PingServiceClient {
+	baseURL = strings.TrimRight(baseURL, "/")
+	return &pingServiceClient{
+		ping: triple_protocol.NewClient(
+			httpClient,
+			baseURL+PingServicePingProcedure,
+			triple_protocol.WithIdempotency(triple_protocol.IdempotencyNoSideEffects),
+			triple_protocol.WithClientOptions(opts...),
+		),
+		fail: triple_protocol.NewClient(
+			httpClient,
+			baseURL+PingServiceFailProcedure,
+			opts...,
+		),
+		//sum: triple_protocol.NewClient(
+		//	httpClient,
+		//	baseURL+PingServiceSumProcedure,
+		//	opts...,
+		//),
+		//countUp: triple_protocol.NewClient(
+		//	httpClient,
+		//	baseURL+PingServiceCountUpProcedure,
+		//	opts...,
+		//),
+		//cumSum: triple_protocol.NewClient(
+		//	httpClient,
+		//	baseURL+PingServiceCumSumProcedure,
+		//	opts...,
+		//),
+	}
+}
+
+// pingServiceClient implements PingServiceClient.
+type pingServiceClient struct {
+	ping    *triple_protocol.Client
+	fail    *triple_protocol.Client
+	sum     *triple_protocol.Client
+	countUp *triple_protocol.Client
+	cumSum  *triple_protocol.Client
+}
+
+// Ping calls connect.ping.v1.PingService.Ping.
+// Ping(context.Context, *pingv1.PingRequest,*pingv1.PingResponse) (error)
+func (c *pingServiceClient) Ping(ctx context.Context, req *triple_protocol.Request, res *triple_protocol.Response) error {
+	return c.ping.CallUnary(ctx, req, res)
+}
+
+// Fail calls connect.ping.v1.PingService.Fail.
+func (c *pingServiceClient) Fail(ctx context.Context, req *triple_protocol.Request, res *triple_protocol.Response) error {
+	return c.fail.CallUnary(ctx, req, res)
+}
+
+//// Sum calls connect.ping.v1.PingService.Sum.
+//func (c *pingServiceClient) Sum(ctx context.Context) (*triple_protocol.ClientStreamForClient,error) {
+//	return c.sum.CallClientStream(ctx)
+//}
+//
+//// CountUp calls connect.ping.v1.PingService.CountUp.
+//func (c *pingServiceClient) CountUp(ctx context.Context, req *triple_protocol.Request) (*triple_protocol.ServerStreamForClient, error) {
+//	return c.countUp.CallServerStream(ctx, req)
+//}
+//
+//// CumSum calls connect.ping.v1.PingService.CumSum.
+//func (c *pingServiceClient) CumSum(ctx context.Context) (*triple_protocol.BidiStreamForClient,error) {
+//	return c.cumSum.CallBidiStream(ctx)
+//}
+
+// PingServiceHandler is an implementation of the connect.ping.v1.PingService service.
+type PingServiceHandler interface {
+	// Ping sends a ping to the server to determine if it's reachable.
+	Ping(context.Context, *triple_protocol.Request) (*triple_protocol.Response, error)
+	// Fail always fails.
+	Fail(context.Context, *triple_protocol.Request) (*triple_protocol.Response, error)
+	//// Sum calculates the sum of the numbers sent on the stream.
+	//Sum(context.Context, *triple_protocol.ClientStream) (*triple_protocol.Response, error)
+	//// CountUp returns a stream of the numbers up to the given request.
+	//CountUp(context.Context, *triple_protocol.Request, *triple_protocol.ServerStream) error
+	//// CumSum determines the cumulative sum of all the numbers sent on the stream.
+	//CumSum(context.Context, *triple_protocol.BidiStream) error
+}
+
+// NewPingServiceHandler builds an HTTP handler from the service implementation. It returns the path
+// on which to mount the handler and the handler itself.
+//
+// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf
+// and JSON codecs. They also support gzip compression.
+func NewPingServiceHandler(svc PingServiceHandler, opts ...triple_protocol.HandlerOption) (string, http.Handler) {
+	pingServicePingHandler := triple_protocol.NewUnaryHandler(
+		PingServicePingProcedure, func() interface{} {
+			return &pingv1.PingRequest{}
+		},
+		svc.Ping,
+		triple_protocol.WithIdempotency(triple_protocol.IdempotencyNoSideEffects),
+		triple_protocol.WithHandlerOptions(opts...),
+	)
+	pingServiceFailHandler := triple_protocol.NewUnaryHandler(
+		PingServiceFailProcedure,
+		func() interface{} {
+			return &pingv1.FailRequest{}
+		},
+		svc.Fail,
+		opts...,
+	)
+	//pingServiceSumHandler := triple_protocol.NewClientStreamHandler(
+	//	PingServiceSumProcedure,
+	//	svc.Sum,
+	//	opts...,
+	//)
+	//pingServiceCountUpHandler := triple_protocol.NewServerStreamHandler(
+	//	PingServiceCountUpProcedure,func() interface{} {
+	//		return &pingv1.PingRequest{}
+	//	},
+	//	svc.CountUp,
+	//	opts...,
+	//)
+	//pingServiceCumSumHandler := triple_protocol.NewBidiStreamHandler(
+	//	PingServiceCumSumProcedure,
+	//	svc.CumSum,
+	//	opts...,
+	//)
+	return "/connect.ping.v1.PingService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		switch r.URL.Path {
+		case PingServicePingProcedure:
+			pingServicePingHandler.ServeHTTP(w, r)
+		case PingServiceFailProcedure:
+			pingServiceFailHandler.ServeHTTP(w, r)
+		//case PingServiceSumProcedure:
+		//	pingServiceSumHandler.ServeHTTP(w, r)
+		//case PingServiceCountUpProcedure:
+		//	pingServiceCountUpHandler.ServeHTTP(w, r)
+		//case PingServiceCumSumProcedure:
+		//	pingServiceCumSumHandler.ServeHTTP(w, r)
+		default:
+			http.NotFound(w, r)
+		}
+	})
+}
+
+// UnimplementedPingServiceHandler returns CodeUnimplemented from all methods.
+type UnimplementedPingServiceHandler struct{}
+
+func (UnimplementedPingServiceHandler) Ping(context.Context, *triple_protocol.Request) (*triple_protocol.Response, error) {
+	return nil, triple_protocol.NewError(triple_protocol.CodeUnimplemented, errors.New("connect.ping.v1.PingService.Ping is not implemented"))
+}
+
+func (UnimplementedPingServiceHandler) Fail(context.Context, *triple_protocol.Request) (*triple_protocol.Response, error) {
+	return nil, triple_protocol.NewError(triple_protocol.CodeUnimplemented, errors.New("connect.ping.v1.PingService.Fail is not implemented"))
+}
+
+//func (UnimplementedPingServiceHandler) Sum(context.Context, *triple_protocol.ClientStream) (*triple_protocol.Response, error) {
+//	return nil, triple_protocol.NewError(triple_protocol.CodeUnimplemented, errors.New("connect.ping.v1.PingService.Sum is not implemented"))
+//}
+//
+//func (UnimplementedPingServiceHandler) CountUp(context.Context, *triple_protocol.Request, *triple_protocol.ServerStream) error {
+//	return triple_protocol.NewError(triple_protocol.CodeUnimplemented, errors.New("connect.ping.v1.PingService.CountUp is not implemented"))
+//}
+//
+//func (UnimplementedPingServiceHandler) CumSum(context.Context, *triple_protocol.BidiStream) error {
+//	return triple_protocol.NewError(triple_protocol.CodeUnimplemented, errors.New("connect.ping.v1.PingService.CumSum is not implemented"))
+//}
diff --git a/protocol/triple/triple_protocol/internal/gen/proto/connectext/grpc/status/v1/status.pb.go b/protocol/triple/triple_protocol/internal/gen/proto/connectext/grpc/status/v1/status.pb.go
new file mode 100644
index 0000000..7573990
--- /dev/null
+++ b/protocol/triple/triple_protocol/internal/gen/proto/connectext/grpc/status/v1/status.pb.go
@@ -0,0 +1,203 @@
+// 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.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.30.0
+// 	protoc        (unknown)
+// source: proto/connectext/grpc/status/v1/status.proto
+
+// This package is for internal use by Connect, and provides no backward
+// compatibility guarantees whatsoever.
+
+package statusv1
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	anypb "google.golang.org/protobuf/types/known/anypb"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// See https://cloud.google.com/apis/design/errors.
+//
+// This struct must remain binary-compatible with
+// https://github.com/googleapis/googleapis/blob/master/google/rpc/status.proto.
+type Status struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Code    int32        `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`      // a google.rpc.Code
+	Message string       `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` // developer-facing, English (localize in details or client-side)
+	Details []*anypb.Any `protobuf:"bytes,3,rep,name=details,proto3" json:"details,omitempty"`
+}
+
+func (x *Status) Reset() {
+	*x = Status{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_proto_connectext_grpc_status_v1_status_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Status) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Status) ProtoMessage() {}
+
+func (x *Status) ProtoReflect() protoreflect.Message {
+	mi := &file_proto_connectext_grpc_status_v1_status_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Status.ProtoReflect.Descriptor instead.
+func (*Status) Descriptor() ([]byte, []int) {
+	return file_proto_connectext_grpc_status_v1_status_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Status) GetCode() int32 {
+	if x != nil {
+		return x.Code
+	}
+	return 0
+}
+
+func (x *Status) GetMessage() string {
+	if x != nil {
+		return x.Message
+	}
+	return ""
+}
+
+func (x *Status) GetDetails() []*anypb.Any {
+	if x != nil {
+		return x.Details
+	}
+	return nil
+}
+
+var File_proto_connectext_grpc_status_v1_status_proto protoreflect.FileDescriptor
+
+var file_proto_connectext_grpc_status_v1_status_proto_rawDesc = []byte{
+	0x0a, 0x2c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65,
+	0x78, 0x74, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2f, 0x76,
+	0x31, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e,
+	0x67, 0x72, 0x70, 0x63, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x76, 0x31, 0x1a, 0x19,
+	0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f,
+	0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x66, 0x0a, 0x06, 0x53, 0x74, 0x61,
+	0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x05, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61,
+	0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
+	0x65, 0x12, 0x2e, 0x0a, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03,
+	0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c,
+	0x73, 0x42, 0xe4, 0x01, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x73,
+	0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x76, 0x31, 0x42, 0x0b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
+	0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x67, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
+	0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2f, 0x64, 0x75, 0x62, 0x62, 0x6f,
+	0x2d, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x74, 0x72, 0x69,
+	0x70, 0x6c, 0x65, 0x2f, 0x74, 0x72, 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x63, 0x6f, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f,
+	0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x73, 0x74,
+	0x61, 0x74, 0x75, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x76, 0x31,
+	0xa2, 0x02, 0x03, 0x47, 0x53, 0x58, 0xaa, 0x02, 0x0e, 0x47, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74,
+	0x61, 0x74, 0x75, 0x73, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0e, 0x47, 0x72, 0x70, 0x63, 0x5c, 0x53,
+	0x74, 0x61, 0x74, 0x75, 0x73, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1a, 0x47, 0x72, 0x70, 0x63, 0x5c,
+	0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74,
+	0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x10, 0x47, 0x72, 0x70, 0x63, 0x3a, 0x3a, 0x53, 0x74,
+	0x61, 0x74, 0x75, 0x73, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_proto_connectext_grpc_status_v1_status_proto_rawDescOnce sync.Once
+	file_proto_connectext_grpc_status_v1_status_proto_rawDescData = file_proto_connectext_grpc_status_v1_status_proto_rawDesc
+)
+
+func file_proto_connectext_grpc_status_v1_status_proto_rawDescGZIP() []byte {
+	file_proto_connectext_grpc_status_v1_status_proto_rawDescOnce.Do(func() {
+		file_proto_connectext_grpc_status_v1_status_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_connectext_grpc_status_v1_status_proto_rawDescData)
+	})
+	return file_proto_connectext_grpc_status_v1_status_proto_rawDescData
+}
+
+var file_proto_connectext_grpc_status_v1_status_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_proto_connectext_grpc_status_v1_status_proto_goTypes = []interface{}{
+	(*Status)(nil),    // 0: grpc.status.v1.Status
+	(*anypb.Any)(nil), // 1: google.protobuf.Any
+}
+var file_proto_connectext_grpc_status_v1_status_proto_depIdxs = []int32{
+	1, // 0: grpc.status.v1.Status.details:type_name -> google.protobuf.Any
+	1, // [1:1] is the sub-list for method output_type
+	1, // [1:1] is the sub-list for method input_type
+	1, // [1:1] is the sub-list for extension type_name
+	1, // [1:1] is the sub-list for extension extendee
+	0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_proto_connectext_grpc_status_v1_status_proto_init() }
+func file_proto_connectext_grpc_status_v1_status_proto_init() {
+	if File_proto_connectext_grpc_status_v1_status_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_proto_connectext_grpc_status_v1_status_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Status); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_proto_connectext_grpc_status_v1_status_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_proto_connectext_grpc_status_v1_status_proto_goTypes,
+		DependencyIndexes: file_proto_connectext_grpc_status_v1_status_proto_depIdxs,
+		MessageInfos:      file_proto_connectext_grpc_status_v1_status_proto_msgTypes,
+	}.Build()
+	File_proto_connectext_grpc_status_v1_status_proto = out.File
+	file_proto_connectext_grpc_status_v1_status_proto_rawDesc = nil
+	file_proto_connectext_grpc_status_v1_status_proto_goTypes = nil
+	file_proto_connectext_grpc_status_v1_status_proto_depIdxs = nil
+}
diff --git a/protocol/triple/triple_protocol/internal/proto/buf.gen.yaml b/protocol/triple/triple_protocol/internal/proto/buf.gen.yaml
new file mode 100644
index 0000000..09e46ca
--- /dev/null
+++ b/protocol/triple/triple_protocol/internal/proto/buf.gen.yaml
@@ -0,0 +1,12 @@
+version: v1
+managed:
+  enabled: true
+  go_package_prefix:
+    default: github.com/apache/dubbo-go/protocol/triple/triple_protocol/gen
+plugins:
+  - name: go
+    out: triple_protocol/gen
+    opt: paths=source_relative
+  - name: triple
+    out: triple_protocol/gen
+    opt: paths=source_relative
diff --git a/protocol/triple/triple_protocol/proto/buf.yaml b/protocol/triple/triple_protocol/internal/proto/buf.yaml
similarity index 100%
rename from protocol/triple/triple_protocol/proto/buf.yaml
rename to protocol/triple/triple_protocol/internal/proto/buf.yaml
diff --git a/protocol/triple/triple_protocol/proto/connectext/grpc/status/v1/status.pb.go b/protocol/triple/triple_protocol/internal/proto/connectext/grpc/status/v1/status.pb.go
similarity index 98%
rename from protocol/triple/triple_protocol/proto/connectext/grpc/status/v1/status.pb.go
rename to protocol/triple/triple_protocol/internal/proto/connectext/grpc/status/v1/status.pb.go
index 051b9a6..c2e1894 100644
--- a/protocol/triple/triple_protocol/proto/connectext/grpc/status/v1/status.pb.go
+++ b/protocol/triple/triple_protocol/internal/proto/connectext/grpc/status/v1/status.pb.go
@@ -16,7 +16,7 @@
 // versions:
 // 	protoc-gen-go v1.30.0
 // 	protoc        v3.17.3
-// source: protocol/grpc_new/connect/proto/connectext/grpc/status/v1/status.proto
+// source: protocol/grpc_new/triple/proto/connectext/grpc/status/v1/status.proto
 
 // This package is for internal use by Connect, and provides no backward
 // compatibility guarantees whatsoever.
diff --git a/protocol/triple/triple_protocol/proto/connectext/grpc/status/v1/status.proto b/protocol/triple/triple_protocol/internal/proto/connectext/grpc/status/v1/status.proto
similarity index 95%
rename from protocol/triple/triple_protocol/proto/connectext/grpc/status/v1/status.proto
rename to protocol/triple/triple_protocol/internal/proto/connectext/grpc/status/v1/status.proto
index 1c8b3a9..4642224 100644
--- a/protocol/triple/triple_protocol/proto/connectext/grpc/status/v1/status.proto
+++ b/protocol/triple/triple_protocol/internal/proto/connectext/grpc/status/v1/status.proto
@@ -17,7 +17,7 @@
 // This package is for internal use by Connect, and provides no backward
 // compatibility guarantees whatsoever.
 package grpc.status.v1;
-option go_package = "dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/connect/proto/connectext/grpc/status/v1;statusv1";
+option go_package = "dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/triple/proto/connectext/grpc/status/v1;statusv1";
 
 import "google/protobuf/any.proto";
 
diff --git a/protocol/triple/triple_protocol/internal/proto/triple/collide/v1/collide.proto b/protocol/triple/triple_protocol/internal/proto/triple/collide/v1/collide.proto
new file mode 100644
index 0000000..dc8d711
--- /dev/null
+++ b/protocol/triple/triple_protocol/internal/proto/triple/collide/v1/collide.proto
@@ -0,0 +1,27 @@
+// 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.
+
+syntax = "proto3";
+
+option go_package = "./;v1";
+
+package connect.collide.v1;
+
+message ImportRequest {}
+
+message ImportResponse {}
+
+service CollideService {
+  rpc Import(ImportRequest) returns (ImportResponse) {}
+}
diff --git a/protocol/triple/triple_protocol/internal/proto/triple/import/v1/import.proto b/protocol/triple/triple_protocol/internal/proto/triple/import/v1/import.proto
new file mode 100644
index 0000000..3241616
--- /dev/null
+++ b/protocol/triple/triple_protocol/internal/proto/triple/import/v1/import.proto
@@ -0,0 +1,19 @@
+// 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.
+
+syntax = "proto3";
+
+package connect.import.v1;
+
+service ImportService {}
diff --git a/protocol/triple/triple_protocol/internal/proto/triple/ping/v1/ping.proto b/protocol/triple/triple_protocol/internal/proto/triple/ping/v1/ping.proto
new file mode 100644
index 0000000..fd8669d
--- /dev/null
+++ b/protocol/triple/triple_protocol/internal/proto/triple/ping/v1/ping.proto
@@ -0,0 +1,76 @@
+// 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.
+
+// The canonical location for this file is
+// https://github.com/bufbuild/connect-go/blob/main/internal/proto/connect/ping/v1/ping.proto.
+syntax = "proto3";
+
+// The connect.ping.v1 package contains an echo service designed to test the
+// connect-go implementation.
+package connect.ping.v1;
+
+message PingRequest {
+  int64 number = 1;
+  string text = 2;
+}
+
+message PingResponse {
+  int64 number = 1;
+  string text = 2;
+}
+
+message FailRequest {
+  int32 code = 1;
+}
+
+message FailResponse {}
+
+message SumRequest {
+  int64 number = 1;
+}
+
+message SumResponse {
+  int64 sum = 1;
+}
+
+message CountUpRequest {
+  int64 number = 1;
+}
+
+message CountUpResponse {
+  int64 number = 1;
+}
+
+message CumSumRequest {
+  int64 number = 1;
+}
+
+message CumSumResponse {
+  int64 sum = 1;
+}
+
+service PingService {
+  // Ping sends a ping to the server to determine if it's reachable.
+  rpc Ping(PingRequest) returns (PingResponse) {
+    option idempotency_level = NO_SIDE_EFFECTS;
+  }
+  // Fail always fails.
+  rpc Fail(FailRequest) returns (FailResponse) {}
+  // Sum calculates the sum of the numbers sent on the stream.
+  rpc Sum(stream SumRequest) returns (SumResponse) {}
+  // CountUp returns a stream of the numbers up to the given request.
+  rpc CountUp(CountUpRequest) returns (stream CountUpResponse) {}
+  // CumSum determines the cumulative sum of all the numbers sent on the stream.
+  rpc CumSum(stream CumSumRequest) returns (stream CumSumResponse) {}
+}
diff --git a/protocol/triple/triple_protocol/testdata/server.crt b/protocol/triple/triple_protocol/internal/testdata/server.crt
similarity index 100%
rename from protocol/triple/triple_protocol/testdata/server.crt
rename to protocol/triple/triple_protocol/internal/testdata/server.crt
diff --git a/protocol/triple/triple_protocol/testdata/server.key b/protocol/triple/triple_protocol/internal/testdata/server.key
similarity index 100%
rename from protocol/triple/triple_protocol/testdata/server.key
rename to protocol/triple/triple_protocol/internal/testdata/server.key
diff --git a/protocol/triple/triple_protocol/option.go b/protocol/triple/triple_protocol/option.go
index 41017a8..d84cb2f 100644
--- a/protocol/triple/triple_protocol/option.go
+++ b/protocol/triple/triple_protocol/option.go
@@ -437,8 +437,7 @@
 	config.IdempotencyLevel = o.idempotencyLevel
 }
 
-type grpcOption struct {
-}
+type grpcOption struct{}
 
 func (o *grpcOption) applyToClient(config *clientConfig) {
 	config.Protocol = &protocolGRPC{}
diff --git a/protocol/triple/triple_protocol/protobuf_util.go b/protocol/triple/triple_protocol/protobuf_util.go
index 2d074ef..da24540 100644
--- a/protocol/triple/triple_protocol/protobuf_util.go
+++ b/protocol/triple/triple_protocol/protobuf_util.go
@@ -20,7 +20,7 @@
 
 // extractProtoPath returns the trailing portion of the URL's path,
 // corresponding to the Protobuf package, service, and method. It always starts
-// with a slash. Within connect, we use this as (1) Spec.Procedure and (2) the
+// with a slash. Within triple, we use this as (1) Spec.Procedure and (2) the
 // path when mounting handlers on muxes.
 func extractProtoPath(path string) string {
 	segments := strings.Split(path, "/")
diff --git a/protocol/triple/triple_protocol/protobuf_util_test.go b/protocol/triple/triple_protocol/protobuf_util_test.go
index ed02c94..85a2ffa 100644
--- a/protocol/triple/triple_protocol/protobuf_util_test.go
+++ b/protocol/triple/triple_protocol/protobuf_util_test.go
@@ -16,10 +16,8 @@
 
 import (
 	"testing"
-)
 
-import (
-	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/assert"
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/assert"
 )
 
 func TestParseProtobufURL(t *testing.T) {
diff --git a/protocol/triple/triple_protocol/protocol.go b/protocol/triple/triple_protocol/protocol.go
index e39cb72..a3475f5 100644
--- a/protocol/triple/triple_protocol/protocol.go
+++ b/protocol/triple/triple_protocol/protocol.go
@@ -48,7 +48,7 @@
 // messages. It ties together codecs, compressors, and net/http to produce
 // Senders and Receivers.
 //
-// For example, connect supports the gRPC protocol using this abstraction. Among
+// For example, triple supports the gRPC protocol using this abstraction. Among
 // many other things, the protocol implementation is responsible for
 // translating timeouts from Go contexts to HTTP and vice versa. For gRPC, it
 // converts timeouts to and from strings (for example, 10*time.Second <->
@@ -57,7 +57,7 @@
 // header, or ignore them entirely.
 //
 // We don't have any short-term plans to export this interface; it's just here
-// to separate the protocol-specific portions of connect from the
+// to separate the protocol-specific portions of triple from the
 // protocol-agnostic plumbing.
 type protocol interface {
 	NewHandler(*protocolHandlerParams) protocolHandler
diff --git a/protocol/triple/triple_protocol/protocol_grpc.go b/protocol/triple/triple_protocol/protocol_grpc.go
index 7b3d666..cad6f46 100644
--- a/protocol/triple/triple_protocol/protocol_grpc.go
+++ b/protocol/triple/triple_protocol/protocol_grpc.go
@@ -28,10 +28,8 @@
 	"strings"
 	"time"
 	"unicode/utf8"
-)
 
-import (
-	statusv1 "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/proto/connectext/grpc/status/v1"
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/proto/connectext/grpc/status/v1"
 )
 
 // protocol specification headers
@@ -88,8 +86,7 @@
 	}
 }
 
-type protocolGRPC struct {
-}
+type protocolGRPC struct{}
 
 // for server side
 
diff --git a/protocol/triple/triple_protocol/protocol_grpc_test.go b/protocol/triple/triple_protocol/protocol_grpc_test.go
index e0dd81e..51d51ca 100644
--- a/protocol/triple/triple_protocol/protocol_grpc_test.go
+++ b/protocol/triple/triple_protocol/protocol_grpc_test.go
@@ -24,16 +24,14 @@
 	"testing/quick"
 	"time"
 	"unicode/utf8"
+
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/assert"
 )
 
 import (
 	"github.com/google/go-cmp/cmp"
 )
 
-import (
-	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/assert"
-)
-
 func TestGRPCHandlerSender(t *testing.T) {
 	t.Parallel()
 	newConn := func(web bool) *grpcHandlerConn {
diff --git a/protocol/triple/triple_protocol/protocol_test.go b/protocol/triple/triple_protocol/protocol_test.go
index 867424f..77a500b 100644
--- a/protocol/triple/triple_protocol/protocol_test.go
+++ b/protocol/triple/triple_protocol/protocol_test.go
@@ -16,10 +16,8 @@
 
 import (
 	"testing"
-)
 
-import (
-	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/assert"
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/assert"
 )
 
 func TestCanonicalizeContentType(t *testing.T) {
diff --git a/protocol/triple/triple_protocol/protocol_triple_test.go b/protocol/triple/triple_protocol/protocol_triple_test.go
index a4241d8..012e267 100644
--- a/protocol/triple/triple_protocol/protocol_triple_test.go
+++ b/protocol/triple/triple_protocol/protocol_triple_test.go
@@ -1,56 +1,55 @@
-// // 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.
+// 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
 
-//
-//import (
-//	"encoding/json"
-//	"strings"
-//	"testing"
-//	"time"
-//
-//	"dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/triple/assert"
-//	"google.golang.org/protobuf/types/known/durationpb"
-//)
-//
-//func TestTripleErrorDetailMarshaling(t *testing.T) {
-//	t.Parallel()
-//	detail, err := NewErrorDetail(durationpb.New(time.Second))
-//	assert.Nil(t, err)
-//	data, err := json.Marshal((*tripleWireDetail)(detail))
-//	assert.Nil(t, err)
-//	t.Logf("marshaled error detail: %s", string(data))
-//
-//	var unmarshaled tripleWireDetail
-//	assert.Nil(t, json.Unmarshal(data, &unmarshaled))
-//	assert.Equal(t, unmarshaled.wireJSON, string(data))
-//	assert.Equal(t, unmarshaled.pb, detail.pb)
-//}
-//
-//func TestTripleErrorDetailMarshalingNoDescriptor(t *testing.T) {
-//	t.Parallel()
-//	raw := `{"type":"acme.user.v1.User","value":"DEADBF",` +
-//		`"debug":{"@type":"acme.user.v1.User","email":"someone@triple.build"}}`
-//	var detail tripleWireDetail
-//	assert.Nil(t, json.Unmarshal([]byte(raw), &detail))
-//	assert.Equal(t, detail.pb.TypeUrl, defaultAnyResolverPrefix+"acme.user.v1.User")
-//
-//	_, err := (*ErrorDetail)(&detail).Value()
-//	assert.NotNil(t, err)
-//	assert.True(t, strings.HasSuffix(err.Error(), "not found"))
-//
-//	encoded, err := json.Marshal(&detail)
-//	assert.Nil(t, err)
-//	assert.Equal(t, string(encoded), raw)
-//}
+import (
+	"encoding/json"
+	"strings"
+	"testing"
+	"time"
+
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/assert"
+	"google.golang.org/protobuf/types/known/durationpb"
+)
+
+func TestTripleErrorDetailMarshaling(t *testing.T) {
+	t.Parallel()
+	detail, err := NewErrorDetail(durationpb.New(time.Second))
+	assert.Nil(t, err)
+	data, err := json.Marshal((*tripleWireDetail)(detail))
+	assert.Nil(t, err)
+	t.Logf("marshaled error detail: %s", string(data))
+
+	var unmarshaled tripleWireDetail
+	assert.Nil(t, json.Unmarshal(data, &unmarshaled))
+	assert.Equal(t, unmarshaled.wireJSON, string(data))
+	assert.Equal(t, unmarshaled.pb, detail.pb)
+}
+
+func TestTripleErrorDetailMarshalingNoDescriptor(t *testing.T) {
+	t.Parallel()
+	raw := `{"type":"acme.user.v1.User","value":"DEADBF",` +
+		`"debug":{"@type":"acme.user.v1.User","email":"someone@triple.build"}}`
+	var detail tripleWireDetail
+	assert.Nil(t, json.Unmarshal([]byte(raw), &detail))
+	assert.Equal(t, detail.pb.TypeUrl, defaultAnyResolverPrefix+"acme.user.v1.User")
+
+	_, err := (*ErrorDetail)(&detail).Value()
+	assert.NotNil(t, err)
+	assert.True(t, strings.HasSuffix(err.Error(), "not found"))
+
+	encoded, err := json.Marshal(&detail)
+	assert.Nil(t, err)
+	assert.Equal(t, string(encoded), raw)
+}
diff --git a/protocol/triple/triple_protocol/recover.go b/protocol/triple/triple_protocol/recover.go
index afc56c7..4933066 100644
--- a/protocol/triple/triple_protocol/recover.go
+++ b/protocol/triple/triple_protocol/recover.go
@@ -60,6 +60,25 @@
 	}
 }
 
+func (i *recoverHandlerInterceptor) WrapUnaryHandler(next UnaryHandlerFunc) UnaryHandlerFunc {
+	return func(ctx context.Context, request AnyRequest) (resp AnyResponse, retErr error) {
+		panicked := true
+		defer func() {
+			if panicked {
+				r := recover()
+				// net/http checks for ErrAbortHandler with ==, so we should too.
+				if r == http.ErrAbortHandler { //nolint:errorlint,goerr113
+					panic(r) //nolint:forbidigo
+				}
+				retErr = i.handle(ctx, request.Spec(), request.Header(), r)
+			}
+		}()
+		response, retErr := next(ctx, request)
+		panicked = false
+		return response, retErr
+	}
+}
+
 func (i *recoverHandlerInterceptor) WrapStreamingHandler(next StreamingHandlerFunc) StreamingHandlerFunc {
 	return func(ctx context.Context, conn StreamingHandlerConn) (retErr error) {
 		panicked := true
diff --git a/protocol/triple/triple_protocol/recover_ext_test.go b/protocol/triple/triple_protocol/recover_ext_test.go
index beef7f6..4b2e4c4 100644
--- a/protocol/triple/triple_protocol/recover_ext_test.go
+++ b/protocol/triple/triple_protocol/recover_ext_test.go
@@ -1,108 +1,107 @@
-// // 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.
+// 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"
-//	triple "dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/triple"
-//	"dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/triple/assert"
-//	"fmt"
-//	"net/http"
-//	"net/http/httptest"
-//	"testing"
-//
-//	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/triple/proto/triple/ping/v1"
-//	"dubbo.apache.org/dubbo-go/v3/protocol/grpc_new/triple/proto/triple/ping/v1/pingv1triple"
-//)
-//
-//type panicPingServer struct {
-//	pingv1triple.UnimplementedPingServiceHandler
-//
-//	panicWith any
-//}
-//
-//func (s *panicPingServer) Ping(
-//	context.Context,
-//	*triple.Request[pingv1.PingRequest],
-//) (*triple.Response[pingv1.PingResponse], error) {
-//	panic(s.panicWith) //nolint:forbidigo
-//}
-//
-//func (s *panicPingServer) CountUp(
-//	_ context.Context,
-//	_ *triple.Request[pingv1.CountUpRequest],
-//	stream *triple.ServerStream[pingv1.CountUpResponse],
-//) error {
-//	if err := stream.Send(&pingv1.CountUpResponse{}); err != nil {
-//		return err
-//	}
-//	panic(s.panicWith) //nolint:forbidigo
-//}
-//
-//func TestWithRecover(t *testing.T) {
-//	t.Parallel()
-//	handle := func(_ context.Context, _ triple.Spec, _ http.Header, r any) error {
-//		return triple.NewError(triple.CodeFailedPrecondition, fmt.Errorf("panic: %v", r))
-//	}
-//	assertHandled := func(err error) {
-//		t.Helper()
-//		assert.NotNil(t, err)
-//		assert.Equal(t, triple.CodeOf(err), triple.CodeFailedPrecondition)
-//	}
-//	assertNotHandled := func(err error) {
-//		t.Helper()
-//		// When HTTP/2 handlers panic, net/http sends an RST_STREAM frame with code
-//		// INTERNAL_ERROR. We should be mapping this back to CodeInternal.
-//		assert.Equal(t, triple.CodeOf(err), triple.CodeInternal)
-//	}
-//	drainStream := func(stream *triple.ServerStreamForClient[pingv1.CountUpResponse]) error {
-//		t.Helper()
-//		defer stream.Close()
-//		assert.True(t, stream.Receive())  // expect one response msg
-//		assert.False(t, stream.Receive()) // expect panic before second response msg
-//		return stream.Err()
-//	}
-//	pinger := &panicPingServer{}
-//	mux := http.NewServeMux()
-//	mux.Handle(pingv1triple.NewPingServiceHandler(pinger, triple.WithRecover(handle)))
-//	server := httptest.NewUnstartedServer(mux)
-//	server.EnableHTTP2 = true
-//	server.StartTLS()
-//	defer server.Close()
-//	client := pingv1triple.NewPingServiceClient(
-//		server.Client(),
-//		server.URL,
-//	)
-//
-//	for _, panicWith := range []any{42, nil} {
-//		pinger.panicWith = panicWith
-//
-//		_, err := client.Ping(context.Background(), triple.NewRequest(&pingv1.PingRequest{}))
-//		assertHandled(err)
-//
-//		stream, err := client.CountUp(context.Background(), triple.NewRequest(&pingv1.CountUpRequest{}))
-//		assert.Nil(t, err)
-//		assertHandled(drainStream(stream))
-//	}
-//
-//	pinger.panicWith = http.ErrAbortHandler
-//
-//	_, err := client.Ping(context.Background(), triple.NewRequest(&pingv1.PingRequest{}))
-//	assertNotHandled(err)
-//
-//	stream, err := client.CountUp(context.Background(), triple.NewRequest(&pingv1.CountUpRequest{}))
-//	assert.Nil(t, err)
-//	assertNotHandled(drainStream(stream))
-//}
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"net/http/httptest"
+	"testing"
+
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
+	"dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/assert"
+	pingv1 "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1"
+	pingv1triple "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol/internal/gen/proto/connect/ping/v1/pingv1connect"
+)
+
+type panicPingServer struct {
+	pingv1triple.UnimplementedPingServiceHandler
+	panicWith any
+}
+
+func (s *panicPingServer) Ping(
+	context.Context,
+	*triple_protocol.Request,
+) (*triple_protocol.Response, error) {
+	panic(s.panicWith) //nolint:forbidigo
+}
+
+func (s *panicPingServer) CountUp(
+	_ context.Context,
+	_ *triple_protocol.Request,
+	stream *triple_protocol.ServerStream,
+) error {
+	if err := stream.Send(&pingv1.CountUpResponse{}); err != nil {
+		return err
+	}
+	panic(s.panicWith) //nolint:forbidigo
+}
+
+func TestWithRecover(t *testing.T) {
+	t.Parallel()
+	handle := func(_ context.Context, _ triple_protocol.Spec, _ http.Header, r any) error {
+		return triple_protocol.NewError(triple_protocol.CodeFailedPrecondition, fmt.Errorf("panic: %v", r))
+	}
+	assertHandled := func(err error) {
+		t.Helper()
+		assert.NotNil(t, err)
+		assert.Equal(t, triple_protocol.CodeOf(err), triple_protocol.CodeFailedPrecondition)
+	}
+	assertNotHandled := func(err error) {
+		t.Helper()
+		// When HTTP/2 handlers panic, net/http sends an RST_STREAM frame with code
+		// INTERNAL_ERROR. We should be mapping this back to CodeInternal.
+		assert.Equal(t, triple_protocol.CodeOf(err), triple_protocol.CodeInternal)
+	}
+	//drainStream := func(stream *triple_protocol.ServerStreamForClient) error {
+	//	t.Helper()
+	//	defer stream.Close()
+	//	assert.True(t, stream.Receive(&pingv1.CountUpResponse{}))  // expect one response msg
+	//	assert.False(t, stream.Receive(&pingv1.CountUpResponse{})) // expect panic before second response msg
+	//	return stream.Err()
+	//}
+	pinger := &panicPingServer{}
+	mux := http.NewServeMux()
+	mux.Handle(pingv1triple.NewPingServiceHandler(pinger, triple_protocol.WithRecover(handle)))
+	server := httptest.NewUnstartedServer(mux)
+	server.EnableHTTP2 = true
+	server.StartTLS()
+	defer server.Close()
+	client := pingv1triple.NewPingServiceClient(
+		server.Client(),
+		server.URL,
+	)
+
+	for _, panicWith := range []any{42, nil} {
+		pinger.panicWith = panicWith
+
+		err := client.Ping(context.Background(), triple_protocol.NewRequest(&pingv1.PingRequest{}), triple_protocol.NewResponse(&pingv1.PingResponse{}))
+		assertHandled(err)
+
+		// stream, err := client.CountUp(context.Background(), triple_protocol.NewRequest(&pingv1.CountUpRequest{}))
+		// assert.Nil(t, err)
+		// assertHandled(drainStream(stream))
+	}
+
+	pinger.panicWith = http.ErrAbortHandler
+
+	err := client.Ping(context.Background(), triple_protocol.NewRequest(&pingv1.PingRequest{}), triple_protocol.NewResponse(&pingv1.PingResponse{}))
+	assertNotHandled(err)
+
+	// stream, err := client.CountUp(context.Background(), triple_protocol.NewRequest(&pingv1.CountUpRequest{}))
+	// assert.Nil(t, err)
+	// assertNotHandled(drainStream(stream))
+}
diff --git a/protocol/triple/triple_protocol/triple.go b/protocol/triple/triple_protocol/triple.go
index 0208d54..e03e819 100644
--- a/protocol/triple/triple_protocol/triple.go
+++ b/protocol/triple/triple_protocol/triple.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// Package connect is a slim RPC framework built on Protocol Buffers and
+// Package triple is a slim RPC framework built on Protocol Buffers and
 // [net/http]. In addition to supporting its own protocol, Connect handlers and
 // clients are wire-compatible with gRPC and gRPC-Web, including streaming.
 //
@@ -326,15 +326,15 @@
 		// todo: add a more reasonable sentence
 		panic("wrong type")
 	}
-	if err := conn.Receive(&resp.Msg); err != nil {
+	if err := conn.Receive(resp.Msg); err != nil {
 		return err
 	}
 	// In a well-formed stream, the response message may be followed by a block
 	// of in-stream trailers or HTTP trailers. To ensure that we receive the
 	// trailers, try to read another message from the stream.
-	//if err := conn.Receive(new(T)); err == nil {
+	// if err := conn.Receive(new(T)); err == nil {
 	// todo:// maybe using copy method
-	if err := conn.Receive(&resp.Msg); err == nil {
+	if err := conn.Receive(resp.Msg); err == nil {
 		return NewError(CodeUnknown, errors.New("unary stream has multiple messages"))
 	} else if err != nil && !errors.Is(err, io.EOF) {
 		return NewError(CodeUnknown, err)