Source file src/net/rpc/jsonrpc/server.go

     1  // Copyright 2010 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package jsonrpc
     6  
     7  import (
     8  	"encoding/json"
     9  	"errors"
    10  	"io"
    11  	"net/rpc"
    12  	"sync"
    13  )
    14  
    15  var errMissingParams = errors.New("jsonrpc: request body missing params")
    16  
    17  type serverCodec struct {
    18  	dec *json.Decoder // for reading JSON values
    19  	enc *json.Encoder // for writing JSON values
    20  	c   io.Closer
    21  
    22  	// temporary work space
    23  	req serverRequest
    24  
    25  	// JSON-RPC clients can use arbitrary json values as request IDs.
    26  	// Package rpc expects uint64 request IDs.
    27  	// We assign uint64 sequence numbers to incoming requests
    28  	// but save the original request ID in the pending map.
    29  	// When rpc responds, we use the sequence number in
    30  	// the response to find the original request ID.
    31  	mutex   sync.Mutex // protects seq, pending
    32  	seq     uint64
    33  	pending map[uint64]*json.RawMessage
    34  }
    35  
    36  // NewServerCodec returns a new [rpc.ServerCodec] using JSON-RPC on conn.
    37  func NewServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec {
    38  	return &serverCodec{
    39  		dec:     json.NewDecoder(conn),
    40  		enc:     json.NewEncoder(conn),
    41  		c:       conn,
    42  		pending: make(map[uint64]*json.RawMessage),
    43  	}
    44  }
    45  
    46  type serverRequest struct {
    47  	Method string           `json:"method"`
    48  	Params *json.RawMessage `json:"params"`
    49  	Id     *json.RawMessage `json:"id"`
    50  }
    51  
    52  func (r *serverRequest) reset() {
    53  	r.Method = ""
    54  	r.Params = nil
    55  	r.Id = nil
    56  }
    57  
    58  type serverResponse struct {
    59  	Id     *json.RawMessage `json:"id"`
    60  	Result any              `json:"result"`
    61  	Error  any              `json:"error"`
    62  }
    63  
    64  func (c *serverCodec) ReadRequestHeader(r *rpc.Request) error {
    65  	c.req.reset()
    66  	if err := c.dec.Decode(&c.req); err != nil {
    67  		return err
    68  	}
    69  	r.ServiceMethod = c.req.Method
    70  
    71  	// JSON request id can be any JSON value;
    72  	// RPC package expects uint64.  Translate to
    73  	// internal uint64 and save JSON on the side.
    74  	c.mutex.Lock()
    75  	c.seq++
    76  	c.pending[c.seq] = c.req.Id
    77  	c.req.Id = nil
    78  	r.Seq = c.seq
    79  	c.mutex.Unlock()
    80  
    81  	return nil
    82  }
    83  
    84  func (c *serverCodec) ReadRequestBody(x any) error {
    85  	if x == nil {
    86  		return nil
    87  	}
    88  	if c.req.Params == nil {
    89  		return errMissingParams
    90  	}
    91  	// JSON params is array value.
    92  	// RPC params is struct.
    93  	// Unmarshal into array containing struct for now.
    94  	// Should think about making RPC more general.
    95  	var params [1]any
    96  	params[0] = x
    97  	return json.Unmarshal(*c.req.Params, &params)
    98  }
    99  
   100  var null = json.RawMessage([]byte("null"))
   101  
   102  func (c *serverCodec) WriteResponse(r *rpc.Response, x any) error {
   103  	c.mutex.Lock()
   104  	b, ok := c.pending[r.Seq]
   105  	if !ok {
   106  		c.mutex.Unlock()
   107  		return errors.New("invalid sequence number in response")
   108  	}
   109  	delete(c.pending, r.Seq)
   110  	c.mutex.Unlock()
   111  
   112  	if b == nil {
   113  		// Invalid request so no id. Use JSON null.
   114  		b = &null
   115  	}
   116  	resp := serverResponse{Id: b}
   117  	if r.Error == "" {
   118  		resp.Result = x
   119  	} else {
   120  		resp.Error = r.Error
   121  	}
   122  	return c.enc.Encode(resp)
   123  }
   124  
   125  func (c *serverCodec) Close() error {
   126  	return c.c.Close()
   127  }
   128  
   129  // ServeConn runs the JSON-RPC server on a single connection.
   130  // ServeConn blocks, serving the connection until the client hangs up.
   131  // The caller typically invokes ServeConn in a go statement.
   132  func ServeConn(conn io.ReadWriteCloser) {
   133  	rpc.ServeCodec(NewServerCodec(conn))
   134  }
   135  

View as plain text