compress.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. package fasthttp
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "os"
  7. "sync"
  8. "github.com/klauspost/compress/flate"
  9. "github.com/klauspost/compress/gzip"
  10. "github.com/klauspost/compress/zlib"
  11. "github.com/valyala/bytebufferpool"
  12. "github.com/valyala/fasthttp/stackless"
  13. )
  14. // Supported compression levels.
  15. const (
  16. CompressNoCompression = flate.NoCompression
  17. CompressBestSpeed = flate.BestSpeed
  18. CompressBestCompression = flate.BestCompression
  19. CompressDefaultCompression = 6 // flate.DefaultCompression
  20. CompressHuffmanOnly = -2 // flate.HuffmanOnly
  21. )
  22. func acquireGzipReader(r io.Reader) (*gzip.Reader, error) {
  23. v := gzipReaderPool.Get()
  24. if v == nil {
  25. return gzip.NewReader(r)
  26. }
  27. zr := v.(*gzip.Reader)
  28. if err := zr.Reset(r); err != nil {
  29. return nil, err
  30. }
  31. return zr, nil
  32. }
  33. func releaseGzipReader(zr *gzip.Reader) {
  34. zr.Close()
  35. gzipReaderPool.Put(zr)
  36. }
  37. var gzipReaderPool sync.Pool
  38. func acquireFlateReader(r io.Reader) (io.ReadCloser, error) {
  39. v := flateReaderPool.Get()
  40. if v == nil {
  41. zr, err := zlib.NewReader(r)
  42. if err != nil {
  43. return nil, err
  44. }
  45. return zr, nil
  46. }
  47. zr := v.(io.ReadCloser)
  48. if err := resetFlateReader(zr, r); err != nil {
  49. return nil, err
  50. }
  51. return zr, nil
  52. }
  53. func releaseFlateReader(zr io.ReadCloser) {
  54. zr.Close()
  55. flateReaderPool.Put(zr)
  56. }
  57. func resetFlateReader(zr io.ReadCloser, r io.Reader) error {
  58. zrr, ok := zr.(zlib.Resetter)
  59. if !ok {
  60. panic("BUG: zlib.Reader doesn't implement zlib.Resetter???")
  61. }
  62. return zrr.Reset(r, nil)
  63. }
  64. var flateReaderPool sync.Pool
  65. func acquireStacklessGzipWriter(w io.Writer, level int) stackless.Writer {
  66. nLevel := normalizeCompressLevel(level)
  67. p := stacklessGzipWriterPoolMap[nLevel]
  68. v := p.Get()
  69. if v == nil {
  70. return stackless.NewWriter(w, func(w io.Writer) stackless.Writer {
  71. return acquireRealGzipWriter(w, level)
  72. })
  73. }
  74. sw := v.(stackless.Writer)
  75. sw.Reset(w)
  76. return sw
  77. }
  78. func releaseStacklessGzipWriter(sw stackless.Writer, level int) {
  79. sw.Close()
  80. nLevel := normalizeCompressLevel(level)
  81. p := stacklessGzipWriterPoolMap[nLevel]
  82. p.Put(sw)
  83. }
  84. func acquireRealGzipWriter(w io.Writer, level int) *gzip.Writer {
  85. nLevel := normalizeCompressLevel(level)
  86. p := realGzipWriterPoolMap[nLevel]
  87. v := p.Get()
  88. if v == nil {
  89. zw, err := gzip.NewWriterLevel(w, level)
  90. if err != nil {
  91. panic(fmt.Sprintf("BUG: unexpected error from gzip.NewWriterLevel(%d): %v", level, err))
  92. }
  93. return zw
  94. }
  95. zw := v.(*gzip.Writer)
  96. zw.Reset(w)
  97. return zw
  98. }
  99. func releaseRealGzipWriter(zw *gzip.Writer, level int) {
  100. zw.Close()
  101. nLevel := normalizeCompressLevel(level)
  102. p := realGzipWriterPoolMap[nLevel]
  103. p.Put(zw)
  104. }
  105. var (
  106. stacklessGzipWriterPoolMap = newCompressWriterPoolMap()
  107. realGzipWriterPoolMap = newCompressWriterPoolMap()
  108. )
  109. // AppendGzipBytesLevel appends gzipped src to dst using the given
  110. // compression level and returns the resulting dst.
  111. //
  112. // Supported compression levels are:
  113. //
  114. // - CompressNoCompression
  115. // - CompressBestSpeed
  116. // - CompressBestCompression
  117. // - CompressDefaultCompression
  118. // - CompressHuffmanOnly
  119. func AppendGzipBytesLevel(dst, src []byte, level int) []byte {
  120. w := &byteSliceWriter{dst}
  121. WriteGzipLevel(w, src, level) //nolint:errcheck
  122. return w.b
  123. }
  124. // WriteGzipLevel writes gzipped p to w using the given compression level
  125. // and returns the number of compressed bytes written to w.
  126. //
  127. // Supported compression levels are:
  128. //
  129. // - CompressNoCompression
  130. // - CompressBestSpeed
  131. // - CompressBestCompression
  132. // - CompressDefaultCompression
  133. // - CompressHuffmanOnly
  134. func WriteGzipLevel(w io.Writer, p []byte, level int) (int, error) {
  135. switch w.(type) {
  136. case *byteSliceWriter,
  137. *bytes.Buffer,
  138. *bytebufferpool.ByteBuffer:
  139. // These writers don't block, so we can just use stacklessWriteGzip
  140. ctx := &compressCtx{
  141. w: w,
  142. p: p,
  143. level: level,
  144. }
  145. stacklessWriteGzip(ctx)
  146. return len(p), nil
  147. default:
  148. zw := acquireStacklessGzipWriter(w, level)
  149. n, err := zw.Write(p)
  150. releaseStacklessGzipWriter(zw, level)
  151. return n, err
  152. }
  153. }
  154. var stacklessWriteGzip = stackless.NewFunc(nonblockingWriteGzip)
  155. func nonblockingWriteGzip(ctxv interface{}) {
  156. ctx := ctxv.(*compressCtx)
  157. zw := acquireRealGzipWriter(ctx.w, ctx.level)
  158. _, err := zw.Write(ctx.p)
  159. if err != nil {
  160. panic(fmt.Sprintf("BUG: gzip.Writer.Write for len(p)=%d returned unexpected error: %v", len(ctx.p), err))
  161. }
  162. releaseRealGzipWriter(zw, ctx.level)
  163. }
  164. // WriteGzip writes gzipped p to w and returns the number of compressed
  165. // bytes written to w.
  166. func WriteGzip(w io.Writer, p []byte) (int, error) {
  167. return WriteGzipLevel(w, p, CompressDefaultCompression)
  168. }
  169. // AppendGzipBytes appends gzipped src to dst and returns the resulting dst.
  170. func AppendGzipBytes(dst, src []byte) []byte {
  171. return AppendGzipBytesLevel(dst, src, CompressDefaultCompression)
  172. }
  173. // WriteGunzip writes ungzipped p to w and returns the number of uncompressed
  174. // bytes written to w.
  175. func WriteGunzip(w io.Writer, p []byte) (int, error) {
  176. r := &byteSliceReader{p}
  177. zr, err := acquireGzipReader(r)
  178. if err != nil {
  179. return 0, err
  180. }
  181. n, err := copyZeroAlloc(w, zr)
  182. releaseGzipReader(zr)
  183. nn := int(n)
  184. if int64(nn) != n {
  185. return 0, fmt.Errorf("too much data gunzipped: %d", n)
  186. }
  187. return nn, err
  188. }
  189. // AppendGunzipBytes appends gunzipped src to dst and returns the resulting dst.
  190. func AppendGunzipBytes(dst, src []byte) ([]byte, error) {
  191. w := &byteSliceWriter{dst}
  192. _, err := WriteGunzip(w, src)
  193. return w.b, err
  194. }
  195. // AppendDeflateBytesLevel appends deflated src to dst using the given
  196. // compression level and returns the resulting dst.
  197. //
  198. // Supported compression levels are:
  199. //
  200. // - CompressNoCompression
  201. // - CompressBestSpeed
  202. // - CompressBestCompression
  203. // - CompressDefaultCompression
  204. // - CompressHuffmanOnly
  205. func AppendDeflateBytesLevel(dst, src []byte, level int) []byte {
  206. w := &byteSliceWriter{dst}
  207. WriteDeflateLevel(w, src, level) //nolint:errcheck
  208. return w.b
  209. }
  210. // WriteDeflateLevel writes deflated p to w using the given compression level
  211. // and returns the number of compressed bytes written to w.
  212. //
  213. // Supported compression levels are:
  214. //
  215. // - CompressNoCompression
  216. // - CompressBestSpeed
  217. // - CompressBestCompression
  218. // - CompressDefaultCompression
  219. // - CompressHuffmanOnly
  220. func WriteDeflateLevel(w io.Writer, p []byte, level int) (int, error) {
  221. switch w.(type) {
  222. case *byteSliceWriter,
  223. *bytes.Buffer,
  224. *bytebufferpool.ByteBuffer:
  225. // These writers don't block, so we can just use stacklessWriteDeflate
  226. ctx := &compressCtx{
  227. w: w,
  228. p: p,
  229. level: level,
  230. }
  231. stacklessWriteDeflate(ctx)
  232. return len(p), nil
  233. default:
  234. zw := acquireStacklessDeflateWriter(w, level)
  235. n, err := zw.Write(p)
  236. releaseStacklessDeflateWriter(zw, level)
  237. return n, err
  238. }
  239. }
  240. var stacklessWriteDeflate = stackless.NewFunc(nonblockingWriteDeflate)
  241. func nonblockingWriteDeflate(ctxv interface{}) {
  242. ctx := ctxv.(*compressCtx)
  243. zw := acquireRealDeflateWriter(ctx.w, ctx.level)
  244. _, err := zw.Write(ctx.p)
  245. if err != nil {
  246. panic(fmt.Sprintf("BUG: zlib.Writer.Write for len(p)=%d returned unexpected error: %v", len(ctx.p), err))
  247. }
  248. releaseRealDeflateWriter(zw, ctx.level)
  249. }
  250. type compressCtx struct {
  251. w io.Writer
  252. p []byte
  253. level int
  254. }
  255. // WriteDeflate writes deflated p to w and returns the number of compressed
  256. // bytes written to w.
  257. func WriteDeflate(w io.Writer, p []byte) (int, error) {
  258. return WriteDeflateLevel(w, p, CompressDefaultCompression)
  259. }
  260. // AppendDeflateBytes appends deflated src to dst and returns the resulting dst.
  261. func AppendDeflateBytes(dst, src []byte) []byte {
  262. return AppendDeflateBytesLevel(dst, src, CompressDefaultCompression)
  263. }
  264. // WriteInflate writes inflated p to w and returns the number of uncompressed
  265. // bytes written to w.
  266. func WriteInflate(w io.Writer, p []byte) (int, error) {
  267. r := &byteSliceReader{p}
  268. zr, err := acquireFlateReader(r)
  269. if err != nil {
  270. return 0, err
  271. }
  272. n, err := copyZeroAlloc(w, zr)
  273. releaseFlateReader(zr)
  274. nn := int(n)
  275. if int64(nn) != n {
  276. return 0, fmt.Errorf("too much data inflated: %d", n)
  277. }
  278. return nn, err
  279. }
  280. // AppendInflateBytes appends inflated src to dst and returns the resulting dst.
  281. func AppendInflateBytes(dst, src []byte) ([]byte, error) {
  282. w := &byteSliceWriter{dst}
  283. _, err := WriteInflate(w, src)
  284. return w.b, err
  285. }
  286. type byteSliceWriter struct {
  287. b []byte
  288. }
  289. func (w *byteSliceWriter) Write(p []byte) (int, error) {
  290. w.b = append(w.b, p...)
  291. return len(p), nil
  292. }
  293. type byteSliceReader struct {
  294. b []byte
  295. }
  296. func (r *byteSliceReader) Read(p []byte) (int, error) {
  297. if len(r.b) == 0 {
  298. return 0, io.EOF
  299. }
  300. n := copy(p, r.b)
  301. r.b = r.b[n:]
  302. return n, nil
  303. }
  304. func (r *byteSliceReader) ReadByte() (byte, error) {
  305. if len(r.b) == 0 {
  306. return 0, io.EOF
  307. }
  308. n := r.b[0]
  309. r.b = r.b[1:]
  310. return n, nil
  311. }
  312. func acquireStacklessDeflateWriter(w io.Writer, level int) stackless.Writer {
  313. nLevel := normalizeCompressLevel(level)
  314. p := stacklessDeflateWriterPoolMap[nLevel]
  315. v := p.Get()
  316. if v == nil {
  317. return stackless.NewWriter(w, func(w io.Writer) stackless.Writer {
  318. return acquireRealDeflateWriter(w, level)
  319. })
  320. }
  321. sw := v.(stackless.Writer)
  322. sw.Reset(w)
  323. return sw
  324. }
  325. func releaseStacklessDeflateWriter(sw stackless.Writer, level int) {
  326. sw.Close()
  327. nLevel := normalizeCompressLevel(level)
  328. p := stacklessDeflateWriterPoolMap[nLevel]
  329. p.Put(sw)
  330. }
  331. func acquireRealDeflateWriter(w io.Writer, level int) *zlib.Writer {
  332. nLevel := normalizeCompressLevel(level)
  333. p := realDeflateWriterPoolMap[nLevel]
  334. v := p.Get()
  335. if v == nil {
  336. zw, err := zlib.NewWriterLevel(w, level)
  337. if err != nil {
  338. panic(fmt.Sprintf("BUG: unexpected error from zlib.NewWriterLevel(%d): %v", level, err))
  339. }
  340. return zw
  341. }
  342. zw := v.(*zlib.Writer)
  343. zw.Reset(w)
  344. return zw
  345. }
  346. func releaseRealDeflateWriter(zw *zlib.Writer, level int) {
  347. zw.Close()
  348. nLevel := normalizeCompressLevel(level)
  349. p := realDeflateWriterPoolMap[nLevel]
  350. p.Put(zw)
  351. }
  352. var (
  353. stacklessDeflateWriterPoolMap = newCompressWriterPoolMap()
  354. realDeflateWriterPoolMap = newCompressWriterPoolMap()
  355. )
  356. func newCompressWriterPoolMap() []*sync.Pool {
  357. // Initialize pools for all the compression levels defined
  358. // in https://golang.org/pkg/compress/flate/#pkg-constants .
  359. // Compression levels are normalized with normalizeCompressLevel,
  360. // so the fit [0..11].
  361. var m []*sync.Pool
  362. for i := 0; i < 12; i++ {
  363. m = append(m, &sync.Pool{})
  364. }
  365. return m
  366. }
  367. func isFileCompressible(f *os.File, minCompressRatio float64) bool {
  368. // Try compressing the first 4kb of of the file
  369. // and see if it can be compressed by more than
  370. // the given minCompressRatio.
  371. b := bytebufferpool.Get()
  372. zw := acquireStacklessGzipWriter(b, CompressDefaultCompression)
  373. lr := &io.LimitedReader{
  374. R: f,
  375. N: 4096,
  376. }
  377. _, err := copyZeroAlloc(zw, lr)
  378. releaseStacklessGzipWriter(zw, CompressDefaultCompression)
  379. f.Seek(0, 0) //nolint:errcheck
  380. if err != nil {
  381. return false
  382. }
  383. n := 4096 - lr.N
  384. zn := len(b.B)
  385. bytebufferpool.Put(b)
  386. return float64(zn) < float64(n)*minCompressRatio
  387. }
  388. // normalizes compression level into [0..11], so it could be used as an index
  389. // in *PoolMap.
  390. func normalizeCompressLevel(level int) int {
  391. // -2 is the lowest compression level - CompressHuffmanOnly
  392. // 9 is the highest compression level - CompressBestCompression
  393. if level < -2 || level > 9 {
  394. level = CompressDefaultCompression
  395. }
  396. return level + 2
  397. }