trpc.group/trpc-go/trpc-go@v1.0.3/http/service_desc.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 15 16 import ( 17 "context" 18 "errors" 19 "fmt" 20 stdhttp "net/http" 21 22 "trpc.group/trpc-go/trpc-go/server" 23 ) 24 25 // ServiceDesc is descriptor for server.RegisterService. 26 var ServiceDesc = server.ServiceDesc{ 27 HandlerType: nil, 28 } 29 30 // Handle registers http handler with custom route. 31 func Handle(pattern string, h stdhttp.Handler) { 32 handler := func(w stdhttp.ResponseWriter, r *stdhttp.Request) error { 33 h.ServeHTTP(w, r) 34 return nil 35 } 36 37 ServiceDesc.Methods = append(ServiceDesc.Methods, generateMethod(pattern, handler)) 38 } 39 40 // HandleFunc registers http handler with custom route. 41 func HandleFunc(pattern string, handler func(w stdhttp.ResponseWriter, r *stdhttp.Request) error) { 42 ServiceDesc.Methods = append(ServiceDesc.Methods, generateMethod(pattern, handler)) 43 } 44 45 // RegisterDefaultService registers service. 46 // See http/README.md for usage details. 47 // Deprecated: use RegisterNoProtocolService(s.Service("your.stdhttp.service.name")) instead. 48 func RegisterDefaultService(s server.Service) { 49 DefaultServerCodec.AutoReadBody = false 50 RegisterNoProtocolService(s) 51 } 52 53 // RegisterNoProtocolService registers no protocol service. 54 // See http/README.md for usage details. 55 func RegisterNoProtocolService(s server.Service) { 56 if err := s.Register(&ServiceDesc, nil); err != nil { 57 panic(fmt.Sprintf("register http no protocol service fail, err: %+v", err)) 58 } 59 } 60 61 // RegisterServiceMux registers service with http standard mux handler. 62 // Business registers routing plug-in by himself. 63 // Deprecated: use RegisterNoProtocolServiceMux(s.Service("your.stdhttp.service.name"), mux) instead. 64 func RegisterServiceMux(s server.Service, mux stdhttp.Handler) { 65 DefaultServerCodec.AutoReadBody = false 66 RegisterNoProtocolServiceMux(s, mux) 67 } 68 69 // RegisterNoProtocolServiceMux registers service with http standard mux handler. 70 // Business registers routing plug-in by himself. 71 func RegisterNoProtocolServiceMux(s server.Service, mux stdhttp.Handler) { 72 handler := func(w stdhttp.ResponseWriter, r *stdhttp.Request) error { 73 mux.ServeHTTP(w, r) 74 return nil 75 } 76 method := generateMethod("*", handler) 77 var serviceDesc = server.ServiceDesc{ 78 HandlerType: nil, 79 Methods: []server.Method{method}, 80 } 81 if err := s.Register(&serviceDesc, nil); err != nil { 82 panic(fmt.Sprintf("register http no protocol service mux fail, err: %+v", err)) 83 } 84 } 85 86 // generateMethod generates server method. 87 func generateMethod(pattern string, handler func(w stdhttp.ResponseWriter, r *stdhttp.Request) error) server.Method { 88 handlerFunc := func(_ interface{}, ctx context.Context, f server.FilterFunc) (rspBody interface{}, err error) { 89 filters, err := f(nil) 90 if err != nil { 91 return nil, err 92 } 93 handleFunc := func(ctx context.Context, _ interface{}) (rspBody interface{}, err error) { 94 head := Head(ctx) 95 if head == nil { 96 return nil, errors.New("http Handle missing http header in context") 97 } 98 req := head.Request.WithContext(ctx) 99 rsp := head.Response 100 err = handler(rsp, req) 101 // Fix issues/778 102 // Currently, Request.MultipartForm is nil if Request.ParseMultipartForm() is not called. 103 // Then head.Request.WithContext cannot carry the corresponding Request.MultipartForm pointer to the user. 104 // If the user parses the multipart form data inside the handler, req will have a valid MultipartForm pointer, 105 // but this pointer is not going to be reflected in head.Request. 106 // Consequence: 107 // The standard http library is unable to remove the temporary files generated by multipart form data. 108 // 109 // The code below attempts to pass the pointer req.MultipartForm to head.Request.MultipartForm (which is 110 // a pointer the standard library code has access to). Thereafter temporary files generated by parsing 111 // multipart form data is guaranteed to be deleted. 112 if head.Request.MultipartForm == nil { 113 head.Request.MultipartForm = req.MultipartForm 114 } 115 return nil, err 116 } 117 return filters.Filter(ctx, nil, handleFunc) 118 } 119 return server.Method{ 120 Name: pattern, 121 Func: handlerFunc, 122 } 123 }