Skip to content

Commit

Permalink
return errParse on incorrect HTTP, fix #4
Browse files Browse the repository at this point in the history
  • Loading branch information
powerman committed Sep 7, 2015
1 parent 7caf9ad commit d04fa12
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 7 deletions.
41 changes: 41 additions & 0 deletions jsonrpc2/all_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@
package jsonrpc2

import (
"bufio"
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"net/http/httptest"
"net/rpc"
"strings"
"testing"
Expand Down Expand Up @@ -244,9 +247,47 @@ func TestServerErrorHasNullResult(t *testing.T) {
func TestUnexpectedError(t *testing.T) {
cli, srv := myPipe()
go cli.PipeWriter.CloseWithError(errors.New("unexpected error")) // reader will get this error
go cli.PipeReader.Close() // writer will get ErrClosedPipe
ServeConn(srv) // must return, not loop
}

func TestBadHTTP2Server(t *testing.T) {
ts := httptest.NewServer(HTTPHandler(nil))
// Don't close because of https://github.com/golang/go/issues/12262
// defer ts.Close()
addr := ts.URL[strings.LastIndex(ts.URL, "/")+1:]
for _, c := range []string{"", " ", "{", `{"jsonrpc":"2.0",`} {
conn, err := net.Dial("tcp", addr)
if err != nil {
t.Fatalf("Dial(%s), err = %v", addr, err)
}
_, err = conn.Write([]byte("POST / HTTP/1.0\r\n" +
"Host: localhost\r\n" +
"Content-Type: application/json\r\n" +
"Accept: application/json\r\n" +
"Content-Length: " + fmt.Sprintf("%d", len(c)) + "\r\n" +
"\r\n" + c))
if err != nil {
t.Fatalf("[%#q] Write(), err = %v", c, err)
}
resp, err := http.ReadResponse(bufio.NewReader(conn), nil)
if err != nil {
t.Fatalf("[%#q] ReadResponse(), err = %v", c, err)
}
if resp.StatusCode != http.StatusOK {
t.Errorf("[%#q] resp.StatusCode = %d, want %d", c, resp.StatusCode, http.StatusOK)
}
var r clientResponse
err = json.NewDecoder(resp.Body).Decode(&r)
if err != nil {
t.Errorf("[%#q] Decode(), err = %v", c, err)
}
if r.Error == nil || r.Error.Code != errParse.Code {
t.Errorf("[%#q] r = %v, wait errParse", c, r)
}
}
}

// Copied from package net.
func myPipe() (*pipe, *pipe) {
r1, w1 := io.Pipe()
Expand Down
21 changes: 14 additions & 7 deletions jsonrpc2/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ import (
)

type serverCodec struct {
dec *json.Decoder // for reading JSON values
enc *json.Encoder // for writing JSON values
c io.Closer
srv *rpc.Server
encmutex sync.Mutex // protects enc
dec *json.Decoder // for reading JSON values
enc *json.Encoder // for writing JSON values
c io.Closer
srv *rpc.Server

// temporary work space
req serverRequest
Expand Down Expand Up @@ -126,9 +127,9 @@ func (c *serverCodec) ReadRequestHeader(r *rpc.Request) (err error) {
// So, try to send error reply to client before returning error.
var raw json.RawMessage
if err := c.dec.Decode(&raw); err != nil {
if _, ok := err.(*json.SyntaxError); ok {
c.enc.Encode(serverResponse{Version: "2.0", ID: &null, Error: errParse})
}
c.encmutex.Lock()
c.enc.Encode(serverResponse{Version: "2.0", ID: &null, Error: errParse})
c.encmutex.Unlock()
return err
}

Expand All @@ -139,7 +140,9 @@ func (c *serverCodec) ReadRequestHeader(r *rpc.Request) (err error) {
c.req.ID = &null
} else if err := json.Unmarshal(raw, &c.req); err != nil {
if err.Error() == "bad request" {
c.encmutex.Lock()
c.enc.Encode(serverResponse{Version: "2.0", ID: &null, Error: errRequest})
c.encmutex.Unlock()
}
return err
}
Expand Down Expand Up @@ -203,6 +206,8 @@ func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) error {
if len(*replies) == 0 {
return nil
}
c.encmutex.Lock()
defer c.encmutex.Unlock()
return c.enc.Encode(replies)
}

Expand All @@ -228,6 +233,8 @@ func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) error {
raw := json.RawMessage(newError(r.Error).Error())
resp.Error = &raw
}
c.encmutex.Lock()
defer c.encmutex.Unlock()
return c.enc.Encode(resp)
}

Expand Down

0 comments on commit d04fa12

Please sign in to comment.