view src/core/ngx_parse.c @ 4005:e56c1e9873cb

Correctly set body if it's preread and there are extra data. Previously all available data was used as body, resulting in garbage after real body e.g. in case of pipelined requests. Make sure to use only as many bytes as request's Content-Length specifies.
author Maxim Dounin <mdounin@mdounin.ru>
date Thu, 18 Aug 2011 15:27:57 +0000
parents 9d2bdbda4ee3
children c352c483263c
line wrap: on
line source


/*
 * Copyright (C) Igor Sysoev
 */


#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;
    ngx_int_t  scale;

    len = line->len;
    unit = line->data[len - 1];

    switch (unit) {
    case 'K':
    case 'k':
        len--;
        scale = 1024;
        break;

    case 'M':
    case 'm':
        len--;
        scale = 1024 * 1024;
        break;

    default:
        scale = 1;
    }

    size = ngx_atosz(line->data, len);
    if (size == NGX_ERROR) {
        return NGX_ERROR;
    }

    size *= scale;

    return size;
}


off_t
ngx_parse_offset(ngx_str_t *line)
{
    u_char     unit;
    off_t      offset;
    size_t     len;
    ngx_int_t  scale;

    len = line->len;
    unit = line->data[len - 1];

    switch (unit) {
    case 'K':
    case 'k':
        len--;
        scale = 1024;
        break;

    case 'M':
    case 'm':
        len--;
        scale = 1024 * 1024;
        break;

    case 'G':
    case 'g':
        len--;
        scale = 1024 * 1024 * 1024;
        break;

    default:
        scale = 1;
    }

    offset = ngx_atoof(line->data, len);
    if (offset == NGX_ERROR) {
        return NGX_ERROR;
    }

    offset *= scale;

    return offset;
}


ngx_int_t
ngx_parse_time(ngx_str_t *line, ngx_uint_t sec)
{
    u_char      *p, *last;
    ngx_int_t    value, total, scale;
    ngx_uint_t   max, 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;
    step = sec ? st_start : st_month;
    scale = sec ? 1 : 1000;

    p = line->data;
    last = p + line->len;

    while (p < last) {

        if (*p >= '0' && *p <= '9') {
            value = value * 10 + (*p++ - '0');
            valid = 1;
            continue;
        }

        switch (*p++) {

        case 'y':
            if (step > st_start) {
                return NGX_ERROR;
            }
            step = st_year;
            max = 68;
            scale = 60 * 60 * 24 * 365;
            break;

        case 'M':
            if (step > st_year) {
                return NGX_ERROR;
            }
            step = st_month;
            max = 828;
            scale = 60 * 60 * 24 * 30;
            break;

        case 'w':
            if (step > st_month) {
                return NGX_ERROR;
            }
            step = st_week;
            max = 3550;
            scale = 60 * 60 * 24 * 7;
            break;

        case 'd':
            if (step > st_week) {
                return NGX_ERROR;
            }
            step = st_day;
            max = 24855;
            scale = 60 * 60 * 24;
            break;

        case 'h':
            if (step > st_day) {
                return NGX_ERROR;
            }
            step = st_hour;
            max = 596523;
            scale = 60 * 60;
            break;

        case 'm':
            if (*p == 's') {
                if (sec || step > st_sec) {
                    return NGX_ERROR;
                }
                p++;
                step = st_msec;
                max = 2147483647;
                scale = 1;
                break;
            }

            if (step > st_hour) {
                return NGX_ERROR;
            }
            step = st_min;
            max = 35791394;
            scale = 60;
            break;

        case 's':
            if (step > st_min) {
                return NGX_ERROR;
            }
            step = st_sec;
            max = 2147483647;
            scale = 1;
            break;

        case ' ':
            if (step > st_min) {
                return NGX_ERROR;
            }
            step = st_last;
            max = 2147483647;
            scale = 1;
            break;

        default:
            return NGX_ERROR;
        }

        if (step != st_msec && !sec) {
            scale *= 1000;
            max /= 1000;
        }

        if ((ngx_uint_t) value > max) {
            return NGX_ERROR;
        }

        total += value * scale;

        if ((ngx_uint_t) total > 2147483647) {
            return NGX_ERROR;
        }

        value = 0;
        scale = sec ? 1 : 1000;

        while (p < last && *p == ' ') {
            p++;
        }
    }

    if (valid) {
        return total + value * scale;
    }

    return NGX_ERROR;
}