iot/http: Add test-case for HTTP header fields
This commit adds the following routines: - test_invalid_header_content - test_invalid_header_content - test_invalid_header_field - test_invalid_header_field - test_preserve_data - test_parse_url - test_method_str - test_header_nread_value - test_double_content_length_error - test_chunked_content_length_error - test_header_cr_no_lf_error - test_invalid_header_field_token_error - test_invalid_header_field_content_error - test_double_content_length_error - test_chunked_content_length_error - test_header_cr_no_lf_error - test_invalid_header_field_token_error - test_invalid_header_field_content_error Origin: https://github.com/nodejs/http-parser/releases/tag/v2.7.1 https://github.com/nodejs/http-parser/archive/v2.7.1.tar.gz This patch reformats some http_parser files to reduce checkpatch warnings. See: https://gitlab.com/santes/http_parser/tree/refactoring1 Commit: c58dd8350fdf6ead0807ba37107b19f58e4f434c Furthermore, method_str overflow test was updated to avoid compiler warnings on some platforms. Before: Line 627: http_method_str(1337) After: Line 627: http_method_str(127) Jira: ZEP-346 Jira: ZEP-776 Change-Id: If6163f59de21186f22f4f02d8c44f43ddbf9b59b Signed-off-by: Flavio Santes <flavio.santes@intel.com>
This commit is contained in:
parent
b965fb5ff1
commit
a1dc687b5d
6 changed files with 1015 additions and 0 deletions
20
tests/iot/test_http_header/Makefile
Normal file
20
tests/iot/test_http_header/Makefile
Normal file
|
@ -0,0 +1,20 @@
|
|||
#
|
||||
# Copyright (c) 2016 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
BOARD ?= qemu_x86
|
||||
CONF_FILE ?= prj.conf
|
||||
|
||||
include $(ZEPHYR_BASE)/Makefile.inc
|
27
tests/iot/test_http_header/README
Normal file
27
tests/iot/test_http_header/README
Normal file
|
@ -0,0 +1,27 @@
|
|||
HTTP header fields test
|
||||
-----------------------
|
||||
|
||||
Sample output:
|
||||
|
||||
tc_start() - HTTP header fields test
|
||||
[PASS] test_preserve_data
|
||||
[PASS] test_parse_url
|
||||
[PASS] test_method_str
|
||||
[PASS] test_header_nread_value
|
||||
[PASS] test_double_content_length_error HTTP_REQUEST
|
||||
[PASS] test_chunked_content_length_error HTTP_REQUEST
|
||||
[PASS] test_header_cr_no_lf_error HTTP_REQUEST
|
||||
[PASS] test_invalid_header_field_token_error HTTP_REQUEST
|
||||
[PASS] test_invalid_header_field_content_error HTTP_REQUEST
|
||||
[PASS] test_double_content_length_error HTTP_RESPONSE
|
||||
[PASS] test_chunked_content_length_error HTTP_RESPONSE
|
||||
[PASS] test_header_cr_no_lf_error HTTP_RESPONSE
|
||||
[PASS] test_invalid_header_field_token_error HTTP_RESPONSE
|
||||
[PASS] test_invalid_header_field_content_error HTTP_RESPONSE
|
||||
|
||||
No errors detected
|
||||
===================================================================
|
||||
PASS - main.
|
||||
===================================================================
|
||||
PROJECT EXECUTION SUCCESSFUL
|
||||
|
5
tests/iot/test_http_header/prj.conf
Normal file
5
tests/iot/test_http_header/prj.conf
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Comment the following line if you want to try another libc
|
||||
CONFIG_MINIMAL_LIBC_EXTENDED=y
|
||||
CONFIG_HTTP_PARSER=y
|
||||
# Enable strict parser by uncommenting the following line
|
||||
# CONFIG_HTTP_PARSER_STRICT=y
|
19
tests/iot/test_http_header/src/Makefile
Normal file
19
tests/iot/test_http_header/src/Makefile
Normal file
|
@ -0,0 +1,19 @@
|
|||
#
|
||||
# Copyright (c) 2016 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
ccflags-y += -I$(ZEPHYR_BASE)/tests/include
|
||||
|
||||
obj-y += test_http_header.o
|
941
tests/iot/test_http_header/src/test_http_header.c
Normal file
941
tests/iot/test_http_header/src/test_http_header.c
Normal file
|
@ -0,0 +1,941 @@
|
|||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <iot/http_parser.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <misc/printk.h>
|
||||
#include <tc_util.h>
|
||||
|
||||
static
|
||||
struct http_parser_settings settings_null = {
|
||||
.on_message_begin = 0,
|
||||
.on_header_field = 0,
|
||||
.on_header_value = 0,
|
||||
.on_url = 0,
|
||||
.on_status = 0,
|
||||
.on_body = 0,
|
||||
.on_headers_complete = 0,
|
||||
.on_message_complete = 0,
|
||||
.on_chunk_header = 0,
|
||||
.on_chunk_complete = 0};
|
||||
|
||||
struct url_test {
|
||||
const char *name;
|
||||
const char *url;
|
||||
int is_connect;
|
||||
struct http_parser_url u;
|
||||
int rv;
|
||||
};
|
||||
|
||||
const struct url_test url_tests[] = {
|
||||
{
|
||||
.name = "proxy request",
|
||||
.url = "http://hostname/",
|
||||
.is_connect = 0,
|
||||
.u = { .field_set = (1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH),
|
||||
.port = 0,
|
||||
.field_data = {
|
||||
{ 0, 4 }, /* UF_SCHEMA */
|
||||
{ 7, 8 }, /* UF_HOST */
|
||||
{ 0, 0 }, /* UF_PORT */
|
||||
{ 15, 1 }, /* UF_PATH */
|
||||
{ 0, 0 }, /* UF_QUERY */
|
||||
{ 0, 0 }, /* UF_FRAGMENT */
|
||||
{ 0, 0 } } }, /* UF_USERINFO */
|
||||
.rv = 0
|
||||
},
|
||||
|
||||
{
|
||||
.name = "proxy request with port",
|
||||
.url = "http://hostname:444/",
|
||||
.is_connect = 0,
|
||||
.u = { .field_set = (1 << UF_SCHEMA) | (1 << UF_HOST) |
|
||||
(1 << UF_PORT) | (1 << UF_PATH),
|
||||
.port = 444,
|
||||
.field_data = {
|
||||
{ 0, 4 }, /* UF_SCHEMA */
|
||||
{ 7, 8 }, /* UF_HOST */
|
||||
{ 16, 3 }, /* UF_PORT */
|
||||
{ 19, 1 }, /* UF_PATH */
|
||||
{ 0, 0 }, /* UF_QUERY */
|
||||
{ 0, 0 }, /* UF_FRAGMENT */
|
||||
{ 0, 0 } } }, /* UF_USERINFO */
|
||||
.rv = 0
|
||||
},
|
||||
|
||||
{
|
||||
.name = "CONNECT request",
|
||||
.url = "hostname:443",
|
||||
.is_connect = 1,
|
||||
.u = { .field_set = (1 << UF_HOST) | (1 << UF_PORT),
|
||||
.port = 443,
|
||||
.field_data = {
|
||||
{ 0, 0 }, /* UF_SCHEMA */
|
||||
{ 0, 8 }, /* UF_HOST */
|
||||
{ 9, 3 }, /* UF_PORT */
|
||||
{ 0, 0 }, /* UF_PATH */
|
||||
{ 0, 0 }, /* UF_QUERY */
|
||||
{ 0, 0 }, /* UF_FRAGMENT */
|
||||
{ 0, 0 } } }, /* UF_USERINFO */
|
||||
.rv = 0
|
||||
},
|
||||
|
||||
{
|
||||
.name = "CONNECT request but not connect",
|
||||
.url = "hostname:443",
|
||||
.is_connect = 0,
|
||||
.rv = 1
|
||||
},
|
||||
|
||||
{
|
||||
.name = "proxy ipv6 request",
|
||||
.url = "http://[1:2::3:4]/",
|
||||
.is_connect = 0,
|
||||
.u = { .field_set = (1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH),
|
||||
.port = 0,
|
||||
.field_data = {
|
||||
{ 0, 4 }, /* UF_SCHEMA */
|
||||
{ 8, 8 }, /* UF_HOST */
|
||||
{ 0, 0 }, /* UF_PORT */
|
||||
{ 17, 1 }, /* UF_PATH */
|
||||
{ 0, 0 }, /* UF_QUERY */
|
||||
{ 0, 0 }, /* UF_FRAGMENT */
|
||||
{ 0, 0 } } }, /* UF_USERINFO */
|
||||
.rv = 0
|
||||
},
|
||||
|
||||
{
|
||||
.name = "proxy ipv6 request with port",
|
||||
.url = "http://[1:2::3:4]:67/",
|
||||
.is_connect = 0,
|
||||
.u = { .field_set = (1 << UF_SCHEMA) | (1 << UF_HOST) |
|
||||
(1 << UF_PORT) | (1 << UF_PATH),
|
||||
.port = 67,
|
||||
.field_data = {
|
||||
{ 0, 4 }, /* UF_SCHEMA */
|
||||
{ 8, 8 }, /* UF_HOST */
|
||||
{ 18, 2 }, /* UF_PORT */
|
||||
{ 20, 1 }, /* UF_PATH */
|
||||
{ 0, 0 }, /* UF_QUERY */
|
||||
{ 0, 0 }, /* UF_FRAGMENT */
|
||||
{ 0, 0 } } }, /* UF_USERINFO */
|
||||
.rv = 0
|
||||
},
|
||||
|
||||
{
|
||||
.name = "CONNECT ipv6 address",
|
||||
.url = "[1:2::3:4]:443",
|
||||
.is_connect = 1,
|
||||
.u = { .field_set = (1 << UF_HOST) | (1 << UF_PORT),
|
||||
.port = 443,
|
||||
.field_data = {
|
||||
{ 0, 0 }, /* UF_SCHEMA */
|
||||
{ 1, 8 }, /* UF_HOST */
|
||||
{ 11, 3 }, /* UF_PORT */
|
||||
{ 0, 0 }, /* UF_PATH */
|
||||
{ 0, 0 }, /* UF_QUERY */
|
||||
{ 0, 0 }, /* UF_FRAGMENT */
|
||||
{ 0, 0 } } }, /* UF_USERINFO */
|
||||
.rv = 0
|
||||
},
|
||||
|
||||
{
|
||||
.name = "ipv4 in ipv6 address",
|
||||
.url = "http://[2001:0000:0000:0000:0000:0000:1.9.1.1]/",
|
||||
.is_connect = 0,
|
||||
.u = { .field_set = (1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH),
|
||||
.port = 0,
|
||||
.field_data = {
|
||||
{ 0, 4 }, /* UF_SCHEMA */
|
||||
{ 8, 37 }, /* UF_HOST */
|
||||
{ 0, 0 }, /* UF_PORT */
|
||||
{ 46, 1 }, /* UF_PATH */
|
||||
{ 0, 0 }, /* UF_QUERY */
|
||||
{ 0, 0 }, /* UF_FRAGMENT */
|
||||
{ 0, 0 } } }, /* UF_USERINFO */
|
||||
.rv = 0
|
||||
},
|
||||
|
||||
{
|
||||
.name = "extra ? in query string",
|
||||
.url = "http://a.tbcdn.cn/p/fp/2010c/??fp-header-min.css,"
|
||||
"fp-base-min.css,fp-channel-min.css,fp-product-min.css,fp-mall-"
|
||||
"min.css,fp-category-min.css,fp-sub-min.css,fp-gdp4p-min.css,"
|
||||
"fp-css3-min.css,fp-misc-min.css?t=20101022.css",
|
||||
.is_connect = 0,
|
||||
.u = { .field_set = (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) |
|
||||
(1<<UF_QUERY),
|
||||
.port = 0,
|
||||
.field_data = {
|
||||
{ 0, 4 }, /* UF_SCHEMA */
|
||||
{ 7, 10 }, /* UF_HOST */
|
||||
{ 0, 0 }, /* UF_PORT */
|
||||
{ 17, 12 }, /* UF_PATH */
|
||||
{ 30, 187}, /* UF_QUERY */
|
||||
{ 0, 0 }, /* UF_FRAGMENT */
|
||||
{ 0, 0 } } }, /* UF_USERINFO */
|
||||
.rv = 0
|
||||
},
|
||||
|
||||
{
|
||||
.name = "space URL encoded",
|
||||
.url = "/toto.html?toto=a%20b",
|
||||
.is_connect = 0,
|
||||
.u = { .field_set = (1<<UF_PATH) | (1<<UF_QUERY),
|
||||
.port = 0,
|
||||
.field_data = {
|
||||
{ 0, 0 }, /* UF_SCHEMA */
|
||||
{ 0, 0 }, /* UF_HOST */
|
||||
{ 0, 0 }, /* UF_PORT */
|
||||
{ 0, 10 }, /* UF_PATH */
|
||||
{ 11, 10 }, /* UF_QUERY */
|
||||
{ 0, 0 }, /* UF_FRAGMENT */
|
||||
{ 0, 0 } } }, /* UF_USERINFO */
|
||||
.rv = 0
|
||||
},
|
||||
|
||||
{
|
||||
.name = "URL fragment",
|
||||
.url = "/toto.html#titi",
|
||||
.is_connect = 0,
|
||||
.u = { .field_set = (1<<UF_PATH) | (1<<UF_FRAGMENT),
|
||||
.port = 0,
|
||||
.field_data = {
|
||||
{ 0, 0 }, /* UF_SCHEMA */
|
||||
{ 0, 0 }, /* UF_HOST */
|
||||
{ 0, 0 }, /* UF_PORT */
|
||||
{ 0, 10 }, /* UF_PATH */
|
||||
{ 0, 0 }, /* UF_QUERY */
|
||||
{ 11, 4 }, /* UF_FRAGMENT */
|
||||
{ 0, 0 } } }, /* UF_USERINFO */
|
||||
.rv = 0
|
||||
},
|
||||
|
||||
{
|
||||
.name = "complex URL fragment",
|
||||
.url = "http://www.webmasterworld.com/r.cgi?f=21&d=8405&url="
|
||||
"http://www.example.com/index.html?foo=bar&hello=world#midpage",
|
||||
.is_connect = 0,
|
||||
.u = { .field_set = (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) |
|
||||
(1<<UF_QUERY) | (1<<UF_FRAGMENT),
|
||||
.port = 0,
|
||||
.field_data = {
|
||||
{ 0, 4 }, /* UF_SCHEMA */
|
||||
{ 7, 22 }, /* UF_HOST */
|
||||
{ 0, 0 }, /* UF_PORT */
|
||||
{ 29, 6 }, /* UF_PATH */
|
||||
{ 36, 69 }, /* UF_QUERY */
|
||||
{106, 7 }, /* UF_FRAGMENT */
|
||||
{ 0, 0 } } }, /* UF_USERINFO */
|
||||
.rv = 0
|
||||
},
|
||||
|
||||
{
|
||||
.name = "complex URL from node js url parser doc",
|
||||
.url = "http://host.com:8080/p/a/t/h?query=string#hash",
|
||||
.is_connect = 0,
|
||||
.u = { .field_set = (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PORT) |
|
||||
(1<<UF_PATH) | (1<<UF_QUERY) | (1<<UF_FRAGMENT),
|
||||
.port = 8080,
|
||||
.field_data = {
|
||||
{ 0, 4 }, /* UF_SCHEMA */
|
||||
{ 7, 8 }, /* UF_HOST */
|
||||
{ 16, 4 }, /* UF_PORT */
|
||||
{ 20, 8 }, /* UF_PATH */
|
||||
{ 29, 12 }, /* UF_QUERY */
|
||||
{ 42, 4 }, /* UF_FRAGMENT */
|
||||
{ 0, 0 } } }, /* UF_USERINFO */
|
||||
.rv = 0
|
||||
},
|
||||
|
||||
{
|
||||
.name = "complex URL with basic auth from node js url parser doc",
|
||||
.url = "http://a:b@host.com:8080/p/a/t/h?query=string#hash",
|
||||
.is_connect = 0,
|
||||
.u = { .field_set = (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PORT) |
|
||||
(1<<UF_PATH) | (1<<UF_QUERY) | (1<<UF_FRAGMENT) |
|
||||
(1<<UF_USERINFO),
|
||||
.port = 8080,
|
||||
.field_data = {
|
||||
{ 0, 4 }, /* UF_SCHEMA */
|
||||
{ 11, 8 }, /* UF_HOST */
|
||||
{ 20, 4 }, /* UF_PORT */
|
||||
{ 24, 8 }, /* UF_PATH */
|
||||
{ 33, 12 }, /* UF_QUERY */
|
||||
{ 46, 4 }, /* UF_FRAGMENT */
|
||||
{ 7, 3 } } }, /* UF_USERINFO */
|
||||
.rv = 0
|
||||
},
|
||||
|
||||
{
|
||||
.name = "double @",
|
||||
.url = "http://a:b@@hostname:443/",
|
||||
.is_connect = 0,
|
||||
.rv = 1
|
||||
},
|
||||
|
||||
{
|
||||
.name = "proxy empty host",
|
||||
.url = "http://:443/",
|
||||
.is_connect = 0,
|
||||
.rv = 1
|
||||
},
|
||||
|
||||
{
|
||||
.name = "proxy empty port",
|
||||
.url = "http://hostname:/",
|
||||
.is_connect = 0,
|
||||
.rv = 1,
|
||||
},
|
||||
|
||||
{
|
||||
.name = "CONNECT with basic auth",
|
||||
.url = "a:b@hostname:443",
|
||||
.is_connect = 1,
|
||||
.rv = 1,
|
||||
},
|
||||
|
||||
{
|
||||
.name = "CONNECT empty host",
|
||||
.url = ":443",
|
||||
.is_connect = 1,
|
||||
.rv = 1,
|
||||
},
|
||||
|
||||
{
|
||||
.name = "CONNECT empty port",
|
||||
.url = "hostname:",
|
||||
.is_connect = 1,
|
||||
.rv = 1,
|
||||
},
|
||||
|
||||
{
|
||||
.name = "CONNECT with extra bits",
|
||||
.url = "hostname:443/",
|
||||
.is_connect = 1,
|
||||
.rv = 1,
|
||||
},
|
||||
|
||||
{
|
||||
.name = "space in URL",
|
||||
.url = "/foo bar/",
|
||||
.rv = 1, /* s_dead */
|
||||
},
|
||||
|
||||
{
|
||||
.name = "proxy basic auth with space url encoded",
|
||||
.url = "http://a%20:b@host.com/",
|
||||
.is_connect = 0,
|
||||
.u = { .field_set = (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) |
|
||||
(1<<UF_USERINFO),
|
||||
.port = 0,
|
||||
.field_data = {
|
||||
{ 0, 4 }, /* UF_SCHEMA */
|
||||
{ 14, 8 }, /* UF_HOST */
|
||||
{ 0, 0 }, /* UF_PORT */
|
||||
{ 22, 1 }, /* UF_PATH */
|
||||
{ 0, 0 }, /* UF_QUERY */
|
||||
{ 0, 0 }, /* UF_FRAGMENT */
|
||||
{ 7, 6 } } }, /* UF_USERINFO */
|
||||
.rv = 0
|
||||
},
|
||||
|
||||
{
|
||||
.name = "carriage return in URL",
|
||||
.url = "/foo\rbar/",
|
||||
.rv = 1 /* s_dead */
|
||||
},
|
||||
|
||||
{
|
||||
.name = "proxy double : in URL",
|
||||
.url = "http://hostname::443/",
|
||||
.rv = 1 /* s_dead */
|
||||
},
|
||||
|
||||
{
|
||||
.name = "proxy basic auth with double :",
|
||||
.url = "http://a::b@host.com/",
|
||||
.is_connect = 0,
|
||||
.u = { .field_set = (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) |
|
||||
(1<<UF_USERINFO),
|
||||
.port = 0,
|
||||
.field_data = {
|
||||
{ 0, 4 }, /* UF_SCHEMA */
|
||||
{ 12, 8 }, /* UF_HOST */
|
||||
{ 0, 0 }, /* UF_PORT */
|
||||
{ 20, 1 }, /* UF_PATH */
|
||||
{ 0, 0 }, /* UF_QUERY */
|
||||
{ 0, 0 }, /* UF_FRAGMENT */
|
||||
{ 7, 4 } } }, /* UF_USERINFO */
|
||||
.rv = 0
|
||||
},
|
||||
|
||||
{
|
||||
.name = "line feed in URL",
|
||||
.url = "/foo\nbar/",
|
||||
.rv = 1 /* s_dead */
|
||||
},
|
||||
|
||||
{
|
||||
.name = "proxy empty basic auth",
|
||||
.url = "http://@hostname/fo",
|
||||
.u = { .field_set = (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH),
|
||||
.port = 0,
|
||||
.field_data = {
|
||||
{ 0, 4 }, /* UF_SCHEMA */
|
||||
{ 8, 8 }, /* UF_HOST */
|
||||
{ 0, 0 }, /* UF_PORT */
|
||||
{ 16, 3 }, /* UF_PATH */
|
||||
{ 0, 0 }, /* UF_QUERY */
|
||||
{ 0, 0 }, /* UF_FRAGMENT */
|
||||
{ 0, 0 } } }, /* UF_USERINFO */
|
||||
.rv = 0
|
||||
},
|
||||
|
||||
{
|
||||
.name = "proxy line feed in hostname",
|
||||
.url = "http://host\name/fo",
|
||||
.rv = 1 /* s_dead */
|
||||
},
|
||||
|
||||
{
|
||||
.name = "proxy % in hostname",
|
||||
.url = "http://host%name/fo",
|
||||
.rv = 1 /* s_dead */
|
||||
},
|
||||
|
||||
{
|
||||
.name = "proxy ; in hostname",
|
||||
.url = "http://host;ame/fo",
|
||||
.rv = 1 /* s_dead */
|
||||
},
|
||||
|
||||
{
|
||||
.name = "proxy basic auth with unreservedchars",
|
||||
.url = "http://a!;-_!=+$@host.com/",
|
||||
.is_connect = 0,
|
||||
.u = { .field_set = (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) |
|
||||
(1<<UF_USERINFO),
|
||||
.port = 0,
|
||||
.field_data = {
|
||||
{ 0, 4 }, /* UF_SCHEMA */
|
||||
{ 17, 8 }, /* UF_HOST */
|
||||
{ 0, 0 }, /* UF_PORT */
|
||||
{ 25, 1 }, /* UF_PATH */
|
||||
{ 0, 0 }, /* UF_QUERY */
|
||||
{ 0, 0 }, /* UF_FRAGMENT */
|
||||
{ 7, 9 } } }, /* UF_USERINFO */
|
||||
.rv = 0
|
||||
},
|
||||
|
||||
{
|
||||
.name = "proxy only empty basic auth",
|
||||
.url = "http://@/fo",
|
||||
.rv = 1 /* s_dead */
|
||||
},
|
||||
|
||||
{
|
||||
.name = "proxy only basic auth",
|
||||
.url = "http://toto@/fo",
|
||||
.rv = 1 /* s_dead */
|
||||
},
|
||||
|
||||
{
|
||||
.name = "proxy emtpy hostname",
|
||||
.url = "http:///fo",
|
||||
.rv = 1 /* s_dead */
|
||||
},
|
||||
|
||||
{
|
||||
.name = "proxy = in URL",
|
||||
.url = "http://host=ame/fo",
|
||||
.rv = 1 /* s_dead */
|
||||
},
|
||||
|
||||
{
|
||||
.name = "ipv6 address with Zone ID",
|
||||
.url = "http://[fe80::a%25eth0]/",
|
||||
.is_connect = 0,
|
||||
.u = { .field_set = (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH),
|
||||
.port = 0,
|
||||
.field_data = {
|
||||
{ 0, 4 }, /* UF_SCHEMA */
|
||||
{ 8, 14 }, /* UF_HOST */
|
||||
{ 0, 0 }, /* UF_PORT */
|
||||
{ 23, 1 }, /* UF_PATH */
|
||||
{ 0, 0 }, /* UF_QUERY */
|
||||
{ 0, 0 }, /* UF_FRAGMENT */
|
||||
{ 0, 0 } } }, /* UF_USERINFO */
|
||||
.rv = 0
|
||||
},
|
||||
|
||||
{
|
||||
.name = "ipv6 address with Zone ID, but '%' is not percent-encoded",
|
||||
.url = "http://[fe80::a%eth0]/",
|
||||
.is_connect = 0,
|
||||
.u = { .field_set = (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH),
|
||||
.port = 0,
|
||||
.field_data = {
|
||||
{ 0, 4 }, /* UF_SCHEMA */
|
||||
{ 8, 12 }, /* UF_HOST */
|
||||
{ 0, 0 }, /* UF_PORT */
|
||||
{ 21, 1 }, /* UF_PATH */
|
||||
{ 0, 0 }, /* UF_QUERY */
|
||||
{ 0, 0 }, /* UF_FRAGMENT */
|
||||
{ 0, 0 } } }, /* UF_USERINFO */
|
||||
.rv = 0
|
||||
},
|
||||
|
||||
{
|
||||
.name = "ipv6 address ending with '%'",
|
||||
.url = "http://[fe80::a%]/",
|
||||
.rv = 1 /* s_dead */
|
||||
},
|
||||
|
||||
{
|
||||
.name = "ipv6 address with Zone ID including bad character",
|
||||
.url = "http://[fe80::a%$HOME]/",
|
||||
.rv = 1 /* s_dead */
|
||||
},
|
||||
|
||||
{
|
||||
.name = "just ipv6 Zone ID",
|
||||
.url = "http://[%eth0]/",
|
||||
.rv = 1 /* s_dead */
|
||||
},
|
||||
|
||||
#ifdef CONFIG_HTTP_PARSER_STRICT
|
||||
{
|
||||
.name = "tab in URL",
|
||||
.url = "/foo\tbar/",
|
||||
.rv = 1 /* s_dead */
|
||||
},
|
||||
|
||||
{
|
||||
.name = "form feed in URL",
|
||||
.url = "/foo\fbar/",
|
||||
.rv = 1 /* s_dead */
|
||||
},
|
||||
|
||||
#else /* !HTTP_PARSER_STRICT */
|
||||
|
||||
{
|
||||
.name = "tab in URL",
|
||||
.url = "/foo\tbar/",
|
||||
.u = { .field_set = (1 << UF_PATH),
|
||||
.field_data = {
|
||||
{ 0, 0 }, /* UF_SCHEMA */
|
||||
{ 0, 0 }, /* UF_HOST */
|
||||
{ 0, 0 }, /* UF_PORT */
|
||||
{ 0, 9 }, /* UF_PATH */
|
||||
{ 0, 0 }, /* UF_QUERY */
|
||||
{ 0, 0 }, /* UF_FRAGMENT */
|
||||
{ 0, 0 } } }, /* UF_USERINFO */
|
||||
.rv = 0
|
||||
},
|
||||
|
||||
{
|
||||
.name = "form feed in URL",
|
||||
.url = "/foo\fbar/",
|
||||
.u = { .field_set = (1 << UF_PATH),
|
||||
.field_data = {
|
||||
{ 0, 0 }, /* UF_SCHEMA */
|
||||
{ 0, 0 }, /* UF_HOST */
|
||||
{ 0, 0 }, /* UF_PORT */
|
||||
{ 0, 9 }, /* UF_PATH */
|
||||
{ 0, 0 }, /* UF_QUERY */
|
||||
{ 0, 0 }, /* UF_FRAGMENT */
|
||||
{ 0, 0 } } }, /* UF_USERINFO */
|
||||
.rv = 0
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
int test_preserve_data(void)
|
||||
{
|
||||
struct http_parser parser;
|
||||
char my_data[] = "application-specific data";
|
||||
|
||||
parser.data = my_data;
|
||||
http_parser_init(&parser, HTTP_REQUEST);
|
||||
if (parser.data != my_data) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
return TC_PASS;
|
||||
}
|
||||
|
||||
int test_parse_url(void)
|
||||
{
|
||||
struct http_parser_url u;
|
||||
const struct url_test *test;
|
||||
unsigned int elements;
|
||||
unsigned int i;
|
||||
int rv;
|
||||
|
||||
elements = sizeof(url_tests) / sizeof(url_tests[0]);
|
||||
for (i = 0; i < elements; i++) {
|
||||
test = &url_tests[i];
|
||||
memset(&u, 0, sizeof(u));
|
||||
|
||||
rv = http_parser_parse_url(test->url,
|
||||
strlen(test->url),
|
||||
test->is_connect,
|
||||
&u);
|
||||
|
||||
if (test->rv == 0) {
|
||||
if (rv != 0) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
if (memcmp(&u, &test->u, sizeof(u)) != 0) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
} else {
|
||||
/* test->rv != 0 */
|
||||
if (rv == 0) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TC_PASS;
|
||||
}
|
||||
|
||||
int test_method_str(void)
|
||||
{
|
||||
if (strcmp("GET", http_method_str(HTTP_GET)) != 0) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
if (strcmp("<unknown>", http_method_str(127)) != 0) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
return TC_PASS;
|
||||
}
|
||||
|
||||
int test_header_nread_value(void)
|
||||
{
|
||||
struct http_parser parser;
|
||||
const char *buf;
|
||||
size_t parsed;
|
||||
|
||||
http_parser_init(&parser, HTTP_REQUEST);
|
||||
buf = "GET / HTTP/1.1\r\nheader: value\nhdr: value\r\n";
|
||||
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
|
||||
|
||||
if (parsed != strlen(buf)) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
if (parser.nread != strlen(buf)) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
return TC_PASS;
|
||||
}
|
||||
|
||||
int test_invalid_header_content(int req, const char *str)
|
||||
{
|
||||
struct http_parser parser;
|
||||
const char *buf;
|
||||
size_t parsed;
|
||||
size_t buflen;
|
||||
|
||||
http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
|
||||
buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.1 200 OK\r\n";
|
||||
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
|
||||
if (parsed != strlen(buf)) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
buf = str;
|
||||
buflen = strlen(buf);
|
||||
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
|
||||
if (parsed != buflen) {
|
||||
if (HTTP_PARSER_ERRNO(&parser) != HPE_INVALID_HEADER_TOKEN) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
return TC_PASS;
|
||||
}
|
||||
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
int test_invalid_header_field_content_error(int req)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = test_invalid_header_content(req, "Foo: F\01ailure");
|
||||
if (rc != 0) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
rc = test_invalid_header_content(req, "Foo: B\02ar");
|
||||
if (rc != 0) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
return TC_PASS;
|
||||
}
|
||||
|
||||
int test_invalid_header_field(int req, const char *str)
|
||||
{
|
||||
struct http_parser parser;
|
||||
const char *buf;
|
||||
size_t parsed;
|
||||
size_t buflen;
|
||||
|
||||
http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
|
||||
buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.1 200 OK\r\n";
|
||||
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
|
||||
if (parsed != strlen(buf)) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
buf = str;
|
||||
buflen = strlen(buf);
|
||||
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
|
||||
if (parsed != buflen) {
|
||||
if (HTTP_PARSER_ERRNO(&parser) != HPE_INVALID_HEADER_TOKEN) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
return TC_PASS;
|
||||
}
|
||||
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
int test_invalid_header_field_token_error(int req)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = test_invalid_header_field(req, "Fo@: Failure");
|
||||
if (rc != 0) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
rc = test_invalid_header_field(req, "Foo\01\test: Bar");
|
||||
if (rc != 0) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
return TC_PASS;
|
||||
}
|
||||
|
||||
int test_double_content_length_error(int req)
|
||||
{
|
||||
struct http_parser parser;
|
||||
const char *buf;
|
||||
size_t parsed;
|
||||
size_t buflen;
|
||||
|
||||
http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
|
||||
buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.1 200 OK\r\n";
|
||||
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
|
||||
if (parsed != strlen(buf)) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
buf = "Content-Length: 0\r\nContent-Length: 1\r\n\r\n";
|
||||
buflen = strlen(buf);
|
||||
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
|
||||
if (parsed != buflen) {
|
||||
int error = HTTP_PARSER_ERRNO(&parser);
|
||||
|
||||
if (error != HPE_UNEXPECTED_CONTENT_LENGTH) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
return TC_PASS;
|
||||
}
|
||||
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
int test_chunked_content_length_error(int req)
|
||||
{
|
||||
struct http_parser parser;
|
||||
const char *buf;
|
||||
size_t parsed;
|
||||
size_t buflen;
|
||||
|
||||
http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
|
||||
|
||||
buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.1 200 OK\r\n";
|
||||
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
|
||||
if (parsed != strlen(buf)) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
buf = "Transfer-Encoding: chunked\r\nContent-Length: 1\r\n\r\n";
|
||||
buflen = strlen(buf);
|
||||
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
|
||||
if (parsed != buflen) {
|
||||
int error = HTTP_PARSER_ERRNO(&parser);
|
||||
|
||||
if (error != HPE_UNEXPECTED_CONTENT_LENGTH) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
return TC_PASS;
|
||||
}
|
||||
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
int test_header_cr_no_lf_error(int req)
|
||||
{
|
||||
struct http_parser parser;
|
||||
const char *buf;
|
||||
size_t parsed;
|
||||
size_t buflen;
|
||||
|
||||
http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
|
||||
buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.1 200 OK\r\n";
|
||||
parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
|
||||
if (parsed != strlen(buf)) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
buf = "Foo: 1\rBar: 1\r\n\r\n";
|
||||
buflen = strlen(buf);
|
||||
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
|
||||
if (parsed != buflen) {
|
||||
int error = HTTP_PARSER_ERRNO(&parser);
|
||||
|
||||
if (error != HPE_LF_EXPECTED) {
|
||||
return TC_FAIL;
|
||||
}
|
||||
return TC_PASS;
|
||||
}
|
||||
|
||||
return TC_FAIL;
|
||||
}
|
||||
|
||||
#define RC_STR(rc) (rc == TC_PASS ? PASS : FAIL)
|
||||
|
||||
void main(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
TC_START("HTTP header fields test");
|
||||
|
||||
/* api */
|
||||
rc = test_preserve_data();
|
||||
TC_PRINT("[%s] test_preserve_data\n", RC_STR(rc));
|
||||
if (rc != TC_PASS) {
|
||||
goto exit_test;
|
||||
}
|
||||
|
||||
rc = test_parse_url();
|
||||
TC_PRINT("[%s] test_parse_url\n", RC_STR(rc));
|
||||
if (rc != TC_PASS) {
|
||||
goto exit_test;
|
||||
}
|
||||
|
||||
rc = test_method_str();
|
||||
TC_PRINT("[%s] test_method_str\n", RC_STR(rc));
|
||||
if (rc != TC_PASS) {
|
||||
goto exit_test;
|
||||
}
|
||||
|
||||
/* nread */
|
||||
rc = test_header_nread_value();
|
||||
TC_PRINT("[%s] test_header_nread_value\n", RC_STR(rc));
|
||||
if (rc != TC_PASS) {
|
||||
goto exit_test;
|
||||
}
|
||||
|
||||
/* header field tests */
|
||||
rc = test_double_content_length_error(HTTP_REQUEST);
|
||||
TC_PRINT("[%s] test_double_content_length_error HTTP_REQUEST\n",
|
||||
RC_STR(rc));
|
||||
if (rc != TC_PASS) {
|
||||
goto exit_test;
|
||||
}
|
||||
|
||||
rc = test_chunked_content_length_error(HTTP_REQUEST);
|
||||
TC_PRINT("[%s] test_chunked_content_length_error HTTP_REQUEST\n",
|
||||
RC_STR(rc));
|
||||
if (rc != TC_PASS) {
|
||||
goto exit_test;
|
||||
}
|
||||
|
||||
rc = test_header_cr_no_lf_error(HTTP_REQUEST);
|
||||
TC_PRINT("[%s] test_header_cr_no_lf_error HTTP_REQUEST\n", RC_STR(rc));
|
||||
if (rc != TC_PASS) {
|
||||
goto exit_test;
|
||||
}
|
||||
|
||||
rc = test_invalid_header_field_token_error(HTTP_REQUEST);
|
||||
TC_PRINT("[%s] test_invalid_header_field_token_error HTTP_REQUEST\n",
|
||||
RC_STR(rc));
|
||||
if (rc != TC_PASS) {
|
||||
goto exit_test;
|
||||
}
|
||||
|
||||
rc = test_invalid_header_field_content_error(HTTP_REQUEST);
|
||||
TC_PRINT("[%s] test_invalid_header_field_content_error HTTP_REQUEST\n",
|
||||
RC_STR(rc));
|
||||
if (rc != TC_PASS) {
|
||||
goto exit_test;
|
||||
}
|
||||
|
||||
rc = test_double_content_length_error(HTTP_RESPONSE);
|
||||
TC_PRINT("[%s] test_double_content_length_error HTTP_RESPONSE\n",
|
||||
RC_STR(rc));
|
||||
if (rc != TC_PASS) {
|
||||
goto exit_test;
|
||||
}
|
||||
|
||||
rc = test_chunked_content_length_error(HTTP_RESPONSE);
|
||||
TC_PRINT("[%s] test_chunked_content_length_error HTTP_RESPONSE\n",
|
||||
RC_STR(rc));
|
||||
if (rc != TC_PASS) {
|
||||
goto exit_test;
|
||||
}
|
||||
|
||||
rc = test_header_cr_no_lf_error(HTTP_RESPONSE);
|
||||
TC_PRINT("[%s] test_header_cr_no_lf_error HTTP_RESPONSE\n", RC_STR(rc));
|
||||
if (rc != TC_PASS) {
|
||||
goto exit_test;
|
||||
}
|
||||
|
||||
rc = test_invalid_header_field_token_error(HTTP_RESPONSE);
|
||||
TC_PRINT("[%s] test_invalid_header_field_token_error HTTP_RESPONSE\n",
|
||||
RC_STR(rc));
|
||||
if (rc != TC_PASS) {
|
||||
goto exit_test;
|
||||
}
|
||||
|
||||
rc = test_invalid_header_field_content_error(HTTP_RESPONSE);
|
||||
TC_PRINT("[%s] test_invalid_header_field_content_error HTTP_RESPONSE\n",
|
||||
RC_STR(rc));
|
||||
if (rc != TC_PASS) {
|
||||
goto exit_test;
|
||||
}
|
||||
|
||||
TC_PRINT("\n\tNo errors detected\n");
|
||||
rc = TC_PASS;
|
||||
|
||||
exit_test:
|
||||
TC_END_RESULT(rc);
|
||||
TC_END_REPORT(rc);
|
||||
}
|
3
tests/iot/test_http_header/testcase.ini
Normal file
3
tests/iot/test_http_header/testcase.ini
Normal file
|
@ -0,0 +1,3 @@
|
|||
[test]
|
||||
tags = http iot
|
||||
build_only = false
|
Loading…
Add table
Add a link
Reference in a new issue