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.
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/>
@ -33,6 +41,7 @@ This module will retain some contents unchanged, in case that they are enclosed
**Context:** `http, server, location`
Enable or disable trim module for inline javascript.
Parameter value can contain variables too.
<br/>
@ -43,6 +52,7 @@ Enable or disable trim module for inline javascript.
**Context:** `http, server, location`
Enable or disable trim module for inline css.
Parameter value can contain variables too.
<br/>
@ -107,3 +117,52 @@ result:
<script type="text/javascript">str.replace(/ /,"hello");</script>
<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`
使模块有效(失效),删除 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/>
**trim_js** `on` | `off`
@ -32,7 +40,8 @@
**上下文:** `http, server, location`
使模块有效(失效),删除 html 内嵌 javascript 的注释以及重复的空白符(\n,\r,\t,' ')。
例外:对于非javascript代码的 `script` 标签内容不作删除操作。
例外:对于非javascript代码的 `script` 标签内容不作删除操作。
参数值可以包含变量。
<br/>
**trim_css** `on` | `off`
@ -42,7 +51,8 @@
**上下文:** `http, server, location`
使模块有效(失效),删除 html 内嵌 css 的注释以及重复的空白符(\n,\r,\t,' ')。
例外:对于非css代码的 `style` 标签内容不作删除操作。
例外:对于非css代码的 `style` 标签内容不作删除操作。
参数值可以包含变量。
<br/>
**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
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;
@ -45,6 +46,9 @@ typedef struct {
ngx_int_t saved;
ngx_int_t count;
ngx_uint_t state;
unsigned js_enable:1;
unsigned css_enable:1;
} 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[] = {
{ 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,
offsetof(ngx_http_trim_loc_conf_t, trim_enable),
offsetof(ngx_http_trim_loc_conf_t, trim),
NULL },
{ 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,
offsetof(ngx_http_trim_loc_conf_t, js_enable),
offsetof(ngx_http_trim_loc_conf_t, js),
NULL },
{ 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,
offsetof(ngx_http_trim_loc_conf_t, css_enable),
offsetof(ngx_http_trim_loc_conf_t, css),
NULL },
{ 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);
if (!conf->trim_enable
if (!conf->trim
|| r->headers_out.status != NGX_HTTP_OK
|| (r->method & NGX_HTTP_HEAD)
|| 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);
}
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));
if (ctx == NULL) {
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 = ' ';
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;
} 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->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) {
if (conf->css_enable
if (ctx->css_enable
&& ctx->looked == ngx_http_trim_style_css.len)
{
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> */
if (ch == look) {
if (ctx->looked == ngx_http_trim_script.len) {
if (conf->js_enable) {
if (ctx->js_enable) {
ctx->state = trim_state_tag_script_js_text;
} 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> */
if (ch == look) {
if (ctx->looked == ngx_http_trim_style.len) {
if (conf->css_enable) {
if (ctx->css_enable) {
ctx->state = trim_state_tag_style_css_text;
} 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;
} 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->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) {
if (conf->css_enable
if (ctx->css_enable
&& ctx->looked == ngx_http_trim_style_css.len)
{
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;
}
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) {
look = ngx_http_trim_script_js.data[ctx->looked++];
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) {
look = ngx_http_trim_style_css.data[ctx->looked++];
if (ch != look) {
@ -1876,7 +1914,7 @@ ngx_http_trim_parse(ngx_http_request_t *r, ngx_buf_t *buf,
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) {
look = ngx_http_trim_script_js.data[ctx->looked++];
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) {
look = ngx_http_trim_style_css.data[ctx->looked++];
if (ch != look) {
@ -1924,12 +1962,11 @@ ngx_http_trim_create_loc_conf(ngx_conf_t *cf)
*
* conf->types = { 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;
}
@ -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 *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,
&prev->types_keys, &prev->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;
}
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;
}

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

@ -738,3 +738,80 @@ h1 > strong { color : red ; }
GET /t/trim.html
--- 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>
=== 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