wsp_headers.c

来自「mms client」· C语言 代码 · 共 2,167 行 · 第 1/5 页

C
2,167
字号
/* * wsp_headers.c - Implement WSP PDU headers *  * References: *   WSP specification version 1.1 *   RFC 2068, Hypertext Transfer Protocol HTTP/1.1 *   RFC 2616, Hypertext Transfer Protocol HTTP/1.1 * *   For push headers, WSP specification, June 2000 conformance release * * This file has two parts.  The first part decodes the request's headers * from WSP to HTTP.  The second part encodes the response's headers from * HTTP to WSP. * * Note that push header encoding and decoding are divided two parts: * first decoding and encoding numeric values and then packing these values * into WSP format and unpacking them from WSP format. This module contains * only packing and unpacking parts. * * Richard Braakman */#include <string.h>#include <limits.h>#include <ctype.h>#include "gwlib/gwlib.h"#include "wsp.h"#include "wsp_headers.h"#include "wsp_strings.h"/* The value defined as Quote in 8.4.2.1 */#define WSP_QUOTE  127/* Largest value that will fit in a Short-integer encoding */#define MAX_SHORT_INTEGER 127/* Marker values used in the encoding */#define BASIC_AUTHENTICATION 128#define ABSOLUTE_TIME 128#define RELATIVE_TIME 129#define BYTE_RANGE 128#define SUFFIX_BYTE_RANGE 129/* Use this value for Expires headers if we can't parse the expiration * date.  It's about one day after the start of the epoch.  We don't * use the exact start of the epoch because some clients have trouble * with that. */#define LONG_AGO_VALUE 100000/* * get field value and return its type as predefined data types * There are three kinds of field encodings: *   WSP_FIELD_VALUE_NUL_STRING: 0-terminated string *   WSP_FIELD_VALUE_ENCODED: short integer, range 0-127 *   WSP_FIELD_VALUE_DATA: octet string defined by length * The function will return one of those values, and modify the parse context * to make it easy to get the field data. *   WSP_FIELD_VALUE_NUL_STRING: Leave parsing position at start of string *   WSP_FIELD_VALUE_ENCODED: Put value in *well_known_value, leave *        parsing position after field value. *   WSP_FIELD_VALUE_DATA: Leave parsing position at start of data, and set *        a parse limit at the end of data. */int field_value(ParseContext *context, int *well_known_value){    int val;    unsigned long len;    val = parse_get_char(context);    if (val >= 0 && val < 31) {        *well_known_value = -1;        parse_limit(context, val);        return WSP_FIELD_VALUE_DATA;    } else if (val == 31) {        *well_known_value = -1;        len = parse_get_uintvar(context);        parse_limit(context, len);        return WSP_FIELD_VALUE_DATA;    } else if (val > 127) {        *well_known_value = val - 128;        return WSP_FIELD_VALUE_ENCODED;    } else if (val == WSP_QUOTE) {  /* 127 */        *well_known_value = -1;        /* We already consumed the Quote */        return WSP_FIELD_VALUE_NUL_STRING;    } else {        *well_known_value = -1;        /* Un-parse the character we just read */        parse_skip(context, -1);        return WSP_FIELD_VALUE_NUL_STRING;    }}/* Skip over a field_value as defined above. */void skip_field_value(ParseContext *context){    int val;    int ret;    ret = field_value(context, &val);    if (ret == WSP_FIELD_VALUE_DATA) {        parse_skip_to_limit(context);        parse_pop_limit(context);    }}/* Multi-octet-integer is defined in 8.4.2.1 */long unpack_multi_octet_integer(ParseContext *context, long len){    long val = 0;    if (len > (long) sizeof(val) || len < 0)        return -1;    while (len > 0) {        val = val * 256 + parse_get_char(context);        len--;    }    if (parse_error(context))        return -1;    return val;}/* This function is similar to field_value, but it is used at various * places in the grammar where we expect either an Integer-value * or some kind of NUL-terminated text. *  * Return values are just like field_value except that WSP_FIELD_VALUE_DATA * will not be returned. * * As a special case, we parse a 0-length Long-integer as an * WSP_FIELD_VALUE_NONE, so that we can distinguish between No-value * and an Integer-value of 0.  (A real integer 0 would be encoded as * a Short-integer; the definition of Long-integer seems to allow * 0-length integers, but the definition of Multi-octet-integer does * not, so this is an unclear area of the specification.) */int secondary_field_value(ParseContext *context, long *result){    int val;    long length;    val = parse_get_char(context);    if (val == 0) {        *result = 0;        return WSP_FIELD_VALUE_NONE;    } else if (val > 0 && val < 31) {        *result = unpack_multi_octet_integer(context, val);        return WSP_FIELD_VALUE_ENCODED;    } else if (val == 31) {        length = parse_get_uintvar(context);        *result = unpack_multi_octet_integer(context, length);        return WSP_FIELD_VALUE_ENCODED;    } else if (val > 127) {        *result = val - 128;        return WSP_FIELD_VALUE_ENCODED;    } else if (val == WSP_QUOTE) {  /* 127 */        *result = -1;        return WSP_FIELD_VALUE_NUL_STRING;    } else {        *result = -1;        /* Un-parse the character we just read */        parse_skip(context, -1);        return WSP_FIELD_VALUE_NUL_STRING;    }}/* Integer-value is defined in 8.4.2.3 */Octstr *unpack_integer_value(ParseContext *context){    Octstr *decoded;    unsigned long value;    int val;    val = parse_get_char(context);    if (val < 31) {        value = unpack_multi_octet_integer(context, val);    } else if (val > 127) {        value = val - 128;    } else {        warning(0, "WSP headers: bad integer-value.");        return NULL;    }    decoded = octstr_create("");    octstr_append_decimal(decoded, value);    return decoded;}/* Q-value is defined in 8.4.2.3 */Octstr *convert_q_value(int q){    Octstr *result = NULL;    /* When quality factor 0 and quality factors with one or two     * decimal digits are encoded, they shall be multiplied by 100     * and incremented by one, so that they encode as a one-octet     * value in range 1-100. */    if (q >= 1 && q <= 100) {        q = q - 1;        result = octstr_create("0.");        octstr_append_char(result, (q / 10) + '0');        if (q % 10 > 0)            octstr_append_char(result, (q % 10) + '0');        return result;    }    /* Three decimal quality factors shall be multiplied with 1000     * and incremented by 100. */    if (q > 100 && q <= 1000) {        q = q - 100;        result = octstr_create("0.");        octstr_append_char(result, (q / 100) + '0');        if (q % 100 > 0)            octstr_append_char(result, (q / 10 % 10) + '0');        if (q % 10 > 0)            octstr_append_char(result, (q % 10) + '0');        return result;    }    return NULL;}/* Q-value is defined in 8.4.2.3 */Octstr *unpack_q_value(ParseContext *context){    int c, c2;    c = parse_get_char(context);    if (c < 0)        return NULL;    if (c & 0x80) {        c2 = parse_get_char(context);        if (c2 < 0 || (c2 & 0x80))            return NULL;        c = ((c & 0x7f) << 8) + c2;    }    return convert_q_value(c);}/* Version-value is defined in 8.4.2.3 */Octstr *unpack_version_value(long value){    Octstr *result;    int major, minor;    major = ((value >> 4) & 0x7);    minor = (value & 0xf);    result = octstr_create("");    octstr_append_char(result, major + '0');    if (minor != 15) {        octstr_append_char(result, '.');        octstr_append_decimal(result, minor);    }    return result;}/* Called with the parse limit set to the end of the parameter data, * and decoded containing the unpacked header line so far. * Parameter is defined in 8.4.2.4. */int unpack_parameter(ParseContext *context, Octstr *decoded){    Octstr *parm = NULL;    Octstr *value = NULL;    int ret;    long type;    long val;    ret = secondary_field_value(context, &type);    if (parse_error(context) || ret == WSP_FIELD_VALUE_NONE) {        warning(0, "bad parameter");        goto error;    }    if (ret == WSP_FIELD_VALUE_ENCODED) {        /* Typed-parameter */        parm = wsp_parameter_to_string(type);        if (!parm)            warning(0, "Unknown parameter %02lx.", type);    } else if (ret == WSP_FIELD_VALUE_NUL_STRING) {        /* Untyped-parameter */        parm = parse_get_nul_string(context);        if (!parm)            warning(0, "Format error in parameter.");        type = -1;        /* We treat Untyped-value as a special type.  Its format         * Integer-value | Text-value is pretty similar to most         * typed formats. */    } else {        panic(0, "Unknown secondary field value type %d.", ret);    }    if (type == 0x00) /* q */        value = unpack_q_value(context);    else {        ret = secondary_field_value(context, &val);        if (parse_error(context)) {            warning(0, "bad parameter value");            goto error;        }        if (ret == WSP_FIELD_VALUE_ENCODED) {            switch (type) {            case -1:  /* untyped: Integer-value */            case 3:  /* type: Integer-value */            case 8:  /* padding: Short-integer */                value = octstr_create("");                octstr_append_decimal(value, val);                break;            case 0:  /* q, already handled above */                gw_assert(0);                break;            case 1:  /* charset: Well-known-charset */                value = wsp_charset_to_string(val);                if (!value)                    warning(0, "Unknown charset %04lx.", val);                break;            case 2:  /* level: Version-value */                value = unpack_version_value(val);                break;            case 5:  /* name: Text-string */            case 6:  /* filename: Text-string */                warning(0, "Text-string parameter with integer encoding");                break;            case 7:  /* differences: Field-name */                value = wsp_header_to_string(val);                if (!value)                    warning(0, "Unknown differences header %02lx.", val);                break;            default:                warning(0, "Unknown parameter encoding %02lx.",                        type);                break;            }        } else if (ret == WSP_FIELD_VALUE_NONE) {            value = octstr_create("");        } else {            gw_assert(ret == WSP_FIELD_VALUE_NUL_STRING);            /* Text-value = No-value | Token-text | Quoted-string */            value = parse_get_nul_string(context);            if (!value)                warning(0, "Format error in parameter value.");            else {                if (octstr_get_char(value, 0) == '"') {                    /* Quoted-string */                    octstr_append_char(value, '"');                }            }        }    }    if (!parm || !value) {        warning(0, "Skipping parameters");        goto error;    }    octstr_append(decoded, octstr_imm("; "));    octstr_append(decoded, parm);    if (octstr_len(value) > 0) {        octstr_append_char(decoded, '=');        octstr_append(decoded, value);    }    octstr_destroy(parm);    octstr_destroy(value);    return 0;error:    parse_skip_to_limit(context);    octstr_destroy(parm);    octstr_destroy(value);    parse_set_error(context);    return -1;}void unpack_all_parameters(ParseContext *context, Octstr *decoded){    int ret = 0;    while (ret >= 0 && !parse_error(context) &&           parse_octets_left(context) > 0) {        ret = unpack_parameter(context, decoded);    }}/* Unpack parameters in the format used by credentials and challenge, * which differs from the format used by all other HTTP headers. */void unpack_broken_parameters(ParseContext *context, Octstr *decoded){    int ret = 0;    int first = 1;    long pos;    while (ret >= 0 && !parse_error(context) &&	   parse_octets_left(context) > 0) {        pos = octstr_len(decoded);        ret = unpack_parameter(context, decoded);        if (ret >= 0) {            if (first) {                /* Zap ';' */                octstr_delete(decoded, pos, 1);                first = 0;            } else {                /* Replace ';' with ',' */                octstr_set_char(decoded, pos, first ? ' ' : ',');            }        }    }}void unpack_optional_q_value(ParseContext *context, Octstr *decoded){    if (parse_octets_left(context) > 0) {        Octstr *qval = unpack_q_value(context);        if (qval) {            octstr_append(decoded, octstr_imm("; q="));            octstr_append(decoded, qval);            octstr_destroy(qval);        } else            warning(0, "Bad q-value");    }}/* Date-value is defined in 8.4.2.3. */Octstr *unpack_date_value(ParseContext *context)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?