Skip to content

Commit

Permalink
implemented the rds_json_user_property directive.
Browse files Browse the repository at this point in the history
  • Loading branch information
agentzh committed Sep 15, 2011
1 parent fc9cce8 commit bc6b2f0
Show file tree
Hide file tree
Showing 5 changed files with 312 additions and 5 deletions.
14 changes: 14 additions & 0 deletions README
Expand Up @@ -105,6 +105,20 @@ Directives
Specify the top-level object property name used in the JSON output Specify the top-level object property name used in the JSON output
for indicating success or false of the query. for indicating success or false of the query.


rds_json_user_property
syntax: rds_json_user_property <key> <value>
default: no

Specify additonal user properties for the top-level object
of the JSON output.

Multiple instances of this directives are allowed in a single scope.

Nginx variables are supported in the <value> argument.

Both of the <key> and <value> arguments will be automatically
quoted according to JSON strings' notation.

rds_json_ret rds_json_ret
syntax: rds_json_ret <error-code> <descrption> syntax: rds_json_ret <error-code> <descrption>
default: no default: no
Expand Down
100 changes: 97 additions & 3 deletions src/ngx_http_rds_json_filter_module.c
Expand Up @@ -40,6 +40,8 @@ static char * ngx_http_rds_json_root(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf); void *conf);
static char * ngx_http_rds_json_success_property(ngx_conf_t *cf, static char * ngx_http_rds_json_success_property(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf); ngx_command_t *cmd, void *conf);
static char * ngx_http_rds_json_user_property(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);




static ngx_command_t ngx_http_rds_json_commands[] = { static ngx_command_t ngx_http_rds_json_commands[] = {
Expand Down Expand Up @@ -71,6 +73,15 @@ static ngx_command_t ngx_http_rds_json_commands[] = {
0, 0,
NULL }, NULL },


{ ngx_string("rds_json_user_property"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_TAKE2,
ngx_http_rds_json_user_property,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },

{ ngx_string("rds_json_format"), { ngx_string("rds_json_format"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
Expand Down Expand Up @@ -333,6 +344,7 @@ ngx_http_rds_json_create_conf(ngx_conf_t *cf)
* conf->content_type = { 0, NULL }; * conf->content_type = { 0, NULL };
* conf->root = { 0, NULL }; * conf->root = { 0, NULL };
* conf->success = { 0, NULL }; * conf->success = { 0, NULL };
* conf->user_props = NULL;
* conf->errcode = { 0, NULL }; * conf->errcode = { 0, NULL };
* conf->errstr = NULL; * conf->errstr = NULL;
*/ */
Expand Down Expand Up @@ -366,7 +378,11 @@ ngx_http_rds_json_merge_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_str_value(conf->success, prev->success, ngx_conf_merge_str_value(conf->success, prev->success,
""); "");


if (conf->success.len && conf->root.len == 0) { if (conf->user_props == NULL) {
conf->user_props = prev->user_props;
}

if (conf->root.len == 0 && (conf->success.len || conf->user_props)) {
ngx_str_set(&conf->root, "\"data\""); ngx_str_set(&conf->root, "\"data\"");
} }


Expand Down Expand Up @@ -493,7 +509,7 @@ ngx_http_rds_json_root(ngx_conf_t *cf, ngx_command_t *cmd,
*p++ = '"'; *p++ = '"';


if (p - jlcf->root.data != (ssize_t) jlcf->root.len) { if (p - jlcf->root.data != (ssize_t) jlcf->root.len) {
return " sees buffer error"; return "sees buffer error";
} }


return NGX_CONF_OK; return NGX_CONF_OK;
Expand Down Expand Up @@ -544,7 +560,85 @@ ngx_http_rds_json_success_property(ngx_conf_t *cf, ngx_command_t *cmd,
*p++ = '"'; *p++ = '"';


if (p - jlcf->success.data != (ssize_t) jlcf->success.len) { if (p - jlcf->success.data != (ssize_t) jlcf->success.len) {
return " sees buffer error"; return "sees buffer error";
}

return NGX_CONF_OK;
}


static char *
ngx_http_rds_json_user_property(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
{
ngx_http_rds_json_conf_t *jlcf = conf;
ngx_str_t *value;
ngx_http_rds_json_property_t *prop;
uintptr_t escape;
u_char *p;

ngx_http_compile_complex_value_t ccv;

value = cf->args->elts;

if (value[1].len == 0) {
return "takes an empty key";
}

if (value[2].len == 0) {
return "takes an empty value";
}

if (jlcf->user_props == NULL) {
jlcf->user_props = ngx_array_create(cf->pool, 4,
sizeof(ngx_http_rds_json_property_t));

if (jlcf->user_props == NULL) {
return NGX_CONF_ERROR;
}
}

prop = ngx_array_push(jlcf->user_props);

/* process the user property key */

escape = ngx_http_rds_json_escape_json_str(NULL, value[1].data,
value[1].len);

prop->key.len = value[1].len + escape + sizeof("\"\"") - 1;

p = ngx_palloc(cf->pool, prop->key.len);
if (p == NULL) {
return NGX_CONF_ERROR;
}

prop->key.data = p;

*p++ = '"';

if (escape == 0) {
p = ngx_copy(p, value[1].data, value[1].len);

} else {
p = (u_char *) ngx_http_rds_json_escape_json_str(p, value[1].data,
value[1].len);
}

*p++ = '"';

if (p - prop->key.data != (ssize_t) prop->key.len) {
return "sees buffer error";
}

/* process the user property value */

ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
ccv.cf = cf;
ccv.value = &value[2];
ccv.complex_value = &prop->value;

if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
return NGX_CONF_ERROR;
} }


return NGX_CONF_OK; return NGX_CONF_OK;
Expand Down
7 changes: 7 additions & 0 deletions src/ngx_http_rds_json_filter_module.h
Expand Up @@ -33,13 +33,20 @@ typedef enum {
} ngx_http_rds_json_format_t; } ngx_http_rds_json_format_t;




typedef struct {
ngx_str_t key;
ngx_http_complex_value_t value;
} ngx_http_rds_json_property_t;


typedef struct { typedef struct {
ngx_flag_t enabled; ngx_flag_t enabled;
ngx_uint_t format; ngx_uint_t format;
ngx_str_t content_type; ngx_str_t content_type;
ngx_str_t root; /* rds_json_root key */ ngx_str_t root; /* rds_json_root key */
ngx_str_t success; /* rds_json_success_property ngx_str_t success; /* rds_json_success_property
* key */ * key */
ngx_array_t *user_props; /* rds_json_user_property */


size_t buf_size; size_t buf_size;


Expand Down
107 changes: 105 additions & 2 deletions src/ngx_http_rds_json_output.c
Expand Up @@ -118,7 +118,11 @@ ngx_http_rds_json_output_header(ngx_http_request_t *r,
size_t size; size_t size;
uintptr_t escape; uintptr_t escape;
unsigned last_buf = 0; unsigned last_buf = 0;
ngx_uint_t i;
ngx_str_t *values = NULL;
uintptr_t *escapes = NULL;


ngx_http_rds_json_property_t *prop = NULL;
ngx_http_rds_json_conf_t *conf; ngx_http_rds_json_conf_t *conf;


conf = ngx_http_get_module_loc_conf(r, ngx_http_rds_json_filter_module); conf = ngx_http_get_module_loc_conf(r, ngx_http_rds_json_filter_module);
Expand All @@ -140,6 +144,34 @@ ngx_http_rds_json_output_header(ngx_http_request_t *r,
} }
} }


if (conf->user_props) {
values = ngx_pnalloc(r->pool,
conf->user_props->nelts * (sizeof(ngx_str_t) +
sizeof(uintptr_t)));

if (values == NULL) {
return NGX_ERROR;
}

escapes = (uintptr_t *) ((u_char *) values +
conf->user_props->nelts * sizeof(ngx_str_t));

prop = conf->user_props->elts;
for (i = 0; i < conf->user_props->nelts; i++) {
if (ngx_http_complex_value(r, &prop[i].value, &values[i])
!= NGX_OK)
{
return NGX_ERROR;
}

escapes[i] = ngx_http_rds_json_escape_json_str(NULL, values[i].data,
values[i].len);

size += sizeof(":\"\",") - 1 + prop[i].key.len + values[i].len
+ escapes[i];
}
}

if (header->errstr.len) { if (header->errstr.len) {
escape = ngx_http_rds_json_escape_json_str(NULL, header->errstr.data, escape = ngx_http_rds_json_escape_json_str(NULL, header->errstr.data,
header->errstr.len); header->errstr.len);
Expand Down Expand Up @@ -188,6 +220,25 @@ ngx_http_rds_json_output_header(ngx_http_request_t *r,
} }
} }


if (conf->user_props) {
for (i = 0; i < conf->user_props->nelts; i++) {
last = ngx_copy(last, prop[i].key.data, prop[i].key.len);
*last++ = ':';
*last++ = '"';

if (escapes[i] == 0) {
last = ngx_copy(last, values[i].data, values[i].len);

} else {
last = (u_char *) ngx_http_rds_json_escape_json_str(last,
values[i].data, values[i].len);
}

*last++ = '"';
*last++ = ',';
}
}

last = ngx_copy_literal(last, "\"errcode\":"); last = ngx_copy_literal(last, "\"errcode\":");


last = ngx_snprintf(last, NGX_UINT16_LEN, "%uD", last = ngx_snprintf(last, NGX_UINT16_LEN, "%uD",
Expand Down Expand Up @@ -244,15 +295,48 @@ ngx_int_t
ngx_http_rds_json_output_props(ngx_http_request_t *r, ngx_http_rds_json_output_props(ngx_http_request_t *r,
ngx_http_rds_json_ctx_t *ctx, ngx_http_rds_json_conf_t *conf) ngx_http_rds_json_ctx_t *ctx, ngx_http_rds_json_conf_t *conf)
{ {
size_t size; size_t size;
u_char *pos, *last; u_char *pos, *last;
ngx_uint_t i;
ngx_str_t *values = NULL;
uintptr_t *escapes = NULL;

ngx_http_rds_json_property_t *prop = NULL;


size = sizeof("{:") - 1 + conf->root.len; size = sizeof("{:") - 1 + conf->root.len;


if (conf->success.len) { if (conf->success.len) {
size += sizeof(",:true") - 1 + conf->success.len; size += sizeof(",:true") - 1 + conf->success.len;
} }


if (conf->user_props) {
values = ngx_pnalloc(r->pool,
conf->user_props->nelts * (sizeof(ngx_str_t) +
sizeof(uintptr_t)));

if (values == NULL) {
return NGX_ERROR;
}

escapes = (uintptr_t *) ((u_char *) values +
conf->user_props->nelts * sizeof(ngx_str_t));

prop = conf->user_props->elts;
for (i = 0; i < conf->user_props->nelts; i++) {
if (ngx_http_complex_value(r, &prop[i].value, &values[i])
!= NGX_OK)
{
return NGX_ERROR;
}

escapes[i] = ngx_http_rds_json_escape_json_str(NULL, values[i].data,
values[i].len);

size += sizeof(":\"\",") - 1 + prop[i].key.len + values[i].len
+ escapes[i];
}
}

pos = ngx_http_rds_json_request_mem(r, ctx, size); pos = ngx_http_rds_json_request_mem(r, ctx, size);
if (pos == NULL) { if (pos == NULL) {
return NGX_ERROR; return NGX_ERROR;
Expand All @@ -267,6 +351,25 @@ ngx_http_rds_json_output_props(ngx_http_request_t *r,
last = ngx_copy_literal(last, ":true,"); last = ngx_copy_literal(last, ":true,");
} }


if (conf->user_props) {
for (i = 0; i < conf->user_props->nelts; i++) {
last = ngx_copy(last, prop[i].key.data, prop[i].key.len);
*last++ = ':';
*last++ = '"';

if (escapes[i] == 0) {
last = ngx_copy(last, values[i].data, values[i].len);

} else {
last = (u_char *) ngx_http_rds_json_escape_json_str(last,
values[i].data, values[i].len);
}

*last++ = '"';
*last++ = ',';
}
}

last = ngx_copy(last, conf->root.data, conf->root.len); last = ngx_copy(last, conf->root.data, conf->root.len);
*last++ = ':'; *last++ = ':';


Expand Down

0 comments on commit bc6b2f0

Please sign in to comment.