~fnux/yggdrasil-go-coap

08fd8a5f6abcff02230b45cbcfe9d4a65cb0f927 — Erik Johnston 2 years ago 4fe6ff7
Fix responding to blockwise requests using Write

When responding to blockwise requests using `ResponseWrite.Write` the
server would use the message ID of the first block message rather than
the last. This meant that clients would fail to handle the response.

This was due to not creating a new response writer when we created a new
request.
4 files changed, 96 insertions(+), 16 deletions(-)

M blockwise.go
M blockwise_test.go
M responsewriter.go
M server.go
M blockwise.go => blockwise.go +7 -1
@@ 666,7 666,13 @@ func handleBlockWiseMsg(w ResponseWriter, r *Request, next func(w ResponseWriter
				if err != nil {
					return
				}
				next(w, &Request{Client: r.Client, Msg: msg})

				// We need to be careful to create a new response writer for the
				// new request, otherwise the server may attempt to respond to
				// the wrong request.
				newReq := &Request{Client: r.Client, Msg: msg}
				newWriter := responseWriterFromRequest(newReq)
				next(newWriter, newReq)
				return
			}
			/*

M blockwise_test.go => blockwise_test.go +68 -0
@@ 1,7 1,9 @@
package coap

import (
	"bytes"
	"fmt"
	"log"
	"testing"
)



@@ 166,3 168,69 @@ func TestServingTCPBigMsgBlockWiseSzx1024(t *testing.T) {
func TestServingTCPBigMsgBlockWiseSzxBERT(t *testing.T) {
	testServingTCPWithMsg(t, "tcp", true, BlockWiseSzxBERT, make([]byte, 10*1024*1024), simpleMsg)
}

// EchoServerUsingWrite echoes request payloads using ResponseWriter.Write
func EchoServerUsingWrite(w ResponseWriter, r *Request) {
	if r.Msg.IsConfirmable() {
		w.SetCode(Content)
		w.SetContentFormat(r.Msg.Option(ContentFormat).(MediaType))
		_, err := w.Write(r.Msg.Payload())
		if err != nil {
			log.Printf("Cannot write echo %v", err)
		}
	}
}

func TestServingUDPBlockWiseUsingWrite(t *testing.T) {
	// Test that responding to blockwise requests using ResponseWrite.write
	// works correctly (as opposed to using WriteMsg directly)

	HandleFunc("/test-with-write", EchoServerUsingWrite)
	defer HandleRemove("/test-with-write")

	payload := make([]byte, 512)

	_, addr, _, err := RunLocalUDPServer("udp", ":0", true, BlockWiseSzx1024)
	if err != nil {
		t.Fatalf("Unexpected error '%v'", err)
	}

	BlockWiseTransfer := true
	BlockWiseTransferSzx := BlockWiseSzx128
	c := &Client{
		Net:                  "udp",
		BlockWiseTransfer:    &BlockWiseTransfer,
		BlockWiseTransferSzx: &BlockWiseTransferSzx,
		MaxMessageSize:       ^uint32(0),
	}
	co, err := c.Dial(addr)
	if err != nil {
		t.Fatal("cannot dial", err)
	}

	req, err := co.NewPostRequest("/test-with-write", TextPlain, bytes.NewBuffer(payload))
	if err != nil {
		t.Fatal("cannot create request", err)
	}

	m, err := co.Exchange(req)
	if err != nil {
		t.Fatal("failed to exchange", err)
	}
	if m == nil {
		t.Fatalf("Didn't receive CoAP response")
	}

	expectedMsg := &DgramMessage{
		MessageBase{
			typ:       Acknowledgement,
			code:      Content,
			messageID: req.MessageID(),
			payload:   req.Payload(),
			token:     req.Token(),
		},
	}
	expectedMsg.SetOption(ContentFormat, req.Option(ContentFormat))

	assertEqualMessages(t, expectedMsg, m)
}

M responsewriter.go => responsewriter.go +20 -0
@@ 38,6 38,26 @@ type responseWriter struct {
	contentFormat *MediaType
}

func responseWriterFromRequest(r *Request) ResponseWriter {
	w := ResponseWriter(&responseWriter{req: r})
	switch {
	case r.Msg.Code() == GET:
		switch {
		// set blockwise notice writer for observe
		case r.Client.networkSession.blockWiseEnabled() && r.Msg.Option(Observe) != nil:
			w = &blockWiseNoticeWriter{responseWriter: w.(*responseWriter)}
		// set blockwise if it is enabled
		case r.Client.networkSession.blockWiseEnabled():
			w = &blockWiseResponseWriter{responseWriter: w.(*responseWriter)}
		}
		w = &getResponseWriter{w}
	case r.Client.networkSession.blockWiseEnabled():
		w = &blockWiseResponseWriter{responseWriter: w.(*responseWriter)}
	}

	return w
}

// NewResponse creates reponse for request
func (r *responseWriter) NewResponse(code COAPCode) Message {
	typ := NonConfirmable

M server.go => server.go +1 -15
@@ 583,21 583,7 @@ func (srv *Server) serveUDP(conn *net.UDPConn) error {
}

func (srv *Server) serve(r *Request) {
	w := ResponseWriter(&responseWriter{req: r})
	switch {
	case r.Msg.Code() == GET:
		switch {
		// set blockwise notice writer for observe
		case r.Client.networkSession.blockWiseEnabled() && r.Msg.Option(Observe) != nil:
			w = &blockWiseNoticeWriter{responseWriter: w.(*responseWriter)}
		// set blockwise if it is enabled
		case r.Client.networkSession.blockWiseEnabled():
			w = &blockWiseResponseWriter{responseWriter: w.(*responseWriter)}
		}
		w = &getResponseWriter{w}
	case r.Client.networkSession.blockWiseEnabled():
		w = &blockWiseResponseWriter{responseWriter: w.(*responseWriter)}
	}
	w := responseWriterFromRequest(r)

	handlePairMsg(w, r, func(w ResponseWriter, r *Request) {
		handleSignalMsg(w, r, func(w ResponseWriter, r *Request) {