use crate::parse::has_token;
use crate::{base64url_decode, Framing, Request, Version};
pub const PREFACE: &[u8; 24] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
pub const SWITCHING_PROTOCOLS: &[u8] = b"HTTP/1.1 101 Switching Protocols\r\nConnection: Upgrade\r\nUpgrade: h2c\r\n\r\n";
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Preface {
H2,
Http1,
Partial,
Invalid,
}
const PREFACE_LINE: usize = 14;
pub fn detect_preface(buf: &[u8]) -> Preface {
let n = buf.len().min(PREFACE.len());
if buf[..n] != PREFACE[..n] {
if n > PREFACE_LINE && buf[..PREFACE_LINE] == PREFACE[..PREFACE_LINE] {
Preface::Invalid
} else {
Preface::Http1
}
} else if n == PREFACE.len() {
Preface::H2
} else {
Preface::Partial
}
}
pub fn upgrade_settings(req: &Request<'_, '_>, settings: &mut Vec<u8>) -> bool {
let Some(up) = req.upgrade else { return false };
if req.version != Version::Http11 || req.framing != Framing::None || !has_token(up, b"h2c") {
return false;
}
let names_settings =
req.headers.iter().any(|h| h.name.eq_ignore_ascii_case(b"connection") && has_token(h.value, b"http2-settings"));
let mut fields = req.headers.iter().filter(|h| h.name.eq_ignore_ascii_case(b"http2-settings"));
let (Some(field), None) = (fields.next(), fields.next()) else { return false };
if !names_settings {
return false;
}
let start = settings.len();
if !base64url_decode(field.value, settings) || (settings.len() - start) % 6 != 0 {
settings.truncate(start);
return false;
}
true
}