📄 wsp_headers.c
字号:
}/* We represent qvalues as integers from 0 through 1000, rather than * as floating values. */static int parse_qvalue(Octstr *value){ int qvalue; if (value == NULL) return -1; if (!isdigit(octstr_get_char(value, 0))) return -1; qvalue = (octstr_get_char(value, 0) - '0') * 1000; if (octstr_get_char(value, 1) != '.') goto gotvalue; if (!isdigit(octstr_get_char(value, 2))) goto gotvalue; qvalue += (octstr_get_char(value, 2) - '0') * 100; if (!isdigit(octstr_get_char(value, 3))) goto gotvalue; qvalue += (octstr_get_char(value, 3) - '0') * 10; if (!isdigit(octstr_get_char(value, 4))) goto gotvalue; qvalue += (octstr_get_char(value, 4) - '0');gotvalue: if (qvalue < 0 || qvalue > 1000) return -1; return qvalue;}static int get_qvalue(List *parms, int default_qvalue){ long i; Parameter *parm; int qvalue; for (i = 0; i < list_len(parms); i++) { parm = list_get(parms, i); if (octstr_str_compare(parm->key, "q") == 0 || octstr_str_compare(parm->key, "Q") == 0) { qvalue = parse_qvalue(parm->value); if (qvalue >= 0) return qvalue; } } return default_qvalue;}static int pack_qvalue(Octstr *packed, int qvalue){ /* "Quality factor 1 is the default value and shall never * be sent." */ if (qvalue == 1000) return -1; /* Remember that our qvalues are already multiplied by 1000. */ if (qvalue % 10 == 0) qvalue = qvalue / 10 + 1; else qvalue = qvalue + 100; octstr_append_uintvar(packed, qvalue); return 0;}/* Pack value as a Value-length followed by the encoded value. */void wsp_pack_value(Octstr *packed, Octstr *encoded){ long len; len = octstr_len(encoded); if (len <= 30) octstr_append_char(packed, len); else { octstr_append_char(packed, 31); octstr_append_uintvar(packed, len); } octstr_append(packed, encoded);}void wsp_pack_long_integer(Octstr *packed, unsigned long integer){ long oldlen = octstr_len(packed); unsigned char octet; long len; if (integer == 0) { /* The Multi-octet-integer has to be at least 1 octet long. */ octstr_append_char(packed, 1); /* length */ octstr_append_char(packed, 0); /* value */ return; } /* Encode it back-to-front, by repeatedly inserting * at the same position, because that's easier. */ for (len = 0; integer != 0; integer >>= 8, len++) { octet = integer & 0xff; octstr_insert_data(packed, oldlen, &octet, 1); } octet = len; octstr_insert_data(packed, oldlen, &octet, 1);}void wsp_pack_short_integer(Octstr *packed, unsigned long integer){ gw_assert(integer <= MAX_SHORT_INTEGER); octstr_append_char(packed, integer + 0x80);}void wsp_pack_integer_value(Octstr *packed, unsigned long integer){ if (integer <= MAX_SHORT_INTEGER) wsp_pack_short_integer(packed, integer); else wsp_pack_long_integer(packed, integer);}int wsp_pack_integer_string(Octstr *packed, Octstr *value){ unsigned long integer; long pos; int c; int digit; integer = 0; for (pos = 0; pos < octstr_len(value); pos++) { c = octstr_get_char(value, pos); if (!isdigit(c)) break; digit = c - '0'; if (integer > ULONG_MAX / 10) goto overflow; integer *= 10; if (integer > ULONG_MAX - digit) goto overflow; integer += digit; } wsp_pack_integer_value(packed, integer); return 0;overflow: warning(0, "WSP: Number too large to handle: '%s'.", octstr_get_cstr(value)); return -1;}int wsp_pack_version_value(Octstr *packed, Octstr *version){ long major, minor; long pos; pos = octstr_parse_long(&major, version, 0, 10); if (pos < 0 || major < 1 || major > 7) goto usetext; if (pos == octstr_len(version)) minor = 15; else { if (octstr_get_char(version, pos) != '.') goto usetext; pos = octstr_parse_long(&minor, version, pos + 1, 10); if (pos != octstr_len(version) || minor < 0 || minor > 14) goto usetext; } wsp_pack_short_integer(packed, major << 4 | minor); return 0;usetext: wsp_pack_text(packed, version); return 0;}int wsp_pack_constrained_value(Octstr *packed, Octstr *text, long value){ if (value >= 0) wsp_pack_short_integer(packed, value); else wsp_pack_text(packed, text); return 0;}static void pack_parameter(Octstr *packed, Parameter *parm){ long keytoken; long tmp; long start; start = octstr_len(packed); /* Parameter = Typed-parameter | Untyped-parameter */ /* keytoken = wsp_string_to_parameter(parm->key); */ /* XXX this should obey what kind of WSP Encoding-Version the client is using */ keytoken = wsp_string_to_versioned_parameter(parm->key, WSP_1_2); if (keytoken >= 0) { /* Typed-parameter = Well-known-parameter-token Typed-value */ /* Well-known-parameter-token = Integer-value */ wsp_pack_integer_value(packed, keytoken); /* Typed-value = Compact-value | Text-value */ /* First try to pack as Compact-value or No-value. * If that fails, pack as Text-value. */ if (parm->value == NULL) { octstr_append_char(packed, 0); /* No-value */ return; } else switch (keytoken) { case 0: /* q */ tmp = parse_qvalue(parm->value); if (tmp >= 0) { if (pack_qvalue(packed, tmp) < 0) octstr_delete(packed, start, octstr_len(packed) - start); return; } break; case 1: /* charset */ tmp = wsp_string_to_charset(parm->value); if (tmp >= 0) { wsp_pack_integer_value(packed, tmp); return; } break; case 2: /* level */ wsp_pack_version_value(packed, parm->value); return; case 3: /* type */ if (octstr_check_range(parm->value, 0, octstr_len(parm->value), gw_isdigit) && wsp_pack_integer_string(packed, parm->value) >= 0) return; break; case 5: /* name */ case 6: /* filename */ break; case 7: /* differences */ if (pack_field_name(packed, parm->value) >= 0) return; break; case 8: /* padding */ if (octstr_parse_long(&tmp, parm->value, 0, 10) == octstr_len(parm->value) && tmp >= 0 && tmp <= MAX_SHORT_INTEGER) { wsp_pack_short_integer(packed, tmp); return; } break; } pack_quoted_string(packed, parm->value); } else { /* Untyped-parameter = Token-text Untyped-value */ wsp_pack_text(packed, parm->key); /* Untyped-value = Integer-value | Text-value */ if (parm->value == NULL) { octstr_append_char(packed, 0); /* No-value */ return; } /* If we can pack as integer, do so. */ if (octstr_parse_long(&tmp, parm->value, 0, 10) == octstr_len(parm->value)) { wsp_pack_integer_value(packed, tmp); } else { pack_quoted_string(packed, parm->value); } }}void wsp_pack_parameters(Octstr *packed, List *parms){ long i; Parameter *parm; for (i = 0; i < list_len(parms); i++) { parm = list_get(parms, i); pack_parameter(packed, parm); }}static int pack_uri(Octstr *packed, Octstr *value){ wsp_pack_text(packed, value); return 0;}static int pack_md5(Octstr *packed, Octstr *value){ Octstr *binary; binary = octstr_duplicate(value); octstr_base64_to_binary(binary); if (octstr_len(binary) != 16) { error(0, "WSP: MD5 value not 128 bits."); return -1; } octstr_append_char(packed, 16); octstr_append(packed, binary); octstr_destroy(binary); return 0;}/* Actually packs a "Value-length Challenge" *//* Relies on http_split_auth_value to have converted the entry to * the normal HTTP parameter format rather than the comma-separated * one used by challenge and credentials. */static int pack_challenge(Octstr *packed, Octstr *value){ Octstr *encoding = NULL; Octstr *scheme = NULL; Octstr *basic = octstr_imm("Basic"); Octstr *realm = octstr_imm("realm"); Octstr *parmstring = NULL; List *parms = NULL; Parameter *realmparm = NULL; long realmpos = -1; Octstr *realmval = NULL; long pos; encoding = octstr_create(""); /* Get authentication scheme */ for (pos = 0; pos < octstr_len(value); pos++) { if (!is_token_char(octstr_get_char(value, pos))) break; } scheme = octstr_copy(value, 0, pos); octstr_strip_blanks(scheme); /* Skip whitespace */ while (isspace(octstr_get_char(value, pos))) pos++; if (octstr_case_compare(scheme, basic) == 0) { parmstring = octstr_copy(value, pos, octstr_len(value) - pos); realmparm = parm_parse(parmstring); octstr_append_char(encoding, BASIC_AUTHENTICATION); realmpos = octstr_len(encoding); } else { long i; wsp_pack_text(encoding, scheme); realmpos = octstr_len(encoding); /* Find the realm parameter and exclude it */ parms = wsp_strip_parameters(value); for (i = 0; i < list_len(parms); i++) { Parameter *parm = list_get(parms, i); if (octstr_case_compare(realm, parm->key) == 0) { realmparm = parm; list_delete(parms, i, 1); break; } } wsp_pack_parameters(encoding, parms); } /* * In the WSP encoding we have to put the realm value first, but * with non-Basic challenges we don't know if it will come first * in the HTTP header. So we just start parsing parameters, and * go back and insert the realm value later. The same technique * is used for Basic authentication to simplify the code. */ if (realmparm == NULL || octstr_case_compare(realmparm->key, realm) != 0 || realmparm->value == NULL) goto error; /* Zap quote marks */ if (octstr_get_char(realmparm->value, 0) == '"' && octstr_get_char(realmparm->value, octstr_len(realmparm->value) - 1) == '"') { octstr_delete(realmparm->value, 0, 1); octstr_delete(realmparm->value, octstr_len(realmparm->value) - 1, 1); } gw_assert(realmpos >= 0); realmval = octstr_create(""); wsp_pack_text(realmval, realmparm->value); octstr_insert(encoding, realmval, realmpos); wsp_pack_value(packed, encoding); octstr_destroy(encoding); octstr_destroy(scheme); octstr_destroy(parmstring); parm_destroy(realmparm); list_destroy(parms, parm_destroy_item); octstr_destroy(realmval); return 0;error: warning(0, "WSP: Cannot parse challenge."); octstr_destroy(encoding); octstr_destroy(scheme); octstr_destroy(parmstring); parm_destr
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -