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

Commit 422d770

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 422d770

File tree

2 files changed

+79
-0
lines changed

2 files changed

+79
-0
lines changed

http_parser.c

Lines changed: 26 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
};
@@ -2213,6 +2215,23 @@ http_parse_host_char(enum http_host_state s, const char ch) {
22132215
return s_http_host_v6;
22142216
}
22152217

2218+
if (s == s_http_host_v6 && ch == '%') {
2219+
return s_http_host_v6_zone_start;
2220+
}
2221+
break;
2222+
2223+
case s_http_host_v6_zone:
2224+
if (ch == ']') {
2225+
return s_http_host_v6_end;
2226+
}
2227+
2228+
/* FALLTHROUGH */
2229+
case s_http_host_v6_zone_start:
2230+
/* RFC 6874 Zone ID consists of 1*( unreserved / pct-encoded) */
2231+
if (IS_ALPHANUM(ch) || ch == '%' || ch == '.' || ch == '-' || ch == '_' ||
2232+
ch == '~') {
2233+
return s_http_host_v6_zone;
2234+
}
22162235
break;
22172236

22182237
case s_http_host_port:
@@ -2263,6 +2282,11 @@ http_parse_host(const char * buf, struct http_parser_url *u, int found_at) {
22632282
u->field_data[UF_HOST].len++;
22642283
break;
22652284

2285+
case s_http_host_v6_zone_start:
2286+
case s_http_host_v6_zone:
2287+
u->field_data[UF_HOST].len++;
2288+
break;
2289+
22662290
case s_http_host_port:
22672291
if (s != s_http_host_port) {
22682292
u->field_data[UF_PORT].off = p - buf;
@@ -2292,6 +2316,8 @@ http_parse_host(const char * buf, struct http_parser_url *u, int found_at) {
22922316
case s_http_host_start:
22932317
case s_http_host_v6_start:
22942318
case s_http_host_v6:
2319+
case s_http_host_v6_zone_start:
2320+
case s_http_host_v6_zone:
22952321
case s_http_host_port_start:
22962322
case s_http_userinfo:
22972323
case s_http_userinfo_start:

test.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2918,6 +2918,59 @@ 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+
2969+
, {.name="just ipv6 Zone ID"
2970+
,.url="http://[%eth0]/"
2971+
,.rv=1 /* s_dead */
2972+
}
2973+
29212974
#if HTTP_PARSER_STRICT
29222975

29232976
, {.name="tab in URL"

0 commit comments

Comments
 (0)