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#include <ngx_md5.h>
12e18a033bSKonstantin Ananyev
13e18a033bSKonstantin Ananyev
14e18a033bSKonstantin Ananyevtypedef struct {
15e18a033bSKonstantin Ananyev    ngx_http_complex_value_t  *variable;
16e18a033bSKonstantin Ananyev    ngx_http_complex_value_t  *md5;
17e18a033bSKonstantin Ananyev    ngx_str_t                  secret;
18e18a033bSKonstantin Ananyev} ngx_http_secure_link_conf_t;
19e18a033bSKonstantin Ananyev
20e18a033bSKonstantin Ananyev
21e18a033bSKonstantin Ananyevtypedef struct {
22e18a033bSKonstantin Ananyev    ngx_str_t                  expires;
23e18a033bSKonstantin Ananyev} ngx_http_secure_link_ctx_t;
24e18a033bSKonstantin Ananyev
25e18a033bSKonstantin Ananyev
26e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_secure_link_old_variable(ngx_http_request_t *r,
27e18a033bSKonstantin Ananyev    ngx_http_secure_link_conf_t *conf, ngx_http_variable_value_t *v,
28e18a033bSKonstantin Ananyev    uintptr_t data);
29e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_secure_link_expires_variable(ngx_http_request_t *r,
30e18a033bSKonstantin Ananyev    ngx_http_variable_value_t *v, uintptr_t data);
31e18a033bSKonstantin Ananyevstatic void *ngx_http_secure_link_create_conf(ngx_conf_t *cf);
32e18a033bSKonstantin Ananyevstatic char *ngx_http_secure_link_merge_conf(ngx_conf_t *cf, void *parent,
33e18a033bSKonstantin Ananyev    void *child);
34e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_secure_link_add_variables(ngx_conf_t *cf);
35e18a033bSKonstantin Ananyev
36e18a033bSKonstantin Ananyev
37e18a033bSKonstantin Ananyevstatic ngx_command_t  ngx_http_secure_link_commands[] = {
38e18a033bSKonstantin Ananyev
39e18a033bSKonstantin Ananyev    { ngx_string("secure_link"),
40e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
41e18a033bSKonstantin Ananyev      ngx_http_set_complex_value_slot,
42e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
43e18a033bSKonstantin Ananyev      offsetof(ngx_http_secure_link_conf_t, variable),
44e18a033bSKonstantin Ananyev      NULL },
45e18a033bSKonstantin Ananyev
46e18a033bSKonstantin Ananyev    { ngx_string("secure_link_md5"),
47e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
48e18a033bSKonstantin Ananyev      ngx_http_set_complex_value_slot,
49e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
50e18a033bSKonstantin Ananyev      offsetof(ngx_http_secure_link_conf_t, md5),
51e18a033bSKonstantin Ananyev      NULL },
52e18a033bSKonstantin Ananyev
53e18a033bSKonstantin Ananyev    { ngx_string("secure_link_secret"),
54e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
55e18a033bSKonstantin Ananyev      ngx_conf_set_str_slot,
56e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
57e18a033bSKonstantin Ananyev      offsetof(ngx_http_secure_link_conf_t, secret),
58e18a033bSKonstantin Ananyev      NULL },
59e18a033bSKonstantin Ananyev
60e18a033bSKonstantin Ananyev      ngx_null_command
61e18a033bSKonstantin Ananyev};
62e18a033bSKonstantin Ananyev
63e18a033bSKonstantin Ananyev
64e18a033bSKonstantin Ananyevstatic ngx_http_module_t  ngx_http_secure_link_module_ctx = {
65e18a033bSKonstantin Ananyev    ngx_http_secure_link_add_variables,    /* preconfiguration */
66e18a033bSKonstantin Ananyev    NULL,                                  /* postconfiguration */
67e18a033bSKonstantin Ananyev
68e18a033bSKonstantin Ananyev    NULL,                                  /* create main configuration */
69e18a033bSKonstantin Ananyev    NULL,                                  /* init main configuration */
70e18a033bSKonstantin Ananyev
71e18a033bSKonstantin Ananyev    NULL,                                  /* create server configuration */
72e18a033bSKonstantin Ananyev    NULL,                                  /* merge server configuration */
73e18a033bSKonstantin Ananyev
74e18a033bSKonstantin Ananyev    ngx_http_secure_link_create_conf,      /* create location configuration */
75e18a033bSKonstantin Ananyev    ngx_http_secure_link_merge_conf        /* merge location configuration */
76e18a033bSKonstantin Ananyev};
77e18a033bSKonstantin Ananyev
78e18a033bSKonstantin Ananyev
79e18a033bSKonstantin Ananyevngx_module_t  ngx_http_secure_link_module = {
80e18a033bSKonstantin Ananyev    NGX_MODULE_V1,
81e18a033bSKonstantin Ananyev    &ngx_http_secure_link_module_ctx,      /* module context */
82e18a033bSKonstantin Ananyev    ngx_http_secure_link_commands,         /* module directives */
83e18a033bSKonstantin Ananyev    NGX_HTTP_MODULE,                       /* module type */
84e18a033bSKonstantin Ananyev    NULL,                                  /* init master */
85e18a033bSKonstantin Ananyev    NULL,                                  /* init module */
86e18a033bSKonstantin Ananyev    NULL,                                  /* init process */
87e18a033bSKonstantin Ananyev    NULL,                                  /* init thread */
88e18a033bSKonstantin Ananyev    NULL,                                  /* exit thread */
89e18a033bSKonstantin Ananyev    NULL,                                  /* exit process */
90e18a033bSKonstantin Ananyev    NULL,                                  /* exit master */
91e18a033bSKonstantin Ananyev    NGX_MODULE_V1_PADDING
92e18a033bSKonstantin Ananyev};
93e18a033bSKonstantin Ananyev
94e18a033bSKonstantin Ananyev
95e18a033bSKonstantin Ananyevstatic ngx_str_t  ngx_http_secure_link_name = ngx_string("secure_link");
96e18a033bSKonstantin Ananyevstatic ngx_str_t  ngx_http_secure_link_expires_name =
97e18a033bSKonstantin Ananyev    ngx_string("secure_link_expires");
98e18a033bSKonstantin Ananyev
99e18a033bSKonstantin Ananyev
100e18a033bSKonstantin Ananyevstatic ngx_int_t
101e18a033bSKonstantin Ananyevngx_http_secure_link_variable(ngx_http_request_t *r,
102e18a033bSKonstantin Ananyev    ngx_http_variable_value_t *v, uintptr_t data)
103e18a033bSKonstantin Ananyev{
104e18a033bSKonstantin Ananyev    u_char                       *p, *last;
105e18a033bSKonstantin Ananyev    ngx_str_t                     val, hash;
106e18a033bSKonstantin Ananyev    time_t                        expires;
107e18a033bSKonstantin Ananyev    ngx_md5_t                     md5;
108e18a033bSKonstantin Ananyev    ngx_http_secure_link_ctx_t   *ctx;
109e18a033bSKonstantin Ananyev    ngx_http_secure_link_conf_t  *conf;
110e18a033bSKonstantin Ananyev    u_char                        hash_buf[16], md5_buf[16];
111e18a033bSKonstantin Ananyev
112e18a033bSKonstantin Ananyev    conf = ngx_http_get_module_loc_conf(r, ngx_http_secure_link_module);
113e18a033bSKonstantin Ananyev
114e18a033bSKonstantin Ananyev    if (conf->secret.data) {
115e18a033bSKonstantin Ananyev        return ngx_http_secure_link_old_variable(r, conf, v, data);
116e18a033bSKonstantin Ananyev    }
117e18a033bSKonstantin Ananyev
118e18a033bSKonstantin Ananyev    if (conf->variable == NULL || conf->md5 == NULL) {
119e18a033bSKonstantin Ananyev        goto not_found;
120e18a033bSKonstantin Ananyev    }
121e18a033bSKonstantin Ananyev
122e18a033bSKonstantin Ananyev    if (ngx_http_complex_value(r, conf->variable, &val) != NGX_OK) {
123e18a033bSKonstantin Ananyev        return NGX_ERROR;
124e18a033bSKonstantin Ananyev    }
125e18a033bSKonstantin Ananyev
126e18a033bSKonstantin Ananyev    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
127e18a033bSKonstantin Ananyev                   "secure link: \"%V\"", &val);
128e18a033bSKonstantin Ananyev
129e18a033bSKonstantin Ananyev    last = val.data + val.len;
130e18a033bSKonstantin Ananyev
131e18a033bSKonstantin Ananyev    p = ngx_strlchr(val.data, last, ',');
132e18a033bSKonstantin Ananyev    expires = 0;
133e18a033bSKonstantin Ananyev
134e18a033bSKonstantin Ananyev    if (p) {
135e18a033bSKonstantin Ananyev        val.len = p++ - val.data;
136e18a033bSKonstantin Ananyev
137e18a033bSKonstantin Ananyev        expires = ngx_atotm(p, last - p);
138e18a033bSKonstantin Ananyev        if (expires <= 0) {
139e18a033bSKonstantin Ananyev            goto not_found;
140e18a033bSKonstantin Ananyev        }
141e18a033bSKonstantin Ananyev
142e18a033bSKonstantin Ananyev        ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_secure_link_ctx_t));
143e18a033bSKonstantin Ananyev        if (ctx == NULL) {
144e18a033bSKonstantin Ananyev            return NGX_ERROR;
145e18a033bSKonstantin Ananyev        }
146e18a033bSKonstantin Ananyev
147e18a033bSKonstantin Ananyev        ngx_http_set_ctx(r, ctx, ngx_http_secure_link_module);
148e18a033bSKonstantin Ananyev
149e18a033bSKonstantin Ananyev        ctx->expires.len = last - p;
150e18a033bSKonstantin Ananyev        ctx->expires.data = p;
151e18a033bSKonstantin Ananyev    }
152e18a033bSKonstantin Ananyev
153e18a033bSKonstantin Ananyev    if (val.len > 24) {
154e18a033bSKonstantin Ananyev        goto not_found;
155e18a033bSKonstantin Ananyev    }
156e18a033bSKonstantin Ananyev
157e18a033bSKonstantin Ananyev    hash.len = 16;
158e18a033bSKonstantin Ananyev    hash.data = hash_buf;
159e18a033bSKonstantin Ananyev
160e18a033bSKonstantin Ananyev    if (ngx_decode_base64url(&hash, &val) != NGX_OK) {
161e18a033bSKonstantin Ananyev        goto not_found;
162e18a033bSKonstantin Ananyev    }
163e18a033bSKonstantin Ananyev
164e18a033bSKonstantin Ananyev    if (hash.len != 16) {
165e18a033bSKonstantin Ananyev        goto not_found;
166e18a033bSKonstantin Ananyev    }
167e18a033bSKonstantin Ananyev
168e18a033bSKonstantin Ananyev    if (ngx_http_complex_value(r, conf->md5, &val) != NGX_OK) {
169e18a033bSKonstantin Ananyev        return NGX_ERROR;
170e18a033bSKonstantin Ananyev    }
171e18a033bSKonstantin Ananyev
172e18a033bSKonstantin Ananyev    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
173e18a033bSKonstantin Ananyev                   "secure link md5: \"%V\"", &val);
174e18a033bSKonstantin Ananyev
175e18a033bSKonstantin Ananyev    ngx_md5_init(&md5);
176e18a033bSKonstantin Ananyev    ngx_md5_update(&md5, val.data, val.len);
177e18a033bSKonstantin Ananyev    ngx_md5_final(md5_buf, &md5);
178e18a033bSKonstantin Ananyev
179e18a033bSKonstantin Ananyev    if (ngx_memcmp(hash_buf, md5_buf, 16) != 0) {
180e18a033bSKonstantin Ananyev        goto not_found;
181e18a033bSKonstantin Ananyev    }
182e18a033bSKonstantin Ananyev
183e18a033bSKonstantin Ananyev    v->data = (u_char *) ((expires && expires < ngx_time()) ? "0" : "1");
184e18a033bSKonstantin Ananyev    v->len = 1;
185e18a033bSKonstantin Ananyev    v->valid = 1;
186e18a033bSKonstantin Ananyev    v->no_cacheable = 0;
187e18a033bSKonstantin Ananyev    v->not_found = 0;
188e18a033bSKonstantin Ananyev
189e18a033bSKonstantin Ananyev    return NGX_OK;
190e18a033bSKonstantin Ananyev
191e18a033bSKonstantin Ananyevnot_found:
192e18a033bSKonstantin Ananyev
193e18a033bSKonstantin Ananyev    v->not_found = 1;
194e18a033bSKonstantin Ananyev
195e18a033bSKonstantin Ananyev    return NGX_OK;
196e18a033bSKonstantin Ananyev}
197e18a033bSKonstantin Ananyev
198e18a033bSKonstantin Ananyev
199e18a033bSKonstantin Ananyevstatic ngx_int_t
200e18a033bSKonstantin Ananyevngx_http_secure_link_old_variable(ngx_http_request_t *r,
201e18a033bSKonstantin Ananyev    ngx_http_secure_link_conf_t *conf, ngx_http_variable_value_t *v,
202e18a033bSKonstantin Ananyev    uintptr_t data)
203e18a033bSKonstantin Ananyev{
204e18a033bSKonstantin Ananyev    u_char      *p, *start, *end, *last;
205e18a033bSKonstantin Ananyev    size_t       len;
206e18a033bSKonstantin Ananyev    ngx_int_t    n;
207e18a033bSKonstantin Ananyev    ngx_uint_t   i;
208e18a033bSKonstantin Ananyev    ngx_md5_t    md5;
209e18a033bSKonstantin Ananyev    u_char       hash[16];
210e18a033bSKonstantin Ananyev
211e18a033bSKonstantin Ananyev    p = &r->unparsed_uri.data[1];
212e18a033bSKonstantin Ananyev    last = r->unparsed_uri.data + r->unparsed_uri.len;
213e18a033bSKonstantin Ananyev
214e18a033bSKonstantin Ananyev    while (p < last) {
215e18a033bSKonstantin Ananyev        if (*p++ == '/') {
216e18a033bSKonstantin Ananyev            start = p;
217e18a033bSKonstantin Ananyev            goto md5_start;
218e18a033bSKonstantin Ananyev        }
219e18a033bSKonstantin Ananyev    }
220e18a033bSKonstantin Ananyev
221e18a033bSKonstantin Ananyev    goto not_found;
222e18a033bSKonstantin Ananyev
223e18a033bSKonstantin Ananyevmd5_start:
224e18a033bSKonstantin Ananyev
225e18a033bSKonstantin Ananyev    while (p < last) {
226e18a033bSKonstantin Ananyev        if (*p++ == '/') {
227e18a033bSKonstantin Ananyev            end = p - 1;
228e18a033bSKonstantin Ananyev            goto url_start;
229e18a033bSKonstantin Ananyev        }
230e18a033bSKonstantin Ananyev    }
231e18a033bSKonstantin Ananyev
232e18a033bSKonstantin Ananyev    goto not_found;
233e18a033bSKonstantin Ananyev
234e18a033bSKonstantin Ananyevurl_start:
235e18a033bSKonstantin Ananyev
236e18a033bSKonstantin Ananyev    len = last - p;
237e18a033bSKonstantin Ananyev
238e18a033bSKonstantin Ananyev    if (end - start != 32 || len == 0) {
239e18a033bSKonstantin Ananyev        goto not_found;
240e18a033bSKonstantin Ananyev    }
241e18a033bSKonstantin Ananyev
242e18a033bSKonstantin Ananyev    ngx_md5_init(&md5);
243e18a033bSKonstantin Ananyev    ngx_md5_update(&md5, p, len);
244e18a033bSKonstantin Ananyev    ngx_md5_update(&md5, conf->secret.data, conf->secret.len);
245e18a033bSKonstantin Ananyev    ngx_md5_final(hash, &md5);
246e18a033bSKonstantin Ananyev
247e18a033bSKonstantin Ananyev    for (i = 0; i < 16; i++) {
248e18a033bSKonstantin Ananyev        n = ngx_hextoi(&start[2 * i], 2);
249e18a033bSKonstantin Ananyev        if (n == NGX_ERROR || n != hash[i]) {
250e18a033bSKonstantin Ananyev            goto not_found;
251e18a033bSKonstantin Ananyev        }
252e18a033bSKonstantin Ananyev    }
253e18a033bSKonstantin Ananyev
254e18a033bSKonstantin Ananyev    v->len = len;
255e18a033bSKonstantin Ananyev    v->valid = 1;
256e18a033bSKonstantin Ananyev    v->no_cacheable = 0;
257e18a033bSKonstantin Ananyev    v->not_found = 0;
258e18a033bSKonstantin Ananyev    v->data = p;
259e18a033bSKonstantin Ananyev
260e18a033bSKonstantin Ananyev    return NGX_OK;
261e18a033bSKonstantin Ananyev
262e18a033bSKonstantin Ananyevnot_found:
263e18a033bSKonstantin Ananyev
264e18a033bSKonstantin Ananyev    v->not_found = 1;
265e18a033bSKonstantin Ananyev
266e18a033bSKonstantin Ananyev    return NGX_OK;
267e18a033bSKonstantin Ananyev}
268e18a033bSKonstantin Ananyev
269e18a033bSKonstantin Ananyev
270e18a033bSKonstantin Ananyevstatic ngx_int_t
271e18a033bSKonstantin Ananyevngx_http_secure_link_expires_variable(ngx_http_request_t *r,
272e18a033bSKonstantin Ananyev    ngx_http_variable_value_t *v, uintptr_t data)
273e18a033bSKonstantin Ananyev{
274e18a033bSKonstantin Ananyev    ngx_http_secure_link_ctx_t  *ctx;
275e18a033bSKonstantin Ananyev
276e18a033bSKonstantin Ananyev    ctx = ngx_http_get_module_ctx(r, ngx_http_secure_link_module);
277e18a033bSKonstantin Ananyev
278e18a033bSKonstantin Ananyev    if (ctx) {
279e18a033bSKonstantin Ananyev        v->len = ctx->expires.len;
280e18a033bSKonstantin Ananyev        v->valid = 1;
281e18a033bSKonstantin Ananyev        v->no_cacheable = 0;
282e18a033bSKonstantin Ananyev        v->not_found = 0;
283e18a033bSKonstantin Ananyev        v->data = ctx->expires.data;
284e18a033bSKonstantin Ananyev
285e18a033bSKonstantin Ananyev    } else {
286e18a033bSKonstantin Ananyev        v->not_found = 1;
287e18a033bSKonstantin Ananyev    }
288e18a033bSKonstantin Ananyev
289e18a033bSKonstantin Ananyev    return NGX_OK;
290e18a033bSKonstantin Ananyev}
291e18a033bSKonstantin Ananyev
292e18a033bSKonstantin Ananyev
293e18a033bSKonstantin Ananyevstatic void *
294e18a033bSKonstantin Ananyevngx_http_secure_link_create_conf(ngx_conf_t *cf)
295e18a033bSKonstantin Ananyev{
296e18a033bSKonstantin Ananyev    ngx_http_secure_link_conf_t  *conf;
297e18a033bSKonstantin Ananyev
298e18a033bSKonstantin Ananyev    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_secure_link_conf_t));
299e18a033bSKonstantin Ananyev    if (conf == NULL) {
300e18a033bSKonstantin Ananyev        return NULL;
301e18a033bSKonstantin Ananyev    }
302e18a033bSKonstantin Ananyev
303e18a033bSKonstantin Ananyev    /*
304e18a033bSKonstantin Ananyev     * set by ngx_pcalloc():
305e18a033bSKonstantin Ananyev     *
306e18a033bSKonstantin Ananyev     *     conf->variable = NULL;
307e18a033bSKonstantin Ananyev     *     conf->md5 = NULL;
308e18a033bSKonstantin Ananyev     *     conf->secret = { 0, NULL };
309e18a033bSKonstantin Ananyev     */
310e18a033bSKonstantin Ananyev
311e18a033bSKonstantin Ananyev    return conf;
312e18a033bSKonstantin Ananyev}
313e18a033bSKonstantin Ananyev
314e18a033bSKonstantin Ananyev
315e18a033bSKonstantin Ananyevstatic char *
316e18a033bSKonstantin Ananyevngx_http_secure_link_merge_conf(ngx_conf_t *cf, void *parent, void *child)
317e18a033bSKonstantin Ananyev{
318e18a033bSKonstantin Ananyev    ngx_http_secure_link_conf_t *prev = parent;
319e18a033bSKonstantin Ananyev    ngx_http_secure_link_conf_t *conf = child;
320e18a033bSKonstantin Ananyev
321e18a033bSKonstantin Ananyev    if (conf->secret.data) {
322e18a033bSKonstantin Ananyev        if (conf->variable || conf->md5) {
323e18a033bSKonstantin Ananyev            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
324e18a033bSKonstantin Ananyev                               "\"secure_link_secret\" cannot be mixed with "
325e18a033bSKonstantin Ananyev                               "\"secure_link\" and \"secure_link_md5\"");
326e18a033bSKonstantin Ananyev            return NGX_CONF_ERROR;
327e18a033bSKonstantin Ananyev        }
328e18a033bSKonstantin Ananyev
329e18a033bSKonstantin Ananyev        return NGX_CONF_OK;
330e18a033bSKonstantin Ananyev    }
331e18a033bSKonstantin Ananyev
332e18a033bSKonstantin Ananyev    if (conf->variable == NULL) {
333e18a033bSKonstantin Ananyev        conf->variable = prev->variable;
334e18a033bSKonstantin Ananyev    }
335e18a033bSKonstantin Ananyev
336e18a033bSKonstantin Ananyev    if (conf->md5 == NULL) {
337e18a033bSKonstantin Ananyev        conf->md5 = prev->md5;
338e18a033bSKonstantin Ananyev    }
339e18a033bSKonstantin Ananyev
340e18a033bSKonstantin Ananyev    if (conf->variable == NULL && conf->md5 == NULL) {
341e18a033bSKonstantin Ananyev        conf->secret = prev->secret;
342e18a033bSKonstantin Ananyev    }
343e18a033bSKonstantin Ananyev
344e18a033bSKonstantin Ananyev    return NGX_CONF_OK;
345e18a033bSKonstantin Ananyev}
346e18a033bSKonstantin Ananyev
347e18a033bSKonstantin Ananyev
348e18a033bSKonstantin Ananyevstatic ngx_int_t
349e18a033bSKonstantin Ananyevngx_http_secure_link_add_variables(ngx_conf_t *cf)
350e18a033bSKonstantin Ananyev{
351e18a033bSKonstantin Ananyev    ngx_http_variable_t  *var;
352e18a033bSKonstantin Ananyev
353e18a033bSKonstantin Ananyev    var = ngx_http_add_variable(cf, &ngx_http_secure_link_name, 0);
354e18a033bSKonstantin Ananyev    if (var == NULL) {
355e18a033bSKonstantin Ananyev        return NGX_ERROR;
356e18a033bSKonstantin Ananyev    }
357e18a033bSKonstantin Ananyev
358e18a033bSKonstantin Ananyev    var->get_handler = ngx_http_secure_link_variable;
359e18a033bSKonstantin Ananyev
360e18a033bSKonstantin Ananyev    var = ngx_http_add_variable(cf, &ngx_http_secure_link_expires_name, 0);
361e18a033bSKonstantin Ananyev    if (var == NULL) {
362e18a033bSKonstantin Ananyev        return NGX_ERROR;
363e18a033bSKonstantin Ananyev    }
364e18a033bSKonstantin Ananyev
365e18a033bSKonstantin Ananyev    var->get_handler = ngx_http_secure_link_expires_variable;
366e18a033bSKonstantin Ananyev
367e18a033bSKonstantin Ananyev    return NGX_OK;
368e18a033bSKonstantin Ananyev}
369