Browse Source

Terrible, temporary HPACK encoder.

Placeholder to unblock other development.
Brad Fitzpatrick 11 years ago
parent
commit
70c1baa8ab
2 changed files with 87 additions and 0 deletions
  1. 48 0
      hpack/encode.go
  2. 39 0
      hpack/encode_test.go

+ 48 - 0
hpack/encode.go

@@ -0,0 +1,48 @@
+// Copyright 2014 The Go Authors.
+// See https://code.google.com/p/go/source/browse/CONTRIBUTORS
+// Licensed under the same terms as Go itself:
+// https://code.google.com/p/go/source/browse/LICENSE
+
+package hpack
+
+import (
+	"errors"
+	"io"
+)
+
+type Encoder struct {
+	w   io.Writer
+	buf []byte
+}
+
+func NewEncoder(w io.Writer) *Encoder {
+	return &Encoder{w: w}
+}
+
+// WriteField encodes f into a single Write to e's underlying Writer.
+func (e *Encoder) WriteField(f HeaderField) error {
+	// TODO: write a decent Encoder. This is a quick hack job just to move on
+	// to other pieces. With this encoder, we only write literals.
+	// The form this writes is:
+	// http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.2
+	// In particular, that second table. And no huffman
+	// compression.  Oh, and let's be even lazier for now and
+	// reject keys or values with lengths greather than 126 so we
+	// can save some time by not writing a varint encoder for
+	// now. But I'm wasting time writing this comment.
+	if len(f.Name) > 126 || len(f.Value) > 126 {
+		return errors.New("TODO: finish hpack encoder. names/values too long for current laziness, procrastination, impatience.")
+	}
+	e.buf = e.buf[:0]
+	e.buf = append(e.buf, 0)
+	e.buf = append(e.buf, byte(len(f.Name)))
+	e.buf = append(e.buf, f.Name...)
+	e.buf = append(e.buf, byte(len(f.Value)))
+	e.buf = append(e.buf, f.Value...)
+
+	n, err := e.w.Write(e.buf)
+	if err == nil && n != len(e.buf) {
+		err = io.ErrShortWrite
+	}
+	return err
+}

+ 39 - 0
hpack/encode_test.go

@@ -0,0 +1,39 @@
+// Copyright 2014 The Go Authors.
+// See https://code.google.com/p/go/source/browse/CONTRIBUTORS
+// Licensed under the same terms as Go itself:
+// https://code.google.com/p/go/source/browse/LICENSE
+
+package hpack
+
+import (
+	"bytes"
+	"reflect"
+	"testing"
+)
+
+func TestEncoder(t *testing.T) {
+	headers := []HeaderField{
+		HeaderField{Name: "content-type", Value: "text/html"},
+		HeaderField{Name: "x-foo", Value: "x-bar"},
+	}
+
+	var buf bytes.Buffer
+	e := NewEncoder(&buf)
+	for _, hf := range headers {
+		if err := e.WriteField(hf); err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	var got []HeaderField
+	_, err := NewDecoder(4<<10, func(f HeaderField) {
+		got = append(got, f)
+	}).Write(buf.Bytes())
+	if err != nil {
+		t.Error("Decoder Write = %v", err)
+	}
+	if !reflect.DeepEqual(got, headers) {
+		t.Errorf("Decoded %+v; want %+v", got, headers)
+	}
+
+}