Mercurial > hg > nginx
comparison src/http/modules/ngx_http_ssi_filter_module.c @ 553:45033d85b30e release-0.2.5
nginx-0.2.5-RELEASE import
*) Change: the duplicate value of the ngx_http_geo_module variable now
causes the warning and changes old value.
*) Feature: the ngx_http_ssi_module supports the "set" command.
*) Feature: the ngx_http_ssi_module supports the "file" parameter in
the "include" command.
*) Feature: the ngx_http_ssi_module supports the variable value
substitutions in expressions of the "if" command.
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Tue, 04 Oct 2005 10:38:53 +0000 |
parents | 483cca230603 |
children | c1f965ef9718 |
comparison
equal
deleted
inserted
replaced
552:b6f3197058d3 | 553:45033d85b30e |
---|---|
6 | 6 |
7 #include <ngx_config.h> | 7 #include <ngx_config.h> |
8 #include <ngx_core.h> | 8 #include <ngx_core.h> |
9 #include <ngx_http.h> | 9 #include <ngx_http.h> |
10 | 10 |
11 #define NGX_HTTP_SSI_MAX_PARAMS 16 | 11 #define NGX_HTTP_SSI_MAX_PARAMS 16 |
12 | 12 |
13 #define NGX_HTTP_SSI_COMMAND_LEN 31 | 13 #define NGX_HTTP_SSI_COMMAND_LEN 31 |
14 #define NGX_HTTP_SSI_PARAM_LEN 31 | 14 #define NGX_HTTP_SSI_PARAM_LEN 31 |
15 #define NGX_HTTP_SSI_PARAMS_N 4 | 15 #define NGX_HTTP_SSI_PARAMS_N 4 |
16 | 16 |
17 #define NGX_HTTP_SSI_ERROR 1 | 17 #define NGX_HTTP_SSI_ERROR 1 |
18 | 18 |
19 #define NGX_HTTP_SSI_DATE_LEN 2048 | 19 #define NGX_HTTP_SSI_DATE_LEN 2048 |
20 | |
21 | |
22 #define NGX_HTTP_SSI_ADD_PREFIX 1 | |
20 | 23 |
21 | 24 |
22 typedef struct { | 25 typedef struct { |
23 ngx_flag_t enable; | 26 ngx_flag_t enable; |
24 ngx_flag_t silent_errors; | 27 ngx_flag_t silent_errors; |
27 ngx_array_t *types; /* array of ngx_str_t */ | 30 ngx_array_t *types; /* array of ngx_str_t */ |
28 | 31 |
29 size_t min_file_chunk; | 32 size_t min_file_chunk; |
30 size_t value_len; | 33 size_t value_len; |
31 } ngx_http_ssi_conf_t; | 34 } ngx_http_ssi_conf_t; |
35 | |
36 | |
37 typedef struct { | |
38 ngx_str_t name; | |
39 ngx_str_t value; | |
40 } ngx_http_ssi_var_t; | |
32 | 41 |
33 | 42 |
34 typedef struct { | 43 typedef struct { |
35 ngx_buf_t *buf; | 44 ngx_buf_t *buf; |
36 | 45 |
53 ngx_uint_t saved_state; | 62 ngx_uint_t saved_state; |
54 size_t saved; | 63 size_t saved; |
55 size_t looked; | 64 size_t looked; |
56 | 65 |
57 size_t value_len; | 66 size_t value_len; |
67 | |
68 ngx_array_t variables; | |
58 | 69 |
59 ngx_uint_t output; /* unsigned output:1; */ | 70 ngx_uint_t output; /* unsigned output:1; */ |
60 | 71 |
61 ngx_str_t timefmt; | 72 ngx_str_t timefmt; |
62 ngx_str_t errmsg; | 73 ngx_str_t errmsg; |
111 | 122 |
112 static ngx_int_t ngx_http_ssi_output(ngx_http_request_t *r, | 123 static ngx_int_t ngx_http_ssi_output(ngx_http_request_t *r, |
113 ngx_http_ssi_ctx_t *ctx); | 124 ngx_http_ssi_ctx_t *ctx); |
114 static ngx_int_t ngx_http_ssi_parse(ngx_http_request_t *r, | 125 static ngx_int_t ngx_http_ssi_parse(ngx_http_request_t *r, |
115 ngx_http_ssi_ctx_t *ctx); | 126 ngx_http_ssi_ctx_t *ctx); |
116 | 127 static ngx_str_t *ngx_http_ssi_get_variable(ngx_http_request_t *r, |
128 ngx_str_t *name); | |
129 static ngx_int_t ngx_http_ssi_evaluate_string(ngx_http_request_t *r, | |
130 ngx_http_ssi_ctx_t *ctx, ngx_str_t *text, ngx_uint_t flags); | |
131 | |
132 static ngx_int_t ngx_http_ssi_include(ngx_http_request_t *r, | |
133 ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); | |
117 static ngx_int_t ngx_http_ssi_echo(ngx_http_request_t *r, | 134 static ngx_int_t ngx_http_ssi_echo(ngx_http_request_t *r, |
118 ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); | 135 ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); |
119 static ngx_int_t ngx_http_ssi_config(ngx_http_request_t *r, | 136 static ngx_int_t ngx_http_ssi_config(ngx_http_request_t *r, |
120 ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); | 137 ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); |
121 static ngx_int_t ngx_http_ssi_include(ngx_http_request_t *r, | 138 static ngx_int_t ngx_http_ssi_set(ngx_http_request_t *r, |
122 ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); | 139 ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); |
123 static ngx_int_t ngx_http_ssi_if(ngx_http_request_t *r, | 140 static ngx_int_t ngx_http_ssi_if(ngx_http_request_t *r, |
124 ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); | 141 ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); |
125 static ngx_int_t ngx_http_ssi_else(ngx_http_request_t *r, | 142 static ngx_int_t ngx_http_ssi_else(ngx_http_request_t *r, |
126 ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); | 143 ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); |
219 | 236 |
220 static u_char ngx_http_ssi_string[] = "<!--"; | 237 static u_char ngx_http_ssi_string[] = "<!--"; |
221 | 238 |
222 static ngx_str_t ngx_http_ssi_none = ngx_string("(none)"); | 239 static ngx_str_t ngx_http_ssi_none = ngx_string("(none)"); |
223 | 240 |
241 #define NGX_HTTP_SSI_INCLUDE_VIRTUAL 0 | |
242 #define NGX_HTTP_SSI_INCLUDE_FILE 1 | |
224 | 243 |
225 #define NGX_HTTP_SSI_ECHO_VAR 0 | 244 #define NGX_HTTP_SSI_ECHO_VAR 0 |
226 #define NGX_HTTP_SSI_ECHO_DEFAULT 1 | 245 #define NGX_HTTP_SSI_ECHO_DEFAULT 1 |
227 | 246 |
228 #define NGX_HTTP_SSI_CONFIG_ERRMSG 0 | 247 #define NGX_HTTP_SSI_CONFIG_ERRMSG 0 |
229 #define NGX_HTTP_SSI_CONFIG_TIMEFMT 1 | 248 #define NGX_HTTP_SSI_CONFIG_TIMEFMT 1 |
230 | 249 |
231 #define NGX_HTTP_SSI_INCLUDE_VIRTUAL 0 | 250 #define NGX_HTTP_SSI_SET_VAR 0 |
232 #define NGX_HTTP_SSI_INCLUDE_FILE 1 | 251 #define NGX_HTTP_SSI_SET_VALUE 1 |
233 | 252 |
234 #define NGX_HTTP_SSI_IF_EXPR 0 | 253 #define NGX_HTTP_SSI_IF_EXPR 0 |
254 | |
255 | |
256 static ngx_http_ssi_param_t ngx_http_ssi_include_params[] = { | |
257 { ngx_string("virtual"), NGX_HTTP_SSI_INCLUDE_VIRTUAL, 0 }, | |
258 { ngx_string("file"), NGX_HTTP_SSI_INCLUDE_FILE, 0 }, | |
259 { ngx_null_string, 0, 0 } | |
260 }; | |
235 | 261 |
236 | 262 |
237 static ngx_http_ssi_param_t ngx_http_ssi_echo_params[] = { | 263 static ngx_http_ssi_param_t ngx_http_ssi_echo_params[] = { |
238 { ngx_string("var"), NGX_HTTP_SSI_ECHO_VAR, 1 }, | 264 { ngx_string("var"), NGX_HTTP_SSI_ECHO_VAR, 1 }, |
239 { ngx_string("default"), NGX_HTTP_SSI_ECHO_DEFAULT, 0 }, | 265 { ngx_string("default"), NGX_HTTP_SSI_ECHO_DEFAULT, 0 }, |
240 { ngx_null_string, 0, 0 } | 266 { ngx_null_string, 0, 0 } |
241 }; | 267 }; |
242 | 268 |
243 static ngx_http_ssi_param_t ngx_http_ssi_include_params[] = { | |
244 { ngx_string("virtual"), NGX_HTTP_SSI_INCLUDE_VIRTUAL, 0 }, | |
245 #if 0 | |
246 { ngx_string("file"), NGX_HTTP_SSI_INCLUDE_FILE, 0 }, | |
247 #endif | |
248 { ngx_null_string, 0, 0 } | |
249 }; | |
250 | |
251 | 269 |
252 static ngx_http_ssi_param_t ngx_http_ssi_config_params[] = { | 270 static ngx_http_ssi_param_t ngx_http_ssi_config_params[] = { |
253 { ngx_string("errmsg"), NGX_HTTP_SSI_CONFIG_ERRMSG, 0 }, | 271 { ngx_string("errmsg"), NGX_HTTP_SSI_CONFIG_ERRMSG, 0 }, |
254 { ngx_string("timefmt"), NGX_HTTP_SSI_CONFIG_TIMEFMT, 0 }, | 272 { ngx_string("timefmt"), NGX_HTTP_SSI_CONFIG_TIMEFMT, 0 }, |
255 { ngx_null_string, 0, 0 } | 273 { ngx_null_string, 0, 0 } |
256 }; | 274 }; |
257 | 275 |
258 | 276 |
277 static ngx_http_ssi_param_t ngx_http_ssi_set_params[] = { | |
278 { ngx_string("var"), NGX_HTTP_SSI_SET_VAR, 1 }, | |
279 { ngx_string("value"), NGX_HTTP_SSI_SET_VALUE, 1 }, | |
280 { ngx_null_string, 0, 0 } | |
281 }; | |
282 | |
283 | |
259 static ngx_http_ssi_param_t ngx_http_ssi_if_params[] = { | 284 static ngx_http_ssi_param_t ngx_http_ssi_if_params[] = { |
260 { ngx_string("expr"), NGX_HTTP_SSI_IF_EXPR, 0 }, | 285 { ngx_string("expr"), NGX_HTTP_SSI_IF_EXPR, 1 }, |
261 { ngx_null_string, 0, 0 } | 286 { ngx_null_string, 0, 0 } |
262 }; | 287 }; |
263 | 288 |
264 | 289 |
265 static ngx_http_ssi_param_t ngx_http_ssi_no_params[] = { | 290 static ngx_http_ssi_param_t ngx_http_ssi_no_params[] = { |
266 { ngx_null_string, 0, 0 } | 291 { ngx_null_string, 0, 0 } |
267 }; | 292 }; |
268 | 293 |
269 | 294 |
270 static ngx_http_ssi_command_t ngx_http_ssi_commands[] = { | 295 static ngx_http_ssi_command_t ngx_http_ssi_commands[] = { |
296 { ngx_string("include"), ngx_http_ssi_include, | |
297 ngx_http_ssi_include_params, 0, 1 }, | |
271 { ngx_string("echo"), ngx_http_ssi_echo, ngx_http_ssi_echo_params, 0, 0 }, | 298 { ngx_string("echo"), ngx_http_ssi_echo, ngx_http_ssi_echo_params, 0, 0 }, |
272 { ngx_string("config"), ngx_http_ssi_config, | 299 { ngx_string("config"), ngx_http_ssi_config, |
273 ngx_http_ssi_config_params, 0, 0 }, | 300 ngx_http_ssi_config_params, 0, 0 }, |
274 { ngx_string("include"), ngx_http_ssi_include, | 301 { ngx_string("set"), ngx_http_ssi_set, ngx_http_ssi_set_params, 0, 0 }, |
275 ngx_http_ssi_include_params, 0, 1 }, | |
276 | 302 |
277 { ngx_string("if"), ngx_http_ssi_if, ngx_http_ssi_if_params, 0, 0 }, | 303 { ngx_string("if"), ngx_http_ssi_if, ngx_http_ssi_if_params, 0, 0 }, |
278 { ngx_string("else"), ngx_http_ssi_else, ngx_http_ssi_no_params, 1, 0 }, | 304 { ngx_string("else"), ngx_http_ssi_else, ngx_http_ssi_no_params, 1, 0 }, |
279 { ngx_string("endif"), ngx_http_ssi_endif, ngx_http_ssi_no_params, 1, 0 }, | 305 { ngx_string("endif"), ngx_http_ssi_endif, ngx_http_ssi_no_params, 1, 0 }, |
280 | 306 |
353 ctx->errmsg.data = (u_char *) | 379 ctx->errmsg.data = (u_char *) |
354 "[an error occurred while processing the directive]"; | 380 "[an error occurred while processing the directive]"; |
355 | 381 |
356 r->filter_need_in_memory = 1; | 382 r->filter_need_in_memory = 1; |
357 | 383 |
358 if (r->main == NULL) { | 384 if (r->main == r) { |
359 r->headers_out.content_length_n = -1; | 385 r->headers_out.content_length_n = -1; |
360 if (r->headers_out.content_length) { | 386 if (r->headers_out.content_length) { |
361 r->headers_out.content_length->hash = 0; | 387 r->headers_out.content_length->hash = 0; |
362 r->headers_out.content_length = NULL; | 388 r->headers_out.content_length = NULL; |
363 } | 389 } |
1299 | 1325 |
1300 return NGX_AGAIN; | 1326 return NGX_AGAIN; |
1301 } | 1327 } |
1302 | 1328 |
1303 | 1329 |
1330 static ngx_str_t * | |
1331 ngx_http_ssi_get_variable(ngx_http_request_t *r, ngx_str_t *name) | |
1332 { | |
1333 ngx_uint_t i; | |
1334 ngx_http_ssi_var_t *var; | |
1335 ngx_http_ssi_ctx_t *ctx; | |
1336 | |
1337 ctx = ngx_http_get_module_ctx(r->main, ngx_http_ssi_filter_module); | |
1338 | |
1339 var = ctx->variables.elts; | |
1340 for (i = 0; i < ctx->variables.nelts; i++) { | |
1341 if (name->len != var[i].name.len) { | |
1342 continue; | |
1343 } | |
1344 | |
1345 if (ngx_strncasecmp(name->data, var[i].name.data, name->len) == 0) { | |
1346 return &var[i].value; | |
1347 } | |
1348 } | |
1349 | |
1350 return NULL; | |
1351 } | |
1352 | |
1353 | |
1354 static ngx_int_t | |
1355 ngx_http_ssi_evaluate_string(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, | |
1356 ngx_str_t *text, ngx_uint_t flags) | |
1357 { | |
1358 u_char ch, *p, **value, *data; | |
1359 size_t *size, len, prefix; | |
1360 ngx_str_t var, part, *val; | |
1361 ngx_uint_t i, j, n, bracket; | |
1362 ngx_array_t lengths, values; | |
1363 ngx_http_variable_value_t *vv; | |
1364 | |
1365 n = ngx_http_script_variables_count(text); | |
1366 | |
1367 if (n == 0) { | |
1368 | |
1369 if (!(flags & NGX_HTTP_SSI_ADD_PREFIX)) { | |
1370 return NGX_OK; | |
1371 } | |
1372 | |
1373 if (text->data[0] != '/') { | |
1374 for (prefix = r->uri.len; prefix; prefix--) { | |
1375 if (r->uri.data[prefix - 1] == '/') { | |
1376 break; | |
1377 } | |
1378 } | |
1379 | |
1380 if (prefix) { | |
1381 len = prefix + text->len; | |
1382 | |
1383 data = ngx_palloc(r->pool, len); | |
1384 if (data == NULL) { | |
1385 return NGX_ERROR; | |
1386 } | |
1387 | |
1388 p = ngx_cpymem(data, r->uri.data, prefix); | |
1389 ngx_memcpy(p, text->data, text->len); | |
1390 | |
1391 text->len = len; | |
1392 text->data = data; | |
1393 } | |
1394 } | |
1395 | |
1396 return NGX_OK; | |
1397 } | |
1398 | |
1399 if (ngx_array_init(&lengths, r->pool, 8, sizeof(size_t *)) != NGX_OK) { | |
1400 return NGX_ERROR; | |
1401 } | |
1402 | |
1403 if (ngx_array_init(&values, r->pool, 8, sizeof(u_char *)) != NGX_OK) { | |
1404 return NGX_ERROR; | |
1405 } | |
1406 | |
1407 len = 0; | |
1408 i = 0; | |
1409 | |
1410 while (i < text->len) { | |
1411 | |
1412 if (text->data[i] == '$') { | |
1413 | |
1414 var.len = 0; | |
1415 | |
1416 if (++i == text->len) { | |
1417 goto invalid_variable; | |
1418 } | |
1419 | |
1420 if (text->data[i] == '{') { | |
1421 bracket = 1; | |
1422 | |
1423 if (++i == text->len) { | |
1424 goto invalid_variable; | |
1425 } | |
1426 | |
1427 var.data = &text->data[i]; | |
1428 | |
1429 } else { | |
1430 bracket = 0; | |
1431 var.data = &text->data[i]; | |
1432 } | |
1433 | |
1434 for ( /* void */ ; i < text->len; i++, var.len++) { | |
1435 ch = text->data[i]; | |
1436 | |
1437 if (ch == '}' && bracket) { | |
1438 i++; | |
1439 bracket = 0; | |
1440 break; | |
1441 } | |
1442 | |
1443 if ((ch >= 'A' && ch <= 'Z') | |
1444 || (ch >= 'a' && ch <= 'z') | |
1445 || (ch >= '0' && ch <= '9') | |
1446 || ch == '_') | |
1447 { | |
1448 continue; | |
1449 } | |
1450 | |
1451 break; | |
1452 } | |
1453 | |
1454 if (bracket) { | |
1455 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1456 "the closing bracket in \"%V\" " | |
1457 "variable is missing", &var); | |
1458 return NGX_ERROR; | |
1459 } | |
1460 | |
1461 if (var.len == 0) { | |
1462 goto invalid_variable; | |
1463 } | |
1464 | |
1465 for (j = 0; j < var.len; j++) { | |
1466 var.data[j] = ngx_tolower(var.data[j]); | |
1467 } | |
1468 | |
1469 val = ngx_http_ssi_get_variable(r, &var); | |
1470 | |
1471 if (val == NULL) { | |
1472 vv = ngx_http_get_variable(r, &var); | |
1473 | |
1474 if (vv == NULL) { | |
1475 return NGX_ERROR; | |
1476 } | |
1477 | |
1478 if (vv == NGX_HTTP_VAR_NOT_FOUND) { | |
1479 continue; | |
1480 } | |
1481 | |
1482 part = vv->text; | |
1483 | |
1484 } else { | |
1485 part = *val; | |
1486 } | |
1487 | |
1488 } else { | |
1489 part.len = 0; | |
1490 part.data = &text->data[i]; | |
1491 | |
1492 while (i < text->len && text->data[i] != '$') { | |
1493 i++; | |
1494 part.len++; | |
1495 } | |
1496 } | |
1497 | |
1498 len += part.len; | |
1499 | |
1500 size = ngx_array_push(&lengths); | |
1501 if (size == NULL) { | |
1502 return NGX_ERROR; | |
1503 } | |
1504 | |
1505 *size = part.len; | |
1506 | |
1507 value = ngx_array_push(&values); | |
1508 if (value == NULL) { | |
1509 return NGX_ERROR; | |
1510 } | |
1511 | |
1512 *value = part.data; | |
1513 } | |
1514 | |
1515 prefix = 0; | |
1516 | |
1517 size = lengths.elts; | |
1518 value = values.elts; | |
1519 | |
1520 if (flags & NGX_HTTP_SSI_ADD_PREFIX) { | |
1521 for (i = 0; i < values.nelts; i++) { | |
1522 if (size[i] != 0) { | |
1523 if (*value[i] != '/') { | |
1524 for (prefix = r->uri.len; prefix; prefix--) { | |
1525 if (r->uri.data[prefix - 1] == '/') { | |
1526 len += prefix; | |
1527 break; | |
1528 } | |
1529 } | |
1530 } | |
1531 | |
1532 break; | |
1533 } | |
1534 } | |
1535 } | |
1536 | |
1537 p = ngx_palloc(r->pool, len); | |
1538 if (p == NULL) { | |
1539 return NGX_ERROR; | |
1540 } | |
1541 | |
1542 text->len = len; | |
1543 text->data = p; | |
1544 | |
1545 if (prefix) { | |
1546 p = ngx_cpymem(p, r->uri.data, prefix); | |
1547 } | |
1548 | |
1549 for (i = 0; i < values.nelts; i++) { | |
1550 p = ngx_cpymem(p, value[i], size[i]); | |
1551 } | |
1552 | |
1553 return NGX_OK; | |
1554 | |
1555 invalid_variable: | |
1556 | |
1557 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1558 "invalid variable name in \"%V\"", text); | |
1559 | |
1560 return NGX_ERROR; | |
1561 } | |
1562 | |
1563 | |
1564 static ngx_int_t | |
1565 ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, | |
1566 ngx_str_t **params) | |
1567 { | |
1568 ngx_str_t *uri, *file, args; | |
1569 ngx_uint_t i; | |
1570 | |
1571 uri = params[NGX_HTTP_SSI_INCLUDE_VIRTUAL]; | |
1572 file = params[NGX_HTTP_SSI_INCLUDE_FILE]; | |
1573 | |
1574 if (uri && file) { | |
1575 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1576 "inlcusion may be either virtual=\"%V\" or file=\"%V\"", | |
1577 uri, file); | |
1578 return NGX_HTTP_SSI_ERROR; | |
1579 } | |
1580 | |
1581 if (uri == NULL && file == NULL) { | |
1582 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1583 "no parameter in \"include\" SSI command"); | |
1584 return NGX_HTTP_SSI_ERROR; | |
1585 } | |
1586 | |
1587 if (uri == NULL) { | |
1588 uri = file; | |
1589 } | |
1590 | |
1591 if (ngx_http_ssi_evaluate_string(r, ctx, uri, NGX_HTTP_SSI_ADD_PREFIX) | |
1592 != NGX_OK) | |
1593 { | |
1594 return NGX_HTTP_SSI_ERROR; | |
1595 } | |
1596 | |
1597 args.len = 0; | |
1598 args.data = NULL; | |
1599 | |
1600 if (params[NGX_HTTP_SSI_INCLUDE_VIRTUAL]) { | |
1601 for (i = 0; i < uri->len; i++) { | |
1602 if (uri->data[i] == '?') { | |
1603 args.len = uri->len - i - 1; | |
1604 args.data = &uri->data[i + 1]; | |
1605 uri->len -= args.len + 1; | |
1606 | |
1607 break; | |
1608 } | |
1609 } | |
1610 } | |
1611 | |
1612 if (ngx_http_subrequest(r, uri, &args) != NGX_OK) { | |
1613 return NGX_HTTP_SSI_ERROR; | |
1614 } | |
1615 | |
1616 return NGX_OK; | |
1617 } | |
1618 | |
1619 | |
1304 static ngx_int_t | 1620 static ngx_int_t |
1305 ngx_http_ssi_echo(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, | 1621 ngx_http_ssi_echo(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, |
1306 ngx_str_t **params) | 1622 ngx_str_t **params) |
1307 { | 1623 { |
1308 ngx_uint_t i; | 1624 ngx_uint_t i; |
1311 ngx_chain_t *cl; | 1627 ngx_chain_t *cl; |
1312 ngx_http_variable_value_t *vv; | 1628 ngx_http_variable_value_t *vv; |
1313 | 1629 |
1314 var = params[NGX_HTTP_SSI_ECHO_VAR]; | 1630 var = params[NGX_HTTP_SSI_ECHO_VAR]; |
1315 | 1631 |
1316 for (i = 0; i < var->len; i++) { | 1632 value = ngx_http_ssi_get_variable(r, var); |
1317 var->data[i] = ngx_tolower(var->data[i]); | 1633 |
1318 } | 1634 if (value == NULL) { |
1319 | 1635 for (i = 0; i < var->len; i++) { |
1320 vv = ngx_http_get_variable(r, var); | 1636 var->data[i] = ngx_tolower(var->data[i]); |
1321 | 1637 } |
1322 if (vv == NULL) { | 1638 |
1323 return NGX_HTTP_SSI_ERROR; | 1639 vv = ngx_http_get_variable(r, var); |
1324 } | 1640 |
1325 | 1641 if (vv == NULL) { |
1326 if (vv == NGX_HTTP_VAR_NOT_FOUND) { | 1642 return NGX_HTTP_SSI_ERROR; |
1643 } | |
1644 | |
1645 if (vv != NGX_HTTP_VAR_NOT_FOUND) { | |
1646 value = &vv->text; | |
1647 } | |
1648 } | |
1649 | |
1650 if (value == NULL) { | |
1327 value = params[NGX_HTTP_SSI_ECHO_DEFAULT]; | 1651 value = params[NGX_HTTP_SSI_ECHO_DEFAULT]; |
1328 | 1652 |
1329 if (value == NULL) { | 1653 if (value == NULL) { |
1330 value = &ngx_http_ssi_none; | 1654 value = &ngx_http_ssi_none; |
1331 | 1655 |
1332 } else if (value->len == 0) { | 1656 } else if (value->len == 0) { |
1333 return NGX_OK; | 1657 return NGX_OK; |
1334 } | 1658 } |
1335 | 1659 |
1336 } else { | 1660 } else { |
1337 value = &vv->text; | |
1338 | |
1339 if (value->len == 0) { | 1661 if (value->len == 0) { |
1340 return NGX_OK; | 1662 return NGX_OK; |
1341 } | 1663 } |
1342 } | 1664 } |
1343 | 1665 |
1385 return NGX_OK; | 1707 return NGX_OK; |
1386 } | 1708 } |
1387 | 1709 |
1388 | 1710 |
1389 static ngx_int_t | 1711 static ngx_int_t |
1390 ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, | 1712 ngx_http_ssi_set(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, |
1391 ngx_str_t **params) | 1713 ngx_str_t **params) |
1392 { | 1714 { |
1393 u_char ch, *p, **value, *data; | 1715 ngx_str_t *name, *value, *vv; |
1394 size_t *size, len, prefix; | 1716 ngx_http_ssi_var_t *var; |
1395 ngx_uint_t i, j, n, bracket; | 1717 ngx_http_ssi_ctx_t *mctx; |
1396 ngx_str_t uri, args, name; | 1718 |
1397 ngx_array_t lengths, values; | 1719 mctx = ngx_http_get_module_ctx(r->main, ngx_http_ssi_filter_module); |
1398 ngx_http_variable_value_t *vv; | 1720 |
1399 | 1721 if (mctx->variables.elts == NULL) { |
1400 /* TODO: file, virtual vs file */ | 1722 if (ngx_array_init(&mctx->variables, r->pool, 4, |
1401 | 1723 sizeof(ngx_http_ssi_var_t)) != NGX_OK) |
1402 uri = *params[NGX_HTTP_SSI_INCLUDE_VIRTUAL]; | 1724 { |
1403 args.len = 0; | |
1404 args.data = NULL; | |
1405 prefix = 0; | |
1406 | |
1407 n = ngx_http_script_variables_count(&uri); | |
1408 | |
1409 if (n > 0) { | |
1410 | |
1411 if (ngx_array_init(&lengths, r->pool, 8, sizeof(size_t *)) != NGX_OK) { | |
1412 return NGX_HTTP_SSI_ERROR; | 1725 return NGX_HTTP_SSI_ERROR; |
1413 } | 1726 } |
1414 | 1727 } |
1415 if (ngx_array_init(&values, r->pool, 8, sizeof(u_char *)) != NGX_OK) { | 1728 |
1416 return NGX_HTTP_SSI_ERROR; | 1729 name = params[NGX_HTTP_SSI_SET_VAR]; |
1417 } | 1730 value = params[NGX_HTTP_SSI_SET_VALUE]; |
1418 | 1731 |
1419 len = 0; | 1732 if (ngx_http_ssi_evaluate_string(r, ctx, value, 0) != NGX_OK) { |
1420 | |
1421 for (i = 0; i < uri.len; /* void */ ) { | |
1422 | |
1423 name.len = 0; | |
1424 | |
1425 if (uri.data[i] == '$') { | |
1426 | |
1427 if (++i == uri.len) { | |
1428 goto invalid_variable; | |
1429 } | |
1430 | |
1431 if (uri.data[i] == '{') { | |
1432 bracket = 1; | |
1433 | |
1434 if (++i == uri.len) { | |
1435 goto invalid_variable; | |
1436 } | |
1437 | |
1438 name.data = &uri.data[i]; | |
1439 | |
1440 } else { | |
1441 bracket = 0; | |
1442 name.data = &uri.data[i]; | |
1443 } | |
1444 | |
1445 for ( /* void */ ; i < uri.len; i++, name.len++) { | |
1446 ch = uri.data[i]; | |
1447 | |
1448 if (ch == '}' && bracket) { | |
1449 i++; | |
1450 bracket = 0; | |
1451 break; | |
1452 } | |
1453 | |
1454 if ((ch >= 'A' && ch <= 'Z') | |
1455 || (ch >= 'a' && ch <= 'z') | |
1456 || (ch >= '0' && ch <= '9') | |
1457 || ch == '_') | |
1458 { | |
1459 continue; | |
1460 } | |
1461 | |
1462 break; | |
1463 } | |
1464 | |
1465 if (bracket) { | |
1466 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1467 "the closing bracket in \"%V\" " | |
1468 "variable is missing", &name); | |
1469 return NGX_HTTP_SSI_ERROR; | |
1470 } | |
1471 | |
1472 if (name.len == 0) { | |
1473 goto invalid_variable; | |
1474 } | |
1475 | |
1476 for (j = 0; j < name.len; j++) { | |
1477 name.data[j] = ngx_tolower(name.data[j]); | |
1478 } | |
1479 | |
1480 vv = ngx_http_get_variable(r, &name); | |
1481 | |
1482 if (vv == NULL) { | |
1483 return NGX_HTTP_SSI_ERROR; | |
1484 } | |
1485 | |
1486 if (vv == NGX_HTTP_VAR_NOT_FOUND) { | |
1487 continue; | |
1488 } | |
1489 | |
1490 name = vv->text; | |
1491 | |
1492 } else { | |
1493 name.data = &uri.data[i]; | |
1494 | |
1495 while (i < uri.len && uri.data[i] != '$') { | |
1496 i++; | |
1497 name.len++; | |
1498 } | |
1499 } | |
1500 | |
1501 len += name.len; | |
1502 | |
1503 size = ngx_array_push(&lengths); | |
1504 if (size == NULL) { | |
1505 return NGX_HTTP_SSI_ERROR; | |
1506 } | |
1507 | |
1508 *size = name.len; | |
1509 | |
1510 value = ngx_array_push(&values); | |
1511 if (value == NULL) { | |
1512 return NGX_HTTP_SSI_ERROR; | |
1513 } | |
1514 | |
1515 *value = name.data; | |
1516 } | |
1517 | |
1518 size = lengths.elts; | |
1519 value = values.elts; | |
1520 | |
1521 for (i = 0; i < values.nelts; i++) { | |
1522 if (size[i] != 0) { | |
1523 if (*value[i] != '/') { | |
1524 for (prefix = r->uri.len; prefix; prefix--) { | |
1525 if (r->uri.data[prefix - 1] == '/') { | |
1526 len += prefix; | |
1527 break; | |
1528 } | |
1529 } | |
1530 } | |
1531 | |
1532 break; | |
1533 } | |
1534 } | |
1535 | |
1536 p = ngx_palloc(r->pool, len); | |
1537 if (p == NULL) { | |
1538 return NGX_HTTP_SSI_ERROR; | |
1539 } | |
1540 | |
1541 uri.len = len; | |
1542 uri.data = p; | |
1543 | |
1544 if (prefix) { | |
1545 p = ngx_cpymem(p, r->uri.data, prefix); | |
1546 } | |
1547 | |
1548 for (i = 0; i < values.nelts; i++) { | |
1549 p = ngx_cpymem(p, value[i], size[i]); | |
1550 } | |
1551 | |
1552 } else { | |
1553 if (uri.data[0] != '/') { | |
1554 for (prefix = r->uri.len; prefix; prefix--) { | |
1555 if (r->uri.data[prefix - 1] == '/') { | |
1556 break; | |
1557 } | |
1558 } | |
1559 | |
1560 if (prefix) { | |
1561 len = prefix + uri.len; | |
1562 | |
1563 data = ngx_palloc(r->pool, len); | |
1564 if (data == NULL) { | |
1565 return NGX_HTTP_SSI_ERROR; | |
1566 } | |
1567 | |
1568 p = ngx_cpymem(data, r->uri.data, prefix); | |
1569 ngx_memcpy(p, uri.data, uri.len); | |
1570 | |
1571 uri.len = len; | |
1572 uri.data = data; | |
1573 } | |
1574 } | |
1575 } | |
1576 | |
1577 for (i = 0; i < uri.len; i++) { | |
1578 if (uri.data[i] == '?') { | |
1579 args.len = uri.len - i - 1; | |
1580 args.data = &uri.data[i + 1]; | |
1581 uri.len -= args.len + 1; | |
1582 | |
1583 break; | |
1584 } | |
1585 } | |
1586 | |
1587 if (ngx_http_subrequest(r, &uri, &args) != NGX_OK) { | |
1588 return NGX_HTTP_SSI_ERROR; | 1733 return NGX_HTTP_SSI_ERROR; |
1589 } | 1734 } |
1590 | 1735 |
1736 vv = ngx_http_ssi_get_variable(r, name); | |
1737 | |
1738 if (vv) { | |
1739 *vv = *value; | |
1740 return NGX_OK; | |
1741 } | |
1742 | |
1743 var = ngx_array_push(&mctx->variables); | |
1744 if (var == NULL) { | |
1745 return NGX_HTTP_SSI_ERROR; | |
1746 } | |
1747 | |
1748 var->name = *name; | |
1749 var->value = *value; | |
1750 | |
1751 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1752 "set: \"%V\"=\"%V\"", name, value); | |
1753 | |
1591 return NGX_OK; | 1754 return NGX_OK; |
1592 | |
1593 invalid_variable: | |
1594 | |
1595 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1596 "invalid variable name in \"%V\"", &uri); | |
1597 | |
1598 return NGX_ERROR; | |
1599 } | 1755 } |
1600 | 1756 |
1601 | 1757 |
1602 static ngx_int_t | 1758 static ngx_int_t |
1603 ngx_http_ssi_if(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, | 1759 ngx_http_ssi_if(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, |
1604 ngx_str_t **params) | 1760 ngx_str_t **params) |
1605 { | 1761 { |
1606 u_char *p, *last; | 1762 u_char *p, *last; |
1607 ngx_str_t *expr, var, left, right; | 1763 ngx_str_t *expr, left, right; |
1608 ngx_int_t rc; | 1764 ngx_int_t rc; |
1609 ngx_uint_t negative, noregex; | 1765 ngx_uint_t negative, noregex; |
1610 ngx_http_variable_value_t *vv; | |
1611 #if (NGX_PCRE) | 1766 #if (NGX_PCRE) |
1612 ngx_str_t err; | 1767 ngx_str_t err; |
1613 ngx_regex_t *regex; | 1768 ngx_regex_t *regex; |
1614 u_char errstr[NGX_MAX_CONF_ERRSTR]; | 1769 u_char errstr[NGX_MAX_CONF_ERRSTR]; |
1615 #endif | 1770 #endif |
1616 | 1771 |
1617 expr = params[NGX_HTTP_SSI_IF_EXPR]; | 1772 expr = params[NGX_HTTP_SSI_IF_EXPR]; |
1618 | 1773 |
1619 if (expr->data[0] != '$') { | 1774 left.data = expr->data; |
1620 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1621 "invalid variable name in \"%V\"", expr); | |
1622 return NGX_HTTP_SSI_ERROR; | |
1623 } | |
1624 | |
1625 var.data = expr->data + 1; | |
1626 last = expr->data + expr->len; | 1775 last = expr->data + expr->len; |
1627 | 1776 |
1628 for (p = var.data; p < last; p++) { | 1777 for (p = left.data; p < last; p++) { |
1629 if (*p >= 'A' && *p <= 'Z') { | 1778 if (*p >= 'A' && *p <= 'Z') { |
1630 *p |= 0x20; | 1779 *p |= 0x20; |
1631 continue; | 1780 continue; |
1632 } | 1781 } |
1633 | 1782 |
1634 if ((*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') { | 1783 if ((*p >= 'a' && *p <= 'z') |
1784 || (*p >= '0' && *p <= '9') | |
1785 || *p == '$' || *p == '{' || *p == '}' || *p == '_') | |
1786 { | |
1635 continue; | 1787 continue; |
1636 } | 1788 } |
1637 | 1789 |
1638 break; | 1790 break; |
1639 } | 1791 } |
1640 | 1792 |
1641 var.len = p - var.data; | 1793 left.len = p - left.data; |
1642 | 1794 |
1643 while (p < last && *p == ' ') { | 1795 while (p < last && *p == ' ') { |
1644 p++; | 1796 p++; |
1645 } | 1797 } |
1646 | 1798 |
1647 vv = ngx_http_get_variable(r, &var); | 1799 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
1648 | 1800 "left: \"%V\"", &left); |
1649 if (vv == NULL) { | 1801 |
1802 if (ngx_http_ssi_evaluate_string(r, ctx, &left, 0) != NGX_OK) { | |
1650 return NGX_HTTP_SSI_ERROR; | 1803 return NGX_HTTP_SSI_ERROR; |
1651 } | 1804 } |
1652 | 1805 |
1806 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1807 "evaluted left: \"%V\"", &left); | |
1808 | |
1653 if (p == last) { | 1809 if (p == last) { |
1654 if (vv != NGX_HTTP_VAR_NOT_FOUND && vv->text.len != 0) { | 1810 if (left.len) { |
1655 ctx->output = 1; | 1811 ctx->output = 1; |
1656 | 1812 |
1657 } else { | 1813 } else { |
1658 ctx->output = 0; | 1814 ctx->output = 0; |
1659 } | 1815 } |
1691 } | 1847 } |
1692 | 1848 |
1693 right.len = last - p; | 1849 right.len = last - p; |
1694 right.data = p; | 1850 right.data = p; |
1695 | 1851 |
1696 if (vv == NGX_HTTP_VAR_NOT_FOUND) { | 1852 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
1697 left.len = 0; | 1853 "right: \"%V\"", &right); |
1698 left.data = (u_char *) ""; | 1854 |
1699 | 1855 if (ngx_http_ssi_evaluate_string(r, ctx, &right, 0) != NGX_OK) { |
1700 } else { | 1856 return NGX_HTTP_SSI_ERROR; |
1701 left = vv->text; | 1857 } |
1702 } | 1858 |
1703 | 1859 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
1704 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 1860 "evaluted right: \"%V\"", &right); |
1705 "left: \"%V\" right: \"%V\"", &left, &right); | |
1706 | 1861 |
1707 if (noregex) { | 1862 if (noregex) { |
1708 if (left.len != right.len) { | 1863 if (left.len != right.len) { |
1709 rc = -1; | 1864 rc = -1; |
1710 | 1865 |