1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
|
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/http/private/strutil.h>
static struct aws_byte_cursor s_trim(struct aws_byte_cursor cursor, const bool trim_table[256]) {
/* trim leading whitespace */
size_t i;
for (i = 0; i < cursor.len; ++i) {
const uint8_t c = cursor.ptr[i];
if (!trim_table[c]) {
break;
}
}
cursor.ptr += i;
cursor.len -= i;
/* trim trailing whitespace */
for (; cursor.len; --cursor.len) {
const uint8_t c = cursor.ptr[cursor.len - 1];
if (!trim_table[c]) {
break;
}
}
return cursor;
}
static const bool s_http_whitespace_table[256] = {
[' '] = true,
['\t'] = true,
};
struct aws_byte_cursor aws_strutil_trim_http_whitespace(struct aws_byte_cursor cursor) {
return s_trim(cursor, s_http_whitespace_table);
}
/* RFC7230 section 3.2.6:
* token = 1*tchar
* tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
* / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
* / DIGIT / ALPHA
*/
static const bool s_http_token_table[256] = {
['!'] = true, ['#'] = true, ['$'] = true, ['%'] = true, ['&'] = true, ['\''] = true, ['*'] = true, ['+'] = true,
['-'] = true, ['.'] = true, ['^'] = true, ['_'] = true, ['`'] = true, ['|'] = true, ['~'] = true,
['0'] = true, ['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true, ['5'] = true, ['6'] = true, ['7'] = true,
['8'] = true, ['9'] = true,
['A'] = true, ['B'] = true, ['C'] = true, ['D'] = true, ['E'] = true, ['F'] = true, ['G'] = true, ['H'] = true,
['I'] = true, ['J'] = true, ['K'] = true, ['L'] = true, ['M'] = true, ['N'] = true, ['O'] = true, ['P'] = true,
['Q'] = true, ['R'] = true, ['S'] = true, ['T'] = true, ['U'] = true, ['V'] = true, ['W'] = true, ['X'] = true,
['Y'] = true, ['Z'] = true,
['a'] = true, ['b'] = true, ['c'] = true, ['d'] = true, ['e'] = true, ['f'] = true, ['g'] = true, ['h'] = true,
['i'] = true, ['j'] = true, ['k'] = true, ['l'] = true, ['m'] = true, ['n'] = true, ['o'] = true, ['p'] = true,
['q'] = true, ['r'] = true, ['s'] = true, ['t'] = true, ['u'] = true, ['v'] = true, ['w'] = true, ['x'] = true,
['y'] = true, ['z'] = true,
};
/* Same as above, but with uppercase characters removed */
static const bool s_http_lowercase_token_table[256] = {
['!'] = true, ['#'] = true, ['$'] = true, ['%'] = true, ['&'] = true, ['\''] = true, ['*'] = true, ['+'] = true,
['-'] = true, ['.'] = true, ['^'] = true, ['_'] = true, ['`'] = true, ['|'] = true, ['~'] = true,
['0'] = true, ['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true, ['5'] = true, ['6'] = true, ['7'] = true,
['8'] = true, ['9'] = true,
['a'] = true, ['b'] = true, ['c'] = true, ['d'] = true, ['e'] = true, ['f'] = true, ['g'] = true, ['h'] = true,
['i'] = true, ['j'] = true, ['k'] = true, ['l'] = true, ['m'] = true, ['n'] = true, ['o'] = true, ['p'] = true,
['q'] = true, ['r'] = true, ['s'] = true, ['t'] = true, ['u'] = true, ['v'] = true, ['w'] = true, ['x'] = true,
['y'] = true, ['z'] = true,
};
static bool s_is_token(struct aws_byte_cursor token, const bool token_table[256]) {
if (token.len == 0) {
return false;
}
for (size_t i = 0; i < token.len; ++i) {
const uint8_t c = token.ptr[i];
if (token_table[c] == false) {
return false;
}
}
return true;
}
bool aws_strutil_is_http_token(struct aws_byte_cursor token) {
return s_is_token(token, s_http_token_table);
}
bool aws_strutil_is_lowercase_http_token(struct aws_byte_cursor token) {
return s_is_token(token, s_http_lowercase_token_table);
}
/* clang-format off */
/**
* Table with true for all octets allowed in field-content,
* as defined in RFC7230 section 3.2 and 3.2.6 and RFC5234 appendix-B.1:
*
* field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
* field-vchar = VCHAR / obs-text
* VCHAR = %x21-7E ; visible (printing) characters
* obs-text = %x80-FF
*/
static const bool s_http_field_content_table[256] = {
/* clang-format off */
/* whitespace */
['\t'] = true, [' '] = true,
/* VCHAR = 0x21-7E */
[0x21] = true, [0x22] = true, [0x23] = true, [0x24] = true, [0x25] = true, [0x26] = true, [0x27] = true,
[0x28] = true, [0x29] = true, [0x2A] = true, [0x2B] = true, [0x2C] = true, [0x2D] = true, [0x2E] = true,
[0x2F] = true, [0x30] = true, [0x31] = true, [0x32] = true, [0x33] = true, [0x34] = true, [0x35] = true,
[0x36] = true, [0x37] = true, [0x38] = true, [0x39] = true, [0x3A] = true, [0x3B] = true, [0x3C] = true,
[0x3D] = true, [0x3E] = true, [0x3F] = true, [0x40] = true, [0x41] = true, [0x42] = true, [0x43] = true,
[0x44] = true, [0x45] = true, [0x46] = true, [0x47] = true, [0x48] = true, [0x49] = true, [0x4A] = true,
[0x4B] = true, [0x4C] = true, [0x4D] = true, [0x4E] = true, [0x4F] = true, [0x50] = true, [0x51] = true,
[0x52] = true, [0x53] = true, [0x54] = true, [0x55] = true, [0x56] = true, [0x57] = true, [0x58] = true,
[0x59] = true, [0x5A] = true, [0x5B] = true, [0x5C] = true, [0x5D] = true, [0x5E] = true, [0x5F] = true,
[0x60] = true, [0x61] = true, [0x62] = true, [0x63] = true, [0x64] = true, [0x65] = true, [0x66] = true,
[0x67] = true, [0x68] = true, [0x69] = true, [0x6A] = true, [0x6B] = true, [0x6C] = true, [0x6D] = true,
[0x6E] = true, [0x6F] = true, [0x70] = true, [0x71] = true, [0x72] = true, [0x73] = true, [0x74] = true,
[0x75] = true, [0x76] = true, [0x77] = true, [0x78] = true, [0x79] = true, [0x7A] = true, [0x7B] = true,
[0x7C] = true, [0x7D] = true, [0x7E] = true,
/* obs-text = %x80-FF */
[0x80] = true, [0x81] = true, [0x82] = true, [0x83] = true, [0x84] = true, [0x85] = true, [0x86] = true,
[0x87] = true, [0x88] = true, [0x89] = true, [0x8A] = true, [0x8B] = true, [0x8C] = true, [0x8D] = true,
[0x8E] = true, [0x8F] = true, [0x90] = true, [0x91] = true, [0x92] = true, [0x93] = true, [0x94] = true,
[0x95] = true, [0x96] = true, [0x97] = true, [0x98] = true, [0x99] = true, [0x9A] = true, [0x9B] = true,
[0x9C] = true, [0x9D] = true, [0x9E] = true, [0x9F] = true, [0xA0] = true, [0xA1] = true, [0xA2] = true,
[0xA3] = true, [0xA4] = true, [0xA5] = true, [0xA6] = true, [0xA7] = true, [0xA8] = true, [0xA9] = true,
[0xAA] = true, [0xAB] = true, [0xAC] = true, [0xAD] = true, [0xAE] = true, [0xAF] = true, [0xB0] = true,
[0xB1] = true, [0xB2] = true, [0xB3] = true, [0xB4] = true, [0xB5] = true, [0xB6] = true, [0xB7] = true,
[0xB8] = true, [0xB9] = true, [0xBA] = true, [0xBB] = true, [0xBC] = true, [0xBD] = true, [0xBE] = true,
[0xBF] = true, [0xC0] = true, [0xC1] = true, [0xC2] = true, [0xC3] = true, [0xC4] = true, [0xC5] = true,
[0xC6] = true, [0xC7] = true, [0xC8] = true, [0xC9] = true, [0xCA] = true, [0xCB] = true, [0xCC] = true,
[0xCD] = true, [0xCE] = true, [0xCF] = true, [0xD0] = true, [0xD1] = true, [0xD2] = true, [0xD3] = true,
[0xD4] = true, [0xD5] = true, [0xD6] = true, [0xD7] = true, [0xD8] = true, [0xD9] = true, [0xDA] = true,
[0xDB] = true, [0xDC] = true, [0xDD] = true, [0xDE] = true, [0xDF] = true, [0xE0] = true, [0xE1] = true,
[0xE2] = true, [0xE3] = true, [0xE4] = true, [0xE5] = true, [0xE6] = true, [0xE7] = true, [0xE8] = true,
[0xE9] = true, [0xEA] = true, [0xEB] = true, [0xEC] = true, [0xED] = true, [0xEE] = true, [0xEF] = true,
[0xF0] = true, [0xF1] = true, [0xF2] = true, [0xF3] = true, [0xF4] = true, [0xF5] = true, [0xF6] = true,
[0xF7] = true, [0xF8] = true, [0xF9] = true, [0xFA] = true, [0xFB] = true, [0xFC] = true, [0xFD] = true,
[0xFE] = true, [0xFF] = true,
/* clang-format on */
};
/**
* From RFC7230 section 3.2:
* field-value = *( field-content / obs-fold )
* field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
*
* But we're forbidding obs-fold
*/
bool aws_strutil_is_http_field_value(struct aws_byte_cursor cursor) {
if (cursor.len == 0) {
return true;
}
/* first and last char cannot be whitespace */
const uint8_t first_c = cursor.ptr[0];
const uint8_t last_c = cursor.ptr[cursor.len - 1];
if (s_http_whitespace_table[first_c] || s_http_whitespace_table[last_c]) {
return false;
}
/* ensure every char is legal field-content */
size_t i = 0;
do {
const uint8_t c = cursor.ptr[i++];
if (s_http_field_content_table[c] == false) {
return false;
}
} while (i < cursor.len);
return true;
}
/**
* From RFC7230 section 3.1.2:
* reason-phrase = *( HTAB / SP / VCHAR / obs-text )
* VCHAR = %x21-7E ; visible (printing) characters
* obs-text = %x80-FF
*/
bool aws_strutil_is_http_reason_phrase(struct aws_byte_cursor cursor) {
for (size_t i = 0; i < cursor.len; ++i) {
const uint8_t c = cursor.ptr[i];
/* the field-content table happens to allow the exact same characters as reason-phrase */
if (s_http_field_content_table[c] == false) {
return false;
}
}
return true;
}
bool aws_strutil_is_http_request_target(struct aws_byte_cursor cursor) {
if (cursor.len == 0) {
return false;
}
/* TODO: Actually check the complete grammar as defined in RFC7230 5.3 and
* RFC3986. Currently this just checks whether the sequence is blatantly illegal */
size_t i = 0;
do {
const uint8_t c = cursor.ptr[i++];
/* everything <= ' ' is non-visible ascii*/
if (c <= ' ') {
return false;
}
} while (i < cursor.len);
return true;
}
bool aws_strutil_is_http_pseudo_header_name(struct aws_byte_cursor cursor) {
if (cursor.len == 0) {
return false;
}
const uint8_t c = cursor.ptr[0];
if (c != ':') {
/* short cut */
return false;
}
return true;
}
|