Browse Source

trim support variable value (on/off). (https://github.com/alibaba/tengine/issues/368)

pull/411/head
taoyuanyuan 12 years ago
parent
commit
2cabb684bf
  1. 59
      docs/modules/ngx_http_trim_filter_module.md
  2. 16
      docs/modules/ngx_http_trim_filter_module_cn.md
  3. 111
      src/http/modules/ngx_http_trim_filter_module.c
  4. 77
      tests/test-nginx/cases/trim.t

59
docs/modules/ngx_http_trim_filter_module.md

@ -23,6 +23,14 @@ HTML with a state machine.
Enable or disable trim module for pure HTML. Enable or disable trim module for pure HTML.
This module will retain some contents unchanged, in case that they are enclosed by the tag `pre`,`textarea`,`script` and `style`,as well as IE/SSI/ESI comments. This module will retain some contents unchanged, in case that they are enclosed by the tag `pre`,`textarea`,`script` and `style`,as well as IE/SSI/ESI comments.
Parameter value can contain variables.
Example:
set $flag "off";
if ($condition) {
set $flag "on";
}
trim $flag;
<br/> <br/>
@ -33,6 +41,7 @@ This module will retain some contents unchanged, in case that they are enclosed
**Context:** `http, server, location` **Context:** `http, server, location`
Enable or disable trim module for inline javascript. Enable or disable trim module for inline javascript.
Parameter value can contain variables too.
<br/> <br/>
@ -43,6 +52,7 @@ Enable or disable trim module for inline javascript.
**Context:** `http, server, location` **Context:** `http, server, location`
Enable or disable trim module for inline css. Enable or disable trim module for inline css.
Parameter value can contain variables too.
<br/> <br/>
@ -107,3 +117,52 @@ result:
<script type="text/javascript">str.replace(/ /,"hello");</script> <script type="text/javascript">str.replace(/ /,"hello");</script>
<style type="text/css">body{font-size:20px;line-height:150%;}</style> <style type="text/css">body{font-size:20px;line-height:150%;}</style>
## Trim Rule
### Html
##### Whitespace
+ Remove '\r'.
+ Replace '\t' with space.
+ Replace multiple spaces with a single space.
+ Replace multiple '\n' with a single '\n'.
+ Replace multiple '\n' and '\t' in tag with a single space.
+ Do not trim quoted strings in tag.
+ Do not trim the contents enclosed by the tag `pre`,`textarea`,`script` and `style`.
##### Comment
+ Remove html comment(`<!-- -->`).
+ Do not trim IE/SSI/ESI comments.
IE comment: `<!--[if <![endif]-->`
SSI comment: `<!--# -->`
ESI comment: `<!--esi -->`
### Javascript
Contents enclosed by `<script type="text/javascript">` or `<script>` will be identified as javascript.
##### Whitespace
+ Remove '\r'.
+ Remove '\t','\n' and space that behind '(',',','=',':','[','!','&','|','?',';','>','~','*','{'.
+ Replace multiple spaces with a single space.
+ Do not trim quoted strings and regular expression literals.
##### Comment
+ Remove single comment. `//`
+ Remove multi comment. `/* */`
### Css
Contents enclosed by `<style type="text/css">` or `<style>` will be identified as css.
##### Whiltespace
+ Remove '\r'.
+ Remove '\t','\n' and space that around ';','>','{','}',':',','.
+ Replace multiple '\n' and spaces with a single space.
+ Do not trim quoted strings.
##### Comment
+ Remove css comment(`/* */`).
+ Do not remove child seletor and IE5 /Mac hack comments.
Child seletor hack: `html>/**/body p{color:blue}`
IE5 /Mac hack: `/*\*/.selector{color:khaki}/**/`

16
docs/modules/ngx_http_trim_filter_module_cn.md

@ -22,7 +22,15 @@
**上下文:** `http, server, location` **上下文:** `http, server, location`
使模块有效(失效),删除 html 的注释以及重复的空白符(\n,\r,\t,' ')。 使模块有效(失效),删除 html 的注释以及重复的空白符(\n,\r,\t,' ')。
例外:对于 `pre`,`textarea`,`script`,`style` 和 ie/ssi/esi注释 等标签内的内容不作删除操作。
例外:对于 `pre`,`textarea`,`script`,`style` 和 ie/ssi/esi注释 等标签内的内容不作删除操作。
参数值可以包含变量。
例如:
set $flag "off";
if ($condition) {
set $flag "on";
}
trim $flag;
<br/> <br/>
**trim_js** `on` | `off` **trim_js** `on` | `off`
@ -32,7 +40,8 @@
**上下文:** `http, server, location` **上下文:** `http, server, location`
使模块有效(失效),删除 html 内嵌 javascript 的注释以及重复的空白符(\n,\r,\t,' ')。 使模块有效(失效),删除 html 内嵌 javascript 的注释以及重复的空白符(\n,\r,\t,' ')。
例外:对于非javascript代码的 `script` 标签内容不作删除操作。
例外:对于非javascript代码的 `script` 标签内容不作删除操作。
参数值可以包含变量。
<br/> <br/>
**trim_css** `on` | `off` **trim_css** `on` | `off`
@ -42,7 +51,8 @@
**上下文:** `http, server, location` **上下文:** `http, server, location`
使模块有效(失效),删除 html 内嵌 css 的注释以及重复的空白符(\n,\r,\t,' ')。 使模块有效(失效),删除 html 内嵌 css 的注释以及重复的空白符(\n,\r,\t,' ')。
例外:对于非css代码的 `style` 标签内容不作删除操作。
例外:对于非css代码的 `style` 标签内容不作删除操作。
参数值可以包含变量。
<br/> <br/>
**trim_types** `MIME types` **trim_types** `MIME types`

111
src/http/modules/ngx_http_trim_filter_module.c

@ -23,11 +23,12 @@
#define NGX_HTTP_TRIM_TAG_TEXTAREA 4 #define NGX_HTTP_TRIM_TAG_TEXTAREA 4
typedef struct { typedef struct {
ngx_flag_t trim_enable;
ngx_flag_t js_enable;
ngx_flag_t css_enable;
ngx_hash_t types;
ngx_array_t *types_keys;
ngx_hash_t types;
ngx_array_t *types_keys;
ngx_http_complex_value_t *js;
ngx_http_complex_value_t *css;
ngx_http_complex_value_t *trim;
} ngx_http_trim_loc_conf_t; } ngx_http_trim_loc_conf_t;
@ -45,6 +46,9 @@ typedef struct {
ngx_int_t saved; ngx_int_t saved;
ngx_int_t count; ngx_int_t count;
ngx_uint_t state; ngx_uint_t state;
unsigned js_enable:1;
unsigned css_enable:1;
} ngx_http_trim_ctx_t; } ngx_http_trim_ctx_t;
@ -167,24 +171,24 @@ static ngx_int_t ngx_http_trim_filter_init(ngx_conf_t *cf);
static ngx_command_t ngx_http_trim_commands[] = { static ngx_command_t ngx_http_trim_commands[] = {
{ ngx_string("trim"), { ngx_string("trim"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_http_set_complex_value_slot,
NGX_HTTP_LOC_CONF_OFFSET, NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_trim_loc_conf_t, trim_enable),
offsetof(ngx_http_trim_loc_conf_t, trim),
NULL }, NULL },
{ ngx_string("trim_js"), { ngx_string("trim_js"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_http_set_complex_value_slot,
NGX_HTTP_LOC_CONF_OFFSET, NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_trim_loc_conf_t, js_enable),
offsetof(ngx_http_trim_loc_conf_t, js),
NULL }, NULL },
{ ngx_string("trim_css"), { ngx_string("trim_css"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_http_set_complex_value_slot,
NGX_HTTP_LOC_CONF_OFFSET, NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_trim_loc_conf_t, css_enable),
offsetof(ngx_http_trim_loc_conf_t, css),
NULL }, NULL },
{ ngx_string("trim_types"), { ngx_string("trim_types"),
@ -258,7 +262,7 @@ ngx_http_trim_header_filter(ngx_http_request_t *r)
conf = ngx_http_get_module_loc_conf(r, ngx_http_trim_filter_module); conf = ngx_http_get_module_loc_conf(r, ngx_http_trim_filter_module);
if (!conf->trim_enable
if (!conf->trim
|| r->headers_out.status != NGX_HTTP_OK || r->headers_out.status != NGX_HTTP_OK
|| (r->method & NGX_HTTP_HEAD) || (r->method & NGX_HTTP_HEAD)
|| r->headers_out.content_length_n == 0 || r->headers_out.content_length_n == 0
@ -279,11 +283,45 @@ ngx_http_trim_header_filter(ngx_http_request_t *r)
return ngx_http_next_header_filter(r); return ngx_http_next_header_filter(r);
} }
if (ngx_http_complex_value(r, conf->trim, &flag) != NGX_OK) {
return NGX_ERROR;
}
if (!(flag.len == sizeof("on") - 1
&& ngx_strncmp(flag.data, "on", sizeof("on") - 1) == 0))
{
return ngx_http_next_header_filter(r);
}
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_trim_ctx_t)); ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_trim_ctx_t));
if (ctx == NULL) { if (ctx == NULL) {
return NGX_ERROR; return NGX_ERROR;
} }
if (conf->js) {
if (ngx_http_complex_value(r, conf->js, &flag) != NGX_OK) {
return NGX_ERROR;
}
if (flag.len == sizeof("on") - 1
&& ngx_strncmp(flag.data, "on", sizeof("on") - 1) == 0)
{
ctx->js_enable = 1;
}
}
if (conf->css) {
if (ngx_http_complex_value(r, conf->css, &flag) != NGX_OK) {
return NGX_ERROR;
}
if (flag.len == sizeof("on") - 1
&& ngx_strncmp(flag.data, "on", sizeof("on") - 1) == 0)
{
ctx->css_enable = 1;
}
}
ctx->prev = ' '; ctx->prev = ' ';
ngx_http_set_ctx(r, ctx, ngx_http_trim_filter_module); ngx_http_set_ctx(r, ctx, ngx_http_trim_filter_module);
@ -551,7 +589,7 @@ ngx_http_trim_parse(ngx_http_request_t *r, ngx_buf_t *buf,
ctx->state = trim_state_tag_textarea_end; ctx->state = trim_state_tag_textarea_end;
} else if (ctx->tag == NGX_HTTP_TRIM_TAG_SCRIPT) { } else if (ctx->tag == NGX_HTTP_TRIM_TAG_SCRIPT) {
if (conf->js_enable
if (ctx->js_enable
&& ctx->looked == ngx_http_trim_script_js.len) && ctx->looked == ngx_http_trim_script_js.len)
{ {
ctx->state = trim_state_tag_script_js_text; ctx->state = trim_state_tag_script_js_text;
@ -561,7 +599,7 @@ ngx_http_trim_parse(ngx_http_request_t *r, ngx_buf_t *buf,
} }
} else if (ctx->tag == NGX_HTTP_TRIM_TAG_STYLE) { } else if (ctx->tag == NGX_HTTP_TRIM_TAG_STYLE) {
if (conf->css_enable
if (ctx->css_enable
&& ctx->looked == ngx_http_trim_style_css.len) && ctx->looked == ngx_http_trim_style_css.len)
{ {
ctx->state = trim_state_tag_style_css_text; ctx->state = trim_state_tag_style_css_text;
@ -782,7 +820,7 @@ ngx_http_trim_parse(ngx_http_request_t *r, ngx_buf_t *buf,
look = ngx_http_trim_script.data[ctx->looked++]; /* <script> */ look = ngx_http_trim_script.data[ctx->looked++]; /* <script> */
if (ch == look) { if (ch == look) {
if (ctx->looked == ngx_http_trim_script.len) { if (ctx->looked == ngx_http_trim_script.len) {
if (conf->js_enable) {
if (ctx->js_enable) {
ctx->state = trim_state_tag_script_js_text; ctx->state = trim_state_tag_script_js_text;
} else { } else {
@ -1166,7 +1204,7 @@ ngx_http_trim_parse(ngx_http_request_t *r, ngx_buf_t *buf,
look = ngx_http_trim_style.data[ctx->looked++]; /* <style> */ look = ngx_http_trim_style.data[ctx->looked++]; /* <style> */
if (ch == look) { if (ch == look) {
if (ctx->looked == ngx_http_trim_style.len) { if (ctx->looked == ngx_http_trim_style.len) {
if (conf->css_enable) {
if (ctx->css_enable) {
ctx->state = trim_state_tag_style_css_text; ctx->state = trim_state_tag_style_css_text;
} else { } else {
@ -1796,7 +1834,7 @@ ngx_http_trim_parse(ngx_http_request_t *r, ngx_buf_t *buf,
ctx->state = trim_state_tag_textarea_end; ctx->state = trim_state_tag_textarea_end;
} else if (ctx->tag == NGX_HTTP_TRIM_TAG_SCRIPT) { } else if (ctx->tag == NGX_HTTP_TRIM_TAG_SCRIPT) {
if (conf->js_enable
if (ctx->js_enable
&& ctx->looked == ngx_http_trim_script_js.len) && ctx->looked == ngx_http_trim_script_js.len)
{ {
ctx->state = trim_state_tag_script_js_text; ctx->state = trim_state_tag_script_js_text;
@ -1806,7 +1844,7 @@ ngx_http_trim_parse(ngx_http_request_t *r, ngx_buf_t *buf,
} }
} else if (ctx->tag == NGX_HTTP_TRIM_TAG_STYLE) { } else if (ctx->tag == NGX_HTTP_TRIM_TAG_STYLE) {
if (conf->css_enable
if (ctx->css_enable
&& ctx->looked == ngx_http_trim_style_css.len) && ctx->looked == ngx_http_trim_style_css.len)
{ {
ctx->state = trim_state_tag_style_css_text; ctx->state = trim_state_tag_style_css_text;
@ -1847,7 +1885,7 @@ ngx_http_trim_parse(ngx_http_request_t *r, ngx_buf_t *buf,
break; break;
} }
if (conf->js_enable && ctx->tag == NGX_HTTP_TRIM_TAG_SCRIPT) {
if (ctx->js_enable && ctx->tag == NGX_HTTP_TRIM_TAG_SCRIPT) {
if (ctx->looked != ngx_http_trim_script_js.len) { if (ctx->looked != ngx_http_trim_script_js.len) {
look = ngx_http_trim_script_js.data[ctx->looked++]; look = ngx_http_trim_script_js.data[ctx->looked++];
if (ch != look) { if (ch != look) {
@ -1856,7 +1894,7 @@ ngx_http_trim_parse(ngx_http_request_t *r, ngx_buf_t *buf,
} }
} }
if (conf->css_enable && ctx->tag == NGX_HTTP_TRIM_TAG_STYLE) {
if (ctx->css_enable && ctx->tag == NGX_HTTP_TRIM_TAG_STYLE) {
if (ctx->looked != ngx_http_trim_style_css.len) { if (ctx->looked != ngx_http_trim_style_css.len) {
look = ngx_http_trim_style_css.data[ctx->looked++]; look = ngx_http_trim_style_css.data[ctx->looked++];
if (ch != look) { if (ch != look) {
@ -1876,7 +1914,7 @@ ngx_http_trim_parse(ngx_http_request_t *r, ngx_buf_t *buf,
break; break;
} }
if (conf->js_enable && ctx->tag == NGX_HTTP_TRIM_TAG_SCRIPT) {
if (ctx->js_enable && ctx->tag == NGX_HTTP_TRIM_TAG_SCRIPT) {
if (ctx->looked != ngx_http_trim_script_js.len) { if (ctx->looked != ngx_http_trim_script_js.len) {
look = ngx_http_trim_script_js.data[ctx->looked++]; look = ngx_http_trim_script_js.data[ctx->looked++];
if (ch != look) { if (ch != look) {
@ -1885,7 +1923,7 @@ ngx_http_trim_parse(ngx_http_request_t *r, ngx_buf_t *buf,
} }
} }
if (conf->css_enable && ctx->tag == NGX_HTTP_TRIM_TAG_STYLE) {
if (ctx->css_enable && ctx->tag == NGX_HTTP_TRIM_TAG_STYLE) {
if (ctx->looked != ngx_http_trim_style_css.len) { if (ctx->looked != ngx_http_trim_style_css.len) {
look = ngx_http_trim_style_css.data[ctx->looked++]; look = ngx_http_trim_style_css.data[ctx->looked++];
if (ch != look) { if (ch != look) {
@ -1924,12 +1962,11 @@ ngx_http_trim_create_loc_conf(ngx_conf_t *cf)
* *
* conf->types = { NULL }; * conf->types = { NULL };
* conf->types_keys = NULL; * conf->types_keys = NULL;
* conf->trim = NULL;
* conf->js = NULL;
* conf->css = NULL;
*/ */
conf->trim_enable = NGX_CONF_UNSET;
conf->js_enable = NGX_CONF_UNSET;
conf->css_enable = NGX_CONF_UNSET;
return conf; return conf;
} }
@ -1940,10 +1977,6 @@ ngx_http_trim_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_http_trim_loc_conf_t *prev = parent; ngx_http_trim_loc_conf_t *prev = parent;
ngx_http_trim_loc_conf_t *conf = child; ngx_http_trim_loc_conf_t *conf = child;
ngx_conf_merge_value(conf->js_enable, prev->js_enable, 0);
ngx_conf_merge_value(conf->css_enable, prev->css_enable, 0);
ngx_conf_merge_value(conf->trim_enable, prev->trim_enable, 0);
if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types, if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
&prev->types_keys, &prev->types, &prev->types_keys, &prev->types,
ngx_http_html_default_types) ngx_http_html_default_types)
@ -1952,6 +1985,18 @@ ngx_http_trim_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_ERROR; return NGX_CONF_ERROR;
} }
if (conf->trim == NULL) {
conf->trim = prev->trim;
}
if (conf->js == NULL) {
conf->js = prev->js;
}
if (conf->css == NULL) {
conf->css = prev->css;
}
return NGX_CONF_OK; return NGX_CONF_OK;
} }

77
tests/test-nginx/cases/trim.t

@ -738,3 +738,80 @@ h1 > strong { color : red ; }
GET /t/trim.html GET /t/trim.html
--- response_body --- response_body
<style>body{font-size:20px;line-height:150%;}body{font-size:20px;line-height:150%;}body{font-size:20px;line-height:150%;}body{font-size:20px;line-height:150%;}h1>strong{color:red;}.skin-1388458850088 .nav .sm-item-list{border-bottom:2px solid #ee5e80;}.skin-1388458850088 .nav .search-wrap a.local,.skin-1388458850088 .nav .search-wrap a.local:hover{background:#ee5e80;}</style> <style>body{font-size:20px;line-height:150%;}body{font-size:20px;line-height:150%;}body{font-size:20px;line-height:150%;}body{font-size:20px;line-height:150%;}h1>strong{color:red;}.skin-1388458850088 .nav .sm-item-list{border-bottom:2px solid #ee5e80;}.skin-1388458850088 .nav .search-wrap a.local,.skin-1388458850088 .nav .search-wrap a.local:hover{background:#ee5e80;}</style>
=== TEST 27: variable value
--- config
trim on;
trim_js on;
trim_css on;
set $trim "on";
if ($arg_a = 1 ) {
set $trim "off";
}
location /trim.html {trim off; }
location /t/ {
proxy_buffering off;
proxy_pass http://127.0.0.1:$TEST_NGINX_TRIM_PORT/;
trim_js $trim;
trim_css $trim;
}
--- user_files
>>> trim.html
<!DOCTYPE html>
<textarea >
trim
module
</textarea >
<!--remove all-->
<!--[if IE]> trim module <![endif]-->
<!--[if !IE ]>--> trim module <!--<![endif]-->
<!--# ssi-->
<!--esi-->
<pre style =
"color: blue" >Welcome to nginx!</pre >
<script type="text/javascript">
/*** muitl comment
***/
//// single comment
str.replace(/ /,"hello");
</script>
<style type="text/css" >
/*** css comment
! ***/
body
{
font-size: 20px ;
line-height: 150% ;
}
</style>
--- request
GET /t/trim.html?a=1
--- response_body
<!DOCTYPE html>
<textarea>
trim
module
</textarea>
<!--[if IE]> trim module <![endif]-->
<!--[if !IE ]>--> trim module <!--<![endif]-->
<!--# ssi-->
<!--esi-->
<pre style="color: blue">Welcome to nginx!</pre>
<script type="text/javascript">
/*** muitl comment
***/
//// single comment
str.replace(/ /,"hello");
</script>
<style type="text/css">
/*** css comment
! ***/
body
{
font-size: 20px ;
line-height: 150% ;
}
</style>
Loading…
Cancel
Save