1e18a033bSKonstantin Ananyev
2e18a033bSKonstantin Ananyev/*
3e18a033bSKonstantin Ananyev * Copyright (C) Igor Sysoev
4e18a033bSKonstantin Ananyev * Copyright (C) Nginx, Inc.
5e18a033bSKonstantin Ananyev */
6e18a033bSKonstantin Ananyev
7e18a033bSKonstantin Ananyev
8e18a033bSKonstantin Ananyev#include <ngx_config.h>
9e18a033bSKonstantin Ananyev#include <ngx_core.h>
10e18a033bSKonstantin Ananyev#include <ngx_http.h>
11e18a033bSKonstantin Ananyev
12e18a033bSKonstantin Ananyev#include <gd.h>
13e18a033bSKonstantin Ananyev
14e18a033bSKonstantin Ananyev
15e18a033bSKonstantin Ananyev#define NGX_HTTP_IMAGE_OFF       0
16e18a033bSKonstantin Ananyev#define NGX_HTTP_IMAGE_TEST      1
17e18a033bSKonstantin Ananyev#define NGX_HTTP_IMAGE_SIZE      2
18e18a033bSKonstantin Ananyev#define NGX_HTTP_IMAGE_RESIZE    3
19e18a033bSKonstantin Ananyev#define NGX_HTTP_IMAGE_CROP      4
20e18a033bSKonstantin Ananyev#define NGX_HTTP_IMAGE_ROTATE    5
21e18a033bSKonstantin Ananyev
22e18a033bSKonstantin Ananyev
23e18a033bSKonstantin Ananyev#define NGX_HTTP_IMAGE_START     0
24e18a033bSKonstantin Ananyev#define NGX_HTTP_IMAGE_READ      1
25e18a033bSKonstantin Ananyev#define NGX_HTTP_IMAGE_PROCESS   2
26e18a033bSKonstantin Ananyev#define NGX_HTTP_IMAGE_PASS      3
27e18a033bSKonstantin Ananyev#define NGX_HTTP_IMAGE_DONE      4
28e18a033bSKonstantin Ananyev
29e18a033bSKonstantin Ananyev
30e18a033bSKonstantin Ananyev#define NGX_HTTP_IMAGE_NONE      0
31e18a033bSKonstantin Ananyev#define NGX_HTTP_IMAGE_JPEG      1
32e18a033bSKonstantin Ananyev#define NGX_HTTP_IMAGE_GIF       2
33e18a033bSKonstantin Ananyev#define NGX_HTTP_IMAGE_PNG       3
34e18a033bSKonstantin Ananyev#define NGX_HTTP_IMAGE_WEBP      4
35e18a033bSKonstantin Ananyev
36e18a033bSKonstantin Ananyev
37e18a033bSKonstantin Ananyev#define NGX_HTTP_IMAGE_BUFFERED  0x08
38e18a033bSKonstantin Ananyev
39e18a033bSKonstantin Ananyev
40e18a033bSKonstantin Ananyevtypedef struct {
41e18a033bSKonstantin Ananyev    ngx_uint_t                   filter;
42e18a033bSKonstantin Ananyev    ngx_uint_t                   width;
43e18a033bSKonstantin Ananyev    ngx_uint_t                   height;
44e18a033bSKonstantin Ananyev    ngx_uint_t                   angle;
45e18a033bSKonstantin Ananyev    ngx_uint_t                   jpeg_quality;
46e18a033bSKonstantin Ananyev    ngx_uint_t                   webp_quality;
47e18a033bSKonstantin Ananyev    ngx_uint_t                   sharpen;
48e18a033bSKonstantin Ananyev
49e18a033bSKonstantin Ananyev    ngx_flag_t                   transparency;
50e18a033bSKonstantin Ananyev    ngx_flag_t                   interlace;
51e18a033bSKonstantin Ananyev
52e18a033bSKonstantin Ananyev    ngx_http_complex_value_t    *wcv;
53e18a033bSKonstantin Ananyev    ngx_http_complex_value_t    *hcv;
54e18a033bSKonstantin Ananyev    ngx_http_complex_value_t    *acv;
55e18a033bSKonstantin Ananyev    ngx_http_complex_value_t    *jqcv;
56e18a033bSKonstantin Ananyev    ngx_http_complex_value_t    *wqcv;
57e18a033bSKonstantin Ananyev    ngx_http_complex_value_t    *shcv;
58e18a033bSKonstantin Ananyev
59e18a033bSKonstantin Ananyev    size_t                       buffer_size;
60e18a033bSKonstantin Ananyev} ngx_http_image_filter_conf_t;
61e18a033bSKonstantin Ananyev
62e18a033bSKonstantin Ananyev
63e18a033bSKonstantin Ananyevtypedef struct {
64e18a033bSKonstantin Ananyev    u_char                      *image;
65e18a033bSKonstantin Ananyev    u_char                      *last;
66e18a033bSKonstantin Ananyev
67e18a033bSKonstantin Ananyev    size_t                       length;
68e18a033bSKonstantin Ananyev
69e18a033bSKonstantin Ananyev    ngx_uint_t                   width;
70e18a033bSKonstantin Ananyev    ngx_uint_t                   height;
71e18a033bSKonstantin Ananyev    ngx_uint_t                   max_width;
72e18a033bSKonstantin Ananyev    ngx_uint_t                   max_height;
73e18a033bSKonstantin Ananyev    ngx_uint_t                   angle;
74e18a033bSKonstantin Ananyev
75e18a033bSKonstantin Ananyev    ngx_uint_t                   phase;
76e18a033bSKonstantin Ananyev    ngx_uint_t                   type;
77e18a033bSKonstantin Ananyev    ngx_uint_t                   force;
78e18a033bSKonstantin Ananyev} ngx_http_image_filter_ctx_t;
79e18a033bSKonstantin Ananyev
80e18a033bSKonstantin Ananyev
81e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_image_send(ngx_http_request_t *r,
82e18a033bSKonstantin Ananyev    ngx_http_image_filter_ctx_t *ctx, ngx_chain_t *in);
83e18a033bSKonstantin Ananyevstatic ngx_uint_t ngx_http_image_test(ngx_http_request_t *r, ngx_chain_t *in);
84e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_image_read(ngx_http_request_t *r, ngx_chain_t *in);
85e18a033bSKonstantin Ananyevstatic ngx_buf_t *ngx_http_image_process(ngx_http_request_t *r);
86e18a033bSKonstantin Ananyevstatic ngx_buf_t *ngx_http_image_json(ngx_http_request_t *r,
87e18a033bSKonstantin Ananyev    ngx_http_image_filter_ctx_t *ctx);
88e18a033bSKonstantin Ananyevstatic ngx_buf_t *ngx_http_image_asis(ngx_http_request_t *r,
89e18a033bSKonstantin Ananyev    ngx_http_image_filter_ctx_t *ctx);
90e18a033bSKonstantin Ananyevstatic void ngx_http_image_length(ngx_http_request_t *r, ngx_buf_t *b);
91e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_image_size(ngx_http_request_t *r,
92e18a033bSKonstantin Ananyev    ngx_http_image_filter_ctx_t *ctx);
93e18a033bSKonstantin Ananyev
94e18a033bSKonstantin Ananyevstatic ngx_buf_t *ngx_http_image_resize(ngx_http_request_t *r,
95e18a033bSKonstantin Ananyev    ngx_http_image_filter_ctx_t *ctx);
96e18a033bSKonstantin Ananyevstatic gdImagePtr ngx_http_image_source(ngx_http_request_t *r,
97e18a033bSKonstantin Ananyev    ngx_http_image_filter_ctx_t *ctx);
98e18a033bSKonstantin Ananyevstatic gdImagePtr ngx_http_image_new(ngx_http_request_t *r, int w, int h,
99e18a033bSKonstantin Ananyev    int colors);
100e18a033bSKonstantin Ananyevstatic u_char *ngx_http_image_out(ngx_http_request_t *r, ngx_uint_t type,
101e18a033bSKonstantin Ananyev    gdImagePtr img, int *size);
102e18a033bSKonstantin Ananyevstatic void ngx_http_image_cleanup(void *data);
103e18a033bSKonstantin Ananyevstatic ngx_uint_t ngx_http_image_filter_get_value(ngx_http_request_t *r,
104e18a033bSKonstantin Ananyev    ngx_http_complex_value_t *cv, ngx_uint_t v);
105e18a033bSKonstantin Ananyevstatic ngx_uint_t ngx_http_image_filter_value(ngx_str_t *value);
106e18a033bSKonstantin Ananyev
107e18a033bSKonstantin Ananyev
108e18a033bSKonstantin Ananyevstatic void *ngx_http_image_filter_create_conf(ngx_conf_t *cf);
109e18a033bSKonstantin Ananyevstatic char *ngx_http_image_filter_merge_conf(ngx_conf_t *cf, void *parent,
110e18a033bSKonstantin Ananyev    void *child);
111e18a033bSKonstantin Ananyevstatic char *ngx_http_image_filter(ngx_conf_t *cf, ngx_command_t *cmd,
112e18a033bSKonstantin Ananyev    void *conf);
113e18a033bSKonstantin Ananyevstatic char *ngx_http_image_filter_jpeg_quality(ngx_conf_t *cf,
114e18a033bSKonstantin Ananyev    ngx_command_t *cmd, void *conf);
115e18a033bSKonstantin Ananyevstatic char *ngx_http_image_filter_webp_quality(ngx_conf_t *cf,
116e18a033bSKonstantin Ananyev    ngx_command_t *cmd, void *conf);
117e18a033bSKonstantin Ananyevstatic char *ngx_http_image_filter_sharpen(ngx_conf_t *cf, ngx_command_t *cmd,
118e18a033bSKonstantin Ananyev    void *conf);
119e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_image_filter_init(ngx_conf_t *cf);
120e18a033bSKonstantin Ananyev
121e18a033bSKonstantin Ananyev
122e18a033bSKonstantin Ananyevstatic ngx_command_t  ngx_http_image_filter_commands[] = {
123e18a033bSKonstantin Ananyev
124e18a033bSKonstantin Ananyev    { ngx_string("image_filter"),
125e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
126e18a033bSKonstantin Ananyev      ngx_http_image_filter,
127e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
128e18a033bSKonstantin Ananyev      0,
129e18a033bSKonstantin Ananyev      NULL },
130e18a033bSKonstantin Ananyev
131e18a033bSKonstantin Ananyev    { ngx_string("image_filter_jpeg_quality"),
132e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
133e18a033bSKonstantin Ananyev      ngx_http_image_filter_jpeg_quality,
134e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
135e18a033bSKonstantin Ananyev      0,
136e18a033bSKonstantin Ananyev      NULL },
137e18a033bSKonstantin Ananyev
138e18a033bSKonstantin Ananyev    { ngx_string("image_filter_webp_quality"),
139e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
140e18a033bSKonstantin Ananyev      ngx_http_image_filter_webp_quality,
141e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
142e18a033bSKonstantin Ananyev      0,
143e18a033bSKonstantin Ananyev      NULL },
144e18a033bSKonstantin Ananyev
145e18a033bSKonstantin Ananyev    { ngx_string("image_filter_sharpen"),
146e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
147e18a033bSKonstantin Ananyev      ngx_http_image_filter_sharpen,
148e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
149e18a033bSKonstantin Ananyev      0,
150e18a033bSKonstantin Ananyev      NULL },
151e18a033bSKonstantin Ananyev
152e18a033bSKonstantin Ananyev    { ngx_string("image_filter_transparency"),
153e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
154e18a033bSKonstantin Ananyev      ngx_conf_set_flag_slot,
155e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
156e18a033bSKonstantin Ananyev      offsetof(ngx_http_image_filter_conf_t, transparency),
157e18a033bSKonstantin Ananyev      NULL },
158e18a033bSKonstantin Ananyev
159e18a033bSKonstantin Ananyev    { ngx_string("image_filter_interlace"),
160e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
161e18a033bSKonstantin Ananyev      ngx_conf_set_flag_slot,
162e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
163e18a033bSKonstantin Ananyev      offsetof(ngx_http_image_filter_conf_t, interlace),
164e18a033bSKonstantin Ananyev      NULL },
165e18a033bSKonstantin Ananyev
166e18a033bSKonstantin Ananyev    { ngx_string("image_filter_buffer"),
167e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
168e18a033bSKonstantin Ananyev      ngx_conf_set_size_slot,
169e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
170e18a033bSKonstantin Ananyev      offsetof(ngx_http_image_filter_conf_t, buffer_size),
171e18a033bSKonstantin Ananyev      NULL },
172e18a033bSKonstantin Ananyev
173e18a033bSKonstantin Ananyev      ngx_null_command
174e18a033bSKonstantin Ananyev};
175e18a033bSKonstantin Ananyev
176e18a033bSKonstantin Ananyev
177e18a033bSKonstantin Ananyevstatic ngx_http_module_t  ngx_http_image_filter_module_ctx = {
178e18a033bSKonstantin Ananyev    NULL,                                  /* preconfiguration */
179e18a033bSKonstantin Ananyev    ngx_http_image_filter_init,            /* postconfiguration */
180e18a033bSKonstantin Ananyev
181e18a033bSKonstantin Ananyev    NULL,                                  /* create main configuration */
182e18a033bSKonstantin Ananyev    NULL,                                  /* init main configuration */
183e18a033bSKonstantin Ananyev
184e18a033bSKonstantin Ananyev    NULL,                                  /* create server configuration */
185e18a033bSKonstantin Ananyev    NULL,                                  /* merge server configuration */
186e18a033bSKonstantin Ananyev
187e18a033bSKonstantin Ananyev    ngx_http_image_filter_create_conf,     /* create location configuration */
188e18a033bSKonstantin Ananyev    ngx_http_image_filter_merge_conf       /* merge location configuration */
189e18a033bSKonstantin Ananyev};
190e18a033bSKonstantin Ananyev
191e18a033bSKonstantin Ananyev
192e18a033bSKonstantin Ananyevngx_module_t  ngx_http_image_filter_module = {
193e18a033bSKonstantin Ananyev    NGX_MODULE_V1,
194e18a033bSKonstantin Ananyev    &ngx_http_image_filter_module_ctx,     /* module context */
195e18a033bSKonstantin Ananyev    ngx_http_image_filter_commands,        /* module directives */
196e18a033bSKonstantin Ananyev    NGX_HTTP_MODULE,                       /* module type */
197e18a033bSKonstantin Ananyev    NULL,                                  /* init master */
198e18a033bSKonstantin Ananyev    NULL,                                  /* init module */
199e18a033bSKonstantin Ananyev    NULL,                                  /* init process */
200e18a033bSKonstantin Ananyev    NULL,                                  /* init thread */
201e18a033bSKonstantin Ananyev    NULL,                                  /* exit thread */
202e18a033bSKonstantin Ananyev    NULL,                                  /* exit process */
203e18a033bSKonstantin Ananyev    NULL,                                  /* exit master */
204e18a033bSKonstantin Ananyev    NGX_MODULE_V1_PADDING
205e18a033bSKonstantin Ananyev};
206e18a033bSKonstantin Ananyev
207e18a033bSKonstantin Ananyev
208e18a033bSKonstantin Ananyevstatic ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
209e18a033bSKonstantin Ananyevstatic ngx_http_output_body_filter_pt    ngx_http_next_body_filter;
210e18a033bSKonstantin Ananyev
211e18a033bSKonstantin Ananyev
212e18a033bSKonstantin Ananyevstatic ngx_str_t  ngx_http_image_types[] = {
213e18a033bSKonstantin Ananyev    ngx_string("image/jpeg"),
214e18a033bSKonstantin Ananyev    ngx_string("image/gif"),
215e18a033bSKonstantin Ananyev    ngx_string("image/png"),
216e18a033bSKonstantin Ananyev    ngx_string("image/webp")
217e18a033bSKonstantin Ananyev};
218e18a033bSKonstantin Ananyev
219e18a033bSKonstantin Ananyev
220e18a033bSKonstantin Ananyevstatic ngx_int_t
221e18a033bSKonstantin Ananyevngx_http_image_header_filter(ngx_http_request_t *r)
222e18a033bSKonstantin Ananyev{
223e18a033bSKonstantin Ananyev    off_t                          len;
224e18a033bSKonstantin Ananyev    ngx_http_image_filter_ctx_t   *ctx;
225e18a033bSKonstantin Ananyev    ngx_http_image_filter_conf_t  *conf;
226e18a033bSKonstantin Ananyev
227e18a033bSKonstantin Ananyev    if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED) {
228e18a033bSKonstantin Ananyev        return ngx_http_next_header_filter(r);
229e18a033bSKonstantin Ananyev    }
230e18a033bSKonstantin Ananyev
231e18a033bSKonstantin Ananyev    ctx = ngx_http_get_module_ctx(r, ngx_http_image_filter_module);
232e18a033bSKonstantin Ananyev
233e18a033bSKonstantin Ananyev    if (ctx) {
234e18a033bSKonstantin Ananyev        ngx_http_set_ctx(r, NULL, ngx_http_image_filter_module);
235e18a033bSKonstantin Ananyev        return ngx_http_next_header_filter(r);
236e18a033bSKonstantin Ananyev    }
237e18a033bSKonstantin Ananyev
238e18a033bSKonstantin Ananyev    conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module);
239e18a033bSKonstantin Ananyev
240e18a033bSKonstantin Ananyev    if (conf->filter == NGX_HTTP_IMAGE_OFF) {
241e18a033bSKonstantin Ananyev        return ngx_http_next_header_filter(r);
242e18a033bSKonstantin Ananyev    }
243e18a033bSKonstantin Ananyev
244e18a033bSKonstantin Ananyev    if (r->headers_out.content_type.len
245e18a033bSKonstantin Ananyev            >= sizeof("multipart/x-mixed-replace") - 1
246e18a033bSKonstantin Ananyev        && ngx_strncasecmp(r->headers_out.content_type.data,
247e18a033bSKonstantin Ananyev                           (u_char *) "multipart/x-mixed-replace",
248e18a033bSKonstantin Ananyev                           sizeof("multipart/x-mixed-replace") - 1)
249e18a033bSKonstantin Ananyev           == 0)
250e18a033bSKonstantin Ananyev    {
251e18a033bSKonstantin Ananyev        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
252e18a033bSKonstantin Ananyev                      "image filter: multipart/x-mixed-replace response");
253e18a033bSKonstantin Ananyev
254e18a033bSKonstantin Ananyev        return NGX_ERROR;
255e18a033bSKonstantin Ananyev    }
256e18a033bSKonstantin Ananyev
257e18a033bSKonstantin Ananyev    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_image_filter_ctx_t));
258e18a033bSKonstantin Ananyev    if (ctx == NULL) {
259e18a033bSKonstantin Ananyev        return NGX_ERROR;
260e18a033bSKonstantin Ananyev    }
261e18a033bSKonstantin Ananyev
262e18a033bSKonstantin Ananyev    ngx_http_set_ctx(r, ctx, ngx_http_image_filter_module);
263e18a033bSKonstantin Ananyev
264e18a033bSKonstantin Ananyev    len = r->headers_out.content_length_n;
265e18a033bSKonstantin Ananyev
266e18a033bSKonstantin Ananyev    if (len != -1 && len > (off_t) conf->buffer_size) {
267e18a033bSKonstantin Ananyev        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
268e18a033bSKonstantin Ananyev                      "image filter: too big response: %O", len);
269e18a033bSKonstantin Ananyev
270e18a033bSKonstantin Ananyev        return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE;
271e18a033bSKonstantin Ananyev    }
272e18a033bSKonstantin Ananyev
273e18a033bSKonstantin Ananyev    if (len == -1) {
274e18a033bSKonstantin Ananyev        ctx->length = conf->buffer_size;
275e18a033bSKonstantin Ananyev
276e18a033bSKonstantin Ananyev    } else {
277e18a033bSKonstantin Ananyev        ctx->length = (size_t) len;
278e18a033bSKonstantin Ananyev    }
279e18a033bSKonstantin Ananyev
280e18a033bSKonstantin Ananyev    if (r->headers_out.refresh) {
281e18a033bSKonstantin Ananyev        r->headers_out.refresh->hash = 0;
282e18a033bSKonstantin Ananyev    }
283e18a033bSKonstantin Ananyev
284e18a033bSKonstantin Ananyev    r->main_filter_need_in_memory = 1;
285e18a033bSKonstantin Ananyev    r->allow_ranges = 0;
286e18a033bSKonstantin Ananyev
287e18a033bSKonstantin Ananyev    return NGX_OK;
288e18a033bSKonstantin Ananyev}
289e18a033bSKonstantin Ananyev
290e18a033bSKonstantin Ananyev
291e18a033bSKonstantin Ananyevstatic ngx_int_t
292e18a033bSKonstantin Ananyevngx_http_image_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
293e18a033bSKonstantin Ananyev{
294e18a033bSKonstantin Ananyev    ngx_int_t                      rc;
295e18a033bSKonstantin Ananyev    ngx_str_t                     *ct;
296e18a033bSKonstantin Ananyev    ngx_chain_t                    out;
297e18a033bSKonstantin Ananyev    ngx_http_image_filter_ctx_t   *ctx;
298e18a033bSKonstantin Ananyev    ngx_http_image_filter_conf_t  *conf;
299e18a033bSKonstantin Ananyev
300e18a033bSKonstantin Ananyev    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "image filter");
301e18a033bSKonstantin Ananyev
302e18a033bSKonstantin Ananyev    if (in == NULL) {
303e18a033bSKonstantin Ananyev        return ngx_http_next_body_filter(r, in);
304e18a033bSKonstantin Ananyev    }
305e18a033bSKonstantin Ananyev
306e18a033bSKonstantin Ananyev    ctx = ngx_http_get_module_ctx(r, ngx_http_image_filter_module);
307e18a033bSKonstantin Ananyev
308e18a033bSKonstantin Ananyev    if (ctx == NULL) {
309e18a033bSKonstantin Ananyev        return ngx_http_next_body_filter(r, in);
310e18a033bSKonstantin Ananyev    }
311e18a033bSKonstantin Ananyev
312e18a033bSKonstantin Ananyev    switch (ctx->phase) {
313e18a033bSKonstantin Ananyev
314e18a033bSKonstantin Ananyev    case NGX_HTTP_IMAGE_START:
315e18a033bSKonstantin Ananyev
316e18a033bSKonstantin Ananyev        ctx->type = ngx_http_image_test(r, in);
317e18a033bSKonstantin Ananyev
318e18a033bSKonstantin Ananyev        conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module);
319e18a033bSKonstantin Ananyev
320e18a033bSKonstantin Ananyev        if (ctx->type == NGX_HTTP_IMAGE_NONE) {
321e18a033bSKonstantin Ananyev
322e18a033bSKonstantin Ananyev            if (conf->filter == NGX_HTTP_IMAGE_SIZE) {
323e18a033bSKonstantin Ananyev                out.buf = ngx_http_image_json(r, NULL);
324e18a033bSKonstantin Ananyev
325e18a033bSKonstantin Ananyev                if (out.buf) {
326e18a033bSKonstantin Ananyev                    out.next = NULL;
327e18a033bSKonstantin Ananyev                    ctx->phase = NGX_HTTP_IMAGE_DONE;
328e18a033bSKonstantin Ananyev
329e18a033bSKonstantin Ananyev                    return ngx_http_image_send(r, ctx, &out);
330e18a033bSKonstantin Ananyev                }
331e18a033bSKonstantin Ananyev            }
332e18a033bSKonstantin Ananyev
333e18a033bSKonstantin Ananyev            return ngx_http_filter_finalize_request(r,
334e18a033bSKonstantin Ananyev                                              &ngx_http_image_filter_module,
335e18a033bSKonstantin Ananyev                                              NGX_HTTP_UNSUPPORTED_MEDIA_TYPE);
336e18a033bSKonstantin Ananyev        }
337e18a033bSKonstantin Ananyev
338e18a033bSKonstantin Ananyev        /* override content type */
339e18a033bSKonstantin Ananyev
340e18a033bSKonstantin Ananyev        ct = &ngx_http_image_types[ctx->type - 1];
341e18a033bSKonstantin Ananyev        r->headers_out.content_type_len = ct->len;
342e18a033bSKonstantin Ananyev        r->headers_out.content_type = *ct;
343e18a033bSKonstantin Ananyev        r->headers_out.content_type_lowcase = NULL;
344e18a033bSKonstantin Ananyev
345e18a033bSKonstantin Ananyev        if (conf->filter == NGX_HTTP_IMAGE_TEST) {
346e18a033bSKonstantin Ananyev            ctx->phase = NGX_HTTP_IMAGE_PASS;
347e18a033bSKonstantin Ananyev
348e18a033bSKonstantin Ananyev            return ngx_http_image_send(r, ctx, in);
349e18a033bSKonstantin Ananyev        }
350e18a033bSKonstantin Ananyev
351e18a033bSKonstantin Ananyev        ctx->phase = NGX_HTTP_IMAGE_READ;
352e18a033bSKonstantin Ananyev
353e18a033bSKonstantin Ananyev        /* fall through */
354e18a033bSKonstantin Ananyev
355e18a033bSKonstantin Ananyev    case NGX_HTTP_IMAGE_READ:
356e18a033bSKonstantin Ananyev
357e18a033bSKonstantin Ananyev        rc = ngx_http_image_read(r, in);
358e18a033bSKonstantin Ananyev
359e18a033bSKonstantin Ananyev        if (rc == NGX_AGAIN) {
360e18a033bSKonstantin Ananyev            return NGX_OK;
361e18a033bSKonstantin Ananyev        }
362e18a033bSKonstantin Ananyev
363e18a033bSKonstantin Ananyev        if (rc == NGX_ERROR) {
364e18a033bSKonstantin Ananyev            return ngx_http_filter_finalize_request(r,
365e18a033bSKonstantin Ananyev                                              &ngx_http_image_filter_module,
366e18a033bSKonstantin Ananyev                                              NGX_HTTP_UNSUPPORTED_MEDIA_TYPE);
367e18a033bSKonstantin Ananyev        }
368e18a033bSKonstantin Ananyev
369e18a033bSKonstantin Ananyev        /* fall through */
370e18a033bSKonstantin Ananyev
371e18a033bSKonstantin Ananyev    case NGX_HTTP_IMAGE_PROCESS:
372e18a033bSKonstantin Ananyev
373e18a033bSKonstantin Ananyev        out.buf = ngx_http_image_process(r);
374e18a033bSKonstantin Ananyev
375e18a033bSKonstantin Ananyev        if (out.buf == NULL) {
376e18a033bSKonstantin Ananyev            return ngx_http_filter_finalize_request(r,
377e18a033bSKonstantin Ananyev                                              &ngx_http_image_filter_module,
378e18a033bSKonstantin Ananyev                                              NGX_HTTP_UNSUPPORTED_MEDIA_TYPE);
379e18a033bSKonstantin Ananyev        }
380e18a033bSKonstantin Ananyev
381e18a033bSKonstantin Ananyev        out.next = NULL;
382e18a033bSKonstantin Ananyev        ctx->phase = NGX_HTTP_IMAGE_PASS;
383e18a033bSKonstantin Ananyev
384e18a033bSKonstantin Ananyev        return ngx_http_image_send(r, ctx, &out);
385e18a033bSKonstantin Ananyev
386e18a033bSKonstantin Ananyev    case NGX_HTTP_IMAGE_PASS:
387e18a033bSKonstantin Ananyev
388e18a033bSKonstantin Ananyev        return ngx_http_next_body_filter(r, in);
389e18a033bSKonstantin Ananyev
390e18a033bSKonstantin Ananyev    default: /* NGX_HTTP_IMAGE_DONE */
391e18a033bSKonstantin Ananyev
392e18a033bSKonstantin Ananyev        rc = ngx_http_next_body_filter(r, NULL);
393e18a033bSKonstantin Ananyev
394e18a033bSKonstantin Ananyev        /* NGX_ERROR resets any pending data */
395e18a033bSKonstantin Ananyev        return (rc == NGX_OK) ? NGX_ERROR : rc;
396e18a033bSKonstantin Ananyev    }
397e18a033bSKonstantin Ananyev}
398e18a033bSKonstantin Ananyev
399e18a033bSKonstantin Ananyev
400e18a033bSKonstantin Ananyevstatic ngx_int_t
401e18a033bSKonstantin Ananyevngx_http_image_send(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx,
402e18a033bSKonstantin Ananyev    ngx_chain_t *in)
403e18a033bSKonstantin Ananyev{
404e18a033bSKonstantin Ananyev    ngx_int_t  rc;
405e18a033bSKonstantin Ananyev
406e18a033bSKonstantin Ananyev    rc = ngx_http_next_header_filter(r);
407e18a033bSKonstantin Ananyev
408e18a033bSKonstantin Ananyev    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
409e18a033bSKonstantin Ananyev        return NGX_ERROR;
410e18a033bSKonstantin Ananyev    }
411e18a033bSKonstantin Ananyev
412e18a033bSKonstantin Ananyev    rc = ngx_http_next_body_filter(r, in);
413e18a033bSKonstantin Ananyev
414e18a033bSKonstantin Ananyev    if (ctx->