Permalink
2d8b492 Jun 22, 2015
@agentzh @liseen @PiotrSikora
863 lines (627 sloc) 23.1 KB
/*
* Copyright (C) Yichun Zhang (agentzh)
*/
#ifndef DDEBUG
#define DDEBUG 0
#endif
#include "ddebug.h"
#include "ngx_http_rds_json_filter_module.h"
#include "ngx_http_rds_json_util.h"
#include "ngx_http_rds_json_processor.h"
#include "ngx_http_rds_json_handler.h"
#include "ngx_http_rds_json_output.h"
#include <ngx_config.h>
#define ngx_http_rds_json_content_type "application/json"
#define ngx_http_rds_json_errcode_default_key "\"errcode\""
#define ngx_http_rds_json_errstr_default_key "\"errstr\""
static volatile ngx_cycle_t *ngx_http_rds_json_prev_cycle = NULL;
static ngx_conf_enum_t ngx_http_rds_json_formats[] = {
{ ngx_string("normal"), json_format_normal },
{ ngx_string("compact"), json_format_compact },
/* { ngx_string("pretty"), json_format_pretty }, */
{ ngx_null_string, 0 }
};
ngx_http_output_header_filter_pt ngx_http_rds_json_next_header_filter;
ngx_http_output_body_filter_pt ngx_http_rds_json_next_body_filter;
static void *ngx_http_rds_json_create_main_conf(ngx_conf_t *cf);
static char *ngx_http_rds_json_ret(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static void *ngx_http_rds_json_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_rds_json_merge_loc_conf(ngx_conf_t *cf, void *parent,
void *child);
static ngx_int_t ngx_http_rds_json_filter_init(ngx_conf_t *cf);
static char *ngx_http_rds_json_root(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_rds_json_success_property(ngx_conf_t *cf,
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 char *ngx_http_rds_json_errcode_key(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_rds_json_errstr_key(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_rds_json(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_command_t ngx_http_rds_json_commands[] = {
{ ngx_string("rds_json"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_FLAG,
ngx_http_rds_json,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_rds_json_loc_conf_t, enabled),
NULL },
{ ngx_string("rds_json_root"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_TAKE1,
ngx_http_rds_json_root,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("rds_json_success_property"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_TAKE1,
ngx_http_rds_json_success_property,
NGX_HTTP_LOC_CONF_OFFSET,
0,
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_errcode_key"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_TAKE1,
ngx_http_rds_json_errcode_key,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("rds_json_errstr_key"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_TAKE1,
ngx_http_rds_json_errstr_key,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("rds_json_format"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_TAKE1,
ngx_conf_set_enum_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_rds_json_loc_conf_t, format),
&ngx_http_rds_json_formats },
{ ngx_string("rds_json_content_type"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_rds_json_loc_conf_t, content_type),
NULL },
{ ngx_string("rds_json_ret"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_2MORE,
ngx_http_rds_json_ret,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("rds_json_buffer_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_rds_json_loc_conf_t, buf_size),
NULL },
ngx_null_command
};
static ngx_http_module_t ngx_http_rds_json_filter_module_ctx = {
NULL, /* preconfiguration */
ngx_http_rds_json_filter_init, /* postconfiguration */
ngx_http_rds_json_create_main_conf, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_rds_json_create_loc_conf, /* create location configuration */
ngx_http_rds_json_merge_loc_conf /* merge location configuration */
};
ngx_module_t ngx_http_rds_json_filter_module = {
NGX_MODULE_V1,
&ngx_http_rds_json_filter_module_ctx, /* module context */
ngx_http_rds_json_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_int_t
ngx_http_rds_json_header_filter(ngx_http_request_t *r)
{
ngx_http_rds_json_ctx_t *ctx;
ngx_http_rds_json_loc_conf_t *conf;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"rds json header filter, \"%V\"", &r->uri);
/* XXX maybe we can generate stub JSON strings like
* {"errcode":403,"error":"Permission denied"}
* for HTTP error pages? */
if ((r->headers_out.status < NGX_HTTP_OK)
|| (r->headers_out.status >= NGX_HTTP_SPECIAL_RESPONSE)
|| (r->headers_out.status == NGX_HTTP_NO_CONTENT)
|| (r->headers_out.status == NGX_HTTP_RESET_CONTENT))
{
ngx_http_set_ctx(r, NULL, ngx_http_rds_json_filter_module);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"rds json: skipped due to bad status: %ui",
r->headers_out.status);
return ngx_http_rds_json_next_header_filter(r);
}
/* r->headers_out.status = 0; */
conf = ngx_http_get_module_loc_conf(r, ngx_http_rds_json_filter_module);
if (!conf->enabled) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"rds json: skipped because not enabled in the current "
"location");
return ngx_http_rds_json_next_header_filter(r);
}
if (ngx_http_rds_json_test_content_type(r) != NGX_OK) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"rds json: skipped due to unmatched Content-Type "
"response header \"%V\"",
&r->headers_out.content_type);
return ngx_http_rds_json_next_header_filter(r);
}
r->headers_out.content_type = conf->content_type;
r->headers_out.content_type_len = conf->content_type.len;
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_rds_json_ctx_t));
if (ctx == NULL) {
return NGX_ERROR;
}
ctx->tag = (ngx_buf_tag_t) &ngx_http_rds_json_filter_module;
ctx->state = state_expect_header;
ctx->header_sent = 0;
ctx->last_out = &ctx->out;
/* set by ngx_pcalloc
* ctx->out = NULL
* ctx->busy_bufs = NULL
* ctx->free_bufs = NULL
* ctx->cached = (ngx_buf_t) 0
* ctx->postponed = (ngx_buf_t) 0
* ctx->avail_out = 0
* ctx->col_names = NULL
* ctx->col_count = 0
* ctx->cur_col = 0
* ctx->field_offset = 0
* ctx->field_total = 0
* ctx->field_data_rest = 0
*/
ngx_http_set_ctx(r, ctx, ngx_http_rds_json_filter_module);
ngx_http_clear_content_length(r);
r->filter_need_in_memory = 1;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"rds json header filter postponed header sending");
/* we do postpone the header sending to the body filter */
return NGX_OK;
}
static ngx_int_t
ngx_http_rds_json_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
ngx_http_rds_json_ctx_t *ctx;
ngx_int_t rc;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"rds json body filter, \"%V\"", &r->uri);
if (in == NULL || r->header_only) {
return ngx_http_rds_json_next_body_filter(r, in);
}
ctx = ngx_http_get_module_ctx(r, ngx_http_rds_json_filter_module);
if (ctx == NULL) {
return ngx_http_rds_json_next_body_filter(r, in);
}
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"rds json body filter postponed header sending");
switch (ctx->state) {
case state_expect_header:
rc = ngx_http_rds_json_process_header(r, in, ctx);
break;
case state_expect_col:
rc = ngx_http_rds_json_process_col(r, in, ctx);
break;
case state_expect_row:
rc = ngx_http_rds_json_process_row(r, in, ctx);
break;
case state_expect_field:
rc = ngx_http_rds_json_process_field(r, in, ctx);
break;
case state_expect_more_field_data:
rc = ngx_http_rds_json_process_more_field_data(r, in, ctx);
break;
case state_done:
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"rds json body filter discarding unexpected trailing "
"buffers");
/* mark the remaining bufs as consumed */
ngx_http_rds_json_discard_bufs(r->pool, in);
return NGX_OK;
default:
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"rds_json: invalid internal state: %d",
ctx->state);
rc = NGX_ERROR;
break;
}
dd("body filter rc: %d", (int) rc);
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
ctx->state = state_done;
if (!ctx->header_sent) {
ctx->header_sent = 1;
if (rc == NGX_ERROR) {
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
}
r->headers_out.status = rc;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"rds json body filter sending error page headers");
ngx_http_rds_json_next_header_filter(r);
ngx_http_send_special(r, NGX_HTTP_LAST);
return NGX_ERROR;
}
return NGX_ERROR;
}
dd("output bufs");
return ngx_http_rds_json_output_bufs(r, ctx);
}
static ngx_int_t
ngx_http_rds_json_filter_init(ngx_conf_t *cf)
{
int multi_http_blocks;
ngx_http_rds_json_main_conf_t *rmcf;
rmcf = ngx_http_conf_get_module_main_conf(cf,
ngx_http_rds_json_filter_module);
if (ngx_http_rds_json_prev_cycle != ngx_cycle) {
ngx_http_rds_json_prev_cycle = ngx_cycle;
multi_http_blocks = 0;
} else {
multi_http_blocks = 1;
}
dd("setting next filter: %d", (int) rmcf->requires_filters);
if (multi_http_blocks || rmcf->requires_filters) {
dd("register filters");
ngx_http_rds_json_next_header_filter = ngx_http_top_header_filter;
ngx_http_top_header_filter = ngx_http_rds_json_header_filter;
ngx_http_rds_json_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_rds_json_body_filter;
}
return NGX_OK;
}
static void *
ngx_http_rds_json_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_rds_json_loc_conf_t *conf;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_rds_json_loc_conf_t));
if (conf == NULL) {
return NULL;
}
/*
* set by ngx_pcalloc():
*
* conf->content_type = { 0, NULL };
* conf->root = { 0, NULL };
* conf->success = { 0, NULL };
* conf->user_props = NULL;
* conf->errcode = { 0, NULL };
* conf->errstr = NULL;
*/
conf->enabled = NGX_CONF_UNSET;
conf->format = NGX_CONF_UNSET_UINT;
conf->buf_size = NGX_CONF_UNSET_SIZE;
#if 0
conf->buf_size = 1;
#endif
return conf;
}
static char *
ngx_http_rds_json_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_rds_json_loc_conf_t *prev = parent;
ngx_http_rds_json_loc_conf_t *conf = child;
ngx_conf_merge_value(conf->enabled, prev->enabled, 0);
ngx_conf_merge_uint_value(conf->format, prev->format, json_format_normal);
ngx_conf_merge_str_value(conf->root, prev->root, "");
ngx_conf_merge_str_value(conf->success, prev->success, "");
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_conf_merge_str_value(conf->errcode_key, prev->errcode_key,
"\"errcode\"");
ngx_conf_merge_str_value(conf->errstr_key, prev->errstr_key,
"\"errstr\"");
ngx_conf_merge_str_value(conf->content_type, prev->content_type,
ngx_http_rds_json_content_type);
ngx_conf_merge_size_value(conf->buf_size, prev->buf_size,
(size_t) ngx_pagesize);
return NGX_CONF_OK;
}
static char *
ngx_http_rds_json_ret(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_rds_json_loc_conf_t *jlcf = conf;
ngx_http_core_loc_conf_t *clcf;
ngx_str_t *value;
ngx_http_compile_complex_value_t ccv;
ngx_uint_t i;
u_char c;
value = cf->args->elts;
jlcf->errcode = value[1];
if (jlcf->errcode.len == 0) {
ngx_log_error(NGX_LOG_ERR, cf->log, 0,
"rds_json: rds_json_ret: the errcode argument is empty");
return NGX_CONF_ERROR;
}
/* check the validaty of the errcode argument */
for (i = 0; i < jlcf->errcode.len; i++) {
c = jlcf->errcode.data[i];
if (c < '0' || c > '9') {
ngx_log_error(NGX_LOG_ERR, cf->log, 0,
"rds_json: rds_json_ret: invalid errcode argument: "
"\"%V\"", &jlcf->errcode);
return NGX_CONF_ERROR;
}
}
jlcf->errstr = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
if (jlcf->errstr == NULL) {
return NGX_CONF_ERROR;
}
if (value[2].len == 0) {
ngx_memzero(jlcf->errstr, sizeof(ngx_http_complex_value_t));
goto done;
}
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
ccv.cf = cf;
ccv.value = &value[2];
ccv.complex_value = jlcf->errstr;
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
return NGX_CONF_ERROR;
}
done:
clcf = ngx_http_conf_get_module_loc_conf(cf,
ngx_http_core_module);
if (clcf == NULL) {
return NGX_CONF_ERROR;
}
clcf->handler = ngx_http_rds_json_ret_handler;
return NGX_CONF_OK;
}
static char *
ngx_http_rds_json_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_rds_json_loc_conf_t *jlcf = conf;
ngx_str_t *value;
uintptr_t escape;
u_char *p;
value = cf->args->elts;
if (jlcf->root.len) {
return "is duplicate";
}
if (value[1].len == 0) {
return "takes an empty value";
}
escape = ngx_http_rds_json_escape_json_str(NULL, value[1].data,
value[1].len);
jlcf->root.len = value[1].len + escape + sizeof("\"\"") - 1;
p = ngx_palloc(cf->pool, jlcf->root.len);
if (p == NULL) {
return NGX_CONF_ERROR;
}
jlcf->root.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 - jlcf->root.data != (ssize_t) jlcf->root.len) {
return "sees buffer error";
}
return NGX_CONF_OK;
}
static char *
ngx_http_rds_json_success_property(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
{
ngx_http_rds_json_loc_conf_t *jlcf = conf;
ngx_str_t *value;
uintptr_t escape;
u_char *p;
value = cf->args->elts;
if (jlcf->success.len) {
return "is duplicate";
}
if (value[1].len == 0) {
return "takes an empty value";
}
escape = ngx_http_rds_json_escape_json_str(NULL, value[1].data,
value[1].len);
jlcf->success.len = value[1].len + escape + sizeof("\"\"") - 1;
p = ngx_palloc(cf->pool, jlcf->success.len);
if (p == NULL) {
return NGX_CONF_ERROR;
}
jlcf->success.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 - jlcf->success.data != (ssize_t) jlcf->success.len) {
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)
{
u_char *p;
ngx_str_t *value;
uintptr_t escape;
ngx_http_rds_json_property_t *prop;
ngx_http_rds_json_loc_conf_t *jlcf = conf;
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);
if (prop == NULL) {
return NGX_CONF_ERROR;
}
/* 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;
}
static char *
ngx_http_rds_json_errcode_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_rds_json_loc_conf_t *jlcf = conf;
u_char *p;
ngx_str_t *value;
uintptr_t escape;
value = cf->args->elts;
if (jlcf->errcode_key.len) {
return "is duplicate";
}
if (value[1].len == 0) {
return "takes an empty value";
}
escape = ngx_http_rds_json_escape_json_str(NULL, value[1].data,
value[1].len);
jlcf->errcode_key.len = value[1].len + escape + sizeof("\"\"") - 1;
p = ngx_palloc(cf->pool, jlcf->errcode_key.len);
if (p == NULL) {
return NGX_CONF_ERROR;
}
jlcf->errcode_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 - jlcf->errcode_key.data != (ssize_t) jlcf->errcode_key.len) {
return "sees buffer error";
}
return NGX_CONF_OK;
}
static char *
ngx_http_rds_json_errstr_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_rds_json_loc_conf_t *jlcf = conf;
ngx_str_t *value;
uintptr_t escape;
u_char *p;
value = cf->args->elts;
if (jlcf->errstr_key.len) {
return "is duplicate";
}
if (value[1].len == 0) {
return "takes an empty value";
}
escape = ngx_http_rds_json_escape_json_str(NULL, value[1].data,
value[1].len);
jlcf->errstr_key.len = value[1].len + escape + sizeof("\"\"") - 1;
p = ngx_palloc(cf->pool, jlcf->errstr_key.len);
if (p == NULL) {
return NGX_CONF_ERROR;
}
jlcf->errstr_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 - jlcf->errstr_key.data != (ssize_t) jlcf->errstr_key.len) {
return "sees buffer error";
}
return NGX_CONF_OK;
}
static char *
ngx_http_rds_json(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_rds_json_main_conf_t *rmcf;
rmcf = ngx_http_conf_get_module_main_conf(cf,
ngx_http_rds_json_filter_module);
dd("set filter used to 1");
rmcf->requires_filters = 1;
return ngx_conf_set_flag_slot(cf, cmd, conf);
}
static void *
ngx_http_rds_json_create_main_conf(ngx_conf_t *cf)
{
ngx_http_rds_json_main_conf_t *rmcf;
rmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_rds_json_main_conf_t));
if (rmcf == NULL) {
return NULL;
}
/* set by ngx_pcalloc:
* rmcf->requires_filters = 0;
*/
return rmcf;
}