// TestCompressedValue ... func TestCompressedValue(t *testing.T) { Convey("Check nil value", t, func() { val := Compressed{Data: nil} result, err := val.Value() So(result, ShouldBeNil) So(err, ShouldBeNil) }) Convey("Check empty value", t, func() { val := Compressed{Data: []byte("")} result, err := val.Value() So(result, ShouldBeNil) So(err, ShouldBeNil) }) Convey("Check not nil value", t, func() { msg := []byte("text text text") var zContent bytes.Buffer w, _ := zlib.NewWriterLevelDict(&zContent, 6, nil) _, err := w.Write(msg) So(err, ShouldBeNil) err = w.Close() So(err, ShouldBeNil) val := Compressed{Data: msg} result, err := val.Value() So(result, ShouldResemble, zContent.Bytes()) So(err, ShouldBeNil) }) }
//进行zlib压缩 func DoZlibCompress(src []byte) []byte { var in bytes.Buffer w, _ := zlib.NewWriterLevelDict(&in, zlib.BestCompression, dict) w.Write(src) w.Close() // fmt.Printf("%d -> %d\n", len(src), len(in.Bytes())) return in.Bytes() }
// NewFramer allocates a new Framer for a given SPDY connection, repesented by // a io.Writer and io.Reader. Note that Framer will read and write individual fields // from/to the Reader and Writer, so the caller should pass in an appropriately // buffered implementation to optimize performance. func NewFramer(w io.Writer, r io.Reader) *Framer { compressBuf := new(bytes.Buffer) // The only error from NewWriterLevelDict is out of range compression level. compressor, _ := zlib.NewWriterLevelDict(compressBuf, zlib.BestCompression, []byte(headerDictionary)) return &Framer{ w: w, headerBuf: compressBuf, headerCompressor: compressor, r: r, } }
// 压缩 // in:待压缩数据 // level:压缩等级 // 返回值: // 压缩后数据 // 对应的错误 func Compress(data []byte, level int) ([]byte, error) { var buffer bytes.Buffer compressor, err := zlib.NewWriterLevelDict(&buffer, level, nil) if err != nil { return nil, err } compressor.Write(data) compressor.Close() return buffer.Bytes(), nil }
// Compress - compress c.Data value func (c *Compressed) Compress() []byte { if len(c.Data) == 0 { return nil } var zContent bytes.Buffer w, _ := zlib.NewWriterLevelDict(&zContent, 6, nil) _, _ = w.Write(c.Data) _ = w.Close() return zContent.Bytes() }
// NewFramer allocates a new Framer for a given SPDY connection, repesented by // a io.Writer and io.Reader. Note that Framer will read and write individual fields // from/to the Reader and Writer, so the caller should pass in an appropriately // buffered implementation to optimize performance. func NewFramer(w io.Writer, r io.Reader) (*Framer, error) { compressBuf := new(bytes.Buffer) compressor, err := zlib.NewWriterLevelDict(compressBuf, zlib.BestCompression, []byte(headerDictionary)) if err != nil { return nil, err } framer := &Framer{ w: w, headerBuf: compressBuf, headerCompressor: compressor, r: r, } return framer, nil }
func (self *ZlibCompressor) Compress(src []byte) ([]byte, error) { var err error var compressor *zlib.Writer cdest := bytes.NewBuffer(make([]byte, 0, len(src))) if self.dict == nil { compressor, err = zlib.NewWriterLevel(cdest, self.level) } else { compressor, err = zlib.NewWriterLevelDict(cdest, self.level, self.dict) } compressor.Write(src) err = compressor.Close() if err != nil { fmt.Println("Compress Close err:%s", err.Error()) } return cdest.Bytes(), err }
// Compress uses zlib compression to compress the provided // data, according to the SPDY specification of the given version. func (c *compressor) Compress(h http.Header) ([]byte, error) { c.Lock() defer c.Unlock() // Ensure the buffer is prepared. if c.buf == nil { c.buf = new(bytes.Buffer) } else { c.buf.Reset() } // Same for the compressor. if c.w == nil { var err error switch c.version { case 2: select { case c.w = <-zlibV2Writers: c.w.Reset(c.buf) default: c.w, err = zlib.NewWriterLevelDict(c.buf, CompressionLevel, HeaderDictionaryV2) } case 3: select { case c.w = <-zlibV3Writers: c.w.Reset(c.buf) default: c.w, err = zlib.NewWriterLevelDict(c.buf, CompressionLevel, HeaderDictionaryV3) } default: err = versionError } if err != nil { return nil, err } } var size int // Size of length values. switch c.version { case 2: size = 2 case 3: size = 4 default: return nil, versionError } // Remove invalid headers. h.Del("Connection") h.Del("Keep-Alive") h.Del("Proxy-Connection") h.Del("Transfer-Encoding") length := size // The 4-byte or 2-byte number of name/value pairs. pairs := make(map[string]string) // Used to store the validated, joined headers. for name, values := range h { // Ignore invalid names. if _, ok := pairs[name]; ok { // We've already seen this name. return nil, errors.New("Error: Duplicate header name discovered.") } if name == "" { // Ignore empty names. continue } // Multiple values are separated by a single null byte. pairs[name] = strings.Join(values, "\x00") // +size for len(name), +size for len(values). length += len(name) + size + len(pairs[name]) + size } // Uncompressed data. out := make([]byte, length) // Current offset into out. var offset uint32 // Write the number of name/value pairs. num := uint32(len(pairs)) switch c.version { case 3: out[0] = byte(num >> 24) out[1] = byte(num >> 16) out[2] = byte(num >> 8) out[3] = byte(num) offset = 4 case 2: out[0] = byte(num >> 8) out[1] = byte(num) offset = 2 } // For each name/value pair... for name, value := range pairs { // The length of the name. nLen := uint32(len(name)) switch c.version { case 3: out[offset+0] = byte(nLen >> 24) out[offset+1] = byte(nLen >> 16) out[offset+2] = byte(nLen >> 8) out[offset+3] = byte(nLen) offset += 4 case 2: out[offset+0] = byte(nLen >> 8) out[offset+1] = byte(nLen) offset += 2 } // The name itself. copy(out[offset:], []byte(strings.ToLower(name))) offset += nLen // The length of the value. vLen := uint32(len(value)) switch c.version { case 3: out[offset+0] = byte(vLen >> 24) out[offset+1] = byte(vLen >> 16) out[offset+2] = byte(vLen >> 8) out[offset+3] = byte(vLen) offset += 4 case 2: out[offset+0] = byte(vLen >> 8) out[offset+1] = byte(vLen) offset += 2 } // The value itself. copy(out[offset:], []byte(value)) offset += vLen } // Compress. err := WriteExactly(c.w, out) if err != nil { return nil, err } c.w.Flush() return c.buf.Bytes(), nil }
// NewZlibCompressionLevelDict returns a Zlib-based Compression with the given // level, based on the given dictionary. func NewZlibCompressionLevelDict(level int, dict []byte) Compression { return &genericCompression{ func(w io.Writer) (io.WriteCloser, error) { return zlib.NewWriterLevelDict(w, level, dict) }, func(r io.Reader) (io.ReadCloser, error) { return zlib.NewReaderDict(r, dict) }, } }
// creates a headerWriter ready to compress headers func newHeaderWriter() (hw *headerWriter) { hw = &headerWriter{buffer: new(bytes.Buffer)} hw.compressor, _ = zlib.NewWriterLevelDict(hw.buffer, zlib.BestCompression, headerDictionary) return }
// NewHeaderWriter creates a HeaderWriter ready to compress headers. func NewHeaderWriter(level int) (hw *HeaderWriter) { hw = &HeaderWriter{buffer: new(bytes.Buffer)} hw.compressor, _ = zlib.NewWriterLevelDict(hw.buffer, level, []byte(headerDictionary)) return }
// Compress uses zlib compression to compress the provided // data, according to the SPDY specification of the given version. func (c *compressor) Compress(h http.Header) ([]byte, error) { c.m.Lock() defer c.m.Unlock() var err error if c.buf == nil { c.buf = new(bytes.Buffer) if c.w == nil { switch c.version { case 2: c.w, err = zlib.NewWriterLevelDict(c.buf, zlib.BestCompression, headerDictionaryV2) case 3: c.w, err = zlib.NewWriterLevelDict(c.buf, zlib.BestCompression, headerDictionaryV3) default: err = versionError } } if err != nil { return nil, err } } else { c.buf.Reset() } h.Del("Connection") h.Del("Keep-Alive") h.Del("Proxy-Connection") h.Del("Transfer-Encoding") length := 4 num := len(h) lens := make(map[string]int) for name, values := range h { length += len(name) + 8 lens[name] = len(values) - 1 for _, value := range values { length += len(value) lens[name] += len(value) } } out := make([]byte, length) switch c.version { case 3: out[0] = byte(num >> 24) out[1] = byte(num >> 16) out[2] = byte(num >> 8) out[3] = byte(num) case 2: out[0] = byte(num >> 8) out[1] = byte(num) } offset := 4 if c.version == 2 { offset = 2 } for name, values := range h { nLen := len(name) switch c.version { case 3: out[offset+0] = byte(nLen >> 24) out[offset+1] = byte(nLen >> 16) out[offset+2] = byte(nLen >> 8) out[offset+3] = byte(nLen) offset += 4 case 2: out[offset+0] = byte(nLen >> 8) out[offset+1] = byte(nLen) offset += 2 } for i, b := range []byte(strings.ToLower(name)) { out[offset+i] = b } offset += nLen vLen := lens[name] switch c.version { case 3: out[offset+0] = byte(vLen >> 24) out[offset+1] = byte(vLen >> 16) out[offset+2] = byte(vLen >> 8) out[offset+3] = byte(vLen) offset += 4 case 2: out[offset+0] = byte(vLen >> 8) out[offset+1] = byte(vLen) offset += 2 } for n, value := range values { for i, b := range []byte(value) { out[offset+i] = b } offset += len(value) if n < len(values)-1 { out[offset] = '\x00' offset += 1 } } } _, err = c.w.Write(out) if err != nil { return nil, err } c.w.Flush() return c.buf.Bytes(), nil }