|
1 Patch origin: upstream |
|
2 Patch status: will be part of next version |
|
3 |
|
4 http://svn.apache.org/viewvc?view=revision&revision=1611426 |
|
5 |
|
6 --- modules/filters/mod_deflate.c 2014/07/17 18:19:00 1611425 |
|
7 +++ modules/filters/mod_deflate.c 2014/07/17 18:20:46 1611426 |
|
8 @@ -37,6 +37,7 @@ |
|
9 #include "httpd.h" |
|
10 #include "http_config.h" |
|
11 #include "http_log.h" |
|
12 +#include "http_core.h" |
|
13 #include "apr_lib.h" |
|
14 #include "apr_strings.h" |
|
15 #include "apr_general.h" |
|
16 @@ -51,6 +52,9 @@ |
|
17 static const char deflateFilterName[] = "DEFLATE"; |
|
18 module AP_MODULE_DECLARE_DATA deflate_module; |
|
19 |
|
20 +#define AP_INFLATE_RATIO_LIMIT 200 |
|
21 +#define AP_INFLATE_RATIO_BURST 3 |
|
22 + |
|
23 typedef struct deflate_filter_config_t |
|
24 { |
|
25 int windowSize; |
|
26 @@ -62,6 +66,12 @@ |
|
27 char *note_output_name; |
|
28 } deflate_filter_config; |
|
29 |
|
30 +typedef struct deflate_dirconf_t { |
|
31 + apr_off_t inflate_limit; |
|
32 + int ratio_limit, |
|
33 + ratio_burst; |
|
34 +} deflate_dirconf_t; |
|
35 + |
|
36 /* RFC 1952 Section 2.3 defines the gzip header: |
|
37 * |
|
38 * +---+---+---+---+---+---+---+---+---+---+ |
|
39 @@ -193,6 +203,14 @@ |
|
40 return c; |
|
41 } |
|
42 |
|
43 +static void *create_deflate_dirconf(apr_pool_t *p, char *dummy) |
|
44 +{ |
|
45 + deflate_dirconf_t *dc = apr_pcalloc(p, sizeof(*dc)); |
|
46 + dc->ratio_limit = AP_INFLATE_RATIO_LIMIT; |
|
47 + dc->ratio_burst = AP_INFLATE_RATIO_BURST; |
|
48 + return dc; |
|
49 +} |
|
50 + |
|
51 static const char *deflate_set_window_size(cmd_parms *cmd, void *dummy, |
|
52 const char *arg) |
|
53 { |
|
54 @@ -284,6 +302,55 @@ |
|
55 return NULL; |
|
56 } |
|
57 |
|
58 + |
|
59 +static const char *deflate_set_inflate_limit(cmd_parms *cmd, void *dirconf, |
|
60 + const char *arg) |
|
61 +{ |
|
62 + deflate_dirconf_t *dc = (deflate_dirconf_t*) dirconf; |
|
63 + char *errp; |
|
64 + |
|
65 + if (APR_SUCCESS != apr_strtoff(&dc->inflate_limit, arg, &errp, 10)) { |
|
66 + return "DeflateInflateLimitRequestBody is not parsable."; |
|
67 + } |
|
68 + if (*errp || dc->inflate_limit < 0) { |
|
69 + return "DeflateInflateLimitRequestBody requires a non-negative integer."; |
|
70 + } |
|
71 + |
|
72 + return NULL; |
|
73 +} |
|
74 + |
|
75 +static const char *deflate_set_inflate_ratio_limit(cmd_parms *cmd, |
|
76 + void *dirconf, |
|
77 + const char *arg) |
|
78 +{ |
|
79 + deflate_dirconf_t *dc = (deflate_dirconf_t*) dirconf; |
|
80 + int i; |
|
81 + |
|
82 + i = atoi(arg); |
|
83 + if (i <= 0) |
|
84 + return "DeflateInflateRatioLimit must be positive"; |
|
85 + |
|
86 + dc->ratio_limit = i; |
|
87 + |
|
88 + return NULL; |
|
89 +} |
|
90 + |
|
91 +static const char *deflate_set_inflate_ratio_burst(cmd_parms *cmd, |
|
92 + void *dirconf, |
|
93 + const char *arg) |
|
94 +{ |
|
95 + deflate_dirconf_t *dc = (deflate_dirconf_t*) dirconf; |
|
96 + int i; |
|
97 + |
|
98 + i = atoi(arg); |
|
99 + if (i <= 0) |
|
100 + return "DeflateInflateRatioBurst must be positive"; |
|
101 + |
|
102 + dc->ratio_burst = i; |
|
103 + |
|
104 + return NULL; |
|
105 +} |
|
106 + |
|
107 typedef struct deflate_ctx_t |
|
108 { |
|
109 z_stream stream; |
|
110 @@ -294,8 +361,26 @@ |
|
111 unsigned char *validation_buffer; |
|
112 apr_size_t validation_buffer_length; |
|
113 int inflate_init; |
|
114 + int ratio_hits; |
|
115 + apr_off_t inflate_total; |
|
116 } deflate_ctx; |
|
117 |
|
118 +/* Check whether the (inflate) ratio exceeds the configured limit/burst. */ |
|
119 +static int check_ratio(request_rec *r, deflate_ctx *ctx, |
|
120 + const deflate_dirconf_t *dc) |
|
121 +{ |
|
122 + if (ctx->stream.total_in) { |
|
123 + int ratio = ctx->stream.total_out / ctx->stream.total_in; |
|
124 + if (ratio < dc->ratio_limit) { |
|
125 + ctx->ratio_hits = 0; |
|
126 + } |
|
127 + else if (++ctx->ratio_hits > dc->ratio_burst) { |
|
128 + return 0; |
|
129 + } |
|
130 + } |
|
131 + return 1; |
|
132 +} |
|
133 + |
|
134 /* Number of validation bytes (CRC and length) after the compressed data */ |
|
135 #define VALIDATION_SIZE 8 |
|
136 /* Do not update ctx->crc, see comment in flush_libz_buffer */ |
|
137 @@ -744,6 +829,8 @@ |
|
138 int zRC; |
|
139 apr_status_t rv; |
|
140 deflate_filter_config *c; |
|
141 + deflate_dirconf_t *dc; |
|
142 + apr_off_t inflate_limit; |
|
143 |
|
144 /* just get out of the way of things we don't want. */ |
|
145 if (mode != AP_MODE_READBYTES) { |
|
146 @@ -751,6 +838,7 @@ |
|
147 } |
|
148 |
|
149 c = ap_get_module_config(r->server->module_config, &deflate_module); |
|
150 + dc = ap_get_module_config(r->per_dir_config, &deflate_module); |
|
151 |
|
152 if (!ctx) { |
|
153 char deflate_hdr[10]; |
|
154 @@ -803,11 +891,13 @@ |
|
155 if (len != 10 || |
|
156 deflate_hdr[0] != deflate_magic[0] || |
|
157 deflate_hdr[1] != deflate_magic[1]) { |
|
158 + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Failed to inflate input: wrong/partial magic bytes"); |
|
159 return APR_EGENERAL; |
|
160 } |
|
161 |
|
162 /* We can't handle flags for now. */ |
|
163 if (deflate_hdr[3] != 0) { |
|
164 + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Failed to inflate input: cannot handle deflate flags"); |
|
165 return APR_EGENERAL; |
|
166 } |
|
167 |
|
168 @@ -831,6 +921,12 @@ |
|
169 apr_brigade_cleanup(ctx->bb); |
|
170 } |
|
171 |
|
172 + inflate_limit = dc->inflate_limit; |
|
173 + if (inflate_limit == 0) { |
|
174 + /* The core is checking the deflated body, we'll check the inflated */ |
|
175 + inflate_limit = ap_get_limit_req_body(f->r); |
|
176 + } |
|
177 + |
|
178 if (APR_BRIGADE_EMPTY(ctx->proc_bb)) { |
|
179 rv = ap_get_brigade(f->next, ctx->bb, mode, block, readbytes); |
|
180 |
|
181 @@ -863,6 +959,17 @@ |
|
182 |
|
183 ctx->stream.next_out = ctx->buffer; |
|
184 len = c->bufferSize - ctx->stream.avail_out; |
|
185 + |
|
186 + ctx->inflate_total += len; |
|
187 + if (inflate_limit && ctx->inflate_total > inflate_limit) { |
|
188 + inflateEnd(&ctx->stream); |
|
189 + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, |
|
190 + "Inflated content length of %" APR_OFF_T_FMT |
|
191 + " is larger than the configured limit" |
|
192 + " of %" APR_OFF_T_FMT, |
|
193 + ctx->inflate_total, inflate_limit); |
|
194 + return APR_ENOSPC; |
|
195 + } |
|
196 |
|
197 ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len); |
|
198 tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len, |
|
199 @@ -891,6 +998,26 @@ |
|
200 ctx->stream.next_out = ctx->buffer; |
|
201 len = c->bufferSize - ctx->stream.avail_out; |
|
202 |
|
203 + ctx->inflate_total += len; |
|
204 + if (inflate_limit && ctx->inflate_total > inflate_limit) { |
|
205 + inflateEnd(&ctx->stream); |
|
206 + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, |
|
207 + "Inflated content length of %" APR_OFF_T_FMT |
|
208 + " is larger than the configured limit" |
|
209 + " of %" APR_OFF_T_FMT, |
|
210 + ctx->inflate_total, inflate_limit); |
|
211 + return APR_ENOSPC; |
|
212 + } |
|
213 + |
|
214 + if (!check_ratio(r, ctx, dc)) { |
|
215 + inflateEnd(&ctx->stream); |
|
216 + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, |
|
217 + "Inflated content ratio is larger than the " |
|
218 + "configured limit %i by %i time(s)", |
|
219 + dc->ratio_limit, dc->ratio_burst); |
|
220 + return APR_EINVAL; |
|
221 + } |
|
222 + |
|
223 ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len); |
|
224 tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len, |
|
225 NULL, f->c->bucket_alloc); |
|
226 @@ -1003,6 +1130,7 @@ |
|
227 int zRC; |
|
228 apr_status_t rv; |
|
229 deflate_filter_config *c; |
|
230 + deflate_dirconf_t *dc; |
|
231 |
|
232 /* Do nothing if asked to filter nothing. */ |
|
233 if (APR_BRIGADE_EMPTY(bb)) { |
|
234 @@ -1010,6 +1138,7 @@ |
|
235 } |
|
236 |
|
237 c = ap_get_module_config(r->server->module_config, &deflate_module); |
|
238 + dc = ap_get_module_config(r->per_dir_config, &deflate_module); |
|
239 |
|
240 if (!ctx) { |
|
241 |
|
242 @@ -1272,6 +1401,14 @@ |
|
243 while (ctx->stream.avail_in != 0) { |
|
244 if (ctx->stream.avail_out == 0) { |
|
245 |
|
246 + if (!check_ratio(r, ctx, dc)) { |
|
247 + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, |
|
248 + "Inflated content ratio is larger than the " |
|
249 + "configured limit %i by %i time(s)", |
|
250 + dc->ratio_limit, dc->ratio_burst); |
|
251 + return APR_EINVAL; |
|
252 + } |
|
253 + |
|
254 ctx->stream.next_out = ctx->buffer; |
|
255 len = c->bufferSize - ctx->stream.avail_out; |
|
256 |
|
257 @@ -1346,12 +1483,20 @@ |
|
258 "Set the Deflate Memory Level (1-9)"), |
|
259 AP_INIT_TAKE1("DeflateCompressionLevel", deflate_set_compressionlevel, NULL, RSRC_CONF, |
|
260 "Set the Deflate Compression Level (1-9)"), |
|
261 + AP_INIT_TAKE1("DeflateInflateLimitRequestBody", deflate_set_inflate_limit, NULL, OR_ALL, |
|
262 + "Set a limit on size of inflated input"), |
|
263 + AP_INIT_TAKE1("DeflateInflateRatioLimit", deflate_set_inflate_ratio_limit, NULL, OR_ALL, |
|
264 + "Set the inflate ratio limit above which inflation is " |
|
265 + "aborted (default: " APR_STRINGIFY(AP_INFLATE_RATIO_LIMIT) ")"), |
|
266 + AP_INIT_TAKE1("DeflateInflateRatioBurst", deflate_set_inflate_ratio_burst, NULL, OR_ALL, |
|
267 + "Set the maximum number of following inflate ratios above limit " |
|
268 + "(default: " APR_STRINGIFY(AP_INFLATE_RATIO_BURST) ")"), |
|
269 {NULL} |
|
270 }; |
|
271 |
|
272 module AP_MODULE_DECLARE_DATA deflate_module = { |
|
273 STANDARD20_MODULE_STUFF, |
|
274 - NULL, /* dir config creater */ |
|
275 + create_deflate_dirconf, /* dir config creater */ |
|
276 NULL, /* dir merger --- default is to override */ |
|
277 create_deflate_server_config, /* server config */ |
|
278 NULL, /* merge server config */ |