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  }