Move request to a separate file and add test.

This commit is contained in:
2020-12-05 21:25:09 +01:00
parent 34c4385491
commit 74c1ce257a
3 changed files with 216 additions and 133 deletions

View File

@@ -4,8 +4,6 @@ import (
"encoding/binary"
"fmt"
"io"
log "github.com/sirupsen/logrus"
)
// References
@@ -92,137 +90,6 @@ func (v versionNumber) String() string {
return fmt.Sprintf("%x.%x", vn&0xff00>>8, vn&0x00ff)
}
type ippRequestHeader struct {
versionNumber versionNumber
operationId operationId
requestId uint32
}
func (h *ippRequestHeader) marshal(byteStream io.Reader) {
binary.Read(byteStream, binary.BigEndian, &h.versionNumber)
binary.Read(byteStream, binary.BigEndian, &h.operationId)
binary.Read(byteStream, binary.BigEndian, &h.requestId)
}
func (h ippRequestHeader) String() string {
return fmt.Sprintf("Version number: %v Operation Id: %v Request Id: %v", h.versionNumber, h.operationId, h.requestId)
}
type Attribute interface {
valueTag() tag
unmarshal(io.Reader)
marshal() []byte
size() int
}
type Request struct {
header ippRequestHeader
operationAttributes map[string]Attribute
jobAttributes map[string]Attribute
printerAttributes map[string]Attribute
}
func NewRequest() *Request {
r := new(Request)
r.operationAttributes = make(map[string]Attribute)
r.jobAttributes = make(map[string]Attribute)
r.printerAttributes = make(map[string]Attribute)
return r
}
func (r Request) String() string {
s := r.header.String() + "\n" + " OperationAttributes" + "\n"
for _, a := range r.operationAttributes {
s = s + fmt.Sprintf(" %v (%v)\n", a, a.valueTag())
}
return s
}
// log.Info(r.Header)
// log.Info(r.ContentLength)
//body := make([]byte, r.ContentLength)
//body.Read(body)
func (r *Request) UnMarshal(body io.Reader) {
r.header.marshal(body)
log.Infof("Header %v", r.header)
var tag tag
err := binary.Read(body, binary.BigEndian, &tag)
if err != nil {
log.Error(err.Error())
}
log.Infof("got tag - %v", tag)
if tag == operationAttributes {
nextoperationattr:
for tag != endOfAttributes {
var lastKeyword *keyWord
err = binary.Read(body, binary.BigEndian, &tag)
if err != nil {
log.Error(err.Error())
}
log.Infof("Value tag - %v", tag)
switch tag {
case endOfAttributes:
err = binary.Read(body, binary.BigEndian, &tag)
if err == io.EOF {
// No more data
return
}
if err != nil {
log.Error(err.Error())
}
log.Infof("got tag - %v", tag)
err = binary.Read(body, binary.BigEndian, &tag)
if err != nil {
log.Error(err.Error())
}
log.Infof("got tag - %v", tag)
break nextoperationattr
case charsetValueTag:
c := NewCharSetValue("", "")
c.unmarshal(body)
r.operationAttributes[c.name] = c
log.Infof("%v %v", c.name, c.value)
case uriValueTag:
u := newUriValue("", "")
u.unmarshal(body)
r.operationAttributes[u.name] = u
log.Infof("%v %v", u.name, u.value)
case naturalLanguagageValueTag:
n := newNaturalLanguagage("", "")
n.unmarshal(body)
r.operationAttributes[n.name] = n
log.Infof("%v %v", n.name, n.value)
case keyWordValueTag:
k := newKeyWord()
k.unmarshal(body)
r.operationAttributes[k.name] = k
if k.name == "" {
lastKeyword.addValue(k.values[0])
} else {
lastKeyword = k
}
default:
log.Errorf("Unsupported tag %v", tag)
}
}
log.Infof("Value tag %v", tag)
} else {
log.Error("unexpected tag")
// TODO Return something sensible here
}
}
func (r *Request) RequestId() uint32 {
return r.header.requestId
}
func unmarshalSingleValue(byteStream io.Reader) (string, string) {
var length uint16
binary.Read(byteStream, binary.BigEndian, &length)

137
packages/ipp/request.go Normal file
View File

@@ -0,0 +1,137 @@
package ipp
import (
"encoding/binary"
"fmt"
"io"
log "github.com/sirupsen/logrus"
)
type ippRequestHeader struct {
versionNumber versionNumber
operationId operationId
requestId uint32
}
func (h *ippRequestHeader) marshal(byteStream io.Reader) {
binary.Read(byteStream, binary.BigEndian, &h.versionNumber)
binary.Read(byteStream, binary.BigEndian, &h.operationId)
binary.Read(byteStream, binary.BigEndian, &h.requestId)
}
func (h ippRequestHeader) String() string {
return fmt.Sprintf("Version number: %v Operation Id: %v Request Id: %v", h.versionNumber, h.operationId, h.requestId)
}
type Attribute interface {
valueTag() tag
//unmarshal(io.Reader)
marshal() []byte
size() int
}
type Request struct {
header ippRequestHeader
operationAttributes map[string]Attribute
jobAttributes map[string]Attribute
printerAttributes map[string]Attribute
}
func NewRequest() *Request {
r := new(Request)
r.operationAttributes = make(map[string]Attribute)
r.jobAttributes = make(map[string]Attribute)
r.printerAttributes = make(map[string]Attribute)
return r
}
func (r Request) String() string {
s := r.header.String() + "\n" + " OperationAttributes" + "\n"
for _, a := range r.operationAttributes {
s = s + fmt.Sprintf(" %v (%v)\n", a, a.valueTag())
}
return s
}
func (r *Request) UnMarshal(body io.Reader) {
r.header.marshal(body)
log.Infof("Header %v", r.header)
var tag tag
err := binary.Read(body, binary.BigEndian, &tag)
if err != nil {
log.Error(err.Error())
}
log.Infof("got tag - %v", tag)
if tag == operationAttributes {
var lastKeyword *keyWord
nextoperationattr:
for tag != endOfAttributes {
err = binary.Read(body, binary.BigEndian, &tag)
if err != nil {
log.Error(err.Error())
}
log.Infof("Value tag - %v", tag)
switch tag {
case endOfAttributes:
err = binary.Read(body, binary.BigEndian, &tag)
if err == io.EOF {
// No more data
return
}
if err != nil {
log.Error(err.Error())
}
log.Infof("got tag - %v", tag)
err = binary.Read(body, binary.BigEndian, &tag)
if err != nil {
log.Error(err.Error())
}
log.Infof("got tag - %v", tag)
break nextoperationattr
case charsetValueTag:
c := NewCharSetValue("", "")
c.unmarshal(body)
r.operationAttributes[c.name] = c
log.Infof("%v %v", c.name, c.value)
case uriValueTag:
u := newUriValue("", "")
u.unmarshal(body)
r.operationAttributes[u.name] = u
log.Infof("%v %v", u.name, u.value)
case naturalLanguagageValueTag:
n := newNaturalLanguagage("", "")
n.unmarshal(body)
r.operationAttributes[n.name] = n
log.Infof("%v %v", n.name, n.value)
case keyWordValueTag:
name, value := unmarshalSingleValue(body)
if name == "" {
lastKeyword.addValue(value)
} else {
k := newKeyWord()
k.name = name
k.addValue(value)
r.operationAttributes[k.name] = k
lastKeyword = k
}
default:
log.Errorf("Unsupported tag %v", tag)
}
}
log.Infof("Value tag %v", tag)
} else {
log.Error("unexpected tag")
// TODO Return something sensible here
}
}
func (r *Request) RequestId() uint32 {
return r.header.requestId
}

View File

@@ -0,0 +1,79 @@
package ipp
import (
"bytes"
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
var testRequest = []byte{0x01, 0x01, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x11,
0x01,
0x47,
0x00, 0x12,
0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74,
0x00, 0x05,
0x75, 0x74, 0x66, 0x2d, 0x38,
0x48,
0x00, 0x1b,
0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2d, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x61, 0x6c, 0x2d, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65,
0x00, 0x05,
0x65, 0x6e, 0x2d, 0x75, 0x73,
0x45, // uriValueTag
0x00, 0x0b,
0x70, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x2d, 0x75, 0x72, 0x69,
0x00, 0x20,
0x69, 0x70, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, 0x32, 0x3a, 0x31, 0x32, 0x33, 0x34, 0x2f, 0x69, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x69, 0x6e, 0x74,
0x44, // keywordValueTag
0x00, 0x14,
0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x2d, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73,
0x00, 0x16,
0x70, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x2d, 0x6d, 0x61, 0x6b, 0x65, 0x2d, 0x61, 0x6e, 0x64, 0x2d, 0x6d, 0x6f, 0x64, 0x65, 0x6c,
0x44, // keywordValueTag
0x00, 0x00,
0x00, 0x16,
0x69, 0x70, 0x70, 0x2d, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2d, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64,
0x44, // keywordValueTag
0x00, 0x00,
0x00, 0x16,
0x69, 0x70, 0x70, 0x2d, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x2d, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64,
0x44, // keywordValueTag
0x00, 0x00,
0x00, 0x19,
0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2d, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2d, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64,
0x44,
0x00, 0x00,
0x00, 0x0d,
0x70, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x65,
0x44,
0x00, 0x00,
0x00, 0x15,
0x70, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2d, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x73,
0x44,
0x00, 0x00,
0x00, 0x15,
0x70, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
0x03}
func TestUnmarshalRequestPrinterAttributes(T *testing.T) {
buf := bytes.NewBuffer(testRequest)
req := NewRequest()
req.UnMarshal(buf)
fmt.Print(req)
assert.Equal(T, versionNumber(0x0101), req.header.versionNumber, "Wrong version number")
assert.Equal(T, GetPrinterAttributes, req.header.operationId, "Wrong Operation")
assert.Equal(T, uint32(17), req.header.requestId, "Wrong request id")
assert.Len(T, req.operationAttributes, 4)
v := req.operationAttributes["requested-attributes"].(*keyWord).values
assert.Len(T, v, 7)
assert.Contains(T, v, "printer-make-and-model")
assert.Contains(T, v, "ipp-versions-supported")
assert.Contains(T, v, "ipp-features-supported")
assert.Contains(T, v, "document-format-supported")
assert.Contains(T, v, "printer-state-reasons")
assert.Contains(T, v, "printer-state-message")
assert.Contains(T, v, "printer-state")
}