github.com/haalcala/mattermost-server-change-repo@v0.0.0-20210713015153-16753fbeee5f/plugin/http.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package plugin 5 6 import ( 7 "bufio" 8 "errors" 9 "fmt" 10 "io" 11 "net" 12 "net/http" 13 "net/rpc" 14 15 "github.com/mattermost/mattermost-server/v5/mlog" 16 ) 17 18 type hijackedResponse struct { 19 conn net.Conn 20 bufrw *bufio.ReadWriter 21 readBuf []byte 22 } 23 24 type httpResponseWriterRPCServer struct { 25 w http.ResponseWriter 26 log *mlog.Logger 27 hjr *hijackedResponse 28 } 29 30 func (w *httpResponseWriterRPCServer) Header(args struct{}, reply *http.Header) error { 31 *reply = w.w.Header() 32 return nil 33 } 34 35 func (w *httpResponseWriterRPCServer) Write(args []byte, reply *struct{}) error { 36 _, err := w.w.Write(args) 37 return err 38 } 39 40 func (w *httpResponseWriterRPCServer) WriteHeader(args int, reply *struct{}) error { 41 // Check if args is a valid http status code. This prevents plugins from crashing the server with a panic. 42 // This is a copy of the checkWriteHeaderCode function in net/http/server.go in the go source. 43 if args < 100 || args > 999 { 44 w.log.Error(fmt.Sprintf("Plugin tried to write an invalid http status code: %v. Did not write the invalid header.", args)) 45 return errors.New("invalid http status code") 46 } 47 w.w.WriteHeader(args) 48 return nil 49 } 50 51 func (w *httpResponseWriterRPCServer) SyncHeader(args http.Header, reply *struct{}) error { 52 dest := w.w.Header() 53 for k := range dest { 54 if _, ok := args[k]; !ok { 55 delete(dest, k) 56 } 57 } 58 for k, v := range args { 59 dest[k] = v 60 } 61 return nil 62 } 63 64 type httpResponseWriterRPCClient struct { 65 client *rpc.Client 66 header http.Header 67 } 68 69 var _ http.ResponseWriter = (*httpResponseWriterRPCClient)(nil) 70 71 func (w *httpResponseWriterRPCClient) Header() http.Header { 72 if w.header == nil { 73 w.client.Call("Plugin.Header", struct{}{}, &w.header) 74 } 75 return w.header 76 } 77 78 func (w *httpResponseWriterRPCClient) Write(b []byte) (int, error) { 79 if err := w.client.Call("Plugin.SyncHeader", w.header, nil); err != nil { 80 return 0, err 81 } 82 if err := w.client.Call("Plugin.Write", b, nil); err != nil { 83 return 0, err 84 } 85 return len(b), nil 86 } 87 88 func (w *httpResponseWriterRPCClient) WriteHeader(statusCode int) { 89 if err := w.client.Call("Plugin.SyncHeader", w.header, nil); err != nil { 90 return 91 } 92 w.client.Call("Plugin.WriteHeader", statusCode, nil) 93 } 94 95 func (w *httpResponseWriterRPCClient) Close() error { 96 return w.client.Close() 97 } 98 99 func connectHTTPResponseWriter(conn io.ReadWriteCloser) *httpResponseWriterRPCClient { 100 return &httpResponseWriterRPCClient{ 101 client: rpc.NewClient(conn), 102 } 103 }