mirror of
https://github.com/denoland/deno.git
synced 2024-10-29 08:58:01 -04:00
fix(ext/http): fortify "is websocket?" check (#12179)
Check for expected headers more rigorously and check that it's a HTTP/1.1 GET request. The logic mirrors what Deno Deploy and the tungstenite crate do. The presence of "Sec-Websocket-Version: 13" is now also enforced. I don't expect that to break anything: conforming clients already send it and tungstenite can't talk to older clients anyway. The new code is more efficient due to heap-allocating less and aligns more closely with the checks in ext/http/01_http.js now.
This commit is contained in:
parent
1a6249c971
commit
16ea39ee48
1 changed files with 19 additions and 12 deletions
|
@ -22,6 +22,10 @@ use deno_core::Resource;
|
|||
use deno_core::ResourceId;
|
||||
use deno_core::ZeroCopyBuf;
|
||||
use hyper::body::HttpBody;
|
||||
use hyper::header::CONNECTION;
|
||||
use hyper::header::SEC_WEBSOCKET_KEY;
|
||||
use hyper::header::SEC_WEBSOCKET_VERSION;
|
||||
use hyper::header::UPGRADE;
|
||||
use hyper::http;
|
||||
use hyper::server::conn::Http;
|
||||
use hyper::service::Service as HyperService;
|
||||
|
@ -312,20 +316,23 @@ fn req_headers(
|
|||
}
|
||||
|
||||
fn is_websocket_request(req: &hyper::Request<hyper::Body>) -> bool {
|
||||
req_header_contains(req, hyper::header::CONNECTION, "upgrade")
|
||||
&& req_header_contains(req, hyper::header::UPGRADE, "websocket")
|
||||
req.version() == hyper::Version::HTTP_11
|
||||
&& req.method() == hyper::Method::GET
|
||||
&& req.headers().contains_key(&SEC_WEBSOCKET_KEY)
|
||||
&& header(req.headers(), &SEC_WEBSOCKET_VERSION) == b"13"
|
||||
&& header(req.headers(), &UPGRADE).eq_ignore_ascii_case(b"websocket")
|
||||
&& header(req.headers(), &CONNECTION)
|
||||
.split(|c| *c == b' ' || *c == b',')
|
||||
.any(|token| token.eq_ignore_ascii_case(b"upgrade"))
|
||||
}
|
||||
|
||||
fn req_header_contains(
|
||||
req: &hyper::Request<hyper::Body>,
|
||||
key: impl hyper::header::AsHeaderName,
|
||||
value: &str,
|
||||
) -> bool {
|
||||
req.headers().get_all(key).iter().any(|v| {
|
||||
v.to_str()
|
||||
.map(|s| s.to_lowercase().contains(value))
|
||||
.unwrap_or(false)
|
||||
})
|
||||
fn header<'a>(
|
||||
h: &'a hyper::http::HeaderMap,
|
||||
name: &hyper::header::HeaderName,
|
||||
) -> &'a [u8] {
|
||||
h.get(name)
|
||||
.map(hyper::header::HeaderValue::as_bytes)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn should_ignore_error(e: &AnyError) -> bool {
|
||||
|
|
Loading…
Reference in a new issue