comparison src/http/modules/ngx_http_ssi_filter_module.c @ 102:f63280c59dd5 NGINX_0_2_5

nginx 0.2.5 *) 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 <http://sysoev.ru>
date Tue, 04 Oct 2005 00:00:00 +0400
parents d6800bbe720e
children cf3d6edb3ad6
comparison
equal deleted inserted replaced
101:5bb09dde34e7 102:f63280c59dd5
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