Skip to content

Instantly share code, notes, and snippets.

@ajkeeton
Created July 18, 2016 19:56
Show Gist options
  • Save ajkeeton/87352777b8f458b05f363fe8cd73803c to your computer and use it in GitHub Desktop.
Save ajkeeton/87352777b8f458b05f363fe8cd73803c to your computer and use it in GitHub Desktop.
Permessage-deflate issue with Go's deflate
package main
import (
"compress/flate"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
// "bufio"
"bytes"
"os"
"time"
)
func main() {
gonuts_permessage_poc() // <--- doesn't work
//gonuts_readall_poc() // <--- works
}
var magic_seperator = []byte{'\r', '\n', '\r', '\n'}
func gonuts_readall_poc() {
f, err := os.Open("flate_log.d")
if err != nil {
panic(err)
}
buf := bytes.NewBuffer(nil)
_, err = buf.ReadFrom(f)
if err != nil {
panic(err)
}
messages := bytes.Split(buf.Bytes(), magic_seperator)
fmt.Printf("Messages: %d\n", len(messages))
compData := bytes.NewBuffer(nil)
deflater := flate.NewReader(compData)
// Unsplit into a single contiguous stream
for _, msg := range messages {
// msg is a single websockets message
compData.Write(msg)
}
decompressed, err := ioutil.ReadAll(deflater)
fmt.Printf("Err: %v. Decompressed:\n%s\n\n", err, hex.Dump(decompressed[0:len(decompressed)]))
}
func gonuts_permessage_poc() {
f, err := os.Open("flate_log.d")
if err != nil {
panic(err)
}
buf := bytes.NewBuffer(nil)
_, err = buf.ReadFrom(f)
if err != nil {
panic(err)
}
messages := bytes.Split(buf.Bytes(), magic_seperator)
fmt.Printf("Messages: %d\n", len(messages))
compData := bytes.NewBuffer(nil)
deflater := flate.NewReader(compData)
for _, msg := range messages {
// msg is a single websockets message
compData.Write(msg)
decompressed, err := ioutil.ReadAll(deflater)
fmt.Printf("Err: %v. Decompressed:\n%s\n\n", err, hex.Dump(decompressed[0:len(decompressed)]))
if err == io.ErrUnexpectedEOF {
// Interestingly, ignoring an unexpected EOF allows more messages to be decompressed
// provided we use Reset here:
deflater.(flate.Resetter).Reset(compData, nil)
continue
}
if err != nil {
break
}
compData.Reset()
time.Sleep(1 * time.Second)
}
}
@ajkeeton
Copy link
Author

@ajkeeton
Copy link
Author

ajkeeton commented Jul 18, 2016

Data was collected by dumping the payload from a series of compressed websockets messages (after appending 0x00 0x00 0xff 0xff) to a file and adding an arbitrary separater (CRLFCRLF). The traffic used permessage-deflate. The separater is used to split out the individual messages in the proof of concept code above to simulate the scenario.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment