Skip to content
This repository was archived by the owner on Nov 6, 2022. It is now read-only.

Commit 354c3a6

Browse files
committed
Support IPv6 Zone ID as per RFC 6874
IPv6 scoped address contains Zone ID, which is appended to IPv6 address after '%' separator. RFC 6874 says that Zone ID after '%' must consist of 1*(unreserved or pct-encoded). This commit adds this IPv6 Zone ID support.
1 parent 39ff097 commit 354c3a6

File tree

2 files changed

+73
-0
lines changed

2 files changed

+73
-0
lines changed

http_parser.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,8 @@ enum http_host_state
400400
, s_http_host
401401
, s_http_host_v6
402402
, s_http_host_v6_end
403+
, s_http_host_v6_zone_start
404+
, s_http_host_v6_zone
403405
, s_http_host_port_start
404406
, s_http_host_port
405407
};
@@ -2212,7 +2214,23 @@ http_parse_host_char(enum http_host_state s, const char ch) {
22122214
if (IS_HEX(ch) || ch == ':' || ch == '.') {
22132215
return s_http_host_v6;
22142216
}
2217+
if (ch == '%') {
2218+
return s_http_host_v6_zone_start;
2219+
}
2220+
break;
2221+
2222+
case s_http_host_v6_zone:
2223+
if (ch == ']') {
2224+
return s_http_host_v6_end;
2225+
}
22152226

2227+
/* FALLTHROUGH */
2228+
case s_http_host_v6_zone_start:
2229+
/* RFC 6874 Zone ID consists of 1*( unreserved / pct-encoded) */
2230+
if (IS_ALPHANUM(ch) || ch == '%' || ch == '.' || ch == '-' || ch == '_' ||
2231+
ch == '~') {
2232+
return s_http_host_v6_zone;
2233+
}
22162234
break;
22172235

22182236
case s_http_host_port:
@@ -2263,6 +2281,11 @@ http_parse_host(const char * buf, struct http_parser_url *u, int found_at) {
22632281
u->field_data[UF_HOST].len++;
22642282
break;
22652283

2284+
case s_http_host_v6_zone_start:
2285+
case s_http_host_v6_zone:
2286+
u->field_data[UF_HOST].len++;
2287+
break;
2288+
22662289
case s_http_host_port:
22672290
if (s != s_http_host_port) {
22682291
u->field_data[UF_PORT].off = p - buf;
@@ -2292,6 +2315,8 @@ http_parse_host(const char * buf, struct http_parser_url *u, int found_at) {
22922315
case s_http_host_start:
22932316
case s_http_host_v6_start:
22942317
case s_http_host_v6:
2318+
case s_http_host_v6_zone_start:
2319+
case s_http_host_v6_zone:
22952320
case s_http_host_port_start:
22962321
case s_http_userinfo:
22972322
case s_http_userinfo_start:

test.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2918,6 +2918,54 @@ const struct url_test url_tests[] =
29182918
,.rv=1 /* s_dead */
29192919
}
29202920

2921+
, {.name="ipv6 address with Zone ID"
2922+
,.url="http://[fe80::a%25eth0]/"
2923+
,.is_connect=0
2924+
,.u=
2925+
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH)
2926+
,.port=0
2927+
,.field_data=
2928+
{{ 0, 4 } /* UF_SCHEMA */
2929+
,{ 8, 14 } /* UF_HOST */
2930+
,{ 0, 0 } /* UF_PORT */
2931+
,{ 23, 1 } /* UF_PATH */
2932+
,{ 0, 0 } /* UF_QUERY */
2933+
,{ 0, 0 } /* UF_FRAGMENT */
2934+
,{ 0, 0 } /* UF_USERINFO */
2935+
}
2936+
}
2937+
,.rv=0
2938+
}
2939+
2940+
, {.name="ipv6 address with Zone ID, but '%' is not percent-encoded"
2941+
,.url="http://[fe80::a%eth0]/"
2942+
,.is_connect=0
2943+
,.u=
2944+
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH)
2945+
,.port=0
2946+
,.field_data=
2947+
{{ 0, 4 } /* UF_SCHEMA */
2948+
,{ 8, 12 } /* UF_HOST */
2949+
,{ 0, 0 } /* UF_PORT */
2950+
,{ 21, 1 } /* UF_PATH */
2951+
,{ 0, 0 } /* UF_QUERY */
2952+
,{ 0, 0 } /* UF_FRAGMENT */
2953+
,{ 0, 0 } /* UF_USERINFO */
2954+
}
2955+
}
2956+
,.rv=0
2957+
}
2958+
2959+
, {.name="ipv6 address ending with '%'"
2960+
,.url="http://[fe80::a%]/"
2961+
,.rv=1 /* s_dead */
2962+
}
2963+
2964+
, {.name="ipv6 address with Zone ID including bad character"
2965+
,.url="http://[fe80::a%$HOME]/"
2966+
,.rv=1 /* s_dead */
2967+
}
2968+
29212969
#if HTTP_PARSER_STRICT
29222970

29232971
, {.name="tab in URL"

0 commit comments

Comments
 (0)