Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
nghttp2
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
nghttp2
Commits
67553d47
Commit
67553d47
authored
Oct 25, 2013
by
Tatsuhiro Tsujikawa
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
nghttpx: Use :authority and host instead of :host
parent
c4ae19e2
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
175 additions
and
78 deletions
+175
-78
src/http2.cc
src/http2.cc
+13
-4
src/http2.h
src/http2.h
+4
-0
src/shrpx_downstream.cc
src/shrpx_downstream.cc
+20
-0
src/shrpx_downstream.h
src/shrpx_downstream.h
+10
-0
src/shrpx_http2_upstream.cc
src/shrpx_http2_upstream.cc
+25
-25
src/shrpx_http_downstream_connection.cc
src/shrpx_http_downstream_connection.cc
+35
-6
src/shrpx_spdy_downstream_connection.cc
src/shrpx_spdy_downstream_connection.cc
+48
-15
src/shrpx_spdy_upstream.cc
src/shrpx_spdy_upstream.cc
+20
-28
No files found.
src/http2.cc
View file @
67553d47
...
...
@@ -144,7 +144,6 @@ bool check_http2_allowed_header(const uint8_t *name, size_t namelen)
namespace
{
const
char
*
DISALLOWED_HD
[]
=
{
"connection"
,
"host"
,
"keep-alive"
,
"proxy-connection"
,
"te"
,
...
...
@@ -161,7 +160,6 @@ namespace {
const
char
*
IGN_HD
[]
=
{
"connection"
,
"expect"
,
"host"
,
"http2-settings"
,
"keep-alive"
,
"proxy-connection"
,
...
...
@@ -247,12 +245,18 @@ const nghttp2_nv* get_header(const nghttp2_nv *nva, size_t nvlen,
std
::
string
name_to_str
(
const
nghttp2_nv
*
nv
)
{
return
std
::
string
(
reinterpret_cast
<
const
char
*>
(
nv
->
name
),
nv
->
namelen
);
if
(
nv
)
{
return
std
::
string
(
reinterpret_cast
<
const
char
*>
(
nv
->
name
),
nv
->
namelen
);
}
return
""
;
}
std
::
string
value_to_str
(
const
nghttp2_nv
*
nv
)
{
return
std
::
string
(
reinterpret_cast
<
const
char
*>
(
nv
->
value
),
nv
->
valuelen
);
if
(
nv
)
{
return
std
::
string
(
reinterpret_cast
<
const
char
*>
(
nv
->
value
),
nv
->
valuelen
);
}
return
""
;
}
bool
value_lws
(
const
nghttp2_nv
*
nv
)
...
...
@@ -269,6 +273,11 @@ bool value_lws(const nghttp2_nv *nv)
return
true
;
}
bool
non_empty_value
(
const
nghttp2_nv
*
nv
)
{
return
nv
&&
!
http2
::
value_lws
(
nv
)
&&
http2
::
check_header_value
(
nv
);
}
void
copy_norm_headers_to_nv
(
std
::
vector
<
const
char
*>&
nv
,
const
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>&
headers
)
...
...
src/http2.h
View file @
67553d47
...
...
@@ -89,6 +89,10 @@ std::string value_to_str(const nghttp2_nv *nv);
// Returns true if the value of |nv| includes only ' ' (0x20) or '\t'.
bool
value_lws
(
const
nghttp2_nv
*
nv
);
// Returns true if the value of |nv| is not empty value and not LWS
// and not contain illegal characters.
bool
non_empty_value
(
const
nghttp2_nv
*
nv
);
// Appends headers in |headers| to |nv|. Certain headers, including
// disallowed headers in HTTP/2.0 spec and headers which require
// special handling (i.e. via), are not copied.
...
...
src/shrpx_downstream.cc
View file @
67553d47
...
...
@@ -249,6 +249,26 @@ const std::string& Downstream::get_request_path() const
return
request_path_
;
}
const
std
::
string
&
Downstream
::
get_request_http2_scheme
()
const
{
return
request_http2_scheme_
;
}
void
Downstream
::
set_request_http2_scheme
(
std
::
string
scheme
)
{
request_http2_scheme_
=
std
::
move
(
scheme
);
}
const
std
::
string
&
Downstream
::
get_request_http2_authority
()
const
{
return
request_http2_authority_
;
}
void
Downstream
::
set_request_http2_authority
(
std
::
string
authority
)
{
request_http2_authority_
=
std
::
move
(
authority
);
}
void
Downstream
::
set_request_major
(
int
major
)
{
request_major_
=
major
;
...
...
src/shrpx_downstream.h
View file @
67553d47
...
...
@@ -104,7 +104,15 @@ public:
const
std
::
string
&
get_request_method
()
const
;
void
set_request_path
(
std
::
string
path
);
void
append_request_path
(
const
char
*
data
,
size_t
len
);
// Returns request path. For HTTP/1.1, this is request-target. For
// HTTP/2, this is :path header field value.
const
std
::
string
&
get_request_path
()
const
;
// Returns HTTP/2 :scheme header field value.
const
std
::
string
&
get_request_http2_scheme
()
const
;
void
set_request_http2_scheme
(
std
::
string
scheme
);
// Returns HTTP/2 :authority header field value.
const
std
::
string
&
get_request_http2_authority
()
const
;
void
set_request_http2_authority
(
std
::
string
authority
);
void
set_request_major
(
int
major
);
void
set_request_minor
(
int
minor
);
int
get_request_major
()
const
;
...
...
@@ -184,6 +192,8 @@ private:
int
request_state_
;
std
::
string
request_method_
;
std
::
string
request_path_
;
std
::
string
request_http2_scheme_
;
std
::
string
request_http2_authority_
;
int
request_major_
;
int
request_minor_
;
bool
chunked_request_
;
...
...
src/shrpx_http2_upstream.cc
View file @
67553d47
...
...
@@ -222,22 +222,33 @@ int on_frame_recv_callback
}
}
auto
host
=
http2
::
get_unique_header
(
nva
,
nvlen
,
":host"
);
auto
host
=
http2
::
get_unique_header
(
nva
,
nvlen
,
"host"
);
auto
authority
=
http2
::
get_unique_header
(
nva
,
nvlen
,
":authority"
);
auto
path
=
http2
::
get_unique_header
(
nva
,
nvlen
,
":path"
);
auto
method
=
http2
::
get_unique_header
(
nva
,
nvlen
,
":method"
);
auto
scheme
=
http2
::
get_unique_header
(
nva
,
nvlen
,
":scheme"
);
bool
is_connect
=
method
&&
util
::
streq
(
"CONNECT"
,
method
->
value
,
method
->
valuelen
);
if
(
!
host
||
!
path
||
!
method
||
http2
::
value_lws
(
host
)
||
http2
::
value_lws
(
path
)
||
http2
::
value_lws
(
method
)
||
(
!
is_connect
&&
(
!
scheme
||
http2
::
value_lws
(
scheme
)))
||
!
http2
::
check_header_value
(
host
)
||
!
http2
::
check_header_value
(
path
)
||
!
http2
::
check_header_value
(
method
)
||
(
scheme
&&
!
http2
::
check_header_value
(
scheme
)))
{
upstream
->
rst_stream
(
downstream
,
NGHTTP2_PROTOCOL_ERROR
);
return
0
;
bool
having_host
=
http2
::
non_empty_value
(
host
);
bool
having_authority
=
http2
::
non_empty_value
(
authority
);
if
(
is_connect
)
{
// Here we strictly require :authority header field.
if
(
scheme
||
path
||
!
having_authority
)
{
upstream
->
rst_stream
(
downstream
,
NGHTTP2_PROTOCOL_ERROR
);
return
0
;
}
}
else
{
// For proxy, :authority is required. Otherwise, we can accept
// :authority or host for methods.
if
(
!
http2
::
non_empty_value
(
method
)
||
!
http2
::
non_empty_value
(
scheme
)
||
(
get_config
()
->
spdy_proxy
&&
!
having_authority
)
||
(
!
get_config
()
->
spdy_proxy
&&
!
having_authority
&&
!
having_host
)
||
!
http2
::
non_empty_value
(
path
))
{
upstream
->
rst_stream
(
downstream
,
NGHTTP2_PROTOCOL_ERROR
);
return
0
;
}
}
if
(
!
is_connect
&&
(
frame
->
hd
.
flags
&
NGHTTP2_FLAG_END_STREAM
)
==
0
)
{
...
...
@@ -251,21 +262,10 @@ int on_frame_recv_callback
}
downstream
->
set_request_method
(
http2
::
value_to_str
(
method
));
downstream
->
set_request_http2_scheme
(
http2
::
value_to_str
(
scheme
));
downstream
->
set_request_http2_authority
(
http2
::
value_to_str
(
authority
));
downstream
->
set_request_path
(
http2
::
value_to_str
(
path
));
// SpdyDownstreamConnection examines request path to find
// scheme. We construct abs URI for spdy_bridge mode as well as
// spdy_proxy mode.
if
((
get_config
()
->
spdy_proxy
||
get_config
()
->
spdy_bridge
)
&&
scheme
&&
path
->
value
[
0
]
==
'/'
)
{
auto
reqpath
=
http2
::
value_to_str
(
scheme
);
reqpath
+=
"://"
;
reqpath
+=
http2
::
value_to_str
(
host
);
reqpath
+=
http2
::
value_to_str
(
path
);
downstream
->
set_request_path
(
std
::
move
(
reqpath
));
}
else
{
downstream
->
set_request_path
(
http2
::
value_to_str
(
path
));
}
downstream
->
add_request_header
(
"host"
,
http2
::
value_to_str
(
host
));
downstream
->
check_upgrade_request
();
auto
dconn
=
upstream
->
get_client_handler
()
->
get_downstream_connection
();
...
...
src/shrpx_http_downstream_connection.cc
View file @
67553d47
...
...
@@ -116,13 +116,39 @@ int HttpDownstreamConnection::attach_downstream(Downstream *downstream)
int
HttpDownstreamConnection
::
push_request_headers
()
{
downstream_
->
normalize_request_headers
();
auto
end_headers
=
std
::
end
(
downstream_
->
get_request_headers
());
// Assume that method and request path do not contain \r\n.
std
::
string
hdrs
=
downstream_
->
get_request_method
();
hdrs
+=
" "
;
hdrs
+=
downstream_
->
get_request_path
();
if
(
downstream_
->
get_request_method
()
==
"CONNECT"
)
{
if
(
!
downstream_
->
get_request_http2_authority
().
empty
())
{
hdrs
+=
downstream_
->
get_request_http2_authority
();
}
else
{
hdrs
+=
downstream_
->
get_request_path
();
}
}
else
if
(
get_config
()
->
spdy_proxy
&&
!
downstream_
->
get_request_http2_scheme
().
empty
()
&&
!
downstream_
->
get_request_http2_authority
().
empty
()
&&
downstream_
->
get_request_path
().
c_str
()[
0
]
==
'/'
)
{
// Construct absolute-form request target because we are going to
// send a request to a HTTP/1 proxy.
hdrs
+=
downstream_
->
get_request_http2_scheme
();
hdrs
+=
"://"
;
hdrs
+=
downstream_
->
get_request_http2_authority
();
hdrs
+=
downstream_
->
get_request_path
();
}
else
{
// No proxy case. get_request_path() may be absolute-form but we
// don't care.
hdrs
+=
downstream_
->
get_request_path
();
}
hdrs
+=
" HTTP/1.1
\r\n
"
;
downstream_
->
normalize_request_headers
();
auto
end_headers
=
std
::
end
(
downstream_
->
get_request_headers
());
if
(
downstream_
->
get_norm_request_header
(
"host"
)
==
end_headers
&&
!
downstream_
->
get_request_http2_authority
().
empty
())
{
hdrs
+=
"Host: "
;
hdrs
+=
downstream_
->
get_request_http2_authority
();
hdrs
+=
"
\r\n
"
;
}
http2
::
build_http1_headers_from_norm_headers
(
hdrs
,
downstream_
->
get_request_headers
());
...
...
@@ -147,10 +173,13 @@ int HttpDownstreamConnection::push_request_headers()
}
if
(
downstream_
->
get_request_method
()
!=
"CONNECT"
)
{
hdrs
+=
"X-Forwarded-Proto: "
;
if
(
util
::
istartsWith
(
downstream_
->
get_request_path
(),
"http:"
))
{
hdrs
+=
"http
\r\n
"
;
}
else
{
if
(
!
downstream_
->
get_request_http2_scheme
().
empty
())
{
hdrs
+=
downstream_
->
get_request_http2_scheme
();
hdrs
+=
"
\r\n
"
;
}
else
if
(
util
::
istartsWith
(
downstream_
->
get_request_path
(),
"https:"
))
{
hdrs
+=
"https
\r\n
"
;
}
else
{
hdrs
+=
"http
\r\n
"
;
}
}
auto
expect
=
downstream_
->
get_norm_request_header
(
"expect"
);
...
...
src/shrpx_spdy_downstream_connection.cc
View file @
67553d47
...
...
@@ -232,19 +232,43 @@ int SpdyDownstreamConnection::push_request_headers()
size_t
nheader
=
downstream_
->
get_request_headers
().
size
();
downstream_
->
normalize_request_headers
();
auto
end_headers
=
std
::
end
(
downstream_
->
get_request_headers
());
// 10 means :method, :scheme, :path and possible via and
// x-forwarded-for header fields. We rename host header field as
// :host.
// 12 means:
// 1. :method
// 2. :scheme
// 3. :path
// 4. :authority (optional)
// 5. via (optional)
// 6. x-forwarded-for (optional)
auto
nv
=
std
::
vector
<
const
char
*>
();
nv
.
reserve
(
nheader
*
2
+
10
+
1
);
std
::
string
via_value
;
std
::
string
xff_value
;
std
::
string
scheme
,
path
,
query
;
std
::
string
scheme
,
authority
,
path
,
query
;
if
(
downstream_
->
get_request_method
()
==
"CONNECT"
)
{
// No :scheme header field for CONNECT method.
// The upstream may be HTTP/2 or HTTP/1
nv
.
push_back
(
":authority"
);
if
(
!
downstream_
->
get_request_http2_authority
().
empty
())
{
nv
.
push_back
(
downstream_
->
get_request_http2_authority
().
c_str
());
}
else
{
nv
.
push_back
(
downstream_
->
get_request_path
().
c_str
());
}
}
else
if
(
!
downstream_
->
get_request_http2_scheme
().
empty
())
{
// Here the upstream is HTTP/2
nv
.
push_back
(
":scheme"
);
nv
.
push_back
(
downstream_
->
get_request_http2_scheme
().
c_str
());
nv
.
push_back
(
":path"
);
nv
.
push_back
(
downstream_
->
get_request_path
().
c_str
());
if
(
!
downstream_
->
get_request_http2_authority
().
empty
())
{
nv
.
push_back
(
":authority"
);
nv
.
push_back
(
downstream_
->
get_request_http2_authority
().
c_str
());
}
else
if
(
downstream_
->
get_norm_request_header
(
"host"
)
==
end_headers
)
{
if
(
LOG_ENABLED
(
INFO
))
{
DCLOG
(
INFO
,
this
)
<<
"host header field missing"
;
}
return
-
1
;
}
}
else
{
// The upstream is HTTP/1
http_parser_url
u
;
const
char
*
url
=
downstream_
->
get_request_path
().
c_str
();
memset
(
&
u
,
0
,
sizeof
(
u
));
...
...
@@ -253,6 +277,7 @@ int SpdyDownstreamConnection::push_request_headers()
0
,
&
u
);
if
(
rv
==
0
)
{
http2
::
copy_url_component
(
scheme
,
&
u
,
UF_SCHEMA
,
url
);
http2
::
copy_url_component
(
authority
,
&
u
,
UF_HOST
,
url
);
http2
::
copy_url_component
(
path
,
&
u
,
UF_PATH
,
url
);
http2
::
copy_url_component
(
query
,
&
u
,
UF_QUERY
,
url
);
if
(
path
.
empty
())
{
...
...
@@ -277,6 +302,24 @@ int SpdyDownstreamConnection::push_request_headers()
}
else
{
nv
.
push_back
(
path
.
c_str
());
}
if
(
!
authority
.
empty
())
{
// TODO properly check IPv6 numeric address
if
(
authority
.
find
(
":"
)
!=
std
::
string
::
npos
)
{
authority
=
"["
+
authority
;
authority
+=
"]"
;
}
if
(
u
.
field_set
&
(
1
<<
UF_PORT
))
{
authority
+=
":"
;
authority
+=
util
::
utos
(
u
.
port
);
}
nv
.
push_back
(
":authority"
);
nv
.
push_back
(
authority
.
c_str
());
}
else
if
(
downstream_
->
get_norm_request_header
(
"host"
)
==
end_headers
)
{
if
(
LOG_ENABLED
(
INFO
))
{
DCLOG
(
INFO
,
this
)
<<
"host header field missing"
;
}
return
-
1
;
}
}
nv
.
push_back
(
":method"
);
...
...
@@ -284,16 +327,6 @@ int SpdyDownstreamConnection::push_request_headers()
http2
::
copy_norm_headers_to_nv
(
nv
,
downstream_
->
get_request_headers
());
auto
host
=
downstream_
->
get_norm_request_header
(
"host"
);
if
(
host
==
end_headers
)
{
if
(
LOG_ENABLED
(
INFO
))
{
DCLOG
(
INFO
,
this
)
<<
"host header field missing"
;
}
return
-
1
;
}
nv
.
push_back
(
":host"
);
nv
.
push_back
((
*
host
).
second
.
c_str
());
bool
content_length
=
false
;
if
(
downstream_
->
get_norm_request_header
(
"content-length"
)
!=
end_headers
)
{
content_length
=
true
;
...
...
src/shrpx_spdy_upstream.cc
View file @
67553d47
...
...
@@ -143,25 +143,24 @@ void on_ctrl_recv_callback
(
spdylay_session
*
session
,
spdylay_frame_type
type
,
spdylay_frame
*
frame
,
void
*
user_data
)
{
SpdyUpstream
*
upstream
=
reinterpret_cast
<
SpdyUpstream
*>
(
user_data
);
auto
upstream
=
reinterpret_cast
<
SpdyUpstream
*>
(
user_data
);
switch
(
type
)
{
case
SPDYLAY_SYN_STREAM
:
{
if
(
LOG_ENABLED
(
INFO
))
{
ULOG
(
INFO
,
upstream
)
<<
"Received upstream SYN_STREAM stream_id="
<<
frame
->
syn_stream
.
stream_id
;
}
Downstream
*
downstream
;
downstream
=
new
Downstream
(
upstream
,
frame
->
syn_stream
.
stream_id
,
frame
->
syn_stream
.
pri
);
auto
downstream
=
new
Downstream
(
upstream
,
frame
->
syn_stream
.
stream_id
,
frame
->
syn_stream
.
pri
);
upstream
->
add_downstream
(
downstream
);
downstream
->
init_response_body_buf
();
char
**
nv
=
frame
->
syn_stream
.
nv
;
const
char
*
path
=
0
;
const
char
*
scheme
=
0
;
const
char
*
host
=
0
;
const
char
*
method
=
0
;
auto
nv
=
frame
->
syn_stream
.
nv
;
const
char
*
path
=
nullptr
;
const
char
*
scheme
=
nullptr
;
const
char
*
host
=
nullptr
;
const
char
*
method
=
nullptr
;
const
char
*
content_length
=
0
;
for
(
size_t
i
=
0
;
nv
[
i
];
i
+=
2
)
{
if
(
strcmp
(
nv
[
i
],
":path"
)
==
0
)
{
...
...
@@ -170,7 +169,6 @@ void on_ctrl_recv_callback
scheme
=
nv
[
i
+
1
];
}
else
if
(
strcmp
(
nv
[
i
],
":method"
)
==
0
)
{
method
=
nv
[
i
+
1
];
downstream
->
set_request_method
(
nv
[
i
+
1
]);
}
else
if
(
strcmp
(
nv
[
i
],
":host"
)
==
0
)
{
host
=
nv
[
i
+
1
];
}
else
if
(
nv
[
i
][
0
]
!=
':'
)
{
...
...
@@ -180,36 +178,31 @@ void on_ctrl_recv_callback
downstream
->
add_request_header
(
nv
[
i
],
nv
[
i
+
1
]);
}
}
bool
is_connect
=
method
&&
strcmp
(
"CONNECT"
,
method
)
==
0
;
if
(
!
path
||
!
host
||
!
method
||
!
http2
::
check_header_value
(
host
)
||
!
http2
::
check_header_value
(
path
)
||
!
http2
::
check_header_value
(
method
)
||
(
scheme
&&
!
http2
::
check_header_value
(
scheme
)))
{
(
!
is_connect
&&
(
!
scheme
||
!
http2
::
check_header_value
(
scheme
)
)))
{
upstream
->
rst_stream
(
downstream
,
SPDYLAY_INTERNAL_ERROR
);
return
;
}
// Require content-length if FIN flag is not set.
if
(
strcmp
(
"CONNECT"
,
method
)
!=
0
&&
(
frame
->
syn_stream
.
hd
.
flags
&
SPDYLAY_CTRL_FLAG_FIN
)
==
0
&&
!
content_length
)
{
if
(
!
is_connect
&&
!
content_length
&&
(
frame
->
syn_stream
.
hd
.
flags
&
SPDYLAY_CTRL_FLAG_FIN
)
==
0
)
{
upstream
->
rst_stream
(
downstream
,
SPDYLAY_PROTOCOL_ERROR
);
return
;
}
// SpdyDownstreamConnection examines request path to find
// scheme. We construct abs URI for spdy_bridge mode as well as
// spdy_proxy mode.
if
((
get_config
()
->
spdy_proxy
||
get_config
()
->
spdy_bridge
)
&&
scheme
&&
path
[
0
]
==
'/'
)
{
std
::
string
reqpath
=
scheme
;
reqpath
+=
"://"
;
reqpath
+=
host
;
reqpath
+=
path
;
downstream
->
set_request_path
(
std
::
move
(
reqpath
));
downstream
->
set_request_method
(
method
);
if
(
is_connect
)
{
downstream
->
set_request_http2_authority
(
path
);
}
else
{
downstream
->
set_request_http2_scheme
(
scheme
);
downstream
->
set_request_http2_authority
(
host
);
downstream
->
set_request_path
(
path
);
}
downstream
->
add_request_header
(
"host"
,
host
);
downstream
->
check_upgrade_request
();
if
(
LOG_ENABLED
(
INFO
))
{
...
...
@@ -222,8 +215,7 @@ void on_ctrl_recv_callback
<<
"
\n
"
<<
ss
.
str
();
}
DownstreamConnection
*
dconn
;
dconn
=
upstream
->
get_client_handler
()
->
get_downstream_connection
();
auto
dconn
=
upstream
->
get_client_handler
()
->
get_downstream_connection
();
int
rv
=
dconn
->
attach_downstream
(
downstream
);
if
(
rv
!=
0
)
{
// If downstream connection fails, issue RST_STREAM.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment