| line | stmt | bran | cond | sub | pod | time | code | 
| 1 | 1 |  |  | 1 |  | 3 | use strict; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 22 |  | 
| 2 | 1 |  |  | 1 |  | 4 | use warnings; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 24 |  | 
| 3 |  |  |  |  |  |  | package App::DubiousHTTP::Tests::Compressed; | 
| 4 | 1 |  |  | 1 |  | 3 | use App::DubiousHTTP::Tests::Common; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 119 |  | 
| 5 | 1 |  |  | 1 |  | 3 | use Compress::Raw::Zlib; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 132 |  | 
| 6 | 1 |  |  | 1 |  | 922 | use Compress::Raw::Lzma; | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 7 |  |  |  |  |  |  |  | 
| 8 |  |  |  |  |  |  | SETUP( | 
| 9 |  |  |  |  |  |  | 'compressed', | 
| 10 |  |  |  |  |  |  | "Variations on content compression", | 
| 11 |  |  |  |  |  |  | <<'DESC', | 
| 12 |  |  |  |  |  |  | Compression of Content is usueally done with a Content-Encoding header and a | 
| 13 |  |  |  |  |  |  | value of 'gzip' (RFC1952) or 'deflate' (RFC1951). Most browsers additionally | 
| 14 |  |  |  |  |  |  | accept RFC1950 compressed data (zlib) if 'deflate' is specified. | 
| 15 |  |  |  |  |  |  | Some browsers also support compression with the Transfer-Encoding header, | 
| 16 |  |  |  |  |  |  | which is actually specified in the HTTP RFC, but most browsers don't. | 
| 17 |  |  |  |  |  |  | Some browsers just guess the encoding, e.g. accept gzip even if deflate is | 
| 18 |  |  |  |  |  |  | specified. | 
| 19 |  |  |  |  |  |  | And some browsers accept x-gzip and x-deflate specifications, and some even | 
| 20 |  |  |  |  |  |  | specifications like "x gzip" or "gzip x". | 
| 21 |  |  |  |  |  |  | Most browsers accept multiple content-encoding headers, even if it does not | 
| 22 |  |  |  |  |  |  | make much sense to compress content twice with the same encoding. | 
| 23 |  |  |  |  |  |  | DESC | 
| 24 |  |  |  |  |  |  |  | 
| 25 |  |  |  |  |  |  | # ------------------------- Tests ---------------------------------------- | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | # these should be fine | 
| 28 |  |  |  |  |  |  | [ 'VALID: correct compressed requests' ], | 
| 29 |  |  |  |  |  |  | [ SHOULDBE_VALID, 'ce:gzip;gzip' => 'content-encoding gzip, served gzipped'], | 
| 30 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:x-gzip;gzip' => 'content-encoding "x-gzip", served gzipped'], # not IE11 | 
| 31 |  |  |  |  |  |  | [ SHOULDBE_VALID, 'ce:deflate;deflate' => 'content-encoding deflate, served with deflate'], | 
| 32 |  |  |  |  |  |  | [ VALID, 'ce:deFLaTe;deflate' => 'content-encoding deflate mixed case, served with deflate'], | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | # various kinds of flush between compression parts | 
| 35 |  |  |  |  |  |  | [ 'UNCOMMON_VALID: various kinds of flush between compression parts' ], | 
| 36 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:gzip;gzip2p,partial' => 'content-encoding gzip, served gzipped with 2 compressed blocks with partial flush in between'], | 
| 37 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:deflate;deflate2p,partial' => 'content-encoding deflate, served with deflate with 2 compressed blocks with partial flush in between'], | 
| 38 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:gzip;gzip2p,block' => 'content-encoding gzip, served gzipped with 2 compressed blocks with block flush in between'], | 
| 39 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:deflate;deflate2p,block' => 'content-encoding deflate, served with deflate with 2 compressed blocks with block flush in between'], | 
| 40 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:gzip;gzip2p,sync' => 'content-encoding gzip, served gzipped with 2 compressed blocks with sync flush in between'], | 
| 41 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:deflate;deflate2p,sync' => 'content-encoding deflate, served with deflate with 2 compressed blocks with sync flush in between'], | 
| 42 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:gzip;gzip2p' => 'content-encoding gzip, served gzipped with 2 compressed blocks with full flush in between'], | 
| 43 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:deflate;deflate2p' => 'content-encoding deflate, served with deflate with 2 compressed blocks with full flush in between'], | 
| 44 |  |  |  |  |  |  | [ INVALID, 'ce:gzip;gzip2p,finish' => 'content-encoding gzip, served gzipped with 2 compressed blocks with finish in between'], | 
| 45 |  |  |  |  |  |  | [ INVALID, 'ce:deflate;deflate2p,finish' => 'content-encoding deflate, served with deflate with 2 compressed blocks with finish in between'], | 
| 46 |  |  |  |  |  |  |  | 
| 47 |  |  |  |  |  |  | [ 'INVALID: only part of data compressed, followed by uncompressed data' ], | 
| 48 |  |  |  |  |  |  | [ INVALID, 'ce:gzip;gzip2s' => 'content-encoding gzip, first segment compressed with gzip, next uncompressed' ], | 
| 49 |  |  |  |  |  |  | [ INVALID, 'ce:deflate;deflate2s' => 'content-encoding deflate, first segment compressed with deflate, next uncompressed' ], | 
| 50 |  |  |  |  |  |  | [ INVALID, 'ce:deflate;zlib2s' => 'content-encoding deflate, first segment compressed with zlib, next uncompressed' ], | 
| 51 |  |  |  |  |  |  | [ INVALID, 'ce:deflate;pkt:zlib+deflate' => 'content-encoding deflate, first segment compressed with zlib but ADLER32 removed, next with deflate in new TCP packet' ], | 
| 52 |  |  |  |  |  |  | [ INVALID, 'ce:deflate;chk:zlib+deflate' => 'content-encoding deflate, first segment compressed with zlib but ADLER32 removed, next with deflate in new chunk with chunked encoding' ], | 
| 53 |  |  |  |  |  |  | [ INVALID, 'ce:deflate;pkt:zlib+deflate+deflate' => 'content-encoding deflate, first segment compressed with zlib but ADLER32 removed, next two with deflate in new TCP packets' ], | 
| 54 |  |  |  |  |  |  | [ INVALID, 'ce:deflate;chk:zlib+deflate+deflate' => 'content-encoding deflate, first segment compressed with zlib but ADLER32 removed, next two with deflate in new chunk with chunked encoding' ], | 
| 55 |  |  |  |  |  |  |  | 
| 56 |  |  |  |  |  |  | [ 'VALID: lzma (supported by at least Opera)' ], | 
| 57 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:lzma;lzma1' => 'content-encoding lzma, lzma1 (lzma_alone) encoded'], | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | [ 'VALID: brotli (supported by at least Firefox when used with https)' ], | 
| 60 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:br;brotli' => 'content-encoding br, encoded with brotli'], | 
| 61 |  |  |  |  |  |  |  | 
| 62 |  |  |  |  |  |  | [ 'INVALID: gzip header combined with zlib (RFC1952) instead of deflate (RFC1951)' ], | 
| 63 |  |  |  |  |  |  | [ INVALID, 'ce:gzip;gzip-zlib' => 'content-encoding gzip, encoded with zlib prefixed by gzip header'], | 
| 64 |  |  |  |  |  |  |  | 
| 65 |  |  |  |  |  |  | # these might be strange/unsupported | 
| 66 |  |  |  |  |  |  | [ 'VALID: less common but valid requests' ], | 
| 67 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:deflate;zlib' => 'content-encoding deflate, served with RFC1950 style deflate (zlib)'], | 
| 68 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:deflate;zlib2p' => 'content-encoding deflate, served with RFC1950 style deflate (zlib) with 2 compressed blocks'], | 
| 69 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:nl-gzip;gzip' => 'content-encoding gzip but with continuation line, served gzipped'], | 
| 70 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:nl-deflate;deflate' => 'content-encoding deflate but with continuation line, served with deflate'], | 
| 71 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:nl-nl-deflate;deflate' => 'content-encoding deflate but with double continuation line, served with deflate'], | 
| 72 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:deflate,;deflate' => 'content-encoding "deflate,", served with deflate'], | 
| 73 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:deflate-nl-,;deflate' => 'content-encoding "deflate ,", served with deflate'], | 
| 74 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:deflate-nl-,-nl-;deflate' => 'content-encoding "deflate , ", served with deflate'], | 
| 75 |  |  |  |  |  |  |  | 
| 76 |  |  |  |  |  |  | # These should be fine according to RFC, but are not supported in the browsers | 
| 77 |  |  |  |  |  |  | # Thus treat is as problem if they get supported. | 
| 78 |  |  |  |  |  |  | [ 'INVALID: transfer-encoding with compression should not be supported' ], | 
| 79 |  |  |  |  |  |  | [ INVALID, 'te:gzip;gzip' => 'transfer-encoding gzip, served gzipped'], | 
| 80 |  |  |  |  |  |  | [ INVALID, 'te:deflate;deflate' => 'transfer-encoding deflate, served with deflate'], | 
| 81 |  |  |  |  |  |  | [ INVALID, 'te:gzip;ce:gzip;gzip;gzip' => 'transfer-encoding and content-encoding gzip, gzipped twice'], | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  | # double encodings | 
| 84 |  |  |  |  |  |  | [ 'VALID: double encodings' ], | 
| 85 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:gzip;ce:gzip;gzip;gzip' => 'double content-encoding header gzip, served twice gzipped'], | 
| 86 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:gzip,gzip;gzip;gzip' => 'single content-encoding header "gzip,gzip", served twice gzipped'], | 
| 87 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:deflate;ce:deflate;deflate;deflate' => 'double content-encoding header deflate, compressed twice with deflate'], | 
| 88 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:deflate,deflate;deflate;deflate' => 'single content-encoding header "deflate,deflate", compressed twice with deflate'], | 
| 89 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:deflate-nl-,-nl-deflate;deflate;deflate' => 'single content-encoding header "deflate , deflate", compressed twice with deflate'], | 
| 90 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:deflate-nl-,-nl-deflate-nl-;deflate;deflate' => 'single content-encoding header "deflate , deflate ", compressed twice with deflate'], | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:gzip;ce:deflate;gzip;deflate' => 'content-encoding header for gzip and deflate, content compressed in this order'], | 
| 93 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:gzip,deflate;gzip;deflate' => 'single content-encoding "gzip,deflate", content compressed in this order'], | 
| 94 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:deflate;ce:gzip;deflate;gzip' => 'content-encoding header for deflate and gzip, content compressed in this order'], | 
| 95 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:deflate,gzip;deflate;gzip' => 'single content-encoding header "deflate,gzip", content compressed in this order'], | 
| 96 |  |  |  |  |  |  |  | 
| 97 |  |  |  |  |  |  | # according to RFC2616 identity SHOULD only be used in Accept-Encoding, not Content-Encoding | 
| 98 |  |  |  |  |  |  | [ 'INVALID: using "content-encoding: identity"' ], | 
| 99 |  |  |  |  |  |  | [ UNCOMMON_INVALID, 'ce:identity', '"content-encoding:identity", served without encoding' ], | 
| 100 |  |  |  |  |  |  | [ UNCOMMON_INVALID, 'ce:identity;ce:identity', 'twice "content-encoding:identity", served without encoding' ], | 
| 101 |  |  |  |  |  |  | [ UNCOMMON_INVALID, 'ce:identity,identity', '"content-encoding:identity,identity", served without encoding' ], | 
| 102 |  |  |  |  |  |  | [ UNCOMMON_INVALID, 'ce:identity;ce:gzip;gzip' => 'content-encoding header for identity and gzip, compressed with gzip'], | 
| 103 |  |  |  |  |  |  | [ UNCOMMON_INVALID, 'ce:identity,gzip;gzip' => 'single content-encoding "identity,gzip", compressed with gzip'], | 
| 104 |  |  |  |  |  |  | [ UNCOMMON_INVALID, 'ce:gzip;ce:identity;gzip' => 'content-encoding header for gzip and identity, compressed with gzip'], | 
| 105 |  |  |  |  |  |  | [ UNCOMMON_INVALID, 'ce:gzip,identity;gzip' => 'single content-encoding header "gzip,identity", compressed with gzip'], | 
| 106 |  |  |  |  |  |  |  | 
| 107 |  |  |  |  |  |  | [ UNCOMMON_INVALID, 'ce:identity;ce:deflate;deflate' => 'content-encoding header for identity and deflate, compressed with deflate'], | 
| 108 |  |  |  |  |  |  | [ UNCOMMON_INVALID, 'ce:identity,deflate;deflate' => 'single content-encoding "identity,deflate", compressed with deflate'], | 
| 109 |  |  |  |  |  |  | [ UNCOMMON_INVALID, 'ce:deflate;ce:identity;deflate' => 'content-encoding header for deflate and identity, compressed with deflate'], | 
| 110 |  |  |  |  |  |  | [ UNCOMMON_INVALID, 'ce:deflate,identity;deflate' => 'single content-encoding header "deflate,identity", compressed with deflate'], | 
| 111 |  |  |  |  |  |  |  | 
| 112 |  |  |  |  |  |  | # triple encodings | 
| 113 |  |  |  |  |  |  | [ 'VALID: triple encodings' ], | 
| 114 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:gzip;ce:deflate;ce:gzip;gzip;deflate;gzip' => 'served gzip + deflate + gzip, separate content-encoding header'], | 
| 115 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:gzip,deflate,gzip;gzip;deflate;gzip' => 'served gzip + deflate + gzip, single content-encoding header'], | 
| 116 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:gzip,deflate;ce:gzip;gzip;deflate;gzip' => 'served gzip + deflate + gzip, two content-encoding headers'], | 
| 117 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:deflate;ce:gzip;ce:deflate;deflate;gzip;deflate' => 'served deflate + gzip + gzip, separate content-encoding header'], | 
| 118 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:deflate,gzip,deflate;deflate;gzip;deflate' => 'served deflate + gzip + deflate, single content-encoding header'], | 
| 119 |  |  |  |  |  |  | [ UNCOMMON_VALID, 'ce:deflate,gzip;ce:deflate;deflate;gzip;deflate' => 'served deflate + gzip + deflate, two content-encoding headers'], | 
| 120 |  |  |  |  |  |  |  | 
| 121 |  |  |  |  |  |  | [ 'INVALID: specified double encodings, but content not or only once encoded or in the wrong order' ], | 
| 122 |  |  |  |  |  |  | [  INVALID, 'ce:gzip;ce:gzip;gzip' => 'double content-encoding header gzip, but served with single gzip'], | 
| 123 |  |  |  |  |  |  | [  INVALID, 'ce:gzip;ce:gzip' => 'double content-encoding header gzip, but served without encoding'], | 
| 124 |  |  |  |  |  |  | [  INVALID, 'ce:deflate;ce:deflate;deflate' => 'double content-encoding header deflate, but served with single deflate'], | 
| 125 |  |  |  |  |  |  | [  INVALID, 'ce:deflate;ce:deflate' => 'double content-encoding header deflate, but server without encoding'], | 
| 126 |  |  |  |  |  |  |  | 
| 127 |  |  |  |  |  |  | [  INVALID, 'ce:gzip;ce:deflate;deflate;gzip' => 'content-encoding header for gzip and deflate, compressed in opposite order'], | 
| 128 |  |  |  |  |  |  | [  INVALID, 'ce:gzip;ce:deflate;deflate' => 'content-encoding header for gzip and deflate, but served only with single deflate'], | 
| 129 |  |  |  |  |  |  | [  INVALID, 'ce:gzip;ce:deflate;gzip' => 'content-encoding header for gzip and deflate, but server only with single gzip'], | 
| 130 |  |  |  |  |  |  | [  INVALID, 'ce:gzip;ce:deflate' => 'content-encoding header for gzip and deflate, server without encoding'], | 
| 131 |  |  |  |  |  |  | [  INVALID, 'ce:gzip,deflate;deflate;gzip' => 'single content-encoding header for "gzip,deflate", compressed in opposite order'], | 
| 132 |  |  |  |  |  |  | [  INVALID, 'ce:gzip,deflate;deflate' => 'single content-encoding header for "gzip,deflate", but served with single deflate'], | 
| 133 |  |  |  |  |  |  | [  INVALID, 'ce:gzip,deflate;gzip' => 'single content-encoding header for "gzip,deflate", but served with single gzip'], | 
| 134 |  |  |  |  |  |  | [  INVALID, 'ce:gzip,deflate' => 'single content-encoding header for "gzip,deflate", but served without encoding'], | 
| 135 |  |  |  |  |  |  |  | 
| 136 |  |  |  |  |  |  | [  INVALID, 'ce:deflate;ce:gzip;gzip;deflate' => 'content-encoding header for deflate and gzip, compressed in opposite order'], | 
| 137 |  |  |  |  |  |  | [  INVALID, 'ce:deflate;ce:gzip;gzip' => 'content-encoding header for deflate and gzip, but served only with single gzip'], | 
| 138 |  |  |  |  |  |  | [  INVALID, 'ce:deflate;ce:gzip;deflate' => 'content-encoding header for deflate and gzip, but server only with single deflate'], | 
| 139 |  |  |  |  |  |  | [  INVALID, 'ce:deflate;ce:gzip' => 'content-encoding header for deflate and gzip, server without encoding'], | 
| 140 |  |  |  |  |  |  | [  INVALID, 'ce:deflate,gzip;gzip;deflate' => 'single content-encoding header for "deflate,gzip", compressed in opposite order'], | 
| 141 |  |  |  |  |  |  | [  INVALID, 'ce:deflate,gzip;gzip' => 'single content-encoding header for "deflate,gzip", but served with single gzip'], | 
| 142 |  |  |  |  |  |  | [  INVALID, 'ce:deflate,gzip;deflate' => 'single content-encoding header for "deflate,gzip", but served with single deflate'], | 
| 143 |  |  |  |  |  |  | [  INVALID, 'ce:deflate,gzip' => 'single content-encoding header for "deflate,gzip", but served without encoding'], | 
| 144 |  |  |  |  |  |  |  | 
| 145 |  |  |  |  |  |  | # and the bad ones | 
| 146 |  |  |  |  |  |  | [ 'INVALID: incorrect compressed response, should not succeed' ], | 
| 147 |  |  |  |  |  |  | [ INVALID, 'ce:x-deflate;deflate' => 'content-encoding x-deflate, served with deflate'], | 
| 148 |  |  |  |  |  |  | [ INVALID, 'ce:x-deflate;zlib' => 'content-encoding x-deflate, served with RFC1950 style deflate (zlib)'], | 
| 149 |  |  |  |  |  |  | [ INVALID, 'ce:gzipx;gzip' => 'content-encoding "gzipx", served with gzip' ], | 
| 150 |  |  |  |  |  |  | [ INVALID, 'ce:xgzip;gzip' => 'content-encoding "xgzip", served with gzip' ], | 
| 151 |  |  |  |  |  |  | [ INVALID, 'ce:gzip_x;gzip' => 'content-encoding "gzip x", served with gzip' ], | 
| 152 |  |  |  |  |  |  | [ INVALID, 'ce:x_gzip;gzip' => 'content-encoding "x gzip", served with gzip' ], | 
| 153 |  |  |  |  |  |  | [ INVALID, 'ce:deflate;gzip' => 'content-encoding deflate but served with gzip'], | 
| 154 |  |  |  |  |  |  | [ INVALID, 'ce:gzip;deflate' => 'content-encoding gzip but served with decode'], | 
| 155 |  |  |  |  |  |  | [ INVALID, 'ce:deflate' => 'content-encoding "deflate", not encoded'], | 
| 156 |  |  |  |  |  |  | [ INVALID, 'ce:deflate,' => 'content-encoding "deflate,", not encoded'], | 
| 157 |  |  |  |  |  |  | [ INVALID, 'ce:deflate-nl-,' => 'content-encoding "deflate ,", not encoded'], | 
| 158 |  |  |  |  |  |  | [ INVALID, 'ce:deflate-nl-,-nl-' => 'content-encoding "deflate , ", not encoded'], | 
| 159 |  |  |  |  |  |  |  | 
| 160 |  |  |  |  |  |  | [ 'INVALID: invalid content-encodings should not be ignored' ], | 
| 161 |  |  |  |  |  |  | [ INVALID, 'ce:gzip_x' => 'content-encoding "gzip x", but not encoded' ], | 
| 162 |  |  |  |  |  |  | [ INVALID, 'ce:deflate;ce:gzip_x;deflate' => 'content-encoding deflate + "gzip x", but only deflated' ], | 
| 163 |  |  |  |  |  |  | [ INVALID, 'ce:gzip_x;ce:deflate;deflate' => 'content-encoding  "gzip x" + deflate, but only deflated' ], | 
| 164 |  |  |  |  |  |  | [ INVALID, 'ce:foo', '"content-encoding:foo" and no encoding' ], | 
| 165 |  |  |  |  |  |  | [ INVALID, 'ce:rfc2047-deflate', '"content-encoding:rfc2047(deflate)" and no encoding' ], | 
| 166 |  |  |  |  |  |  | [ INVALID, 'ce:rfc2047-deflate;deflate', '"content-encoding:rfc2047(deflate)" with encoding' ], | 
| 167 |  |  |  |  |  |  |  | 
| 168 |  |  |  |  |  |  | [ 'VALID: transfer-encoding should be ignored for compression' ], | 
| 169 |  |  |  |  |  |  | [ UNCOMMON_VALID,'te:gzip' => 'transfer-encoding gzip but not compressed'], | 
| 170 |  |  |  |  |  |  |  | 
| 171 |  |  |  |  |  |  | [ 'INVALID: "Hiding the Content-encoding header"' ], | 
| 172 |  |  |  |  |  |  | [ INVALID, 'ce-space-colon-deflate;deflate' => '"Content-Encoding: deflate", served with deflate' ], | 
| 173 |  |  |  |  |  |  | [ UNCOMMON_INVALID, 'ce-space-colon-deflate' => '"Content-Encoding: deflate", served not with deflate' ], | 
| 174 |  |  |  |  |  |  | [ INVALID, 'ce-space-colon-gzip;gzip' => '"Content-Encoding: gzip", served with gzip' ], | 
| 175 |  |  |  |  |  |  | [ UNCOMMON_INVALID, 'ce-space-colon-gzip' => '"Content-Encoding: gzip", served not with gzip' ], | 
| 176 |  |  |  |  |  |  |  | 
| 177 |  |  |  |  |  |  | [ INVALID, 'ce-colon-colon-deflate;deflate' => '"Content-Encoding:: deflate", served with deflate' ], | 
| 178 |  |  |  |  |  |  | [ UNCOMMON_INVALID, 'ce-colon-colon-deflate' => '"Content-Encoding:: deflate", served not with deflate' ], | 
| 179 |  |  |  |  |  |  | [ INVALID, 'ce-colon-colon-gzip;gzip' => '"Content-Encoding:: gzip", served with gzip' ], | 
| 180 |  |  |  |  |  |  | [ UNCOMMON_INVALID, 'ce-colon-colon-gzip' => '"Content-Encoding:: gzip", served not with gzip' ], | 
| 181 |  |  |  |  |  |  |  | 
| 182 |  |  |  |  |  |  | [ INVALID, 'cronly-deflate;deflate' => 'Content-Encoding with only  as line delimiter before, served deflate' ], | 
| 183 |  |  |  |  |  |  | [ INVALID, 'crxonly-deflate;deflate' => 'Only  as line delimiter followed by "xContent-Encoding", served deflate' ], | 
| 184 |  |  |  |  |  |  | [ UNCOMMON_INVALID, 'cronly-deflate' => 'Content-Encoding with only  as line delimiter before, not served deflate' ], | 
| 185 |  |  |  |  |  |  | [ INVALID, 'cronly-gzip;gzip' => 'Content-Encoding with only  as line delimiter before, served gzip' ], | 
| 186 |  |  |  |  |  |  | [ INVALID, 'crxonly-gzip;gzip' => 'Only  as line delimiter followed by "xContent-Encoding", served gzip' ], | 
| 187 |  |  |  |  |  |  | [ UNCOMMON_INVALID, 'cronly-gzip' => 'Content-Encoding with only  as line delimiter before, not served gzip' ], | 
| 188 |  |  |  |  |  |  |  | 
| 189 |  |  |  |  |  |  | [ UNCOMMON_INVALID, 'lfonly-deflate;deflate' => 'Content-Encoding with only  as line delimiter before, served deflate' ], | 
| 190 |  |  |  |  |  |  | [ INVALID, 'lfonly-deflate' => 'Content-Encoding with only  as line delimiter before, not served deflate' ], | 
| 191 |  |  |  |  |  |  | [ UNCOMMON_INVALID, 'lfonly-gzip;gzip' => 'Content-Encoding with only  as line delimiter before, served gzip' ], | 
| 192 |  |  |  |  |  |  | [ INVALID, 'lfonly-gzip' => 'Content-Encoding with only  as line delimiter before, not served gzip' ], | 
| 193 |  |  |  |  |  |  |  | 
| 194 |  |  |  |  |  |  | [ INVALID, 'ce:crdeflate;deflate' => 'Content-Encoding:deflate, served with deflate' ], | 
| 195 |  |  |  |  |  |  | [ INVALID, 'ce:crdeflate' => 'Content-Encoding:deflate, not served with deflate' ], | 
| 196 |  |  |  |  |  |  | [ INVALID, 'ce:cr-deflate;deflate' => 'Content-Encoding:deflate, served with deflate' ], | 
| 197 |  |  |  |  |  |  | [ INVALID, 'ce:cr-deflate' => 'Content-Encoding:deflate, not served with deflate' ], | 
| 198 |  |  |  |  |  |  | [ INVALID, 'ce:crgzip;gzip' => 'Content-Encoding:gzip, served with gzip' ], | 
| 199 |  |  |  |  |  |  | [ INVALID, 'ce:crgzip' => 'Content-Encoding:gzip, not served with gzip' ], | 
| 200 |  |  |  |  |  |  | [ INVALID, 'ce:cr-gzip;gzip' => 'Content-Encoding:gzip, served with gzip' ], | 
| 201 |  |  |  |  |  |  | [ INVALID, 'ce:cr-gzip' => 'Content-Encoding:gzip, not served with gzip' ], | 
| 202 |  |  |  |  |  |  |  | 
| 203 |  |  |  |  |  |  | [ 'INVALID: slightly invalid gzip encodings' ], | 
| 204 |  |  |  |  |  |  | [ INVALID,'ce:gzip;gzip;replace:0,2=1f8c', 'wrong gzip magic header'], | 
| 205 |  |  |  |  |  |  | [ INVALID,'ce:gzip;gzip;replace:2,1=88', 'wrong compression method 88 instead of 08'], | 
| 206 |  |  |  |  |  |  | [ UNCOMMON_VALID,'ce:gzip;gzip;replace:3,1|01', 'set flag FTEXT'], | 
| 207 |  |  |  |  |  |  | [ INVALID,'ce:gzip;gzip;replace:3,1|02', 'set flag FHCRC without having CRC'], | 
| 208 |  |  |  |  |  |  | [ INVALID,'ce:gzip;gzip;replace:3,1|02;replace:10,0=0000', 'set flag FHCRC and add CRC with 0'], | 
| 209 |  |  |  |  |  |  | [ UNCOMMON_VALID,'ce:gzip;gzip;replace:3,1|04;replace:10,0=0000', 'set flag FEXTRA and extra part with XLEN 0'], | 
| 210 |  |  |  |  |  |  | [ UNCOMMON_VALID,'ce:gzip;gzip;replace:3,1|04;replace:10,0=05004170010000', 'set flag FEXTRA and extra part with XLEN 5'], | 
| 211 |  |  |  |  |  |  | [ INVALID,'ce:gzip;gzip;replace:3,1|04;replace:10,0=0500', 'set flag FEXTRA and XLEN 5 but no extra part'], | 
| 212 |  |  |  |  |  |  | [ INVALID,'ce:gzip;gzip-payload-as-extra', 'gzip, but hide the real (deflate) payload inside the EXTRA part'], | 
| 213 |  |  |  |  |  |  | [ UNCOMMON_VALID,'ce:gzip;gzip;replace:3,1|08;replace:10,0=2000', 'set flag FNAME and add short file name'], | 
| 214 |  |  |  |  |  |  | [ UNCOMMON_VALID,'ce:gzip;gzip;replace:3,1|10;replace:10,0=2000', 'set flag FCOMMENT and add short comment'], | 
| 215 |  |  |  |  |  |  | [ INVALID,'ce:gzip;gzip;replace:3,1|20', 'set flag reserved bit 5'], | 
| 216 |  |  |  |  |  |  | [ INVALID,'ce:gzip;gzip;replace:3,1|40', 'set flag reserved bit 6'], | 
| 217 |  |  |  |  |  |  | [ INVALID,'ce:gzip;gzip;replace:3,1|80', 'set flag reserved bit 7'], | 
| 218 |  |  |  |  |  |  | [ INVALID,'ce:gzip;gzip;replace:-8,4^ffffffff', 'invalidate final checksum'], | 
| 219 |  |  |  |  |  |  | [ INVALID,'ce:gzip;gzip;replace:-4,1^ff', 'invalidate length'], | 
| 220 |  |  |  |  |  |  | [ INVALID,'ce:gzip;gzip;replace:-4,4=', 'remove length'], | 
| 221 |  |  |  |  |  |  | [ INVALID,'ce:gzip;gzip;replace:-8,8=', 'remove checksum and length'], | 
| 222 |  |  |  |  |  |  | [ INVALID,'ce:gzip;gzip;replace:-4,4=;clen+4', 'remove length but set content-length header to original size'], | 
| 223 |  |  |  |  |  |  | [ INVALID,'ce:gzip;gzip;replace:-8,8=;clen+8', 'remove checksum and length but set content-length header to original size'], | 
| 224 |  |  |  |  |  |  | [ INVALID,'ce:gzip;gzip;replace:-4,4=;noclen', 'remove length and close with eof without sending length'], | 
| 225 |  |  |  |  |  |  | [ INVALID,'ce:gzip;gzip;replace:-8,8=;noclen', 'remove checksum and and close with eof without sending length'], | 
| 226 |  |  |  |  |  |  | # and now hide the 'gzip' behind a \r so that some firewalls will use the | 
| 227 |  |  |  |  |  |  | # heuristics of the antivirus which might be different from the the proxy | 
| 228 |  |  |  |  |  |  | [ INVALID,'ce:cr-gzip;gzip;replace:3,1|01', 'set flag FTEXT (hide gzip with "content-encoding:\r gzip")'], | 
| 229 |  |  |  |  |  |  | [ INVALID,'ce:cr-gzip;gzip;replace:3,1|02;replace:10,0=0000', 'set flag FHCRC and add CRC with 0 (hide gzip with "content-encoding:\r gzip")'], | 
| 230 |  |  |  |  |  |  | [ INVALID,'ce:cr-gzip;gzip;replace:3,1|08;replace:10,0=2000', 'set flag FNAME and add short file name (hide gzip with "content-encoding:\r gzip")'], | 
| 231 |  |  |  |  |  |  | [ INVALID,'ce:cr-gzip;gzip;replace:3,1|10;replace:10,0=2000', 'set flag FCOMMENT and add short comment (hide gzip with "content-encoding:\r gzip")'], | 
| 232 |  |  |  |  |  |  | [ INVALID,'ce:cr-gzip;gzip;replace:3,1|04;replace:10,0=0000', 'set flag FEXTRA and extra part with XLEN 0 (hide gzip with "content-encoding:\r gzip")'], | 
| 233 |  |  |  |  |  |  | [ INVALID,'ce:cr-gzip;gzip;replace:3,1|04;replace:10,0=05004170010000', 'set flag FEXTRA and extra part with XLEN 5 (hide gzip with "content-encoding:\r gzip")'], | 
| 234 |  |  |  |  |  |  | [ INVALID,'ce:cr-gzip;gzip;replace:3,1|20', 'set flag reserved bit 5 (hide gzip with "content-encoding:\r gzip")'], | 
| 235 |  |  |  |  |  |  | [ INVALID,'ce:cr-gzip;gzip;replace:3,1|40', 'set flag reserved bit 6 (hide gzip with "content-encoding:\r gzip")'], | 
| 236 |  |  |  |  |  |  | [ INVALID,'ce:cr-gzip;gzip;replace:3,1|80', 'set flag reserved bit 7 (hide gzip with "content-encoding:\r gzip")'], | 
| 237 |  |  |  |  |  |  | [ INVALID,'ce:cr-gzip;gzip;replace:-8,4^ffffffff', 'invalidate final checksum (hide gzip with "content-encoding:\r gzip")'], | 
| 238 |  |  |  |  |  |  | [ INVALID,'ce:cr-gzip;gzip;replace:-4,1^ff', 'invalidate length (hide gzip with "content-encoding:\r gzip")'], | 
| 239 |  |  |  |  |  |  | [ INVALID,'ce:cr-gzip;gzip;replace:-4,4=', 'remove length (hide gzip with "content-encoding:\r gzip")'], | 
| 240 |  |  |  |  |  |  | [ INVALID,'ce:cr-gzip;gzip;replace:-8,8=', 'remove checksum and length (hide gzip with "content-encoding:\r gzip")'], | 
| 241 |  |  |  |  |  |  | # same game, but with Content-Encoding: for other firewalls | 
| 242 |  |  |  |  |  |  | [ INVALID,'ce-space-colon-gzip;gzip;replace:3,1|01', 'set flag FTEXT (hide gzip with "content-encoding : gzip")'], | 
| 243 |  |  |  |  |  |  | [ INVALID,'ce-space-colon-gzip;gzip;replace:3,1|02;replace:10,0=0000', 'set flag FHCRC and add CRC with 0 (hide gzip with "content-encoding : gzip")'], | 
| 244 |  |  |  |  |  |  | [ INVALID,'ce-space-colon-gzip;gzip;replace:3,1|08;replace:10,0=2000', 'set flag FNAME and add short file name (hide gzip with "content-encoding : gzip")'], | 
| 245 |  |  |  |  |  |  | [ INVALID,'ce-space-colon-gzip;gzip;replace:3,1|10;replace:10,0=2000', 'set flag FCOMMENT and add short comment (hide gzip with "content-encoding : gzip")'], | 
| 246 |  |  |  |  |  |  | [ INVALID,'ce-space-colon-gzip;gzip;replace:3,1|04;replace:10,0=0000', 'set flag FEXTRA and extra part with XLEN 0 (hide gzip with "content-encoding : gzip")'], | 
| 247 |  |  |  |  |  |  | [ INVALID,'ce-space-colon-gzip;gzip;replace:3,1|04;replace:10,0=05004170010000', 'set flag FEXTRA and extra part with XLEN 5 (hide gzip with "content-encoding : gzip")'], | 
| 248 |  |  |  |  |  |  | [ INVALID,'ce-space-colon-gzip;gzip;replace:3,1|20', 'set flag reserved bit 5 (hide gzip with "content-encoding : gzip")'], | 
| 249 |  |  |  |  |  |  | [ INVALID,'ce-space-colon-gzip;gzip;replace:3,1|40', 'set flag reserved bit 6 (hide gzip with "content-encoding : gzip")'], | 
| 250 |  |  |  |  |  |  | [ INVALID,'ce-space-colon-gzip;gzip;replace:3,1|80', 'set flag reserved bit 7 (hide gzip with "content-encoding : gzip")'], | 
| 251 |  |  |  |  |  |  | [ INVALID,'ce-space-colon-gzip;gzip;replace:-8,4^ffffffff', 'invalidate final checksum (hide gzip with "content-encoding : gzip")'], | 
| 252 |  |  |  |  |  |  | [ INVALID,'ce-space-colon-gzip;gzip;replace:-4,1^ff', 'invalidate length (hide gzip with "content-encoding : gzip")'], | 
| 253 |  |  |  |  |  |  | [ INVALID,'ce-space-colon-gzip;gzip;replace:-4,4=', 'remove length (hide gzip with "content-encoding : gzip")'], | 
| 254 |  |  |  |  |  |  | [ INVALID,'ce-space-colon-gzip;gzip;replace:-8,8=', 'remove checksum and length (hide gzip with "content-encoding : gzip")'], | 
| 255 |  |  |  |  |  |  |  | 
| 256 |  |  |  |  |  |  | # data before gzip | 
| 257 |  |  |  |  |  |  | [ INVALID,'ce:gzip;gzip;\012-before-body','new line at start of gzip body' ], | 
| 258 |  |  |  |  |  |  | ); | 
| 259 |  |  |  |  |  |  |  | 
| 260 |  |  |  |  |  |  | sub make_response { | 
| 261 |  |  |  |  |  |  | my ($self,$page,$spec) = @_; | 
| 262 |  |  |  |  |  |  | return make_index_page() if $page eq ''; | 
| 263 |  |  |  |  |  |  | my ($hdr,$data) = content($page,$self->ID."-".$spec) or die "unknown page $page"; | 
| 264 |  |  |  |  |  |  | my $version = '1.1'; | 
| 265 |  |  |  |  |  |  | my $clen_extend; | 
| 266 |  |  |  |  |  |  | my $body_prefix = ''; | 
| 267 |  |  |  |  |  |  | my $te = 'clen'; | 
| 268 |  |  |  |  |  |  | my @data; # preferred against $data if given | 
| 269 |  |  |  |  |  |  | for (split(';',$spec)) { | 
| 270 |  |  |  |  |  |  | if ($_ eq 'ce:rfc2047-deflate') { | 
| 271 |  |  |  |  |  |  | $hdr .= "Content-Encoding: =?UTF-8?B?ZGVmbGF0ZQo=?=\r\n"; | 
| 272 |  |  |  |  |  |  | } elsif ( my ($field,$v) = m{^(ce|te):(.*)$}i ) { | 
| 273 |  |  |  |  |  |  | my $changed; | 
| 274 |  |  |  |  |  |  | $changed++ if $v =~s{(?<=cr|lf|nl)-}{ }g; | 
| 275 |  |  |  |  |  |  | $changed++ if $v =~s{cr}{\r}g; | 
| 276 |  |  |  |  |  |  | $changed++ if $v =~s{lf}{\n}g; | 
| 277 |  |  |  |  |  |  | $changed++ if $v =~s{nl}{\r\n}g; | 
| 278 |  |  |  |  |  |  | $changed++ if $v =~s{_}{ }g; | 
| 279 |  |  |  |  |  |  | $v =~s{(? | 
| 280 |  |  |  |  |  |  | $hdr .= "Connection: close\r\n" if $changed; | 
| 281 |  |  |  |  |  |  | $hdr .= $field eq 'ce' ? 'Content-Encoding:':'Transfer-Encoding:'; | 
| 282 |  |  |  |  |  |  | $hdr .= "$v\r\n"; | 
| 283 |  |  |  |  |  |  | } elsif ( m{^(pkt|chk):zlib\+deflate(\+deflate)?\z} ) { | 
| 284 |  |  |  |  |  |  | # [zlib-header][deflate][more-deflate].... | 
| 285 |  |  |  |  |  |  | # zlib will return with Z_DATA_ERROR when trying to process | 
| 286 |  |  |  |  |  |  | # more-deflate because it actually expected the correct ADLER32 | 
| 287 |  |  |  |  |  |  | # checksum there. Browsers will then assume that this should be | 
| 288 |  |  |  |  |  |  | # raw-deflate instead and retry with an edded zlib header. | 
| 289 |  |  |  |  |  |  | # With some browsers this process can be repeated. | 
| 290 |  |  |  |  |  |  |  | 
| 291 |  |  |  |  |  |  | my ($enc,$nchunks) = ($1, $2? 3:2); | 
| 292 |  |  |  |  |  |  | my $size = int(length($data)/$nchunks); | 
| 293 |  |  |  |  |  |  | @data = (); | 
| 294 |  |  |  |  |  |  | for(my $i=0;$i<$nchunks;$i++) { | 
| 295 |  |  |  |  |  |  | push @data, substr($data,0,$size,''); | 
| 296 |  |  |  |  |  |  | } | 
| 297 |  |  |  |  |  |  | $data[-1] .= $data; # in case something left | 
| 298 |  |  |  |  |  |  | $_ = zlib_compress($_,'deflate') for(@data); | 
| 299 |  |  |  |  |  |  | $data[0] = "\x78\x9c".$data[0]; | 
| 300 |  |  |  |  |  |  | if ($enc eq 'chk') { | 
| 301 |  |  |  |  |  |  | $te = 'chunked'; | 
| 302 |  |  |  |  |  |  | $data = join("", map { | 
| 303 |  |  |  |  |  |  | sprintf("%x\r\n%s\r\n",length($_),$_) | 
| 304 |  |  |  |  |  |  | } (@data,'')); | 
| 305 |  |  |  |  |  |  | @data = (); | 
| 306 |  |  |  |  |  |  | } | 
| 307 |  |  |  |  |  |  | } elsif ( m{^(?:(gzip)|deflate|(zlib))(?:(\d+)([ps]))?(?:,(sync|partial|block|full|finish))?$} ) { | 
| 308 |  |  |  |  |  |  | my $zlib = Compress::Raw::Zlib::Deflate->new( | 
| 309 |  |  |  |  |  |  | -WindowBits => $1 ? WANT_GZIP : $2 ? +MAX_WBITS() : -MAX_WBITS(), | 
| 310 |  |  |  |  |  |  | -AppendOutput => 1, | 
| 311 |  |  |  |  |  |  | ); | 
| 312 |  |  |  |  |  |  | my $size = int(length($data)/($3||1)) || 1; | 
| 313 |  |  |  |  |  |  | my @chunks; | 
| 314 |  |  |  |  |  |  | while ($data ne '') { | 
| 315 |  |  |  |  |  |  | push @chunks,substr($data,0,$size,'') | 
| 316 |  |  |  |  |  |  | } | 
| 317 |  |  |  |  |  |  | my $plain_chunk = ''; | 
| 318 |  |  |  |  |  |  | $plain_chunk = join('',splice(@chunks,1)) if $4 && $4 eq 's'; | 
| 319 |  |  |  |  |  |  |  | 
| 320 |  |  |  |  |  |  | my $flush = | 
| 321 |  |  |  |  |  |  | ! $5 ? Z_FULL_FLUSH : | 
| 322 |  |  |  |  |  |  | $5 eq 'partial' ? Z_PARTIAL_FLUSH : | 
| 323 |  |  |  |  |  |  | $5 eq 'sync'    ? Z_SYNC_FLUSH : | 
| 324 |  |  |  |  |  |  | $5 eq 'full'    ? Z_FULL_FLUSH : | 
| 325 |  |  |  |  |  |  | $5 eq 'block'   ? Z_BLOCK : | 
| 326 |  |  |  |  |  |  | $5 eq 'finish'  ? Z_FINISH : | 
| 327 |  |  |  |  |  |  | die $5; | 
| 328 |  |  |  |  |  |  | my $newdata = ''; | 
| 329 |  |  |  |  |  |  | while (@chunks) { | 
| 330 |  |  |  |  |  |  | $zlib->deflate( shift(@chunks), $newdata); | 
| 331 |  |  |  |  |  |  | if (defined $flush && @chunks) { | 
| 332 |  |  |  |  |  |  | $zlib->flush($newdata,$flush); | 
| 333 |  |  |  |  |  |  | $zlib->deflateReset if $flush == Z_FINISH; | 
| 334 |  |  |  |  |  |  | } | 
| 335 |  |  |  |  |  |  | } | 
| 336 |  |  |  |  |  |  | $zlib->flush($newdata,Z_FINISH); | 
| 337 |  |  |  |  |  |  | $data = $newdata . $plain_chunk; | 
| 338 |  |  |  |  |  |  | } elsif (m{^(lzma[12]|xz)$}) { | 
| 339 |  |  |  |  |  |  | my ($lzma,$status) = | 
| 340 |  |  |  |  |  |  | $_ eq 'xz'    ? Compress::Raw::Lzma::EasyEncoder->new(AppendOutput => 1)  : | 
| 341 |  |  |  |  |  |  | $_ eq 'lzma1' ? Compress::Raw::Lzma::AloneEncoder->new(AppendOutput => 1) : | 
| 342 |  |  |  |  |  |  | Compress::Raw::Lzma::RawEncoder->new(AppendOutput =>1); | 
| 343 |  |  |  |  |  |  | $status == LZMA_OK or die "failed to create LZMA object"; | 
| 344 |  |  |  |  |  |  | my $newdata = ''; | 
| 345 |  |  |  |  |  |  | $lzma->code($data,$newdata) == LZMA_OK or die "failed to lzma encode data"; | 
| 346 |  |  |  |  |  |  | $lzma->flush($newdata,LZMA_FINISH) == LZMA_STREAM_END or die "failed to close lzma stream"; | 
| 347 |  |  |  |  |  |  | $data = $newdata; | 
| 348 |  |  |  |  |  |  |  | 
| 349 |  |  |  |  |  |  | } elsif ($_ eq 'brotli') { | 
| 350 |  |  |  |  |  |  | $data = bro_compress($data) or do { | 
| 351 |  |  |  |  |  |  | # no brotli for this content | 
| 352 |  |  |  |  |  |  | return "HTTP/$version 500 no brotli\r\nContent-length:0\r\n\r\n"; | 
| 353 |  |  |  |  |  |  | }; | 
| 354 |  |  |  |  |  |  | } elsif ($_ eq 'gzip-zlib') { | 
| 355 |  |  |  |  |  |  | my $zlib = Compress::Raw::Zlib::Deflate->new( | 
| 356 |  |  |  |  |  |  | -WindowBits => +MAX_WBITS(), | 
| 357 |  |  |  |  |  |  | -AppendOutput => 1, | 
| 358 |  |  |  |  |  |  | ); | 
| 359 |  |  |  |  |  |  | my $gzip_hdr = pack("CCCCVCC",0x1f,0x8b,0x8,0,0,2,0); | 
| 360 |  |  |  |  |  |  | my $gzip_trailer = pack("VV",Compress::Raw::Zlib::crc32($data),length($data)); | 
| 361 |  |  |  |  |  |  | my $newdata = ''; | 
| 362 |  |  |  |  |  |  | $zlib->deflate($data,$newdata); | 
| 363 |  |  |  |  |  |  | $zlib->flush($newdata,Z_FINISH); | 
| 364 |  |  |  |  |  |  | $data = $gzip_hdr.$newdata.$gzip_trailer; | 
| 365 |  |  |  |  |  |  |  | 
| 366 |  |  |  |  |  |  | } elsif (m{^ce-space-colon-(.*)}) { | 
| 367 |  |  |  |  |  |  | $hdr .= "Content-Encoding : $1\r\n"; | 
| 368 |  |  |  |  |  |  | } elsif (m{^ce-colon-colon-(.*)}) { | 
| 369 |  |  |  |  |  |  | $hdr .= "Content-Encoding:: $1\r\n"; | 
| 370 |  |  |  |  |  |  | } elsif ( my ($crlf,$encoding) = m{^((?:lf|cr|x)+)only-(.*)}) { | 
| 371 |  |  |  |  |  |  | $hdr = "X-Foo: bar" if $hdr !~s{\r\n\z}{}; | 
| 372 |  |  |  |  |  |  | $crlf =~s{cr}{\r}g; | 
| 373 |  |  |  |  |  |  | $crlf =~s{lf}{\n}g; | 
| 374 |  |  |  |  |  |  | $hdr .= $crlf . "Content-Encoding: $encoding\r\n"; | 
| 375 |  |  |  |  |  |  | } elsif ( my ($off,$len,$op,$replacement) = m{replace:(-?\d+),(\d+)([=|^])(.*)}) { | 
| 376 |  |  |  |  |  |  | $replacement = pack('C*',map { hex($_) } $replacement=~m{(..)}g); | 
| 377 |  |  |  |  |  |  | if ($op eq '=') { | 
| 378 |  |  |  |  |  |  | substr($data,$off,$len,$replacement); | 
| 379 |  |  |  |  |  |  | } elsif ($op eq '|') { | 
| 380 |  |  |  |  |  |  | die "'$_' flags are already set" if (substr($data,$off,$len) & $replacement) eq $replacement; | 
| 381 |  |  |  |  |  |  | substr($data,$off,$len) |= $replacement; | 
| 382 |  |  |  |  |  |  | } elsif ($op eq '^') { | 
| 383 |  |  |  |  |  |  | substr($data,$off,$len) ^= $replacement; | 
| 384 |  |  |  |  |  |  | } else { | 
| 385 |  |  |  |  |  |  | die "bad op=$op in '$_'" | 
| 386 |  |  |  |  |  |  | } | 
| 387 |  |  |  |  |  |  |  | 
| 388 |  |  |  |  |  |  | } elsif ( $_ eq 'gzip-payload-as-extra') { | 
| 389 |  |  |  |  |  |  |  | 
| 390 |  |  |  |  |  |  | # header with FEXTRA set | 
| 391 |  |  |  |  |  |  | my $gzip = pack("CCCCVCC",0x1f,0x8b,0x8,0b100,0,2,0); | 
| 392 |  |  |  |  |  |  |  | 
| 393 |  |  |  |  |  |  | # add XLEN + payload with deflate data | 
| 394 |  |  |  |  |  |  | my $zlib = Compress::Raw::Zlib::Deflate->new( | 
| 395 |  |  |  |  |  |  | -WindowBits => -MAX_WBITS(), | 
| 396 |  |  |  |  |  |  | -AppendOutput => 1, | 
| 397 |  |  |  |  |  |  | ); | 
| 398 |  |  |  |  |  |  | my $newdata = ''; | 
| 399 |  |  |  |  |  |  | $zlib->deflate($data,$newdata); | 
| 400 |  |  |  |  |  |  | $zlib->flush($newdata,Z_FINISH); | 
| 401 |  |  |  |  |  |  | $gzip .= pack("v/a*",$newdata); | 
| 402 |  |  |  |  |  |  |  | 
| 403 |  |  |  |  |  |  | # then add some innocent compressed data | 
| 404 |  |  |  |  |  |  | $data = 'This is not what you are looking for.'; | 
| 405 |  |  |  |  |  |  | $zlib = Compress::Raw::Zlib::Deflate->new( | 
| 406 |  |  |  |  |  |  | -WindowBits => -MAX_WBITS(), | 
| 407 |  |  |  |  |  |  | -AppendOutput => 1, | 
| 408 |  |  |  |  |  |  | ); | 
| 409 |  |  |  |  |  |  | $newdata = ''; | 
| 410 |  |  |  |  |  |  | $zlib->deflate($data,$newdata); | 
| 411 |  |  |  |  |  |  | $zlib->flush($newdata,Z_FINISH); | 
| 412 |  |  |  |  |  |  | $gzip .= $newdata; | 
| 413 |  |  |  |  |  |  |  | 
| 414 |  |  |  |  |  |  | # and add the trailer with CRC and length based on the innocent data | 
| 415 |  |  |  |  |  |  | $gzip .= pack("VV",Compress::Raw::Zlib::crc32($data),length($data)); | 
| 416 |  |  |  |  |  |  | $data = $gzip; | 
| 417 |  |  |  |  |  |  |  | 
| 418 |  |  |  |  |  |  | } elsif (m{^clen\+(\d+)$}) { | 
| 419 |  |  |  |  |  |  | $clen_extend = $1 | 
| 420 |  |  |  |  |  |  | } elsif ($_ eq 'noclen') { | 
| 421 |  |  |  |  |  |  | $clen_extend = -1; | 
| 422 |  |  |  |  |  |  | } elsif (m{(.+)-before-body$}) { | 
| 423 |  |  |  |  |  |  | ( my $d = $1 ) =~s{\\([0-7]{3})}{ chr(oct($1)) }esg; | 
| 424 |  |  |  |  |  |  | $body_prefix .= $d; | 
| 425 |  |  |  |  |  |  | } else { | 
| 426 |  |  |  |  |  |  | die $_ | 
| 427 |  |  |  |  |  |  | } | 
| 428 |  |  |  |  |  |  | } | 
| 429 |  |  |  |  |  |  |  | 
| 430 |  |  |  |  |  |  | $data = $body_prefix . $data; | 
| 431 |  |  |  |  |  |  | if (! @data) { | 
| 432 |  |  |  |  |  |  | @data = $data; | 
| 433 |  |  |  |  |  |  | } else { | 
| 434 |  |  |  |  |  |  | $data = join('',@data); | 
| 435 |  |  |  |  |  |  | } | 
| 436 |  |  |  |  |  |  | my $len = length($data); | 
| 437 |  |  |  |  |  |  | if ($te eq 'chunked') { | 
| 438 |  |  |  |  |  |  | $hdr .= "Transfer-Encoding: chunked\r\n" | 
| 439 |  |  |  |  |  |  | } elsif (!$clen_extend) { | 
| 440 |  |  |  |  |  |  | $hdr = "Content-length: ".length($data)."\r\n".$hdr; | 
| 441 |  |  |  |  |  |  | } elsif ($clen_extend<0) { | 
| 442 |  |  |  |  |  |  | $hdr = "Connection: close\r\n$hdr"; | 
| 443 |  |  |  |  |  |  | } else { | 
| 444 |  |  |  |  |  |  | $hdr = "Connection: close\r\nContent-length: ".(length($data)+$clen_extend)."\r\n".$hdr; | 
| 445 |  |  |  |  |  |  | } | 
| 446 |  |  |  |  |  |  | return ( | 
| 447 |  |  |  |  |  |  | "HTTP/$version 200 ok\r\n$hdr\r\n$data[0]", | 
| 448 |  |  |  |  |  |  | (@data>1) ? (@data[1..$#data]):(), | 
| 449 |  |  |  |  |  |  | ); | 
| 450 |  |  |  |  |  |  | } | 
| 451 |  |  |  |  |  |  |  | 
| 452 |  |  |  |  |  |  | 1; |