github.com/haalcala/mattermost-server-change-repo@v0.0.0-20210713015153-16753fbeee5f/plugin/hijack.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 "net" 10 "net/http" 11 "net/rpc" 12 "time" 13 ) 14 15 const ( 16 hijackedConnReadBufSize = 4096 17 ) 18 19 var ( 20 ErrNotHijacked = errors.New("response is not hijacked") 21 ErrAlreadyHijacked = errors.New("response was already hijacked") 22 ErrCannotHijack = errors.New("response cannot be hijacked") 23 ) 24 25 func (w *httpResponseWriterRPCServer) HjConnRWRead(b []byte, reply *[]byte) error { 26 if w.hjr == nil { 27 return ErrNotHijacked 28 } 29 data := make([]byte, len(b)) 30 n, err := w.hjr.bufrw.Read(data) 31 if err != nil { 32 return err 33 } 34 *reply = data[:n] 35 return nil 36 } 37 38 func (w *httpResponseWriterRPCServer) HjConnRWWrite(b []byte, reply *int) error { 39 if w.hjr == nil { 40 return ErrNotHijacked 41 } 42 n, err := w.hjr.bufrw.Write(b) 43 if err != nil { 44 return err 45 } 46 *reply = n 47 return nil 48 } 49 50 func (w *httpResponseWriterRPCServer) HjConnRead(size int, reply *[]byte) error { 51 if w.hjr == nil { 52 return ErrNotHijacked 53 } 54 if len(w.hjr.readBuf) < size { 55 w.hjr.readBuf = make([]byte, size) 56 } 57 n, err := w.hjr.conn.Read(w.hjr.readBuf[:size]) 58 if err != nil { 59 return err 60 } 61 *reply = w.hjr.readBuf[:n] 62 return nil 63 } 64 65 func (w *httpResponseWriterRPCServer) HjConnWrite(b []byte, reply *int) error { 66 if w.hjr == nil { 67 return ErrNotHijacked 68 } 69 n, err := w.hjr.conn.Write(b) 70 if err != nil { 71 return err 72 } 73 *reply = n 74 return nil 75 } 76 77 func (w *httpResponseWriterRPCServer) HjConnClose(args struct{}, reply *struct{}) error { 78 if w.hjr == nil { 79 return ErrNotHijacked 80 } 81 return w.hjr.conn.Close() 82 } 83 84 func (w *httpResponseWriterRPCServer) HjConnSetDeadline(t time.Time, reply *struct{}) error { 85 if w.hjr == nil { 86 return ErrNotHijacked 87 } 88 return w.hjr.conn.SetDeadline(t) 89 } 90 91 func (w *httpResponseWriterRPCServer) HjConnSetReadDeadline(t time.Time, reply *struct{}) error { 92 if w.hjr == nil { 93 return ErrNotHijacked 94 } 95 return w.hjr.conn.SetReadDeadline(t) 96 } 97 98 func (w *httpResponseWriterRPCServer) HjConnSetWriteDeadline(t time.Time, reply *struct{}) error { 99 if w.hjr == nil { 100 return ErrNotHijacked 101 } 102 return w.hjr.conn.SetWriteDeadline(t) 103 } 104 105 func (w *httpResponseWriterRPCServer) HijackResponse(args struct{}, reply *struct{}) error { 106 if w.hjr != nil { 107 return ErrAlreadyHijacked 108 } 109 hj, ok := w.w.(http.Hijacker) 110 if !ok { 111 return ErrCannotHijack 112 } 113 conn, bufrw, err := hj.Hijack() 114 if err != nil { 115 return err 116 } 117 118 w.hjr = &hijackedResponse{ 119 conn: conn, 120 bufrw: bufrw, 121 readBuf: make([]byte, hijackedConnReadBufSize), 122 } 123 return nil 124 } 125 126 type hijackedConn struct { 127 client *rpc.Client 128 } 129 130 type hijackedConnRW struct { 131 client *rpc.Client 132 } 133 134 func (w *hijackedConnRW) Read(b []byte) (int, error) { 135 var data []byte 136 if err := w.client.Call("Plugin.HjConnRWRead", b, &data); err != nil { 137 return 0, err 138 } 139 copy(b, data) 140 return len(data), nil 141 } 142 143 func (w *hijackedConnRW) Write(b []byte) (int, error) { 144 var n int 145 if err := w.client.Call("Plugin.HjConnRWWrite", b, &n); err != nil { 146 return 0, err 147 } 148 return n, nil 149 } 150 151 func (w *hijackedConn) Read(b []byte) (int, error) { 152 var data []byte 153 if err := w.client.Call("Plugin.HjConnRead", len(b), &data); err != nil { 154 return 0, err 155 } 156 copy(b, data) 157 return len(data), nil 158 } 159 160 func (w *hijackedConn) Write(b []byte) (int, error) { 161 var n int 162 if err := w.client.Call("Plugin.HjConnWrite", b, &n); err != nil { 163 return 0, err 164 } 165 return n, nil 166 } 167 168 func (w *hijackedConn) Close() error { 169 return w.client.Call("Plugin.HjConnClose", struct{}{}, nil) 170 } 171 172 func (w *hijackedConn) LocalAddr() net.Addr { 173 return nil 174 } 175 176 func (w *hijackedConn) RemoteAddr() net.Addr { 177 return nil 178 } 179 180 func (w *hijackedConn) SetDeadline(t time.Time) error { 181 return w.client.Call("Plugin.HjConnSetDeadline", t, nil) 182 } 183 184 func (w *hijackedConn) SetReadDeadline(t time.Time) error { 185 return w.client.Call("Plugin.HjConnSetReadDeadline", t, nil) 186 } 187 188 func (w *hijackedConn) SetWriteDeadline(t time.Time) error { 189 return w.client.Call("Plugin.HjConnSetWriteDeadline", t, nil) 190 } 191 192 func (w *httpResponseWriterRPCClient) Hijack() (net.Conn, *bufio.ReadWriter, error) { 193 c := &hijackedConn{ 194 client: w.client, 195 } 196 rw := &hijackedConnRW{ 197 client: w.client, 198 } 199 200 if err := w.client.Call("Plugin.HijackResponse", struct{}{}, nil); err != nil { 201 return nil, nil, err 202 } 203 204 return c, bufio.NewReadWriter(bufio.NewReader(rw), bufio.NewWriter(rw)), nil 205 }