Controller: more HTTP headers and detailed JSON parsing errors.
This commit is contained in:
357
src/nxt_conf.c
357
src/nxt_conf.c
@@ -48,8 +48,8 @@ struct nxt_conf_value_s {
|
|||||||
double number;
|
double number;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint8_t length;
|
|
||||||
u_char start[NXT_CONF_MAX_SHORT_STRING];
|
u_char start[NXT_CONF_MAX_SHORT_STRING];
|
||||||
|
uint8_t length;
|
||||||
} str;
|
} str;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@@ -93,9 +93,9 @@ struct nxt_conf_op_s {
|
|||||||
|
|
||||||
static u_char *nxt_conf_json_skip_space(u_char *start, u_char *end);
|
static u_char *nxt_conf_json_skip_space(u_char *start, u_char *end);
|
||||||
static u_char *nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value,
|
static u_char *nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value,
|
||||||
u_char *start, u_char *end);
|
u_char *start, u_char *end, nxt_conf_json_error_t *error);
|
||||||
static u_char *nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value,
|
static u_char *nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value,
|
||||||
u_char *start, u_char *end);
|
u_char *start, u_char *end, nxt_conf_json_error_t *error);
|
||||||
static nxt_int_t nxt_conf_object_hash_add(nxt_mp_t *mp,
|
static nxt_int_t nxt_conf_object_hash_add(nxt_mp_t *mp,
|
||||||
nxt_lvlhsh_t *lvlhsh, nxt_conf_object_member_t *member);
|
nxt_lvlhsh_t *lvlhsh, nxt_conf_object_member_t *member);
|
||||||
static nxt_int_t nxt_conf_object_hash_test(nxt_lvlhsh_query_t *lhq,
|
static nxt_int_t nxt_conf_object_hash_test(nxt_lvlhsh_query_t *lhq,
|
||||||
@@ -103,11 +103,13 @@ static nxt_int_t nxt_conf_object_hash_test(nxt_lvlhsh_query_t *lhq,
|
|||||||
static void *nxt_conf_object_hash_alloc(void *data, size_t size);
|
static void *nxt_conf_object_hash_alloc(void *data, size_t size);
|
||||||
static void nxt_conf_object_hash_free(void *data, void *p);
|
static void nxt_conf_object_hash_free(void *data, void *p);
|
||||||
static u_char *nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value,
|
static u_char *nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value,
|
||||||
u_char *start, u_char *end);
|
u_char *start, u_char *end, nxt_conf_json_error_t *error);
|
||||||
static u_char *nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value,
|
static u_char *nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value,
|
||||||
u_char *start, u_char *end);
|
u_char *start, u_char *end, nxt_conf_json_error_t *error);
|
||||||
static u_char *nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value,
|
static u_char *nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value,
|
||||||
u_char *start, u_char *end);
|
u_char *start, u_char *end, nxt_conf_json_error_t *error);
|
||||||
|
static void nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos,
|
||||||
|
const char *detail);
|
||||||
|
|
||||||
static nxt_int_t nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op,
|
static nxt_int_t nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op,
|
||||||
nxt_conf_value_t *dst, nxt_conf_value_t *src);
|
nxt_conf_value_t *dst, nxt_conf_value_t *src);
|
||||||
@@ -192,8 +194,8 @@ nxt_conf_create_object(nxt_mp_t *mp, nxt_uint_t count)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
nxt_int_t
|
void
|
||||||
nxt_conf_set_object_member(nxt_conf_value_t *object, nxt_str_t *name,
|
nxt_conf_set_member(nxt_conf_value_t *object, nxt_str_t *name,
|
||||||
nxt_conf_value_t *value, uint32_t index)
|
nxt_conf_value_t *value, uint32_t index)
|
||||||
{
|
{
|
||||||
nxt_conf_value_t *name_value;
|
nxt_conf_value_t *name_value;
|
||||||
@@ -215,8 +217,71 @@ nxt_conf_set_object_member(nxt_conf_value_t *object, nxt_str_t *name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
member->value = *value;
|
member->value = *value;
|
||||||
|
}
|
||||||
|
|
||||||
return NXT_OK;
|
|
||||||
|
void
|
||||||
|
nxt_conf_set_member_string(nxt_conf_value_t *object, nxt_str_t *name,
|
||||||
|
nxt_str_t *value, uint32_t index)
|
||||||
|
{
|
||||||
|
nxt_conf_value_t *set;
|
||||||
|
nxt_conf_object_member_t *member;
|
||||||
|
|
||||||
|
member = &object->u.object->members[index];
|
||||||
|
set = &member->name;
|
||||||
|
|
||||||
|
if (name->length > NXT_CONF_MAX_SHORT_STRING) {
|
||||||
|
set->type = NXT_CONF_VALUE_STRING;
|
||||||
|
set->u.string.length = name->length;
|
||||||
|
set->u.string.start = name->start;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
set->type = NXT_CONF_VALUE_SHORT_STRING;
|
||||||
|
set->u.str.length = name->length;
|
||||||
|
|
||||||
|
nxt_memcpy(set->u.str.start, name->start, name->length);
|
||||||
|
}
|
||||||
|
|
||||||
|
set = &member->value;
|
||||||
|
|
||||||
|
if (value->length > NXT_CONF_MAX_SHORT_STRING) {
|
||||||
|
set->type = NXT_CONF_VALUE_STRING;
|
||||||
|
set->u.string.length = value->length;
|
||||||
|
set->u.string.start = value->start;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
set->type = NXT_CONF_VALUE_SHORT_STRING;
|
||||||
|
set->u.str.length = value->length;
|
||||||
|
|
||||||
|
nxt_memcpy(set->u.str.start, value->start, value->length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
nxt_conf_set_member_integer(nxt_conf_value_t *object, nxt_str_t *name,
|
||||||
|
int64_t value, uint32_t index)
|
||||||
|
{
|
||||||
|
nxt_conf_value_t *name_value;
|
||||||
|
nxt_conf_object_member_t *member;
|
||||||
|
|
||||||
|
member = &object->u.object->members[index];
|
||||||
|
name_value = &member->name;
|
||||||
|
|
||||||
|
if (name->length > NXT_CONF_MAX_SHORT_STRING) {
|
||||||
|
name_value->type = NXT_CONF_VALUE_STRING;
|
||||||
|
name_value->u.string.length = name->length;
|
||||||
|
name_value->u.string.start = name->start;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
name_value->type = NXT_CONF_VALUE_SHORT_STRING;
|
||||||
|
name_value->u.str.length = name->length;
|
||||||
|
|
||||||
|
nxt_memcpy(name_value->u.str.start, name->start, name->length);
|
||||||
|
}
|
||||||
|
|
||||||
|
member->value.u.integer = value;
|
||||||
|
member->value.type = NXT_CONF_VALUE_INTEGER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -802,7 +867,8 @@ nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst,
|
|||||||
|
|
||||||
|
|
||||||
nxt_conf_value_t *
|
nxt_conf_value_t *
|
||||||
nxt_conf_json_parse(nxt_mp_t *mp, u_char *start, u_char *end)
|
nxt_conf_json_parse(nxt_mp_t *mp, u_char *start, u_char *end,
|
||||||
|
nxt_conf_json_error_t *error)
|
||||||
{
|
{
|
||||||
u_char *p;
|
u_char *p;
|
||||||
nxt_conf_value_t *value;
|
nxt_conf_value_t *value;
|
||||||
@@ -815,10 +881,17 @@ nxt_conf_json_parse(nxt_mp_t *mp, u_char *start, u_char *end)
|
|||||||
p = nxt_conf_json_skip_space(start, end);
|
p = nxt_conf_json_skip_space(start, end);
|
||||||
|
|
||||||
if (nxt_slow_path(p == end)) {
|
if (nxt_slow_path(p == end)) {
|
||||||
|
|
||||||
|
nxt_conf_json_parse_error(error, start,
|
||||||
|
"An empty JSON isn't allowed. It must be either literal "
|
||||||
|
"(null, true, or false), number, string (in double quotes \"\"), "
|
||||||
|
"array (with brackets []), or object (with braces {})."
|
||||||
|
);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = nxt_conf_json_parse_value(mp, value, p, end);
|
p = nxt_conf_json_parse_value(mp, value, p, end, error);
|
||||||
|
|
||||||
if (nxt_slow_path(p == NULL)) {
|
if (nxt_slow_path(p == NULL)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -827,6 +900,11 @@ nxt_conf_json_parse(nxt_mp_t *mp, u_char *start, u_char *end)
|
|||||||
p = nxt_conf_json_skip_space(p, end);
|
p = nxt_conf_json_skip_space(p, end);
|
||||||
|
|
||||||
if (nxt_slow_path(p != end)) {
|
if (nxt_slow_path(p != end)) {
|
||||||
|
|
||||||
|
nxt_conf_json_parse_error(error, p,
|
||||||
|
"Unexpected character after the end of valid JSON value."
|
||||||
|
);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -858,21 +936,21 @@ nxt_conf_json_skip_space(u_char *start, u_char *end)
|
|||||||
|
|
||||||
static u_char *
|
static u_char *
|
||||||
nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
||||||
u_char *end)
|
u_char *end, nxt_conf_json_error_t *error)
|
||||||
{
|
{
|
||||||
u_char ch;
|
u_char ch, *p;
|
||||||
|
|
||||||
ch = *start;
|
ch = *start;
|
||||||
|
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case '{':
|
case '{':
|
||||||
return nxt_conf_json_parse_object(mp, value, start, end);
|
return nxt_conf_json_parse_object(mp, value, start, end, error);
|
||||||
|
|
||||||
case '[':
|
case '[':
|
||||||
return nxt_conf_json_parse_array(mp, value, start, end);
|
return nxt_conf_json_parse_array(mp, value, start, end, error);
|
||||||
|
|
||||||
case '"':
|
case '"':
|
||||||
return nxt_conf_json_parse_string(mp, value, start, end);
|
return nxt_conf_json_parse_string(mp, value, start, end, error);
|
||||||
|
|
||||||
case 't':
|
case 't':
|
||||||
if (nxt_fast_path(end - start >= 4
|
if (nxt_fast_path(end - start >= 4
|
||||||
@@ -884,7 +962,7 @@ nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
return start + 4;
|
return start + 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
goto error;
|
||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
if (nxt_fast_path(end - start >= 5
|
if (nxt_fast_path(end - start >= 5
|
||||||
@@ -896,7 +974,7 @@ nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
return start + 5;
|
return start + 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
goto error;
|
||||||
|
|
||||||
case 'n':
|
case 'n':
|
||||||
if (nxt_fast_path(end - start >= 4
|
if (nxt_fast_path(end - start >= 4
|
||||||
@@ -906,13 +984,47 @@ nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
return start + 4;
|
return start + 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
goto error;
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
if (nxt_fast_path(end - start > 1)) {
|
||||||
|
ch = start[1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nxt_fast_path(ch == '-' || (ch - '0') <= 9)) {
|
if (nxt_fast_path((ch - '0') <= 9)) {
|
||||||
return nxt_conf_json_parse_number(mp, value, start, end);
|
p = nxt_conf_json_parse_number(mp, value, start, end, error);
|
||||||
|
|
||||||
|
if (p == end) {
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (*p) {
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
case ',':
|
||||||
|
case '}':
|
||||||
|
case ']':
|
||||||
|
case '{':
|
||||||
|
case '[':
|
||||||
|
case '"':
|
||||||
|
return p;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error:
|
||||||
|
|
||||||
|
nxt_conf_json_parse_error(error, start,
|
||||||
|
"A valid JSON value is expected here. It must be either literal "
|
||||||
|
"(null, true, or false), number, string (in double quotes \"\"), "
|
||||||
|
"array (with brackets []), or object (with braces {})."
|
||||||
|
);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -929,9 +1041,9 @@ static const nxt_lvlhsh_proto_t nxt_conf_object_hash_proto
|
|||||||
|
|
||||||
static u_char *
|
static u_char *
|
||||||
nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
||||||
u_char *end)
|
u_char *end, nxt_conf_json_error_t *error)
|
||||||
{
|
{
|
||||||
u_char *p;
|
u_char *p, *name;
|
||||||
nxt_mp_t *mp_temp;
|
nxt_mp_t *mp_temp;
|
||||||
nxt_int_t rc;
|
nxt_int_t rc;
|
||||||
nxt_uint_t count;
|
nxt_uint_t count;
|
||||||
@@ -954,6 +1066,12 @@ nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
p = nxt_conf_json_skip_space(p + 1, end);
|
p = nxt_conf_json_skip_space(p + 1, end);
|
||||||
|
|
||||||
if (nxt_slow_path(p == end)) {
|
if (nxt_slow_path(p == end)) {
|
||||||
|
|
||||||
|
nxt_conf_json_parse_error(error, p,
|
||||||
|
"Unexpected end of JSON. There's an object without closing "
|
||||||
|
"brace (})."
|
||||||
|
);
|
||||||
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -962,9 +1080,17 @@ nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nxt_conf_json_parse_error(error, p,
|
||||||
|
"A double quote (\") is expected here. There must be a valid "
|
||||||
|
"JSON object member starts with a name, which is a string "
|
||||||
|
"enclosed in double quotes."
|
||||||
|
);
|
||||||
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
name = p;
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
member = nxt_mp_get(mp_temp, sizeof(nxt_conf_object_member_t));
|
member = nxt_mp_get(mp_temp, sizeof(nxt_conf_object_member_t));
|
||||||
@@ -972,7 +1098,7 @@ nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = nxt_conf_json_parse_string(mp, &member->name, p, end);
|
p = nxt_conf_json_parse_string(mp, &member->name, p, end, error);
|
||||||
|
|
||||||
if (nxt_slow_path(p == NULL)) {
|
if (nxt_slow_path(p == NULL)) {
|
||||||
goto error;
|
goto error;
|
||||||
@@ -981,22 +1107,52 @@ nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
rc = nxt_conf_object_hash_add(mp_temp, &hash, member);
|
rc = nxt_conf_object_hash_add(mp_temp, &hash, member);
|
||||||
|
|
||||||
if (nxt_slow_path(rc != NXT_OK)) {
|
if (nxt_slow_path(rc != NXT_OK)) {
|
||||||
|
|
||||||
|
if (rc == NXT_DECLINED) {
|
||||||
|
nxt_conf_json_parse_error(error, name,
|
||||||
|
"Duplicate object member. All JSON object members must "
|
||||||
|
"have unique names."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = nxt_conf_json_skip_space(p, end);
|
p = nxt_conf_json_skip_space(p, end);
|
||||||
|
|
||||||
if (nxt_slow_path(p == end || *p != ':')) {
|
if (nxt_slow_path(p == end)) {
|
||||||
|
|
||||||
|
nxt_conf_json_parse_error(error, p,
|
||||||
|
"Unexpected end of JSON. There's an object member without "
|
||||||
|
"value."
|
||||||
|
);
|
||||||
|
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nxt_slow_path(*p != ':')) {
|
||||||
|
|
||||||
|
nxt_conf_json_parse_error(error, p,
|
||||||
|
"A colon (:) is expected here. There must be a colon between "
|
||||||
|
"JSON member name and value."
|
||||||
|
);
|
||||||
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = nxt_conf_json_skip_space(p + 1, end);
|
p = nxt_conf_json_skip_space(p + 1, end);
|
||||||
|
|
||||||
if (nxt_slow_path(p == end)) {
|
if (nxt_slow_path(p == end)) {
|
||||||
|
|
||||||
|
nxt_conf_json_parse_error(error, p,
|
||||||
|
"Unexpected end of JSON. There's an object member without "
|
||||||
|
"value."
|
||||||
|
);
|
||||||
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = nxt_conf_json_parse_value(mp, &member->value, p, end);
|
p = nxt_conf_json_parse_value(mp, &member->value, p, end, error);
|
||||||
|
|
||||||
if (nxt_slow_path(p == NULL)) {
|
if (nxt_slow_path(p == NULL)) {
|
||||||
goto error;
|
goto error;
|
||||||
@@ -1005,6 +1161,12 @@ nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
p = nxt_conf_json_skip_space(p, end);
|
p = nxt_conf_json_skip_space(p, end);
|
||||||
|
|
||||||
if (nxt_slow_path(p == end)) {
|
if (nxt_slow_path(p == end)) {
|
||||||
|
|
||||||
|
nxt_conf_json_parse_error(error, p,
|
||||||
|
"Unexpected end of JSON. There's an object without closing "
|
||||||
|
"brace (})."
|
||||||
|
);
|
||||||
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1013,6 +1175,12 @@ nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nxt_conf_json_parse_error(error, p,
|
||||||
|
"Either a closing brace (}) or a comma (,) is expected here. "
|
||||||
|
"In JSON, all object members must be enclosed in braces and "
|
||||||
|
"separated by commas."
|
||||||
|
);
|
||||||
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1081,11 +1249,7 @@ nxt_conf_object_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
|
|||||||
|
|
||||||
nxt_conf_get_string(&member->name, &str);
|
nxt_conf_get_string(&member->name, &str);
|
||||||
|
|
||||||
if (nxt_strstr_eq(&lhq->key, &str)) {
|
return nxt_strstr_eq(&lhq->key, &str) ? NXT_OK : NXT_DECLINED;
|
||||||
return NXT_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NXT_DECLINED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1105,7 +1269,7 @@ nxt_conf_object_hash_free(void *data, void *p)
|
|||||||
|
|
||||||
static u_char *
|
static u_char *
|
||||||
nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
||||||
u_char *end)
|
u_char *end, nxt_conf_json_error_t *error)
|
||||||
{
|
{
|
||||||
u_char *p;
|
u_char *p;
|
||||||
nxt_mp_t *mp_temp;
|
nxt_mp_t *mp_temp;
|
||||||
@@ -1131,6 +1295,12 @@ nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
p = nxt_conf_json_skip_space(p + 1, end);
|
p = nxt_conf_json_skip_space(p + 1, end);
|
||||||
|
|
||||||
if (nxt_slow_path(p == end)) {
|
if (nxt_slow_path(p == end)) {
|
||||||
|
|
||||||
|
nxt_conf_json_parse_error(error, p,
|
||||||
|
"Unexpected end of JSON. There's an array without closing "
|
||||||
|
"bracket (])."
|
||||||
|
);
|
||||||
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1145,7 +1315,7 @@ nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = nxt_conf_json_parse_value(mp, element, p, end);
|
p = nxt_conf_json_parse_value(mp, element, p, end, error);
|
||||||
|
|
||||||
if (nxt_slow_path(p == NULL)) {
|
if (nxt_slow_path(p == NULL)) {
|
||||||
goto error;
|
goto error;
|
||||||
@@ -1154,6 +1324,12 @@ nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
p = nxt_conf_json_skip_space(p, end);
|
p = nxt_conf_json_skip_space(p, end);
|
||||||
|
|
||||||
if (nxt_slow_path(p == end)) {
|
if (nxt_slow_path(p == end)) {
|
||||||
|
|
||||||
|
nxt_conf_json_parse_error(error, p,
|
||||||
|
"Unexpected end of JSON. There's an array without closing "
|
||||||
|
"bracket (])."
|
||||||
|
);
|
||||||
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1162,6 +1338,12 @@ nxt_conf_json_parse_array(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nxt_conf_json_parse_error(error, p,
|
||||||
|
"Either a closing bracket (]) or a comma (,) is expected here. "
|
||||||
|
"In JSON, all array members must be enclosed in brackets and "
|
||||||
|
"separated by commas."
|
||||||
|
);
|
||||||
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1195,7 +1377,7 @@ error:
|
|||||||
|
|
||||||
static u_char *
|
static u_char *
|
||||||
nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
||||||
u_char *end)
|
u_char *end, nxt_conf_json_error_t *error)
|
||||||
{
|
{
|
||||||
u_char *p, ch, *last, *s;
|
u_char *p, ch, *last, *s;
|
||||||
size_t size, surplus;
|
size_t size, surplus;
|
||||||
@@ -1235,6 +1417,11 @@ nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nxt_conf_json_parse_error(error, p,
|
||||||
|
"Unexpected character in string. All control characters must "
|
||||||
|
"be escaped in JSON strings."
|
||||||
|
);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
case sw_escape:
|
case sw_escape:
|
||||||
@@ -1265,6 +1452,12 @@ nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nxt_conf_json_parse_error(error, p - 1,
|
||||||
|
"Unexpected reverse solidus in string. Reverse solidus in "
|
||||||
|
"JSON strings must be escaped with a second reverse solidus "
|
||||||
|
"(\\\\)."
|
||||||
|
);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
case sw_encoded1:
|
case sw_encoded1:
|
||||||
@@ -1280,6 +1473,12 @@ nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nxt_conf_json_parse_error(error, p,
|
||||||
|
"Invalid escape sequence. In JSON, escape sequences start "
|
||||||
|
"with a reverse solidus, followed by the lowercase letter u, "
|
||||||
|
"followed by four hexadecimal digits (\\uXXXX)."
|
||||||
|
);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1287,6 +1486,12 @@ nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (nxt_slow_path(p == end)) {
|
if (nxt_slow_path(p == end)) {
|
||||||
|
|
||||||
|
nxt_conf_json_parse_error(error, p,
|
||||||
|
"Unexpected end of JSON. There's a string without ending double "
|
||||||
|
"quote (\")."
|
||||||
|
);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1298,6 +1503,12 @@ nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
if (size > NXT_CONF_MAX_SHORT_STRING) {
|
if (size > NXT_CONF_MAX_SHORT_STRING) {
|
||||||
|
|
||||||
if (nxt_slow_path(size > NXT_CONF_MAX_STRING)) {
|
if (nxt_slow_path(size > NXT_CONF_MAX_STRING)) {
|
||||||
|
|
||||||
|
nxt_conf_json_parse_error(error, start,
|
||||||
|
"Too long string. Such a big JSON string values are not "
|
||||||
|
"supported."
|
||||||
|
);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1377,6 +1588,13 @@ nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
|
|
||||||
if (utf_high != 0) {
|
if (utf_high != 0) {
|
||||||
if (nxt_slow_path(utf < 0xdc00 || utf > 0xdfff)) {
|
if (nxt_slow_path(utf < 0xdc00 || utf > 0xdfff)) {
|
||||||
|
|
||||||
|
nxt_conf_json_parse_error(error, p - 12,
|
||||||
|
"Invalid JSON encoding sequence. There's a 12 bytes "
|
||||||
|
"sequence that composes an illegal UTF-16 surrogate "
|
||||||
|
"pair."
|
||||||
|
);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1390,6 +1608,12 @@ nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (utf > 0xdbff || p[0] != '\\' || p[1] != 'u') {
|
if (utf > 0xdbff || p[0] != '\\' || p[1] != 'u') {
|
||||||
|
|
||||||
|
nxt_conf_json_parse_error(error, p - 6,
|
||||||
|
"Invalid JSON encoding sequence. There's a 6 bytes "
|
||||||
|
"sequence that doesn't represent a valid character."
|
||||||
|
);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1416,7 +1640,7 @@ nxt_conf_json_parse_string(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
|
|
||||||
static u_char *
|
static u_char *
|
||||||
nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
||||||
u_char *end)
|
u_char *end, nxt_conf_json_error_t *error)
|
||||||
{
|
{
|
||||||
u_char *p, ch;
|
u_char *p, ch;
|
||||||
uint64_t integer;
|
uint64_t integer;
|
||||||
@@ -1454,13 +1678,23 @@ nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
if (nxt_slow_path(integer >= cutoff
|
if (nxt_slow_path(integer >= cutoff
|
||||||
&& (integer > cutoff || ch > cutlim)))
|
&& (integer > cutoff || ch > cutlim)))
|
||||||
{
|
{
|
||||||
return NULL;
|
nxt_conf_json_parse_error(error, start,
|
||||||
|
"Too big integer. Such a big JSON integer values are not "
|
||||||
|
"supported."
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
integer = integer * 10 + ch;
|
integer = integer * 10 + ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nxt_slow_path(p == start || (p - start > 1 && *start == '0'))) {
|
if (nxt_slow_path(p - start > 1 && *start == '0')) {
|
||||||
|
|
||||||
|
nxt_conf_json_parse_error(error, start,
|
||||||
|
"Leading zeros are not allowed in JSON numbers."
|
||||||
|
);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1549,12 +1783,32 @@ nxt_conf_json_parse_number(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start,
|
|||||||
if (nxt_fast_path(isfinite(value->u.number))) {
|
if (nxt_fast_path(isfinite(value->u.number))) {
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
nxt_conf_json_parse_error(error, start,
|
||||||
|
"Invalid number. Only integer JSON numbers without fraction and "
|
||||||
|
"exponent parts are supported."
|
||||||
|
);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos,
|
||||||
|
const char *detail)
|
||||||
|
{
|
||||||
|
if (error == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
error->pos = pos;
|
||||||
|
error->detail = (u_char *) detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
nxt_conf_json_length(nxt_conf_value_t *value, nxt_conf_json_pretty_t *pretty)
|
nxt_conf_json_length(nxt_conf_value_t *value, nxt_conf_json_pretty_t *pretty)
|
||||||
{
|
{
|
||||||
@@ -1983,3 +2237,32 @@ nxt_conf_json_escape(u_char *dst, u_char *src, size_t size)
|
|||||||
|
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
nxt_conf_json_position(u_char *start, u_char *pos, nxt_uint_t *line,
|
||||||
|
nxt_uint_t *column)
|
||||||
|
{
|
||||||
|
u_char *p;
|
||||||
|
ssize_t symbols;
|
||||||
|
nxt_uint_t lines;
|
||||||
|
|
||||||
|
lines = 1;
|
||||||
|
|
||||||
|
for (p = start; p != pos; p++) {
|
||||||
|
|
||||||
|
if (*p != '\n') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
lines++;
|
||||||
|
start = p + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
symbols = nxt_utf8_length(start, p - start);
|
||||||
|
|
||||||
|
if (symbols != -1) {
|
||||||
|
*line = lines;
|
||||||
|
*column = 1 + symbols;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,6 +22,12 @@ typedef struct nxt_conf_value_s nxt_conf_value_t;
|
|||||||
typedef struct nxt_conf_op_s nxt_conf_op_t;
|
typedef struct nxt_conf_op_s nxt_conf_op_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u_char *pos;
|
||||||
|
u_char *detail;
|
||||||
|
} nxt_conf_json_error_t;
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
NXT_CONF_MAP_INT8,
|
NXT_CONF_MAP_INT8,
|
||||||
NXT_CONF_MAP_INT32,
|
NXT_CONF_MAP_INT32,
|
||||||
@@ -65,15 +71,18 @@ nxt_int_t nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops,
|
|||||||
nxt_conf_value_t *nxt_conf_clone(nxt_mp_t *mp, nxt_conf_op_t *op,
|
nxt_conf_value_t *nxt_conf_clone(nxt_mp_t *mp, nxt_conf_op_t *op,
|
||||||
nxt_conf_value_t *value);
|
nxt_conf_value_t *value);
|
||||||
|
|
||||||
nxt_conf_value_t *nxt_conf_json_parse(nxt_mp_t *mp, u_char *start, u_char *end);
|
nxt_conf_value_t *nxt_conf_json_parse(nxt_mp_t *mp, u_char *start, u_char *end,
|
||||||
|
nxt_conf_json_error_t *error);
|
||||||
|
|
||||||
#define nxt_conf_json_parse_str(mp, str) \
|
#define nxt_conf_json_parse_str(mp, str) \
|
||||||
nxt_conf_json_parse(mp, (str)->start, (str)->start + (str)->length)
|
nxt_conf_json_parse(mp, (str)->start, (str)->start + (str)->length, NULL)
|
||||||
|
|
||||||
size_t nxt_conf_json_length(nxt_conf_value_t *value,
|
size_t nxt_conf_json_length(nxt_conf_value_t *value,
|
||||||
nxt_conf_json_pretty_t *pretty);
|
nxt_conf_json_pretty_t *pretty);
|
||||||
u_char *nxt_conf_json_print(u_char *p, nxt_conf_value_t *value,
|
u_char *nxt_conf_json_print(u_char *p, nxt_conf_value_t *value,
|
||||||
nxt_conf_json_pretty_t *pretty);
|
nxt_conf_json_pretty_t *pretty);
|
||||||
|
void nxt_conf_json_position(u_char *start, u_char *pos, nxt_uint_t *line,
|
||||||
|
nxt_uint_t *column);
|
||||||
|
|
||||||
nxt_int_t nxt_conf_validate(nxt_conf_value_t *value);
|
nxt_int_t nxt_conf_validate(nxt_conf_value_t *value);
|
||||||
|
|
||||||
@@ -82,8 +91,12 @@ void nxt_conf_get_string(nxt_conf_value_t *value, nxt_str_t *str);
|
|||||||
// FIXME reimplement and reorder functions below
|
// FIXME reimplement and reorder functions below
|
||||||
nxt_uint_t nxt_conf_object_members_count(nxt_conf_value_t *value);
|
nxt_uint_t nxt_conf_object_members_count(nxt_conf_value_t *value);
|
||||||
nxt_conf_value_t *nxt_conf_create_object(nxt_mp_t *mp, nxt_uint_t count);
|
nxt_conf_value_t *nxt_conf_create_object(nxt_mp_t *mp, nxt_uint_t count);
|
||||||
nxt_int_t nxt_conf_set_object_member(nxt_conf_value_t *object, nxt_str_t *name,
|
void nxt_conf_set_member(nxt_conf_value_t *object, nxt_str_t *name,
|
||||||
nxt_conf_value_t *value, uint32_t index);
|
nxt_conf_value_t *value, uint32_t index);
|
||||||
|
void nxt_conf_set_member_string(nxt_conf_value_t *object, nxt_str_t *name,
|
||||||
|
nxt_str_t *value, uint32_t index);
|
||||||
|
void nxt_conf_set_member_integer(nxt_conf_value_t *object, nxt_str_t *name,
|
||||||
|
int64_t value, uint32_t index);
|
||||||
|
|
||||||
|
|
||||||
#endif /* _NXT_CONF_INCLUDED_ */
|
#endif /* _NXT_CONF_INCLUDED_ */
|
||||||
|
|||||||
@@ -27,9 +27,14 @@ typedef struct {
|
|||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
nxt_str_t status_line;
|
nxt_uint_t status;
|
||||||
nxt_conf_value_t *conf;
|
nxt_conf_value_t *conf;
|
||||||
nxt_str_t json;
|
|
||||||
|
u_char *title;
|
||||||
|
u_char *detail;
|
||||||
|
ssize_t offset;
|
||||||
|
nxt_uint_t line;
|
||||||
|
nxt_uint_t column;
|
||||||
} nxt_controller_response_t;
|
} nxt_controller_response_t;
|
||||||
|
|
||||||
|
|
||||||
@@ -63,8 +68,8 @@ static nxt_int_t nxt_controller_conf_pass(nxt_task_t *task,
|
|||||||
nxt_conf_value_t *conf);
|
nxt_conf_value_t *conf);
|
||||||
static void nxt_controller_response(nxt_task_t *task,
|
static void nxt_controller_response(nxt_task_t *task,
|
||||||
nxt_controller_request_t *req, nxt_controller_response_t *resp);
|
nxt_controller_request_t *req, nxt_controller_response_t *resp);
|
||||||
static nxt_buf_t *nxt_controller_response_body(nxt_controller_response_t *resp,
|
static u_char *nxt_controller_date(u_char *buf, nxt_realtime_t *now,
|
||||||
nxt_mp_t *pool);
|
struct tm *tm, size_t size, const char *format);
|
||||||
|
|
||||||
|
|
||||||
static nxt_http_fields_hash_entry_t nxt_controller_request_fields[] = {
|
static nxt_http_fields_hash_entry_t nxt_controller_request_fields[] = {
|
||||||
@@ -561,10 +566,10 @@ nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req)
|
|||||||
nxt_int_t rc;
|
nxt_int_t rc;
|
||||||
nxt_str_t path;
|
nxt_str_t path;
|
||||||
nxt_conn_t *c;
|
nxt_conn_t *c;
|
||||||
nxt_uint_t status;
|
|
||||||
nxt_buf_mem_t *mbuf;
|
nxt_buf_mem_t *mbuf;
|
||||||
nxt_conf_op_t *ops;
|
nxt_conf_op_t *ops;
|
||||||
nxt_conf_value_t *value;
|
nxt_conf_value_t *value;
|
||||||
|
nxt_conf_json_error_t error;
|
||||||
nxt_controller_response_t resp;
|
nxt_controller_response_t resp;
|
||||||
|
|
||||||
static const nxt_str_t empty_obj = nxt_string("{}");
|
static const nxt_str_t empty_obj = nxt_string("{}");
|
||||||
@@ -583,14 +588,14 @@ nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req)
|
|||||||
value = nxt_conf_get_path(nxt_controller_conf.root, &path);
|
value = nxt_conf_get_path(nxt_controller_conf.root, &path);
|
||||||
|
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
status = 404;
|
goto not_found;
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resp.status = 200;
|
||||||
resp.conf = value;
|
resp.conf = value;
|
||||||
|
|
||||||
status = 200;
|
nxt_controller_response(task, req, &resp);
|
||||||
goto done;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nxt_str_eq(&req->parser.method, "PUT", 3)) {
|
if (nxt_str_eq(&req->parser.method, "PUT", 3)) {
|
||||||
@@ -598,19 +603,32 @@ nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req)
|
|||||||
mp = nxt_mp_create(1024, 128, 256, 32);
|
mp = nxt_mp_create(1024, 128, 256, 32);
|
||||||
|
|
||||||
if (nxt_slow_path(mp == NULL)) {
|
if (nxt_slow_path(mp == NULL)) {
|
||||||
status = 500;
|
goto alloc_fail;
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mbuf = &c->read->mem;
|
mbuf = &c->read->mem;
|
||||||
|
|
||||||
value = nxt_conf_json_parse(mp, mbuf->pos, mbuf->free);
|
nxt_memzero(&error, sizeof(nxt_conf_json_error_t));
|
||||||
|
|
||||||
|
value = nxt_conf_json_parse(mp, mbuf->pos, mbuf->free, &error);
|
||||||
|
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
nxt_mp_destroy(mp);
|
nxt_mp_destroy(mp);
|
||||||
status = 400;
|
|
||||||
nxt_str_set(&resp.json, "{ \"error\": \"Invalid JSON.\" }");
|
if (error.pos == NULL) {
|
||||||
goto done;
|
goto alloc_fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.status = 400;
|
||||||
|
resp.title = (u_char *) "Invalid JSON.";
|
||||||
|
resp.detail = error.detail;
|
||||||
|
resp.offset = error.pos - mbuf->pos;
|
||||||
|
|
||||||
|
nxt_conf_json_position(mbuf->pos, error.pos,
|
||||||
|
&resp.line, &resp.column);
|
||||||
|
|
||||||
|
nxt_controller_response(task, req, &resp);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path.length != 1) {
|
if (path.length != 1) {
|
||||||
@@ -620,29 +638,23 @@ nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req)
|
|||||||
|
|
||||||
if (rc != NXT_OK) {
|
if (rc != NXT_OK) {
|
||||||
if (rc == NXT_DECLINED) {
|
if (rc == NXT_DECLINED) {
|
||||||
status = 404;
|
goto not_found;
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
status = 500;
|
goto alloc_fail;
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
value = nxt_conf_clone(mp, ops, nxt_controller_conf.root);
|
value = nxt_conf_clone(mp, ops, nxt_controller_conf.root);
|
||||||
|
|
||||||
if (nxt_slow_path(value == NULL)) {
|
if (nxt_slow_path(value == NULL)) {
|
||||||
nxt_mp_destroy(mp);
|
nxt_mp_destroy(mp);
|
||||||
status = 500;
|
goto alloc_fail;
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nxt_slow_path(nxt_conf_validate(value) != NXT_OK)) {
|
if (nxt_slow_path(nxt_conf_validate(value) != NXT_OK)) {
|
||||||
nxt_mp_destroy(mp);
|
nxt_mp_destroy(mp);
|
||||||
status = 400;
|
goto invalid_conf;
|
||||||
nxt_str_set(&resp.json,
|
|
||||||
"{ \"error\": \"Invalid configuration.\" }");
|
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
req->conf.root = value;
|
req->conf.root = value;
|
||||||
@@ -650,8 +662,7 @@ nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req)
|
|||||||
|
|
||||||
if (nxt_controller_conf_apply(task, req) != NXT_OK) {
|
if (nxt_controller_conf_apply(task, req) != NXT_OK) {
|
||||||
nxt_mp_destroy(mp);
|
nxt_mp_destroy(mp);
|
||||||
status = 500;
|
goto alloc_fail;
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -663,8 +674,7 @@ nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req)
|
|||||||
mp = nxt_mp_create(1024, 128, 256, 32);
|
mp = nxt_mp_create(1024, 128, 256, 32);
|
||||||
|
|
||||||
if (nxt_slow_path(mp == NULL)) {
|
if (nxt_slow_path(mp == NULL)) {
|
||||||
status = 500;
|
goto alloc_fail;
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
value = nxt_conf_json_parse_str(mp, &empty_obj);
|
value = nxt_conf_json_parse_str(mp, &empty_obj);
|
||||||
@@ -676,19 +686,16 @@ nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req)
|
|||||||
|
|
||||||
if (rc != NXT_OK) {
|
if (rc != NXT_OK) {
|
||||||
if (rc == NXT_DECLINED) {
|
if (rc == NXT_DECLINED) {
|
||||||
status = 404;
|
goto not_found;
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
status = 500;
|
goto alloc_fail;
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mp = nxt_mp_create(1024, 128, 256, 32);
|
mp = nxt_mp_create(1024, 128, 256, 32);
|
||||||
|
|
||||||
if (nxt_slow_path(mp == NULL)) {
|
if (nxt_slow_path(mp == NULL)) {
|
||||||
status = 500;
|
goto alloc_fail;
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
value = nxt_conf_clone(mp, ops, nxt_controller_conf.root);
|
value = nxt_conf_clone(mp, ops, nxt_controller_conf.root);
|
||||||
@@ -696,16 +703,12 @@ nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req)
|
|||||||
|
|
||||||
if (nxt_slow_path(value == NULL)) {
|
if (nxt_slow_path(value == NULL)) {
|
||||||
nxt_mp_destroy(mp);
|
nxt_mp_destroy(mp);
|
||||||
status = 500;
|
goto alloc_fail;
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nxt_slow_path(nxt_conf_validate(value) != NXT_OK)) {
|
if (nxt_slow_path(nxt_conf_validate(value) != NXT_OK)) {
|
||||||
nxt_mp_destroy(mp);
|
nxt_mp_destroy(mp);
|
||||||
status = 400;
|
goto invalid_conf;
|
||||||
nxt_str_set(&resp.json,
|
|
||||||
"{ \"error\": \"Invalid configuration.\" }");
|
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
req->conf.root = value;
|
req->conf.root = value;
|
||||||
@@ -713,44 +716,45 @@ nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req)
|
|||||||
|
|
||||||
if (nxt_controller_conf_apply(task, req) != NXT_OK) {
|
if (nxt_controller_conf_apply(task, req) != NXT_OK) {
|
||||||
nxt_mp_destroy(mp);
|
nxt_mp_destroy(mp);
|
||||||
status = 500;
|
goto alloc_fail;
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = 405;
|
resp.status = 405;
|
||||||
|
resp.title = (u_char *) "Invalid method.";
|
||||||
done:
|
resp.offset = -1;
|
||||||
|
|
||||||
switch (status) {
|
|
||||||
|
|
||||||
case 200:
|
|
||||||
nxt_str_set(&resp.status_line, "200 OK");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 400:
|
|
||||||
nxt_str_set(&resp.status_line, "400 Bad Request");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 404:
|
|
||||||
nxt_str_set(&resp.status_line, "404 Not Found");
|
|
||||||
nxt_str_set(&resp.json, "{ \"error\": \"Value doesn't exist.\" }");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 405:
|
|
||||||
nxt_str_set(&resp.status_line, "405 Method Not Allowed");
|
|
||||||
nxt_str_set(&resp.json, "{ \"error\": \"Invalid method.\" }");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 500:
|
|
||||||
nxt_str_set(&resp.status_line, "500 Internal Server Error");
|
|
||||||
nxt_str_set(&resp.json, "{ \"error\": \"Memory allocation failed.\" }");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
nxt_controller_response(task, req, &resp);
|
nxt_controller_response(task, req, &resp);
|
||||||
|
return;
|
||||||
|
|
||||||
|
alloc_fail:
|
||||||
|
|
||||||
|
resp.status = 500;
|
||||||
|
resp.title = (u_char *) "Memory allocation failed.";
|
||||||
|
resp.offset = -1;
|
||||||
|
|
||||||
|
nxt_controller_response(task, req, &resp);
|
||||||
|
return;
|
||||||
|
|
||||||
|
not_found:
|
||||||
|
|
||||||
|
resp.status = 404;
|
||||||
|
resp.title = (u_char *) "Value doesn't exist.";
|
||||||
|
resp.offset = -1;
|
||||||
|
|
||||||
|
nxt_controller_response(task, req, &resp);
|
||||||
|
return;
|
||||||
|
|
||||||
|
invalid_conf:
|
||||||
|
|
||||||
|
resp.status = 400;
|
||||||
|
resp.title = (u_char *) "Invalid configuration.";
|
||||||
|
resp.offset = -1;
|
||||||
|
|
||||||
|
nxt_controller_response(task, req, &resp);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -796,15 +800,15 @@ nxt_controller_conf_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
|
|||||||
|
|
||||||
nxt_controller_conf = req->conf;
|
nxt_controller_conf = req->conf;
|
||||||
|
|
||||||
nxt_str_set(&resp.status_line, "200 OK");
|
resp.status = 200;
|
||||||
nxt_str_set(&resp.json, "{ \"success\": \"Reconfiguration done.\" }");
|
resp.title = (u_char *) "Reconfiguration done.";
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
nxt_mp_destroy(req->conf.pool);
|
nxt_mp_destroy(req->conf.pool);
|
||||||
|
|
||||||
nxt_str_set(&resp.status_line, "500 Internal Server Error");
|
resp.status = 500;
|
||||||
nxt_str_set(&resp.json,
|
resp.title = (u_char *) "Failed to apply new configuration.";
|
||||||
"{ \"error\": \"Failed to apply new configuration.\" }");
|
resp.offset = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
nxt_controller_response(task, req, &resp);
|
nxt_controller_response(task, req, &resp);
|
||||||
@@ -830,9 +834,11 @@ nxt_controller_process_waiting(nxt_task_t *task)
|
|||||||
|
|
||||||
nxt_mp_destroy(req->conf.pool);
|
nxt_mp_destroy(req->conf.pool);
|
||||||
|
|
||||||
nxt_str_set(&resp.status_line, "500 Internal Server Error");
|
nxt_memzero(&resp, sizeof(nxt_controller_response_t));
|
||||||
nxt_str_set(&resp.json,
|
|
||||||
"{ \"error\": \"Memory allocation failed.\" }");
|
resp.status = 500;
|
||||||
|
resp.title = (u_char *) "Memory allocation failed.";
|
||||||
|
resp.offset = -1;
|
||||||
|
|
||||||
nxt_controller_response(task, req, &resp);
|
nxt_controller_response(task, req, &resp);
|
||||||
|
|
||||||
@@ -877,18 +883,137 @@ nxt_controller_conf_pass(nxt_task_t *task, nxt_conf_value_t *conf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nxt_controller_response(nxt_task_t *task, nxt_controller_request_t *req,
|
nxt_controller_response(nxt_task_t *task, nxt_controller_request_t *req,
|
||||||
nxt_controller_response_t *resp)
|
nxt_controller_response_t *resp)
|
||||||
{
|
{
|
||||||
size_t size;
|
size_t size;
|
||||||
nxt_buf_t *b;
|
nxt_str_t status_line, str;
|
||||||
nxt_conn_t *c;
|
nxt_buf_t *b, *body;
|
||||||
|
nxt_conn_t *c;
|
||||||
|
nxt_uint_t n;
|
||||||
|
nxt_conf_value_t *value, *location;
|
||||||
|
nxt_conf_json_pretty_t pretty;
|
||||||
|
|
||||||
|
static nxt_str_t success_str = nxt_string("success");
|
||||||
|
static nxt_str_t error_str = nxt_string("error");
|
||||||
|
static nxt_str_t detail_str = nxt_string("detail");
|
||||||
|
static nxt_str_t location_str = nxt_string("location");
|
||||||
|
static nxt_str_t offset_str = nxt_string("offset");
|
||||||
|
static nxt_str_t line_str = nxt_string("line");
|
||||||
|
static nxt_str_t column_str = nxt_string("column");
|
||||||
|
|
||||||
|
static nxt_time_string_t date_cache = {
|
||||||
|
(nxt_atomic_uint_t) -1,
|
||||||
|
nxt_controller_date,
|
||||||
|
"%s, %02d %s %4d %02d:%02d:%02d GMT",
|
||||||
|
sizeof("Wed, 31 Dec 1986 16:40:00 GMT") - 1,
|
||||||
|
NXT_THREAD_TIME_GMT,
|
||||||
|
NXT_THREAD_TIME_SEC,
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (resp->status) {
|
||||||
|
|
||||||
|
case 200:
|
||||||
|
nxt_str_set(&status_line, "200 OK");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 400:
|
||||||
|
nxt_str_set(&status_line, "400 Bad Request");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 404:
|
||||||
|
nxt_str_set(&status_line, "404 Not Found");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 405:
|
||||||
|
nxt_str_set(&status_line, "405 Method Not Allowed");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 500:
|
||||||
|
nxt_str_set(&status_line, "500 Internal Server Error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
c = req->conn;
|
c = req->conn;
|
||||||
|
value = resp->conf;
|
||||||
|
|
||||||
size = sizeof("HTTP/1.0 " "\r\n\r\n") - 1 + resp->status_line.length;
|
if (value == NULL) {
|
||||||
|
n = 1
|
||||||
|
+ (resp->detail != NULL)
|
||||||
|
+ (resp->status >= 400 && resp->offset != -1);
|
||||||
|
|
||||||
|
value = nxt_conf_create_object(c->mem_pool, n);
|
||||||
|
|
||||||
|
if (nxt_slow_path(value == NULL)) {
|
||||||
|
nxt_controller_conn_close(task, c, req);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
str.length = nxt_strlen(resp->title);
|
||||||
|
str.start = resp->title;
|
||||||
|
|
||||||
|
if (resp->status < 400) {
|
||||||
|
nxt_conf_set_member_string(value, &success_str, &str, 0);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
nxt_conf_set_member_string(value, &error_str, &str, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
|
||||||
|
if (resp->detail != NULL) {
|
||||||
|
str.length = nxt_strlen(resp->detail);
|
||||||
|
str.start = resp->detail;
|
||||||
|
|
||||||
|
n++;
|
||||||
|
|
||||||
|
nxt_conf_set_member_string(value, &detail_str, &str, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resp->status >= 400 && resp->offset != -1) {
|
||||||
|
n++;
|
||||||
|
|
||||||
|
location = nxt_conf_create_object(c->mem_pool,
|
||||||
|
resp->line != 0 ? 3 : 1);
|
||||||
|
|
||||||
|
nxt_conf_set_member(value, &location_str, location, n);
|
||||||
|
|
||||||
|
nxt_conf_set_member_integer(location, &offset_str, resp->offset, 0);
|
||||||
|
|
||||||
|
if (resp->line != 0) {
|
||||||
|
nxt_conf_set_member_integer(location, &line_str,
|
||||||
|
resp->line, 1);
|
||||||
|
|
||||||
|
nxt_conf_set_member_integer(location, &column_str,
|
||||||
|
resp->column, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t));
|
||||||
|
|
||||||
|
size = nxt_conf_json_length(value, &pretty) + 2;
|
||||||
|
|
||||||
|
body = nxt_buf_mem_alloc(c->mem_pool, size, 0);
|
||||||
|
if (nxt_slow_path(body == NULL)) {
|
||||||
|
nxt_controller_conn_close(task, c, req);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t));
|
||||||
|
|
||||||
|
body->mem.free = nxt_conf_json_print(body->mem.free, value, &pretty);
|
||||||
|
|
||||||
|
body->mem.free = nxt_cpymem(body->mem.free, "\r\n", 2);
|
||||||
|
|
||||||
|
size = sizeof("HTTP/1.1 " "\r\n") - 1 + status_line.length
|
||||||
|
+ sizeof("Server: nginext/0.1\r\n") - 1
|
||||||
|
+ sizeof("Date: Wed, 31 Dec 1986 16:40:00 GMT\r\n") - 1
|
||||||
|
+ sizeof("Content-Type: application/json\r\n") - 1
|
||||||
|
+ sizeof("Content-Length: " "\r\n") - 1 + NXT_SIZE_T_LEN
|
||||||
|
+ sizeof("Connection: close\r\n") - 1
|
||||||
|
+ sizeof("\r\n") - 1;
|
||||||
|
|
||||||
b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
|
b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
|
||||||
if (nxt_slow_path(b == NULL)) {
|
if (nxt_slow_path(b == NULL)) {
|
||||||
@@ -896,18 +1021,37 @@ nxt_controller_response(nxt_task_t *task, nxt_controller_request_t *req,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
b->mem.free = nxt_cpymem(b->mem.free, "HTTP/1.0 ", sizeof("HTTP/1.0 ") - 1);
|
b->next = body;
|
||||||
b->mem.free = nxt_cpymem(b->mem.free, resp->status_line.start,
|
|
||||||
resp->status_line.length);
|
|
||||||
|
|
||||||
b->mem.free = nxt_cpymem(b->mem.free, "\r\n\r\n", sizeof("\r\n\r\n") - 1);
|
nxt_str_set(&str, "HTTP/1.1 ");
|
||||||
|
|
||||||
b->next = nxt_controller_response_body(resp, c->mem_pool);
|
b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length);
|
||||||
|
b->mem.free = nxt_cpymem(b->mem.free, status_line.start,
|
||||||
|
status_line.length);
|
||||||
|
|
||||||
if (nxt_slow_path(b->next == NULL)) {
|
nxt_str_set(&str, "\r\n"
|
||||||
nxt_controller_conn_close(task, c, req);
|
"Server: nginext/0.1\r\n"
|
||||||
return;
|
"Date: ");
|
||||||
}
|
|
||||||
|
b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length);
|
||||||
|
|
||||||
|
b->mem.free = nxt_thread_time_string(task->thread, &date_cache,
|
||||||
|
b->mem.free);
|
||||||
|
|
||||||
|
nxt_str_set(&str, "\r\n"
|
||||||
|
"Content-Type: application/json\r\n"
|
||||||
|
"Content-Length: ");
|
||||||
|
|
||||||
|
b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length);
|
||||||
|
|
||||||
|
b->mem.free = nxt_sprintf(b->mem.free, b->mem.end, "%uz",
|
||||||
|
nxt_buf_mem_used_size(&body->mem));
|
||||||
|
|
||||||
|
nxt_str_set(&str, "\r\n"
|
||||||
|
"Connection: close\r\n"
|
||||||
|
"\r\n");
|
||||||
|
|
||||||
|
b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length);
|
||||||
|
|
||||||
c->write = b;
|
c->write = b;
|
||||||
c->write_state = &nxt_controller_conn_write_state;
|
c->write_state = &nxt_controller_conn_write_state;
|
||||||
@@ -916,40 +1060,18 @@ nxt_controller_response(nxt_task_t *task, nxt_controller_request_t *req,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static nxt_buf_t *
|
static u_char *
|
||||||
nxt_controller_response_body(nxt_controller_response_t *resp, nxt_mp_t *pool)
|
nxt_controller_date(u_char *buf, nxt_realtime_t *now, struct tm *tm,
|
||||||
|
size_t size, const char *format)
|
||||||
{
|
{
|
||||||
size_t size;
|
static const char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri",
|
||||||
nxt_buf_t *b;
|
"Sat" };
|
||||||
nxt_conf_value_t *value;
|
|
||||||
nxt_conf_json_pretty_t pretty;
|
|
||||||
|
|
||||||
if (resp->conf) {
|
static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||||
value = resp->conf;
|
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
|
||||||
|
|
||||||
} else {
|
return nxt_sprintf(buf, buf + size, format,
|
||||||
value = nxt_conf_json_parse_str(pool, &resp->json);
|
week[tm->tm_wday], tm->tm_mday,
|
||||||
|
month[tm->tm_mon], tm->tm_year + 1900,
|
||||||
if (nxt_slow_path(value == NULL)) {
|
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t));
|
|
||||||
|
|
||||||
size = nxt_conf_json_length(value, &pretty) + 2;
|
|
||||||
|
|
||||||
b = nxt_buf_mem_alloc(pool, size, 0);
|
|
||||||
if (nxt_slow_path(b == NULL)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t));
|
|
||||||
|
|
||||||
b->mem.free = nxt_conf_json_print(b->mem.free, value, &pretty);
|
|
||||||
|
|
||||||
*b->mem.free++ = '\r';
|
|
||||||
*b->mem.free++ = '\n';
|
|
||||||
|
|
||||||
return b;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ nxt_port_master_start_worker_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
|
|||||||
|
|
||||||
start += app_conf.name.length + 1;
|
start += app_conf.name.length + 1;
|
||||||
|
|
||||||
conf = nxt_conf_json_parse(mp, start, b->mem.free);
|
conf = nxt_conf_json_parse(mp, start, b->mem.free, NULL);
|
||||||
|
|
||||||
if (conf == NULL) {
|
if (conf == NULL) {
|
||||||
nxt_log(task, NXT_LOG_CRIT, "configuration parsing error");
|
nxt_log(task, NXT_LOG_CRIT, "configuration parsing error");
|
||||||
|
|||||||
@@ -661,7 +661,7 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
|
|||||||
static nxt_str_t applications_path = nxt_string("/applications");
|
static nxt_str_t applications_path = nxt_string("/applications");
|
||||||
static nxt_str_t listeners_path = nxt_string("/listeners");
|
static nxt_str_t listeners_path = nxt_string("/listeners");
|
||||||
|
|
||||||
conf = nxt_conf_json_parse(tmcf->mem_pool, start, end);
|
conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL);
|
||||||
if (conf == NULL) {
|
if (conf == NULL) {
|
||||||
nxt_log(task, NXT_LOG_CRIT, "configuration parsing error");
|
nxt_log(task, NXT_LOG_CRIT, "configuration parsing error");
|
||||||
return NXT_ERROR;
|
return NXT_ERROR;
|
||||||
|
|||||||
Reference in New Issue
Block a user