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
11e18a033bSKonstantin Ananyev
12e18a033bSKonstantin Ananyevssize_t
13e18a033bSKonstantin Ananyevngx_parse_size(ngx_str_t *line)
14e18a033bSKonstantin Ananyev{
15e18a033bSKonstantin Ananyev    u_char   unit;
16e18a033bSKonstantin Ananyev    size_t   len;
17e18a033bSKonstantin Ananyev    ssize_t  size, scale, max;
18e18a033bSKonstantin Ananyev
19e18a033bSKonstantin Ananyev    len = line->len;
20e18a033bSKonstantin Ananyev
21e18a033bSKonstantin Ananyev    if (len == 0) {
22e18a033bSKonstantin Ananyev        return NGX_ERROR;
23e18a033bSKonstantin Ananyev    }
24e18a033bSKonstantin Ananyev
25e18a033bSKonstantin Ananyev    unit = line->data[len - 1];
26e18a033bSKonstantin Ananyev
27e18a033bSKonstantin Ananyev    switch (unit) {
28e18a033bSKonstantin Ananyev    case 'K':
29e18a033bSKonstantin Ananyev    case 'k':
30e18a033bSKonstantin Ananyev        len--;
31e18a033bSKonstantin Ananyev        max = NGX_MAX_SIZE_T_VALUE / 1024;
32e18a033bSKonstantin Ananyev        scale = 1024;
33e18a033bSKonstantin Ananyev        break;
34e18a033bSKonstantin Ananyev
35e18a033bSKonstantin Ananyev    case 'M':
36e18a033bSKonstantin Ananyev    case 'm':
37e18a033bSKonstantin Ananyev        len--;
38e18a033bSKonstantin Ananyev        max = NGX_MAX_SIZE_T_VALUE / (1024 * 1024);
39e18a033bSKonstantin Ananyev        scale = 1024 * 1024;
40e18a033bSKonstantin Ananyev        break;
41e18a033bSKonstantin Ananyev
42e18a033bSKonstantin Ananyev    default:
43e18a033bSKonstantin Ananyev        max = NGX_MAX_SIZE_T_VALUE;
44e18a033bSKonstantin Ananyev        scale = 1;
45e18a033bSKonstantin Ananyev    }
46e18a033bSKonstantin Ananyev
47e18a033bSKonstantin Ananyev    size = ngx_atosz(line->data, len);
48e18a033bSKonstantin Ananyev    if (size == NGX_ERROR || size > max) {
49e18a033bSKonstantin Ananyev        return NGX_ERROR;
50e18a033bSKonstantin Ananyev    }
51e18a033bSKonstantin Ananyev
52e18a033bSKonstantin Ananyev    size *= scale;
53e18a033bSKonstantin Ananyev
54e18a033bSKonstantin Ananyev    return size;
55e18a033bSKonstantin Ananyev}
56e18a033bSKonstantin Ananyev
57e18a033bSKonstantin Ananyev
58e18a033bSKonstantin Ananyevoff_t
59e18a033bSKonstantin Ananyevngx_parse_offset(ngx_str_t *line)
60e18a033bSKonstantin Ananyev{
61e18a033bSKonstantin Ananyev    u_char  unit;
62e18a033bSKonstantin Ananyev    off_t   offset, scale, max;
63e18a033bSKonstantin Ananyev    size_t  len;
64e18a033bSKonstantin Ananyev
65e18a033bSKonstantin Ananyev    len = line->len;
66e18a033bSKonstantin Ananyev
67e18a033bSKonstantin Ananyev    if (len == 0) {
68e18a033bSKonstantin Ananyev        return NGX_ERROR;
69e18a033bSKonstantin Ananyev    }
70e18a033bSKonstantin Ananyev
71e18a033bSKonstantin Ananyev    unit = line->data[len - 1];
72e18a033bSKonstantin Ananyev
73e18a033bSKonstantin Ananyev    switch (unit) {
74e18a033bSKonstantin Ananyev    case 'K':
75e18a033bSKonstantin Ananyev    case 'k':
76e18a033bSKonstantin Ananyev        len--;
77e18a033bSKonstantin Ananyev        max = NGX_MAX_OFF_T_VALUE / 1024;
78e18a033bSKonstantin Ananyev        scale = 1024;
79e18a033bSKonstantin Ananyev        break;
80e18a033bSKonstantin Ananyev
81e18a033bSKonstantin Ananyev    case 'M':
82e18a033bSKonstantin Ananyev    case 'm':
83e18a033bSKonstantin Ananyev        len--;
84e18a033bSKonstantin Ananyev        max = NGX_MAX_OFF_T_VALUE / (1024 * 1024);
85e18a033bSKonstantin Ananyev        scale = 1024 * 1024;
86e18a033bSKonstantin Ananyev        break;
87e18a033bSKonstantin Ananyev
88e18a033bSKonstantin Ananyev    case 'G':
89e18a033bSKonstantin Ananyev    case 'g':
90e18a033bSKonstantin Ananyev        len--;
91e18a033bSKonstantin Ananyev        max = NGX_MAX_OFF_T_VALUE / (1024 * 1024 * 1024);
92e18a033bSKonstantin Ananyev        scale = 1024 * 1024 * 1024;
93e18a033bSKonstantin Ananyev        break;
94e18a033bSKonstantin Ananyev
95e18a033bSKonstantin Ananyev    default:
96e18a033bSKonstantin Ananyev        max = NGX_MAX_OFF_T_VALUE;
97e18a033bSKonstantin Ananyev        scale = 1;
98e18a033bSKonstantin Ananyev    }
99e18a033bSKonstantin Ananyev
100e18a033bSKonstantin Ananyev    offset = ngx_atoof(line->data, len);
101e18a033bSKonstantin Ananyev    if (offset == NGX_ERROR || offset > max) {
102e18a033bSKonstantin Ananyev        return NGX_ERROR;
103e18a033bSKonstantin Ananyev    }
104e18a033bSKonstantin Ananyev
105e18a033bSKonstantin Ananyev    offset *= scale;
106e18a033bSKonstantin Ananyev
107e18a033bSKonstantin Ananyev    return offset;
108e18a033bSKonstantin Ananyev}
109e18a033bSKonstantin Ananyev
110e18a033bSKonstantin Ananyev
111e18a033bSKonstantin Ananyevngx_int_t
112e18a033bSKonstantin Ananyevngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec)
113e18a033bSKonstantin Ananyev{
114e18a033bSKonstantin Ananyev    u_char      *p, *last;
115e18a033bSKonstantin Ananyev    ngx_int_t    value, total, scale;
116e18a033bSKonstantin Ananyev    ngx_int_t    max, cutoff, cutlim;
117e18a033bSKonstantin Ananyev    ngx_uint_t   valid;
118e18a033bSKonstantin Ananyev    enum {
119e18a033bSKonstantin Ananyev        st_start = 0,
120e18a033bSKonstantin Ananyev        st_year,
121e18a033bSKonstantin Ananyev        st_month,
122e18a033bSKonstantin Ananyev        st_week,
123e18a033bSKonstantin Ananyev        st_day,
124e18a033bSKonstantin Ananyev        st_hour,
125e18a033bSKonstantin Ananyev        st_min,
126e18a033bSKonstantin Ananyev        st_sec,
127e18a033bSKonstantin Ananyev        st_msec,
128e18a033bSKonstantin Ananyev        st_last
129e18a033bSKonstantin Ananyev    } step;
130e18a033bSKonstantin Ananyev
131e18a033bSKonstantin Ananyev    valid = 0;
132e18a033bSKonstantin Ananyev    value = 0;
133e18a033bSKonstantin Ananyev    total = 0;
134e18a033bSKonstantin Ananyev    cutoff = NGX_MAX_INT_T_VALUE / 10;
135e18a033bSKonstantin Ananyev    cutlim = NGX_MAX_INT_T_VALUE % 10;
136e18a033bSKonstantin Ananyev    step = is_sec ? st_start : st_month;
137e18a033bSKonstantin Ananyev
138e18a033bSKonstantin Ananyev    p = line->data;
139e18a033bSKonstantin Ananyev    last = p + line->len;
140e18a033bSKonstantin Ananyev
141e18a033bSKonstantin Ananyev    while (p < last) {
142e18a033bSKonstantin Ananyev
143e18a033bSKonstantin Ananyev        if (*p >= '0' && *p <= '9') {
144e18a033bSKonstantin Ananyev            if (value >= cutoff && (value > cutoff || *p - '0' > cutlim)) {
145e18a033bSKonstantin Ananyev                return NGX_ERROR;
146e18a033bSKonstantin Ananyev            }
147e18a033bSKonstantin Ananyev
148e18a033bSKonstantin Ananyev            value = value * 10 + (*p++ - '0');
149e18a033bSKonstantin Ananyev            valid = 1;
150e18a033bSKonstantin Ananyev            continue;
151e18a033bSKonstantin Ananyev        }
152e18a033bSKonstantin Ananyev
153e18a033bSKonstantin Ananyev        switch (*p++) {
154e18a033bSKonstantin Ananyev
155e18a033bSKonstantin Ananyev        case 'y':
156e18a033bSKonstantin Ananyev            if (step > st_start) {
157e18a033bSKonstantin Ananyev                return NGX_ERROR;
158e18a033bSKonstantin Ananyev            }
159e18a033bSKonstantin Ananyev            step = st_year;
160e18a033bSKonstantin Ananyev            max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 365);
161e18a033bSKonstantin Ananyev            scale = 60 * 60 * 24 * 365;
162e18a033bSKonstantin Ananyev            break;
163e18a033bSKonstantin Ananyev
164e18a033bSKonstantin Ananyev        case 'M':
165e18a033bSKonstantin Ananyev            if (step >= st_month) {
166e18a033bSKonstantin Ananyev                return NGX_ERROR;
167e18a033bSKonstantin Ananyev            }
168e18a033bSKonstantin Ananyev            step = st_month;
169e18a033bSKonstantin Ananyev            max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 30);
170e18a033bSKonstantin Ananyev            scale = 60 * 60 * 24 * 30;
171e18a033bSKonstantin Ananyev            break;
172e18a033bSKonstantin Ananyev
173e18a033bSKonstantin Ananyev        case 'w':
174e18a033bSKonstantin Ananyev            if (step >= st_week) {
175e18a033bSKonstantin Ananyev                return NGX_ERROR;
176e18a033bSKonstantin Ananyev            }
177e18a033bSKonstantin Ananyev            step = st_week;
178e18a033bSKonstantin Ananyev            max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 7);
179e18a033bSKonstantin Ananyev            scale = 60 * 60 * 24 * 7;
180e18a033bSKonstantin Ananyev            break;
181e18a033bSKonstantin Ananyev
182e18a033bSKonstantin Ananyev        case 'd':
183e18a033bSKonstantin Ananyev            if (step >= st_day) {
184e18a033bSKonstantin Ananyev                return NGX_ERROR;
185e18a033bSKonstantin Ananyev            }
186e18a033bSKonstantin Ananyev            step = st_day;
187e18a033bSKonstantin Ananyev            max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24);
188e18a033bSKonstantin Ananyev            scale = 60 * 60 * 24;
189e18a033bSKonstantin Ananyev            break;
190e18a033bSKonstantin Ananyev
191e18a033bSKonstantin Ananyev        case 'h':
192e18a033bSKonstantin Ananyev            if (step >= st_hour) {
193e18a033bSKonstantin Ananyev                return NGX_ERROR;
194e18a033bSKonstantin Ananyev            }
195e18a033bSKonstantin Ananyev            step = st_hour;
196e18a033bSKonstantin Ananyev            max = NGX_MAX_INT_T_VALUE / (60 * 60);
197e18a033bSKonstantin Ananyev            scale = 60 * 60;
198e18a033bSKonstantin Ananyev            break;
199e18a033bSKonstantin Ananyev
200e18a033bSKonstantin Ananyev        case 'm':
201e18a033bSKonstantin Ananyev            if (p < last && *p == 's') {
202e18a033bSKonstantin Ananyev                if (is_sec || step >= st_msec) {
203e18a033bSKonstantin Ananyev                    return NGX_ERROR;
204e18a033bSKonstantin Ananyev                }
205e18a033bSKonstantin Ananyev                p++;
206e18a033bSKonstantin Ananyev                step = st_msec;
207e18a033bSKonstantin Ananyev                max = NGX_MAX_INT_T_VALUE;
208e18a033bSKonstantin Ananyev                scale = 1;
209e18a033bSKonstantin Ananyev                break;
210e18a033bSKonstantin Ananyev            }
211e18a033bSKonstantin Ananyev
212e18a033bSKonstantin Ananyev            if (step >= st_min) {
213e18a033bSKonstantin Ananyev                return NGX_ERROR;
214e18a033bSKonstantin Ananyev            }
215e18a033bSKonstantin Ananyev            step = st_min;
216e18a033bSKonstantin Ananyev            max = NGX_MAX_INT_T_VALUE / 60;
217e18a033bSKonstantin Ananyev            scale = 60;
218e18a033bSKonstantin Ananyev            break;
219e18a033bSKonstantin Ananyev
220e18a033bSKonstantin Ananyev        case 's':
221e18a033bSKonstantin Ananyev            if (step >= st_sec) {
222e18a033bSKonstantin Ananyev                return NGX_ERROR;
223e18a033bSKonstantin Ananyev            }
224e18a033bSKonstantin Ananyev            step = st_sec;
225e18a033bSKonstantin Ananyev            max = NGX_MAX_INT_T_VALUE;
226e18a033bSKonstantin Ananyev            scale = 1;
227e18a033bSKonstantin Ananyev            break;
228e18a033bSKonstantin Ananyev
229e18a033bSKonstantin Ananyev        case ' ':
230e18a033bSKonstantin Ananyev            if (step >= st_sec) {
231e18a033bSKonstantin Ananyev                return NGX_ERROR;
232e18a033bSKonstantin Ananyev            }
233e18a033bSKonstantin Ananyev            step = st_last;
234e18a033bSKonstantin Ananyev            max = NGX_MAX_INT_T_VALUE;
235e18a033bSKonstantin Ananyev            scale = 1;
236e18a033bSKonstantin Ananyev            break;
237e18a033bSKonstantin Ananyev
238e18a033bSKonstantin Ananyev        default:
239e18a033bSKonstantin Ananyev            return NGX_ERROR;
240e18a033bSKonstantin Ananyev        }
241e18a033bSKonstantin Ananyev
242e18a033bSKonstantin Ananyev        if (step != st_msec && !is_sec) {
243e18a033bSKonstantin Ananyev            scale *= 1000;
244e18a033bSKonstantin Ananyev            max /= 1000;
245e18a033bSKonstantin Ananyev        }
246e18a033bSKonstantin Ananyev
247e18a033bSKonstantin Ananyev        if (value > max) {
248e18a033bSKonstantin Ananyev            return NGX_ERROR;
249e18a033bSKonstantin Ananyev        }
250e18a033bSKonstantin Ananyev
251e18a033bSKonstantin Ananyev        value *= scale;
252e18a033bSKonstantin Ananyev
253e18a033bSKonstantin Ananyev        if (total > NGX_MAX_INT_T_VALUE - value) {
254e18a033bSKonstantin Ananyev            return NGX_ERROR;
255e18a033bSKonstantin Ananyev        }
256e18a033bSKonstantin Ananyev
257e18a033bSKonstantin Ananyev        total += value;
258e18a033bSKonstantin Ananyev
259e18a033bSKonstantin Ananyev        value = 0;
260e18a033bSKonstantin Ananyev
261e18a033bSKonstantin Ananyev        while (p < last && *p == ' ') {
262e18a033bSKonstantin Ananyev            p++;
263e18a033bSKonstantin Ananyev        }
264e18a033bSKonstantin Ananyev    }
265e18a033bSKonstantin Ananyev
266e18a033bSKonstantin Ananyev    if (!valid) {
267e18a033bSKonstantin Ananyev        return NGX_ERROR;
268e18a033bSKonstantin Ananyev    }
269e18a033bSKonstantin Ananyev
270e18a033bSKonstantin Ananyev    if (!is_sec) {
271e18a033bSKonstantin Ananyev        if (value > NGX_MAX_INT_T_VALUE / 1000) {
272e18a033bSKonstantin Ananyev            return NGX_ERROR;
273e18a033bSKonstantin Ananyev        }
274e18a033bSKonstantin Ananyev
275e18a033bSKonstantin Ananyev        value *= 1000;
276e18a033bSKonstantin Ananyev    }
277e18a033bSKonstantin Ananyev
278e18a033bSKonstantin Ananyev    if (total > NGX_MAX_INT_T_VALUE - value) {
279e18a033bSKonstantin Ananyev        return NGX_ERROR;
280e18a033bSKonstantin Ananyev    }
281e18a033bSKonstantin Ananyev
282e18a033bSKonstantin Ananyev    return total + value;
283e18a033bSKonstantin Ananyev}
284