| /* | |
| * Copyright (C) Igor Sysoev | |
| * Copyright (C) Nginx, Inc. | |
| */ | |
| #include <ngx_config.h> | |
| #include <ngx_core.h> | |
| ssize_t | |
| ngx_parse_size(ngx_str_t *line) | |
| { | |
| u_char unit; | |
| size_t len; | |
| ssize_t size, scale, max; | |
| len = line->len; | |
| if (len == 0) { | |
| return NGX_ERROR; | |
| } | |
| unit = line->data[len - 1]; | |
| switch (unit) { | |
| case 'K': | |
| case 'k': | |
| len--; | |
| max = NGX_MAX_SIZE_T_VALUE / 1024; | |
| scale = 1024; | |
| break; | |
| case 'M': | |
| case 'm': | |
| len--; | |
| max = NGX_MAX_SIZE_T_VALUE / (1024 * 1024); | |
| scale = 1024 * 1024; | |
| break; | |
| default: | |
| max = NGX_MAX_SIZE_T_VALUE; | |
| scale = 1; | |
| } | |
| size = ngx_atosz(line->data, len); | |
| if (size == NGX_ERROR || size > max) { | |
| return NGX_ERROR; | |
| } | |
| size *= scale; | |
| return size; | |
| } | |
| off_t | |
| ngx_parse_offset(ngx_str_t *line) | |
| { | |
| u_char unit; | |
| off_t offset, scale, max; | |
| size_t len; | |
| len = line->len; | |
| if (len == 0) { | |
| return NGX_ERROR; | |
| } | |
| unit = line->data[len - 1]; | |
| switch (unit) { | |
| case 'K': | |
| case 'k': | |
| len--; | |
| max = NGX_MAX_OFF_T_VALUE / 1024; | |
| scale = 1024; | |
| break; | |
| case 'M': | |
| case 'm': | |
| len--; | |
| max = NGX_MAX_OFF_T_VALUE / (1024 * 1024); | |
| scale = 1024 * 1024; | |
| break; | |
| case 'G': | |
| case 'g': | |
| len--; | |
| max = NGX_MAX_OFF_T_VALUE / (1024 * 1024 * 1024); | |
| scale = 1024 * 1024 * 1024; | |
| break; | |
| default: | |
| max = NGX_MAX_OFF_T_VALUE; | |
| scale = 1; | |
| } | |
| offset = ngx_atoof(line->data, len); | |
| if (offset == NGX_ERROR || offset > max) { | |
| return NGX_ERROR; | |
| } | |
| offset *= scale; | |
| return offset; | |
| } | |
| ngx_int_t | |
| ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec) | |
| { | |
| u_char *p, *last; | |
| ngx_int_t value, total, scale; | |
| ngx_int_t max, cutoff, cutlim; | |
| ngx_uint_t valid; | |
| enum { | |
| st_start = 0, | |
| st_year, | |
| st_month, | |
| st_week, | |
| st_day, | |
| st_hour, | |
| st_min, | |
| st_sec, | |
| st_msec, | |
| st_last | |
| } step; | |
| valid = 0; | |
| value = 0; | |
| total = 0; | |
| cutoff = NGX_MAX_INT_T_VALUE / 10; | |
| cutlim = NGX_MAX_INT_T_VALUE % 10; | |
| step = is_sec ? st_start : st_month; | |
| p = line->data; | |
| last = p + line->len; | |
| while (p < last) { | |
| if (*p >= '0' && *p <= '9') { | |
| if (value >= cutoff && (value > cutoff || *p - '0' > cutlim)) { | |
| return NGX_ERROR; | |
| } | |
| value = value * 10 + (*p++ - '0'); | |
| valid = 1; | |
| continue; | |
| } | |
| switch (*p++) { | |
| case 'y': | |
| if (step > st_start) { | |
| return NGX_ERROR; | |
| } | |
| step = st_year; | |
| max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 365); | |
| scale = 60 * 60 * 24 * 365; | |
| break; | |
| case 'M': | |
| if (step >= st_month) { | |
| return NGX_ERROR; | |
| } | |
| step = st_month; | |
| max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 30); | |
| scale = 60 * 60 * 24 * 30; | |
| break; | |
| case 'w': | |
| if (step >= st_week) { | |
| return NGX_ERROR; | |
| } | |
| step = st_week; | |
| max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 7); | |
| scale = 60 * 60 * 24 * 7; | |
| break; | |
| case 'd': | |
| if (step >= st_day) { | |
| return NGX_ERROR; | |
| } | |
| step = st_day; | |
| max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24); | |
| scale = 60 * 60 * 24; | |
| break; | |
| case 'h': | |
| if (step >= st_hour) { | |
| return NGX_ERROR; | |
| } | |
| step = st_hour; | |
| max = NGX_MAX_INT_T_VALUE / (60 * 60); | |
| scale = 60 * 60; | |
| break; | |
| case 'm': | |
| if (p < last && *p == 's') { | |
| if (is_sec || step >= st_msec) { | |
| return NGX_ERROR; | |
| } | |
| p++; | |
| step = st_msec; | |
| max = NGX_MAX_INT_T_VALUE; | |
| scale = 1; | |
| break; | |
| } | |
| if (step >= st_min) { | |
| return NGX_ERROR; | |
| } | |
| step = st_min; | |
| max = NGX_MAX_INT_T_VALUE / 60; | |
| scale = 60; | |
| break; | |
| case 's': | |
| if (step >= st_sec) { | |
| return NGX_ERROR; | |
| } | |
| step = st_sec; | |
| max = NGX_MAX_INT_T_VALUE; | |
| scale = 1; | |
| break; | |
| case ' ': | |
| if (step >= st_sec) { | |
| return NGX_ERROR; | |
| } | |
| step = st_last; | |
| max = NGX_MAX_INT_T_VALUE; | |
| scale = 1; | |
| break; | |
| default: | |
| return NGX_ERROR; | |
| } | |
| if (step != st_msec && !is_sec) { | |
| scale *= 1000; | |
| max /= 1000; | |
| } | |
| if (value > max) { | |
| return NGX_ERROR; | |
| } | |
| value *= scale; | |
| if (total > NGX_MAX_INT_T_VALUE - value) { | |
| return NGX_ERROR; | |
| } | |
| total += value; | |
| value = 0; | |
| while (p < last && *p == ' ') { | |
| p++; | |
| } | |
| } | |
| if (!valid) { | |
| return NGX_ERROR; | |
| } | |
| if (!is_sec) { | |
| if (value > NGX_MAX_INT_T_VALUE / 1000) { | |
| return NGX_ERROR; | |
| } | |
| value *= 1000; | |
| } | |
| if (total > NGX_MAX_INT_T_VALUE - value) { | |
| return NGX_ERROR; | |
| } | |
| return total + value; | |
| } |