trpc.group/trpc-go/trpc-go@v1.0.3/http/codec_test.go (about)

     1  //
     2  //
     3  // Tencent is pleased to support the open source community by making tRPC available.
     4  //
     5  // Copyright (C) 2023 THL A29 Limited, a Tencent company.
     6  // All rights reserved.
     7  //
     8  // If you have downloaded a copy of the tRPC source code from Tencent,
     9  // please note that tRPC source code is licensed under the  Apache 2.0 License,
    10  // A copy of the Apache 2.0 License is included in this file.
    11  //
    12  //
    13  
    14  package http_test
    15  
    16  import (
    17  	"bufio"
    18  	"bytes"
    19  	"context"
    20  	"encoding/base64"
    21  	"encoding/json"
    22  	"errors"
    23  	"fmt"
    24  	"io"
    25  	"net"
    26  	"net/http"
    27  	"net/http/httptest"
    28  	"net/url"
    29  	"strings"
    30  	"testing"
    31  
    32  	trpcpb "trpc.group/trpc/trpc-protocol/pb/go/trpc"
    33  
    34  	"trpc.group/trpc-go/trpc-go/client"
    35  	"trpc.group/trpc-go/trpc-go/codec"
    36  	"trpc.group/trpc-go/trpc-go/errs"
    37  	thttp "trpc.group/trpc-go/trpc-go/http"
    38  	"trpc.group/trpc-go/trpc-go/server"
    39  	"trpc.group/trpc-go/trpc-go/testdata/restful/helloworld"
    40  
    41  	"github.com/stretchr/testify/assert"
    42  	"github.com/stretchr/testify/require"
    43  )
    44  
    45  func TestRegister(t *testing.T) {
    46  	thttp.SetContentType("application/proto", codec.SerializationTypePB)
    47  	thttp.RegisterContentType("application/proto", codec.SerializationTypePB)
    48  	thttp.RegisterSerializer("application/proto", codec.SerializationTypePB, &codec.PBSerialization{})
    49  	thttp.RegisterContentEncoding("gzip", codec.CompressTypeGzip)
    50  	thttp.RegisterStatus(100, 500)
    51  
    52  	req := thttp.Request(context.Background())
    53  	require.Nil(t, req, "request empty")
    54  	rsp := thttp.Response(context.Background())
    55  	require.Nil(t, rsp, "response empty")
    56  }
    57  
    58  func TestServerEncode(t *testing.T) {
    59  	r := &http.Request{}
    60  	w := &httptest.ResponseRecorder{}
    61  	m := &thttp.Header{Request: r, Response: w}
    62  	ctx := thttp.WithHeader(context.Background(), m)
    63  	msg := codec.Message(ctx)
    64  	msg.WithCompressType(codec.CompressTypeGzip)
    65  	sc := thttp.ServerCodec{}
    66  	_, err := sc.Encode(msg, nil)
    67  	require.Nil(t, err, "failed to encode http")
    68  	require.NotNil(t, thttp.Request(ctx))
    69  	require.NotNil(t, thttp.Response(ctx))
    70  }
    71  
    72  func TestServerEncodeWithContentType(t *testing.T) {
    73  	r := &http.Request{}
    74  	w := httptest.NewRecorder()
    75  	w.Header().Set("Content-Type", "application/json")
    76  	m := &thttp.Header{Request: r, Response: w}
    77  	ctx := thttp.WithHeader(context.Background(), m)
    78  	msg := codec.Message(ctx)
    79  	sc := thttp.ServerCodec{}
    80  	_, err := sc.Encode(msg, nil)
    81  	require.Nil(t, err, "failed to encode http")
    82  }
    83  
    84  func TestServerErrEncode(t *testing.T) {
    85  	req := &http.Request{}
    86  	w := &httptest.ResponseRecorder{}
    87  	h := &thttp.Header{Request: req, Response: w}
    88  	ctx := thttp.WithHeader(context.Background(), h)
    89  	msg := codec.Message(ctx)
    90  	msg.WithServerRspErr(errs.ErrServerNoFunc)
    91  	sc := thttp.DefaultServerCodec
    92  	_, err := sc.Encode(msg, nil)
    93  	require.Nil(t, err, "failed to encode err http")
    94  
    95  	// After the server returns an error, even there is a response data,
    96  	// it will be ignored and will not be processed or returned.
    97  	rsp := &responseRecorder{}
    98  	h = &thttp.Header{Request: req, Response: rsp}
    99  	ctx = thttp.WithHeader(context.Background(), h)
   100  	msg = codec.Message(ctx)
   101  	msg.WithServerRspErr(errs.ErrServerNoFunc)
   102  	_, err = sc.Encode(msg, []byte("write failed"))
   103  	require.Nil(t, err)
   104  }
   105  
   106  func TestNotHead(t *testing.T) {
   107  	msg := codec.Message(context.Background())
   108  	_, err := thttp.DefaultServerCodec.Decode(msg, nil)
   109  	require.NotNil(t, err, "failed to decode get head")
   110  	_, err = thttp.DefaultServerCodec.Encode(msg, nil)
   111  	require.NotNil(t, err, "failed to encode get head")
   112  }
   113  
   114  func TestMultipartFormData(t *testing.T) {
   115  	require := require.New(t)
   116  	r, _ := http.NewRequest("POST", "http://www.qq.com/trpc.http.test.helloworld/SayHello", bytes.NewReader([]byte("")))
   117  	r.Header.Add("Content-Type", "multipart/form-data; boundary=--------------------------487682300036072392114180")
   118  	body := `----------------------------487682300036072392114180
   119  Content-Disposition: form-data; name="competition"
   120  
   121  NBA
   122  ----------------------------487682300036072392114180
   123  Content-Disposition: form-data; name="teams"
   124  
   125  湖人
   126  ----------------------------487682300036072392114180
   127  Content-Disposition: form-data; name="teams"
   128  
   129  勇士
   130  ----------------------------487682300036072392114180
   131  Content-Disposition: form-data; name="season"
   132  
   133  2021
   134  ----------------------------487682300036072392114180
   135  Content-Disposition: form-data; name="file1"; filename="1.txt"
   136  Content-Type: text/plain
   137  
   138  1
   139  ----------------------------487682300036072392114180
   140  Content-Disposition: form-data; name="file2"; filename="1px.png"
   141  Content-Type: image/png
   142  
   143  �PNG
   144  
   145  IHDR%�V�PLTE�����
   146  IDA�c�!�3IEND�B�
   147  ----------------------------487682300036072392114180
   148  Content-Disposition: form-data; name="file3"; filename="json.json"
   149  Content-Type: application/json
   150  
   151  {
   152      "name":"1"
   153  }
   154  ----------------------------487682300036072392114180--
   155  `
   156  	// Decode multipart form data.
   157  	r.Body = io.NopCloser(strings.NewReader(body))
   158  	w := &httptest.ResponseRecorder{}
   159  	header := &thttp.Header{Request: r, Response: w}
   160  	msg := codec.Message(thttp.WithHeader(context.Background(), header))
   161  	in, err := thttp.DefaultServerCodec.Decode(msg, nil)
   162  	require.Nil(err)
   163  	require.Equal("competition=NBA&season=2021&teams=%E6%B9%96%E4%BA%BA&teams=%E5%8B%87%E5%A3%AB", string(in))
   164  	head := thttp.Head(msg.Context())
   165  
   166  	// Content-Type: text/plain.
   167  	file1, fileHeader1, err := head.Request.FormFile("file1")
   168  	require.Nil(err)
   169  	defer func() { require.Nil(file1.Close()) }()
   170  	require.Equal("text/plain", fileHeader1.Header.Get("Content-Type"))
   171  	require.Equal("1.txt", fileHeader1.Filename)
   172  	file1Content := make([]byte, 256)
   173  	n, err := io.ReadFull(file1, file1Content)
   174  	require.NotNil(err)
   175  	file1Content = file1Content[:n]
   176  	require.Equal("1", string(file1Content))
   177  
   178  	// Content-Type: image/png.
   179  	file2, fileHeader2, err := head.Request.FormFile("file2")
   180  	require.Nil(err)
   181  	defer func() { require.Nil(file2.Close()) }()
   182  	require.Equal("image/png", fileHeader2.Header.Get("Content-Type"))
   183  	require.Equal("1px.png", fileHeader2.Filename)
   184  
   185  	// Content-Type: application/json.
   186  	file3, fileHeader3, err := head.Request.FormFile("file3")
   187  	require.Nil(err)
   188  	defer func() { require.Nil(file3.Close()) }()
   189  	require.Equal("application/json", fileHeader3.Header.Get("Content-Type"))
   190  	require.Equal("json.json", fileHeader3.Filename)
   191  	defer func() { require.Nil(file1.Close()) }()
   192  	file3Content := make([]byte, 256)
   193  	n, err = io.ReadFull(file3, file3Content)
   194  	require.NotNil(err)
   195  	file3Content = file3Content[:n]
   196  	expected := `{
   197      "name":"1"
   198  }`
   199  	require.Equal(expected, string(file3Content))
   200  
   201  	// Encode json response data.
   202  	rsp := []byte(`{"competitionID":100000,"player":"opta"}`)
   203  	b, err := thttp.DefaultServerCodec.Encode(msg, rsp)
   204  	require.Nil(err)
   205  	ct := header.Response.Header().Get("Content-Type")
   206  	require.Equal("application/json", ct)
   207  	require.Nil(b)
   208  }
   209  
   210  func TestServerDecodeHTTPHeader(t *testing.T) {
   211  	r, err := http.NewRequest("POST", "http://www.qq.com/trpc.http.test.helloworld/SayHello", bytes.NewReader([]byte("")))
   212  	require.Nil(t, err)
   213  	r.Header.Add("Content-Encoding", "gzip")
   214  	r.Header.Add("Content-Type", "application/json")
   215  	r.Header.Add(thttp.TrpcVersion, "1")
   216  	r.Header.Add(thttp.TrpcCallType, "1")
   217  	r.Header.Add(thttp.TrpcMessageType, "1")
   218  	r.Header.Add(thttp.TrpcRequestID, "1")
   219  	r.Header.Add(thttp.TrpcTimeout, "1000")
   220  	r.Header.Add(thttp.TrpcCaller, "trpc.app.server.helloworld")
   221  	r.Header.Add(thttp.TrpcCallee, "trpc.http.test.helloworld")
   222  	// Request data must encode by base64 first.
   223  	// val1 -> dmFsMQ==   val2 -> dmFsMg==
   224  	r.Header.Add(thttp.TrpcTransInfo, `{"key1":"dmFsMQ==", "key2":"dmFsMg=="}`)
   225  	w := &httptest.ResponseRecorder{}
   226  	h := &thttp.Header{Request: r, Response: w}
   227  	ctx := thttp.WithHeader(context.Background(), h)
   228  	msg := codec.Message(ctx)
   229  	_, err = thttp.DefaultServerCodec.Decode(msg, nil)
   230  	require.Nil(t, err, "failed to decode get body")
   231  
   232  	require.Equal(t, codec.CompressTypeGzip, msg.CompressType())
   233  	require.Equal(t, codec.SerializationTypeJSON, msg.SerializationType())
   234  
   235  	req, ok := msg.ServerReqHead().(*trpcpb.RequestProtocol)
   236  	require.True(t, ok)
   237  	require.NotNil(t, req, "failed to decode get trpc req head")
   238  	require.Equal(t, 1, int(req.GetVersion()))
   239  	require.Equal(t, 1, int(req.GetCallType()))
   240  	require.Equal(t, 1, int(req.GetMessageType()))
   241  	require.Equal(t, 1, int(req.GetRequestId()))
   242  	require.Equal(t, 1000, int(req.GetTimeout()))
   243  	require.Equal(t, "trpc.app.server.helloworld", string(req.GetCaller()))
   244  	require.Equal(t, "trpc.http.test.helloworld", string(req.GetCallee()))
   245  	require.Equal(t, "val1", string(req.GetTransInfo()["key1"]))
   246  	require.Equal(t, "val2", string(req.GetTransInfo()["key2"]))
   247  
   248  	// JSON unmarshal failed.
   249  	r.Header.Set(thttp.TrpcTransInfo, `{"key1":"dmFsMQ==", "key2":"dmFsMg=="`)
   250  	w = &httptest.ResponseRecorder{}
   251  	h = &thttp.Header{Request: r, Response: w}
   252  	ctx = thttp.WithHeader(context.Background(), h)
   253  	msg = codec.Message(ctx)
   254  	_, err = thttp.DefaultServerCodec.Decode(msg, nil)
   255  	require.NotNil(t, err)
   256  
   257  	// base64 decode failed.
   258  	// If parsing fails then use raw data.
   259  	r.Header.Set(thttp.TrpcTransInfo, fmt.Sprintf(`{"%s":"%s"}`, thttp.TrpcEnv, "Production"))
   260  	w = &httptest.ResponseRecorder{}
   261  	h = &thttp.Header{Request: r, Response: w}
   262  	ctx = thttp.WithHeader(context.Background(), h)
   263  	msg = codec.Message(ctx)
   264  	_, err = thttp.DefaultServerCodec.Decode(msg, nil)
   265  	req, _ = msg.ServerReqHead().(*trpcpb.RequestProtocol)
   266  	require.Nil(t, err)
   267  	require.Equal(t, "Production", string(req.GetTransInfo()[thttp.TrpcEnv]))
   268  
   269  	// ReadAll failed.
   270  	r.Header.Set(thttp.TrpcTransInfo, `{"key1":"dmFsMQ==", "key2":"dmFsM-1"}`)
   271  	w = &httptest.ResponseRecorder{}
   272  	rp, _ := io.Pipe()
   273  	_ = rp.CloseWithError(err)
   274  	r.Body = rp
   275  	h = &thttp.Header{Request: r, Response: w}
   276  	ctx = thttp.WithHeader(context.Background(), h)
   277  	msg = codec.Message(ctx)
   278  	_, err = thttp.DefaultServerCodec.Decode(msg, nil)
   279  	require.NotNil(t, err)
   280  }
   281  
   282  func TestServerDecode(t *testing.T) {
   283  	r, _ := http.NewRequest("GET", "www.qq.com/xyz=abc", bytes.NewReader([]byte("")))
   284  	w := &httptest.ResponseRecorder{}
   285  	m := &thttp.Header{Request: r, Response: w}
   286  	ctx := thttp.WithHeader(context.Background(), m)
   287  	msg := codec.Message(ctx)
   288  	msg.WithServerRspErr(errs.ErrServerNoFunc)
   289  	_, err := thttp.DefaultServerCodec.Decode(msg, nil)
   290  	require.Nil(t, err, "failed to decode get body")
   291  }
   292  
   293  func TestServerPostDecode(t *testing.T) {
   294  	r, _ := http.NewRequest("POST", "www.qq.com", bytes.NewReader([]byte("{xyz:\"abc\"")))
   295  	w := &httptest.ResponseRecorder{}
   296  	m := &thttp.Header{Request: r, Response: w}
   297  	ctx := thttp.WithHeader(context.Background(), m)
   298  	msg := codec.Message(ctx)
   299  	msg.WithServerRspErr(errs.ErrServerNoFunc)
   300  	sc := thttp.ServerCodec{}
   301  	_, err := sc.Decode(msg, nil)
   302  	require.Nil(t, err, "failed to decode post body")
   303  }
   304  
   305  func TestClientEncode(t *testing.T) {
   306  	_, msg := codec.WithNewMessage(context.Background())
   307  	cc := thttp.ClientCodec{}
   308  	_, err := cc.Encode(msg, []byte("{\"username\":\"xyz\",\"password\":\"xyz\",\"from\":\"xyz\"}"))
   309  	require.Nil(t, err, "Failed to encode")
   310  	require.NotNil(t, msg.ClientReqHead(), "req head is nil")
   311  }
   312  
   313  func TestClientEncodeWithHeader(t *testing.T) {
   314  	_, msg := codec.WithNewMessage(context.Background())
   315  	httpReqHeader := &thttp.ClientReqHeader{}
   316  	msg.WithClientReqHead(httpReqHeader)
   317  	cc := thttp.ClientCodec{}
   318  	_, err := cc.Encode(msg, []byte("{\"username\":\"xyz\",\"password\":\"xyz\",\"from\":\"xyz\"}"))
   319  	require.Nil(t, err, "failed to encode")
   320  	require.NotNil(t, msg.ClientReqHead(), "req head is nil")
   321  
   322  	// Failed to parse req header.
   323  	_, msg = codec.WithNewMessage(context.Background())
   324  	reqHeader := &thttp.ClientRspHeader{}
   325  	msg.WithClientReqHead(reqHeader)
   326  	cc = thttp.ClientCodec{}
   327  	_, err = cc.Encode(msg, nil)
   328  	require.NotNil(t, err)
   329  
   330  	// Failed to parse rsp header.
   331  	_, msg = codec.WithNewMessage(context.Background())
   332  	rspHeader := &thttp.ClientReqHeader{}
   333  	msg.WithClientRspHead(rspHeader)
   334  	cc = thttp.ClientCodec{}
   335  	_, err = cc.Encode(msg, nil)
   336  	require.NotNil(t, err)
   337  }
   338  
   339  func TestClientErrDecode(t *testing.T) {
   340  	_, msg := codec.WithNewMessage(context.Background())
   341  	httprsp, err := http.ReadResponse(bufio.NewReader(strings.NewReader(respTests[0].Raw)), &http.Request{Method: "POST"})
   342  	require.Nil(t, err)
   343  	msg.WithClientRspHead(&thttp.ClientRspHeader{Response: httprsp})
   344  	cc := thttp.ClientCodec{}
   345  	_, err = cc.Decode(msg, []byte("{\"username\":\"xyz\",\"password\":\"xyz\",\"from\":\"xyz\"}"))
   346  	require.Nil(t, err)
   347  	require.NotNil(t, msg.ClientRspHead(), "req head is nil")
   348  
   349  	// Failed to parse rsp header.
   350  	_, m := codec.WithNewMessage(context.Background())
   351  	m.WithClientRspHead(&thttp.ClientReqHeader{})
   352  	cc = thttp.ClientCodec{}
   353  	_, err = cc.Decode(m, nil)
   354  	require.NotNil(t, err)
   355  
   356  	// Failed to read body.
   357  	rp, _ := io.Pipe()
   358  	_ = rp.CloseWithError(errors.New("read failed"))
   359  	httprsp, err = http.ReadResponse(bufio.NewReader(strings.NewReader(respTests[0].Raw)),
   360  		&http.Request{Method: "POST"})
   361  	require.Nil(t, err)
   362  	httprsp.Body = rp
   363  	httprsp.StatusCode = http.StatusOK
   364  
   365  	msg.WithClientRspHead(&thttp.ClientRspHeader{Response: httprsp})
   366  	cc = thttp.ClientCodec{}
   367  	_, err = cc.Decode(msg, []byte("{\"username\":\"xyz\",\"password\":\"xyz\",\"from\":\"xyz\"}"))
   368  	require.NotNil(t, err)
   369  
   370  	// HTTP status code is 300 (when status code >= 300, ClientCodec.Decode should return response error).
   371  	httprsp, err = http.ReadResponse(bufio.NewReader(strings.NewReader(respTests[0].Raw)),
   372  		&http.Request{Method: "POST"})
   373  	require.Nil(t, err)
   374  	httprsp.StatusCode = http.StatusMultipleChoices
   375  	msg.WithClientRspHead(&thttp.ClientRspHeader{Response: httprsp})
   376  
   377  	cc = thttp.ClientCodec{}
   378  	_, err = cc.Decode(msg, []byte("{\"username\":\"xyz\",\"password\":\"xyz\",\"from\":\"xyz\"}"))
   379  	require.Nil(t, err, "Failed to decode")
   380  	require.NotNil(t, msg.ClientRspErr(), "response error should not be nil")
   381  }
   382  
   383  func TestClientSuccessDecode(t *testing.T) {
   384  	_, msg := codec.WithNewMessage(context.Background())
   385  	httprsp, _ := http.ReadResponse(bufio.NewReader(strings.NewReader(respTests[1].Raw)),
   386  		&http.Request{Method: "POST"})
   387  	httprsp.Header.Add("Content-Encoding", "gzip")
   388  	httprsp.Header.Add("trpc-trans-info", `{"key1":"val1", "key2":"val2"}`)
   389  	msg.WithClientRspHead(&thttp.ClientRspHeader{Response: httprsp})
   390  	body, err := thttp.DefaultClientCodec.Decode(msg, []byte("{\"username\":\"xyz\","+
   391  		"\"password\":\"xyz\",\"from\":\"xyz\"}"))
   392  	require.Nil(t, err, "Failed to decode")
   393  	require.NotNil(t, msg.ClientRspHead(), "req head is nil")
   394  	require.Equal(t, string(body), respTests[1].Body, "body is error", string(body))
   395  	require.Equal(t, codec.CompressTypeGzip, msg.CompressType())
   396  
   397  	// HTTP status code 101.
   398  	httprsp, err = http.ReadResponse(bufio.NewReader(strings.NewReader(respTests[2].Raw)),
   399  		&http.Request{Method: "POST"})
   400  	require.Nil(t, err)
   401  	msg.WithClientRspHead(&thttp.ClientRspHeader{Response: httprsp})
   402  
   403  	msg.WithClientRspHead(&thttp.ClientRspHeader{Response: httprsp})
   404  	cc := thttp.ClientCodec{}
   405  	body, err = cc.Decode(msg, []byte("{\"username\":\"xyz\",\"password\":\"xyz\",\"from\":\"xyz\"}"))
   406  	require.Nil(t, err, "Failed to decode")
   407  	require.Empty(t, body)
   408  
   409  	// HTTP status code 201.
   410  	httprsp, err = http.ReadResponse(bufio.NewReader(strings.NewReader(respTests[0].Raw)),
   411  		&http.Request{Method: "POST"})
   412  	require.Nil(t, err)
   413  	msg.WithClientRspHead(&thttp.ClientRspHeader{Response: httprsp})
   414  	httprsp.StatusCode = http.StatusCreated
   415  
   416  	msg.WithClientRspHead(&thttp.ClientRspHeader{Response: httprsp})
   417  	cc = thttp.ClientCodec{}
   418  	body, err = cc.Decode(msg, []byte("{\"username\":\"xyz\",\"password\":\"xyz\",\"from\":\"xyz\"}"))
   419  	require.Nil(t, err, "Failed to decode")
   420  	require.Equal(t, respTests[0].Body, string(body), "body is error", string(body))
   421  }
   422  
   423  func TestClientRetDecode(t *testing.T) {
   424  	_, msg := codec.WithNewMessage(context.Background())
   425  	httprsp, err := http.ReadResponse(bufio.NewReader(strings.NewReader(respTests[1].Raw)), &http.Request{Method: "POST"})
   426  	require.Nil(t, err)
   427  	httprsp.Header.Add("trpc-ret", "1")
   428  	msg.WithClientRspHead(&thttp.ClientRspHeader{Response: httprsp})
   429  	_, err = thttp.DefaultClientCodec.Decode(msg,
   430  		[]byte("{\"username\":\"xyz\",\"password\":\"xyz\",\"from\":\"xyz\"}"))
   431  	require.Nil(t, err, "Failed to decode")
   432  	require.NotNil(t, msg.ClientRspErr())
   433  	require.EqualValues(t, 1, errs.Code(msg.ClientRspErr()))
   434  }
   435  
   436  func TestClientFuncRetDecode(t *testing.T) {
   437  	_, msg := codec.WithNewMessage(context.Background())
   438  	httprsp, err := http.ReadResponse(bufio.NewReader(strings.NewReader(respTests[1].Raw)), &http.Request{Method: "POST"})
   439  	require.Nil(t, err)
   440  	httprsp.Header.Add("trpc-func-ret", "1000")
   441  	httprsp.Header.Add("Content-Type", "application/json")
   442  	msg.WithClientRspHead(&thttp.ClientRspHeader{Response: httprsp})
   443  	_, err = thttp.DefaultClientCodec.Decode(msg,
   444  		[]byte("{\"username\":\"xyz\",\"password\":\"xyz\",\"from\":\"xyz\"}"))
   445  	require.Nil(t, err, "Failed to decode")
   446  	require.NotNil(t, msg.ClientRspErr())
   447  	require.EqualValues(t, 1000, errs.Code(msg.ClientRspErr()))
   448  }
   449  
   450  func TestServiceDecodeWithHeader(t *testing.T) {
   451  	req := &http.Request{
   452  		URL: &url.URL{
   453  			Path: "my_path",
   454  		},
   455  	}
   456  	header := &thttp.Header{
   457  		Request: req,
   458  	}
   459  
   460  	sc := &thttp.ServerCodec{}
   461  	ctx := thttp.WithHeader(context.Background(), header)
   462  	_, msg := codec.WithNewMessage(ctx)
   463  
   464  	_, err := sc.Decode(msg, nil)
   465  	assert.Nil(t, err)
   466  
   467  	method := msg.CalleeMethod()
   468  	rpcName := msg.ServerRPCName()
   469  
   470  	assert.Equal(t, method, req.URL.Path)
   471  	assert.Equal(t, rpcName, req.URL.Path)
   472  }
   473  
   474  func TestServerCodecDecodeTransInfo(t *testing.T) {
   475  	transInfo := map[string]string{
   476  		thttp.TrpcEnv:       base64.StdEncoding.EncodeToString([]byte("env-test")),
   477  		thttp.TrpcDyeingKey: base64.StdEncoding.EncodeToString([]byte("dyeing-test")),
   478  	}
   479  	data, err := json.Marshal(transInfo)
   480  	require.Nil(t, err)
   481  	head := http.Header{}
   482  	head.Add(thttp.TrpcTransInfo, string(data))
   483  
   484  	req := &http.Request{
   485  		Header: head,
   486  		URL:    &url.URL{},
   487  	}
   488  
   489  	header := &thttp.Header{
   490  		Request: req,
   491  	}
   492  
   493  	sc := &thttp.ServerCodec{
   494  		AutoGenTrpcHead: true,
   495  	}
   496  	ctx := thttp.WithHeader(context.Background(), header)
   497  	_, msg := codec.WithNewMessage(ctx)
   498  
   499  	_, err = sc.Decode(msg, nil)
   500  	require.Nil(t, err)
   501  
   502  	assert.Equal(t, msg.EnvTransfer(), "env-test")
   503  	assert.Equal(t, msg.DyeingKey(), "dyeing-test")
   504  }
   505  
   506  func TestDisableEncodeBase64(t *testing.T) {
   507  	r, err := http.NewRequest("POST", "/SayHello", bytes.NewReader([]byte("")))
   508  	require.Nil(t, err)
   509  	w := &httptest.ResponseRecorder{}
   510  	h := &thttp.Header{Request: r, Response: w}
   511  	ctx := thttp.WithHeader(context.Background(), h)
   512  	ctx, msg := codec.EnsureMessage(ctx)
   513  	msg.WithServerMetaData(codec.MetaData{"meta-key": []byte("meta-value")})
   514  
   515  	serverCodec := thttp.ServerCodec{
   516  		DisableEncodeTransInfoBase64: true,
   517  	}
   518  	_, err = serverCodec.Encode(msg, nil)
   519  	require.Nil(t, err)
   520  	rsp := thttp.Head(ctx).Response
   521  	require.Contains(t, string(rsp.Header().Get(thttp.TrpcTransInfo)), "meta-value")
   522  }
   523  
   524  func TestCoexistenceOfHTTPRPCAndNoProtocol(t *testing.T) {
   525  	defer func() { thttp.ServiceDesc.Methods = thttp.ServiceDesc.Methods[:0] }()
   526  	ln, err := net.Listen("tcp", "127.0.0.1:0")
   527  	require.Nil(t, err)
   528  	defer ln.Close()
   529  	serviceName := "trpc.test.hello.service" + t.Name()
   530  	s := server.New(
   531  		server.WithServiceName(serviceName),
   532  		server.WithListener(ln),
   533  		// Although the "http" protocol is represented as an HTTP RPC service and
   534  		// the standard HTTP service has its own protocol "http_no_protocol", some
   535  		// users require that both protocols can coexist in the same service
   536  		// (with the same ip and port).
   537  		// This requires that the standard HTTP handler function can still read the
   538  		// request body, even if the `AutoReadBody` field in the default server
   539  		// codec `DefaultServerCodec` for the `http` protocol is `true`.
   540  		server.WithProtocol("http"),
   541  	)
   542  	// Register standard HTTP handle.
   543  	thttp.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) error {
   544  		s := &codec.JSONPBSerialization{}
   545  		body, err := io.ReadAll(r.Body)
   546  		if err != nil {
   547  			return err
   548  		}
   549  		req := &helloworld.HelloRequest{}
   550  		if err := s.Unmarshal(body, req); err != nil {
   551  			return err
   552  		}
   553  		rsp := &helloworld.HelloReply{Message: req.Name}
   554  		body, err = s.Marshal(rsp)
   555  		if err != nil {
   556  			return err
   557  		}
   558  		w.WriteHeader(http.StatusOK)
   559  		w.Write(body)
   560  		return nil
   561  	})
   562  	thttp.RegisterNoProtocolService(s)
   563  	// Register protocol file service (HTTP RPC) implementation.
   564  	helloworld.RegisterGreeterService(s, &greeterImpl{})
   565  
   566  	// Start server.
   567  	go s.Serve()
   568  
   569  	ctx := context.Background()
   570  	target := "ip://" + ln.Addr().String()
   571  
   572  	// Send standard HTTP request.
   573  	c := thttp.NewClientProxy(serviceName, client.WithTarget(target))
   574  	msg := "hello"
   575  	req := &helloworld.HelloRequest{Name: msg}
   576  	rsp := &helloworld.HelloReply{}
   577  	require.Nil(t, c.Post(ctx, "/", req, rsp,
   578  		client.WithSerializationType(codec.SerializationTypeJSON)))
   579  	require.Equal(t, msg, rsp.Message)
   580  
   581  	// Send HTTP RPC request.
   582  	proxy := helloworld.NewGreeterClientProxy(client.WithTarget(target), client.WithProtocol("http"))
   583  	resp, err := proxy.SayHello(ctx, &helloworld.HelloRequest{Name: msg})
   584  	require.Nil(t, err)
   585  	require.Equal(t, msg, resp.Message)
   586  }
   587  
   588  type greeterImpl struct{}
   589  
   590  func (i *greeterImpl) SayHello(ctx context.Context, req *helloworld.HelloRequest) (*helloworld.HelloReply, error) {
   591  	return &helloworld.HelloReply{Message: req.Name}, nil
   592  }
   593  
   594  func (i *greeterImpl) SayHi(ctx context.Context, req *helloworld.HelloRequest) (*helloworld.HelloReply, error) {
   595  	return nil, nil
   596  }
   597  
   598  type responseRecorder struct {
   599  	httptest.ResponseRecorder
   600  }
   601  
   602  func (r *responseRecorder) Write(buf []byte) (int, error) {
   603  	return 0, errors.New("write failed")
   604  }
   605  
   606  type respTest struct {
   607  	Raw  string
   608  	Body string
   609  }
   610  
   611  var respTests = []respTest{
   612  	// Unchunked response without Content-Length.
   613  	{
   614  		"HTTP/1.0 404 NOT FOUND\r\n" +
   615  			"Connection: close\r\n" +
   616  			"\r\n" +
   617  			"Body here\n",
   618  
   619  		"Body here\n",
   620  	},
   621  
   622  	// Unchunked HTTP/1.1 response without Content-Length or
   623  	// Connection headers.
   624  	{
   625  		"HTTP/1.1 200 OK\r\n" +
   626  			"\r\n" +
   627  			"{\"msg\":\"from hi\"}\n",
   628  
   629  		"{\"msg\":\"from hi\"}\n",
   630  	},
   631  
   632  	// Unchunked HTTP/1.1 response without body.
   633  	{
   634  		"HTTP/1.1 101 Switching Protocols\r\n" +
   635  			"\r\n",
   636  
   637  		"",
   638  	}}