1 2/* 3 * Copyright (C) NGINX, Inc. 4 */ 5 6#include <nxt_main.h> 7 8 9struct nxt_var_s { 10 size_t length; 11 nxt_uint_t vars; 12 uint8_t strz; /* 1 bit */ 13 u_char data[]; 14 15/* 16 nxt_var_sub_t subs[vars]; 17 u_char raw[length]; 18*/ 19}; 20 21 22typedef struct { 23 uint32_t index; 24 uint32_t length; 25 uint32_t position; 26} nxt_var_sub_t; 27 28 29struct nxt_var_query_s { 30 nxt_mp_t *pool; 31 32 nxt_lvlhsh_t cache; 33 nxt_str_t *spare; 34 35 nxt_uint_t waiting; 36 nxt_uint_t failed; /* 1 bit */ 37 38 void *ctx; 39 void *data; 40 41 nxt_work_handler_t ready; 42 nxt_work_handler_t error; 43}; 44 45 46#define nxt_var_subs(var) ((nxt_var_sub_t *) (var)->data) 47 48#define nxt_var_raw_start(var) \ 49 ((var)->data + (var)->vars * sizeof(nxt_var_sub_t)) 50 51 52static nxt_int_t nxt_var_hash_test(nxt_lvlhsh_query_t *lhq, void *data); 53static nxt_var_decl_t *nxt_var_hash_find(nxt_str_t *name); 54
| 1 2/* 3 * Copyright (C) NGINX, Inc. 4 */ 5 6#include <nxt_main.h> 7 8 9struct nxt_var_s { 10 size_t length; 11 nxt_uint_t vars; 12 uint8_t strz; /* 1 bit */ 13 u_char data[]; 14 15/* 16 nxt_var_sub_t subs[vars]; 17 u_char raw[length]; 18*/ 19}; 20 21 22typedef struct { 23 uint32_t index; 24 uint32_t length; 25 uint32_t position; 26} nxt_var_sub_t; 27 28 29struct nxt_var_query_s { 30 nxt_mp_t *pool; 31 32 nxt_lvlhsh_t cache; 33 nxt_str_t *spare; 34 35 nxt_uint_t waiting; 36 nxt_uint_t failed; /* 1 bit */ 37 38 void *ctx; 39 void *data; 40 41 nxt_work_handler_t ready; 42 nxt_work_handler_t error; 43}; 44 45 46#define nxt_var_subs(var) ((nxt_var_sub_t *) (var)->data) 47 48#define nxt_var_raw_start(var) \ 49 ((var)->data + (var)->vars * sizeof(nxt_var_sub_t)) 50 51 52static nxt_int_t nxt_var_hash_test(nxt_lvlhsh_query_t *lhq, void *data); 53static nxt_var_decl_t *nxt_var_hash_find(nxt_str_t *name); 54
|
| 55static nxt_var_decl_t *nxt_var_decl_get(nxt_str_t *name, nxt_array_t *fields, 56 uint32_t *index); 57static nxt_var_field_t *nxt_var_field_add(nxt_array_t *fields, nxt_str_t *name, 58 uint32_t hash); 59
|
55static nxt_int_t nxt_var_cache_test(nxt_lvlhsh_query_t *lhq, void *data); 56static nxt_str_t *nxt_var_cache_value(nxt_task_t *task, nxt_var_query_t *query, 57 uint32_t index); 58 59static u_char *nxt_var_next_part(u_char *start, size_t length, nxt_str_t *part, 60 nxt_bool_t *is_var); 61 62 63static const nxt_lvlhsh_proto_t nxt_var_hash_proto nxt_aligned(64) = { 64 NXT_LVLHSH_DEFAULT, 65 nxt_var_hash_test, 66 nxt_lvlhsh_alloc, 67 nxt_lvlhsh_free, 68}; 69 70static const nxt_lvlhsh_proto_t nxt_var_cache_proto nxt_aligned(64) = { 71 NXT_LVLHSH_DEFAULT, 72 nxt_var_cache_test, 73 nxt_mp_lvlhsh_alloc, 74 nxt_mp_lvlhsh_free, 75}; 76 77 78static nxt_lvlhsh_t nxt_var_hash; 79static uint32_t nxt_var_count; 80 81static nxt_var_handler_t *nxt_var_index; 82 83 84static nxt_int_t 85nxt_var_hash_test(nxt_lvlhsh_query_t *lhq, void *data) 86{ 87 nxt_var_decl_t *decl; 88 89 decl = data; 90 91 return nxt_strstr_eq(&lhq->key, &decl->name) ? NXT_OK : NXT_DECLINED; 92} 93 94 95static nxt_var_decl_t * 96nxt_var_hash_find(nxt_str_t *name) 97{ 98 nxt_lvlhsh_query_t lhq; 99 100 lhq.key_hash = nxt_djb_hash(name->start, name->length); 101 lhq.key = *name; 102 lhq.proto = &nxt_var_hash_proto; 103 104 if (nxt_lvlhsh_find(&nxt_var_hash, &lhq) != NXT_OK) { 105 return NULL; 106 } 107 108 return lhq.value; 109} 110 111
| 60static nxt_int_t nxt_var_cache_test(nxt_lvlhsh_query_t *lhq, void *data); 61static nxt_str_t *nxt_var_cache_value(nxt_task_t *task, nxt_var_query_t *query, 62 uint32_t index); 63 64static u_char *nxt_var_next_part(u_char *start, size_t length, nxt_str_t *part, 65 nxt_bool_t *is_var); 66 67 68static const nxt_lvlhsh_proto_t nxt_var_hash_proto nxt_aligned(64) = { 69 NXT_LVLHSH_DEFAULT, 70 nxt_var_hash_test, 71 nxt_lvlhsh_alloc, 72 nxt_lvlhsh_free, 73}; 74 75static const nxt_lvlhsh_proto_t nxt_var_cache_proto nxt_aligned(64) = { 76 NXT_LVLHSH_DEFAULT, 77 nxt_var_cache_test, 78 nxt_mp_lvlhsh_alloc, 79 nxt_mp_lvlhsh_free, 80}; 81 82 83static nxt_lvlhsh_t nxt_var_hash; 84static uint32_t nxt_var_count; 85 86static nxt_var_handler_t *nxt_var_index; 87 88 89static nxt_int_t 90nxt_var_hash_test(nxt_lvlhsh_query_t *lhq, void *data) 91{ 92 nxt_var_decl_t *decl; 93 94 decl = data; 95 96 return nxt_strstr_eq(&lhq->key, &decl->name) ? NXT_OK : NXT_DECLINED; 97} 98 99 100static nxt_var_decl_t * 101nxt_var_hash_find(nxt_str_t *name) 102{ 103 nxt_lvlhsh_query_t lhq; 104 105 lhq.key_hash = nxt_djb_hash(name->start, name->length); 106 lhq.key = *name; 107 lhq.proto = &nxt_var_hash_proto; 108 109 if (nxt_lvlhsh_find(&nxt_var_hash, &lhq) != NXT_OK) { 110 return NULL; 111 } 112 113 return lhq.value; 114} 115 116
|
| 117static nxt_var_decl_t * 118nxt_var_decl_get(nxt_str_t *name, nxt_array_t *fields, uint32_t *index) 119{ 120 u_char *p, *end; 121 int64_t hash; 122 uint16_t field; 123 nxt_str_t str; 124 nxt_var_decl_t *decl; 125 nxt_var_field_t *f; 126 127 f = NULL; 128 field = 0; 129 decl = nxt_var_hash_find(name); 130 131 if (decl == NULL) { 132 p = name->start; 133 end = p + name->length; 134 135 while (p < end) { 136 if (*p++ == '_') { 137 break; 138 } 139 } 140 141 if (p == end) { 142 return NULL; 143 } 144 145 str.start = name->start; 146 str.length = p - 1 - name->start; 147 148 decl = nxt_var_hash_find(&str); 149 150 if (decl != NULL) { 151 str.start = p; 152 str.length = end - p; 153 154 hash = decl->field_hash(fields->mem_pool, &str); 155 if (nxt_slow_path(hash == -1)) { 156 return NULL; 157 } 158 159 f = nxt_var_field_add(fields, &str, (uint32_t) hash); 160 if (nxt_slow_path(f == NULL)) { 161 return NULL; 162 } 163 164 field = f->index; 165 } 166 } 167 168 if (decl != NULL) { 169 if (decl->field_hash != NULL && f == NULL) { 170 return NULL; 171 } 172 173 if (index != NULL) { 174 *index = (decl->index << 16) | field; 175 } 176 } 177 178 return decl; 179} 180 181 182static nxt_var_field_t * 183nxt_var_field_add(nxt_array_t *fields, nxt_str_t *name, uint32_t hash) 184{ 185 nxt_uint_t i; 186 nxt_var_field_t *field; 187 188 field = fields->elts; 189 190 for (i = 0; i < fields->nelts; i++) { 191 if (field[i].hash == hash 192 && nxt_strstr_eq(&field[i].name, name)) 193 { 194 return field; 195 } 196 } 197 198 field = nxt_array_add(fields); 199 if (nxt_slow_path(field == NULL)) { 200 return NULL; 201 } 202 203 field->name = *name; 204 field->hash = hash; 205 field->index = fields->nelts - 1; 206 207 return field; 208} 209 210 211nxt_var_field_t * 212nxt_var_field_get(nxt_array_t *fields, uint16_t index) 213{ 214 nxt_uint_t nfields; 215 nxt_var_field_t *field; 216 217 field = fields->elts; 218 nfields = fields->nelts; 219 220 if (nfields > 0 && index <= nfields) { 221 return &field[index]; 222 } 223 224 return NULL; 225} 226 227
|
112static nxt_int_t 113nxt_var_cache_test(nxt_lvlhsh_query_t *lhq, void *data) 114{ 115 return NXT_OK; 116} 117 118 119static nxt_str_t * 120nxt_var_cache_value(nxt_task_t *task, nxt_var_query_t *query, uint32_t index) 121{ 122 nxt_int_t ret; 123 nxt_str_t *value; 124 nxt_lvlhsh_query_t lhq; 125 126 value = query->spare; 127 128 if (value == NULL) { 129 value = nxt_mp_zget(query->pool, sizeof(nxt_str_t)); 130 if (nxt_slow_path(value == NULL)) { 131 return NULL; 132 } 133 134 query->spare = value; 135 } 136 137 lhq.key_hash = nxt_murmur_hash2_uint32(&index); 138 lhq.replace = 0; 139 lhq.key.length = sizeof(uint32_t); 140 lhq.key.start = (u_char *) &index; 141 lhq.value = value; 142 lhq.proto = &nxt_var_cache_proto; 143 lhq.pool = query->pool; 144 145 ret = nxt_lvlhsh_insert(&query->cache, &lhq); 146 if (nxt_slow_path(ret == NXT_ERROR)) { 147 return NULL; 148 } 149 150 if (ret == NXT_OK) {
| 228static nxt_int_t 229nxt_var_cache_test(nxt_lvlhsh_query_t *lhq, void *data) 230{ 231 return NXT_OK; 232} 233 234 235static nxt_str_t * 236nxt_var_cache_value(nxt_task_t *task, nxt_var_query_t *query, uint32_t index) 237{ 238 nxt_int_t ret; 239 nxt_str_t *value; 240 nxt_lvlhsh_query_t lhq; 241 242 value = query->spare; 243 244 if (value == NULL) { 245 value = nxt_mp_zget(query->pool, sizeof(nxt_str_t)); 246 if (nxt_slow_path(value == NULL)) { 247 return NULL; 248 } 249 250 query->spare = value; 251 } 252 253 lhq.key_hash = nxt_murmur_hash2_uint32(&index); 254 lhq.replace = 0; 255 lhq.key.length = sizeof(uint32_t); 256 lhq.key.start = (u_char *) &index; 257 lhq.value = value; 258 lhq.proto = &nxt_var_cache_proto; 259 lhq.pool = query->pool; 260 261 ret = nxt_lvlhsh_insert(&query->cache, &lhq); 262 if (nxt_slow_path(ret == NXT_ERROR)) { 263 return NULL; 264 } 265 266 if (ret == NXT_OK) {
|
151 ret = nxt_var_index[index](task, value, query->ctx);
| 267 ret = nxt_var_index[index >> 16](task, value, query->ctx, 268 index & 0xffff);
|
152 if (nxt_slow_path(ret != NXT_OK)) { 153 return NULL; 154 } 155 156 query->spare = NULL; 157 } 158 159 return lhq.value; 160} 161 162 163nxt_int_t 164nxt_var_register(nxt_var_decl_t *decl, size_t n) 165{ 166 nxt_uint_t i; 167 nxt_lvlhsh_query_t lhq; 168 169 lhq.replace = 0; 170 lhq.proto = &nxt_var_hash_proto; 171 172 for (i = 0; i < n; i++) { 173 lhq.key = decl[i].name; 174 lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); 175 lhq.value = &decl[i]; 176 177 if (nxt_slow_path(nxt_lvlhsh_insert(&nxt_var_hash, &lhq) != NXT_OK)) { 178 return NXT_ERROR; 179 } 180 } 181 182 nxt_var_count += n; 183 184 return NXT_OK; 185} 186 187 188nxt_int_t 189nxt_var_index_init(void) 190{ 191 nxt_uint_t i; 192 nxt_var_decl_t *decl; 193 nxt_var_handler_t *index; 194 nxt_lvlhsh_each_t lhe; 195 196 index = nxt_memalign(64, nxt_var_count * sizeof(nxt_var_handler_t)); 197 if (index == NULL) { 198 return NXT_ERROR; 199 } 200 201 nxt_lvlhsh_each_init(&lhe, &nxt_var_hash_proto); 202 203 for (i = 0; i < nxt_var_count; i++) { 204 decl = nxt_lvlhsh_each(&nxt_var_hash, &lhe); 205 decl->index = i; 206 index[i] = decl->handler; 207 } 208 209 nxt_var_index = index; 210 211 return NXT_OK; 212} 213 214 215nxt_var_t *
| 269 if (nxt_slow_path(ret != NXT_OK)) { 270 return NULL; 271 } 272 273 query->spare = NULL; 274 } 275 276 return lhq.value; 277} 278 279 280nxt_int_t 281nxt_var_register(nxt_var_decl_t *decl, size_t n) 282{ 283 nxt_uint_t i; 284 nxt_lvlhsh_query_t lhq; 285 286 lhq.replace = 0; 287 lhq.proto = &nxt_var_hash_proto; 288 289 for (i = 0; i < n; i++) { 290 lhq.key = decl[i].name; 291 lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); 292 lhq.value = &decl[i]; 293 294 if (nxt_slow_path(nxt_lvlhsh_insert(&nxt_var_hash, &lhq) != NXT_OK)) { 295 return NXT_ERROR; 296 } 297 } 298 299 nxt_var_count += n; 300 301 return NXT_OK; 302} 303 304 305nxt_int_t 306nxt_var_index_init(void) 307{ 308 nxt_uint_t i; 309 nxt_var_decl_t *decl; 310 nxt_var_handler_t *index; 311 nxt_lvlhsh_each_t lhe; 312 313 index = nxt_memalign(64, nxt_var_count * sizeof(nxt_var_handler_t)); 314 if (index == NULL) { 315 return NXT_ERROR; 316 } 317 318 nxt_lvlhsh_each_init(&lhe, &nxt_var_hash_proto); 319 320 for (i = 0; i < nxt_var_count; i++) { 321 decl = nxt_lvlhsh_each(&nxt_var_hash, &lhe); 322 decl->index = i; 323 index[i] = decl->handler; 324 } 325 326 nxt_var_index = index; 327 328 return NXT_OK; 329} 330 331 332nxt_var_t *
|
216nxt_var_compile(nxt_str_t *str, nxt_mp_t *mp, nxt_bool_t strz)
| 333nxt_var_compile(nxt_str_t *str, nxt_mp_t *mp, nxt_array_t *fields, 334 nxt_bool_t strz)
|
217{ 218 u_char *p, *end, *next, *src; 219 size_t size;
| 335{ 336 u_char *p, *end, *next, *src; 337 size_t size;
|
| 338 uint32_t index;
|
220 nxt_var_t *var; 221 nxt_str_t part; 222 nxt_uint_t n; 223 nxt_bool_t is_var; 224 nxt_var_sub_t *subs; 225 nxt_var_decl_t *decl; 226 227 n = 0; 228 229 p = str->start; 230 end = p + str->length; 231 232 while (p < end) { 233 p = nxt_var_next_part(p, end - p, &part, &is_var); 234 if (nxt_slow_path(p == NULL)) { 235 return NULL; 236 } 237 238 if (is_var) { 239 n++; 240 } 241 } 242 243 size = sizeof(nxt_var_t) + n * sizeof(nxt_var_sub_t) + str->length; 244 245 var = nxt_mp_get(mp, size + strz); 246 if (nxt_slow_path(var == NULL)) { 247 return NULL; 248 } 249 250 var->length = str->length; 251 var->vars = n; 252 var->strz = strz; 253 254 subs = nxt_var_subs(var); 255 src = nxt_var_raw_start(var); 256 257 nxt_memcpy(src, str->start, str->length); 258 259 if (strz) { 260 src[str->length] = '\0'; 261 } 262 263 n = 0; 264 p = str->start; 265 266 while (p < end) { 267 next = nxt_var_next_part(p, end - p, &part, &is_var); 268 269 if (is_var) {
| 339 nxt_var_t *var; 340 nxt_str_t part; 341 nxt_uint_t n; 342 nxt_bool_t is_var; 343 nxt_var_sub_t *subs; 344 nxt_var_decl_t *decl; 345 346 n = 0; 347 348 p = str->start; 349 end = p + str->length; 350 351 while (p < end) { 352 p = nxt_var_next_part(p, end - p, &part, &is_var); 353 if (nxt_slow_path(p == NULL)) { 354 return NULL; 355 } 356 357 if (is_var) { 358 n++; 359 } 360 } 361 362 size = sizeof(nxt_var_t) + n * sizeof(nxt_var_sub_t) + str->length; 363 364 var = nxt_mp_get(mp, size + strz); 365 if (nxt_slow_path(var == NULL)) { 366 return NULL; 367 } 368 369 var->length = str->length; 370 var->vars = n; 371 var->strz = strz; 372 373 subs = nxt_var_subs(var); 374 src = nxt_var_raw_start(var); 375 376 nxt_memcpy(src, str->start, str->length); 377 378 if (strz) { 379 src[str->length] = '\0'; 380 } 381 382 n = 0; 383 p = str->start; 384 385 while (p < end) { 386 next = nxt_var_next_part(p, end - p, &part, &is_var); 387 388 if (is_var) {
|
270 decl = nxt_var_hash_find(&part);
| 389 decl = nxt_var_decl_get(&part, fields, &index);
|
271 if (nxt_slow_path(decl == NULL)) { 272 return NULL; 273 } 274
| 390 if (nxt_slow_path(decl == NULL)) { 391 return NULL; 392 } 393
|
275 subs[n].index = decl->index;
| 394 subs[n].index = index;
|
276 subs[n].length = next - p; 277 subs[n].position = p - str->start; 278 279 n++; 280 } 281 282 p = next; 283 } 284 285 return var; 286} 287 288 289nxt_int_t
| 395 subs[n].length = next - p; 396 subs[n].position = p - str->start; 397 398 n++; 399 } 400 401 p = next; 402 } 403 404 return var; 405} 406 407 408nxt_int_t
|
290nxt_var_test(nxt_str_t *str, u_char *error)
| 409nxt_var_test(nxt_str_t *str, nxt_array_t *fields, u_char *error)
|
291{ 292 u_char *p, *end, *next; 293 nxt_str_t part; 294 nxt_bool_t is_var; 295 nxt_var_decl_t *decl; 296 297 p = str->start; 298 end = p + str->length; 299 300 while (p < end) { 301 next = nxt_var_next_part(p, end - p, &part, &is_var); 302 303 if (next == NULL) { 304 nxt_sprintf(error, error + NXT_MAX_ERROR_STR, 305 "Invalid variable at position %uz%Z", p - str->start); 306 307 return NXT_ERROR; 308 } 309 310 if (is_var) {
| 410{ 411 u_char *p, *end, *next; 412 nxt_str_t part; 413 nxt_bool_t is_var; 414 nxt_var_decl_t *decl; 415 416 p = str->start; 417 end = p + str->length; 418 419 while (p < end) { 420 next = nxt_var_next_part(p, end - p, &part, &is_var); 421 422 if (next == NULL) { 423 nxt_sprintf(error, error + NXT_MAX_ERROR_STR, 424 "Invalid variable at position %uz%Z", p - str->start); 425 426 return NXT_ERROR; 427 } 428 429 if (is_var) {
|
311 decl = nxt_var_hash_find(&part);
| 430 decl = nxt_var_decl_get(&part, fields, NULL);
|
312 313 if (decl == NULL) { 314 nxt_sprintf(error, error + NXT_MAX_ERROR_STR, 315 "Unknown variable \"%V\"%Z", &part); 316 317 return NXT_ERROR; 318 } 319 } 320 321 p = next; 322 } 323 324 return NXT_OK; 325} 326 327 328static u_char * 329nxt_var_next_part(u_char *start, size_t length, nxt_str_t *part, 330 nxt_bool_t *is_var) 331{ 332 u_char *p, *end, ch, c; 333 nxt_bool_t bracket; 334 335 end = start + length; 336 337 p = nxt_memchr(start, '$', length); 338 339 if (p == start) { 340 *is_var = 1; 341 342 p++; 343 344 if (p == end) { 345 return NULL; 346 } 347 348 if (*p == '{') { 349 bracket = 1; 350 351 if (end - p < 2) { 352 return NULL; 353 } 354 355 p++; 356 357 } else { 358 bracket = 0; 359 } 360 361 start = p; 362 363 for ( ;; ) { 364 ch = *p; 365 366 c = (u_char) (ch | 0x20); 367 if ((c < 'a' || c > 'z') && ch != '_') { 368 369 if (bracket && ch != '}') { 370 return NULL; 371 } 372 373 break; 374 } 375 376 p++; 377 378 if (p == end) { 379 if (bracket) { 380 return NULL; 381 } 382 383 break; 384 } 385 } 386 387 length = p - start; 388 end = p + bracket; 389 390 } else { 391 *is_var = 0; 392 393 if (p != NULL) { 394 length = p - start; 395 end = p; 396 } 397 } 398 399 part->length = length; 400 part->start = start; 401 402 return end; 403} 404 405 406inline void 407nxt_var_raw(nxt_var_t *var, nxt_str_t *str) 408{ 409 str->length = var->length; 410 str->start = nxt_var_raw_start(var); 411} 412 413 414inline nxt_bool_t 415nxt_var_is_const(nxt_var_t *var) 416{ 417 return (var->vars == 0); 418} 419 420 421nxt_int_t 422nxt_var_query_init(nxt_var_query_t **query_p, void *ctx, nxt_mp_t *mp) 423{ 424 nxt_var_query_t *query; 425 426 query = *query_p; 427 428 if (*query_p == NULL) { 429 query = nxt_mp_zget(mp, sizeof(nxt_var_query_t)); 430 if (nxt_slow_path(query == NULL)) { 431 return NXT_ERROR; 432 } 433 } 434 435 query->pool = mp; 436 query->ctx = ctx; 437 438 *query_p = query; 439 440 return NXT_OK; 441} 442 443 444void 445nxt_var_query(nxt_task_t *task, nxt_var_query_t *query, nxt_var_t *var, 446 nxt_str_t *str) 447{ 448 u_char *p, *src; 449 size_t length, last, next; 450 nxt_str_t *value, **part; 451 nxt_uint_t i; 452 nxt_array_t parts; 453 nxt_var_sub_t *subs; 454 455 if (nxt_var_is_const(var)) { 456 nxt_var_raw(var, str); 457 return; 458 } 459 460 if (nxt_slow_path(query->failed)) { 461 return; 462 } 463 464 nxt_memzero(&parts, sizeof(nxt_array_t)); 465 nxt_array_init(&parts, query->pool, sizeof(nxt_str_t *)); 466 467 subs = nxt_var_subs(var); 468 469 length = var->length; 470 471 for (i = 0; i < var->vars; i++) { 472 value = nxt_var_cache_value(task, query, subs[i].index); 473 if (nxt_slow_path(value == NULL)) { 474 goto fail; 475 } 476 477 part = nxt_array_add(&parts); 478 if (nxt_slow_path(part == NULL)) { 479 goto fail; 480 } 481 482 *part = value; 483 484 length += value->length - subs[i].length; 485 } 486 487 p = nxt_mp_nget(query->pool, length + var->strz); 488 if (nxt_slow_path(p == NULL)) { 489 goto fail; 490 } 491 492 str->length = length; 493 str->start = p; 494 495 part = parts.elts; 496 src = nxt_var_raw_start(var); 497 498 last = 0; 499 500 for (i = 0; i < var->vars; i++) { 501 next = subs[i].position; 502 503 if (next != last) { 504 p = nxt_cpymem(p, &src[last], next - last); 505 } 506 507 p = nxt_cpymem(p, part[i]->start, part[i]->length); 508 509 last = next + subs[i].length; 510 } 511 512 if (last != var->length) { 513 p = nxt_cpymem(p, &src[last], var->length - last); 514 } 515 516 if (var->strz) { 517 *p = '\0'; 518 } 519 520 nxt_debug(task, "var: \"%*s\" -> \"%V\"", length, src, str); 521 522 return; 523 524fail: 525 526 query->failed = 1; 527} 528 529 530void 531nxt_var_query_resolve(nxt_task_t *task, nxt_var_query_t *query, void *data, 532 nxt_work_handler_t ready, nxt_work_handler_t error) 533{ 534 query->data = data; 535 query->ready = ready; 536 query->error = error; 537 538 if (query->waiting == 0) { 539 nxt_work_queue_add(&task->thread->engine->fast_work_queue, 540 query->failed ? query->error : query->ready, 541 task, query->ctx, query->data); 542 } 543} 544 545 546void 547nxt_var_query_handle(nxt_task_t *task, nxt_var_query_t *query, 548 nxt_bool_t failed) 549{ 550 query->failed |= failed; 551 552 if (--query->waiting == 0) { 553 nxt_work_queue_add(&task->thread->engine->fast_work_queue, 554 query->failed ? query->error : query->ready, 555 task, query->ctx, query->data); 556 } 557}
| 431 432 if (decl == NULL) { 433 nxt_sprintf(error, error + NXT_MAX_ERROR_STR, 434 "Unknown variable \"%V\"%Z", &part); 435 436 return NXT_ERROR; 437 } 438 } 439 440 p = next; 441 } 442 443 return NXT_OK; 444} 445 446 447static u_char * 448nxt_var_next_part(u_char *start, size_t length, nxt_str_t *part, 449 nxt_bool_t *is_var) 450{ 451 u_char *p, *end, ch, c; 452 nxt_bool_t bracket; 453 454 end = start + length; 455 456 p = nxt_memchr(start, '$', length); 457 458 if (p == start) { 459 *is_var = 1; 460 461 p++; 462 463 if (p == end) { 464 return NULL; 465 } 466 467 if (*p == '{') { 468 bracket = 1; 469 470 if (end - p < 2) { 471 return NULL; 472 } 473 474 p++; 475 476 } else { 477 bracket = 0; 478 } 479 480 start = p; 481 482 for ( ;; ) { 483 ch = *p; 484 485 c = (u_char) (ch | 0x20); 486 if ((c < 'a' || c > 'z') && ch != '_') { 487 488 if (bracket && ch != '}') { 489 return NULL; 490 } 491 492 break; 493 } 494 495 p++; 496 497 if (p == end) { 498 if (bracket) { 499 return NULL; 500 } 501 502 break; 503 } 504 } 505 506 length = p - start; 507 end = p + bracket; 508 509 } else { 510 *is_var = 0; 511 512 if (p != NULL) { 513 length = p - start; 514 end = p; 515 } 516 } 517 518 part->length = length; 519 part->start = start; 520 521 return end; 522} 523 524 525inline void 526nxt_var_raw(nxt_var_t *var, nxt_str_t *str) 527{ 528 str->length = var->length; 529 str->start = nxt_var_raw_start(var); 530} 531 532 533inline nxt_bool_t 534nxt_var_is_const(nxt_var_t *var) 535{ 536 return (var->vars == 0); 537} 538 539 540nxt_int_t 541nxt_var_query_init(nxt_var_query_t **query_p, void *ctx, nxt_mp_t *mp) 542{ 543 nxt_var_query_t *query; 544 545 query = *query_p; 546 547 if (*query_p == NULL) { 548 query = nxt_mp_zget(mp, sizeof(nxt_var_query_t)); 549 if (nxt_slow_path(query == NULL)) { 550 return NXT_ERROR; 551 } 552 } 553 554 query->pool = mp; 555 query->ctx = ctx; 556 557 *query_p = query; 558 559 return NXT_OK; 560} 561 562 563void 564nxt_var_query(nxt_task_t *task, nxt_var_query_t *query, nxt_var_t *var, 565 nxt_str_t *str) 566{ 567 u_char *p, *src; 568 size_t length, last, next; 569 nxt_str_t *value, **part; 570 nxt_uint_t i; 571 nxt_array_t parts; 572 nxt_var_sub_t *subs; 573 574 if (nxt_var_is_const(var)) { 575 nxt_var_raw(var, str); 576 return; 577 } 578 579 if (nxt_slow_path(query->failed)) { 580 return; 581 } 582 583 nxt_memzero(&parts, sizeof(nxt_array_t)); 584 nxt_array_init(&parts, query->pool, sizeof(nxt_str_t *)); 585 586 subs = nxt_var_subs(var); 587 588 length = var->length; 589 590 for (i = 0; i < var->vars; i++) { 591 value = nxt_var_cache_value(task, query, subs[i].index); 592 if (nxt_slow_path(value == NULL)) { 593 goto fail; 594 } 595 596 part = nxt_array_add(&parts); 597 if (nxt_slow_path(part == NULL)) { 598 goto fail; 599 } 600 601 *part = value; 602 603 length += value->length - subs[i].length; 604 } 605 606 p = nxt_mp_nget(query->pool, length + var->strz); 607 if (nxt_slow_path(p == NULL)) { 608 goto fail; 609 } 610 611 str->length = length; 612 str->start = p; 613 614 part = parts.elts; 615 src = nxt_var_raw_start(var); 616 617 last = 0; 618 619 for (i = 0; i < var->vars; i++) { 620 next = subs[i].position; 621 622 if (next != last) { 623 p = nxt_cpymem(p, &src[last], next - last); 624 } 625 626 p = nxt_cpymem(p, part[i]->start, part[i]->length); 627 628 last = next + subs[i].length; 629 } 630 631 if (last != var->length) { 632 p = nxt_cpymem(p, &src[last], var->length - last); 633 } 634 635 if (var->strz) { 636 *p = '\0'; 637 } 638 639 nxt_debug(task, "var: \"%*s\" -> \"%V\"", length, src, str); 640 641 return; 642 643fail: 644 645 query->failed = 1; 646} 647 648 649void 650nxt_var_query_resolve(nxt_task_t *task, nxt_var_query_t *query, void *data, 651 nxt_work_handler_t ready, nxt_work_handler_t error) 652{ 653 query->data = data; 654 query->ready = ready; 655 query->error = error; 656 657 if (query->waiting == 0) { 658 nxt_work_queue_add(&task->thread->engine->fast_work_queue, 659 query->failed ? query->error : query->ready, 660 task, query->ctx, query->data); 661 } 662} 663 664 665void 666nxt_var_query_handle(nxt_task_t *task, nxt_var_query_t *query, 667 nxt_bool_t failed) 668{ 669 query->failed |= failed; 670 671 if (--query->waiting == 0) { 672 nxt_work_queue_add(&task->thread->engine->fast_work_queue, 673 query->failed ? query->error : query->ready, 674 task, query->ctx, query->data); 675 } 676}
|