| |
| /* |
| * 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; |
| } |