karyon_jsonrpc/server/http/
mod.rs1mod h1h2;
4#[cfg(feature = "http3")]
5mod h3;
6
7use std::{net::SocketAddr, sync::Arc};
8
9use async_trait::async_trait;
10use bytes::Bytes;
11use http_body_util::Full;
12use hyper::{header::CONTENT_TYPE, Response, StatusCode};
13use serde_json::to_value;
14
15use karyon_core::async_runtime::net::TcpListener;
16
17#[cfg(feature = "http3")]
18use karyon_core::async_util::select;
19
20use karyon_net::Endpoint;
21
22pub(super) use crate::hyper_exec::HyperExecutor;
23
24use crate::{
25 codec::{encode_msg, JsonRpcCodec, DEFAULT_CONTENT_TYPE},
26 error::{Error, Result},
27 message,
28 server::{accept_backoff, Server, FAILED_TO_PARSE_ERROR_MSG},
29};
30
31#[derive(Clone, Debug)]
34pub struct HttpConfig {
35 pub content_type: String,
38}
39
40impl Default for HttpConfig {
41 fn default() -> Self {
42 Self {
43 content_type: DEFAULT_CONTENT_TYPE.to_string(),
44 }
45 }
46}
47
48pub(super) const MAX_HTTP_BODY_SIZE: u64 = 1024 * 1024;
50
51pub(super) const ERR_METHOD_NOT_ALLOWED: &str = r#"{"jsonrpc":"2.0","error":{"code":-32600,"message":"Only POST method is accepted"},"id":null}"#;
53pub(super) const ERR_BODY_TOO_LARGE: &str =
54 r#"{"jsonrpc":"2.0","error":{"code":-32600,"message":"Request body too large"},"id":null}"#;
55pub(super) const ERR_READ_BODY: &str = r#"{"jsonrpc":"2.0","error":{"code":-32700,"message":"Failed to read request body"},"id":null}"#;
56pub(super) const ERR_ENCODE_RESPONSE: &str =
57 r#"{"jsonrpc":"2.0","error":{"code":-32603,"message":"Failed to encode response"},"id":null}"#;
58
59#[async_trait]
62pub(crate) trait HttpAcceptor: Send + Sync {
63 async fn accept_loop(&self, server: Arc<Server>) -> Result<()>;
65 fn local_endpoint(&self) -> Result<Endpoint>;
66}
67
68pub(crate) struct HttpServer<C> {
70 tcp_listener: TcpListener,
71 codec: C,
73 #[cfg(feature = "http3")]
74 quic_endpoint: Option<karyon_net::quic::QuicEndpoint>,
75}
76
77impl<C: JsonRpcCodec> HttpServer<C> {
78 pub(crate) async fn new(endpoint: &Endpoint, codec: C) -> Result<Self> {
80 let addr = SocketAddr::try_from(endpoint.clone())?;
81 let tcp_listener = TcpListener::bind(addr).await?;
82 Ok(Self {
83 tcp_listener,
84 codec,
85 #[cfg(feature = "http3")]
86 quic_endpoint: None,
87 })
88 }
89
90 #[cfg(feature = "http3")]
92 pub(crate) async fn new_h3(
93 endpoint: &Endpoint,
94 quic_config: karyon_net::quic::ServerQuicConfig,
95 codec: C,
96 ) -> Result<Self> {
97 let addr = SocketAddr::try_from(endpoint.clone())?;
98 let tcp_listener = TcpListener::bind(addr).await?;
99 let actual_addr = tcp_listener.local_addr()?;
100 let quic_ep_addr = Endpoint::new_quic_addr(actual_addr);
101 let quic_endpoint =
102 karyon_net::quic::QuicEndpoint::listen(&quic_ep_addr, quic_config).await?;
103 Ok(Self {
104 tcp_listener,
105 codec,
106 quic_endpoint: Some(quic_endpoint),
107 })
108 }
109}
110
111#[async_trait]
112impl<C: JsonRpcCodec> HttpAcceptor for HttpServer<C> {
113 async fn accept_loop(&self, server: Arc<Server>) -> Result<()> {
114 let codec = &self.codec;
115 let tcp_backoff = accept_backoff();
117
118 #[cfg(feature = "http3")]
119 if let Some(ref quic_ep) = self.quic_endpoint {
120 let quic_backoff = accept_backoff();
121 loop {
122 select(
123 h1h2::accept_tcp(&server, &self.tcp_listener, codec, &tcp_backoff),
124 h3::accept_h3(&server, quic_ep, codec, &quic_backoff),
125 )
126 .await;
127 }
128 }
129
130 loop {
131 h1h2::accept_tcp(&server, &self.tcp_listener, codec, &tcp_backoff).await;
132 }
133 }
134
135 fn local_endpoint(&self) -> Result<Endpoint> {
136 let addr = self.tcp_listener.local_addr()?;
137 format!("http://{addr}/")
138 .parse()
139 .map_err(|e: karyon_net::Error| Error::HttpError(e.to_string()))
140 }
141}
142
143pub(super) fn json_response(status: StatusCode, body: &str) -> Response<Full<Bytes>> {
147 json_response_bytes(status, DEFAULT_CONTENT_TYPE, Bytes::from(body.to_string()))
148}
149
150pub(super) fn json_response_bytes(
152 status: StatusCode,
153 content_type: &str,
154 body: Bytes,
155) -> Response<Full<Bytes>> {
156 Response::builder()
157 .status(status)
158 .header(CONTENT_TYPE, content_type)
159 .body(Full::new(body))
160 .unwrap()
161}
162
163pub(super) fn encode_response<C: JsonRpcCodec>(
165 codec: &C,
166 resp: &message::Response,
167) -> Result<Bytes> {
168 encode_msg(codec, &to_value(resp)?)
169}
170
171pub(super) fn parse_error_response() -> message::Response {
173 message::Response {
174 error: Some(message::Error {
175 code: message::PARSE_ERROR_CODE,
176 message: FAILED_TO_PARSE_ERROR_MSG.to_string(),
177 data: None,
178 }),
179 ..Default::default()
180 }
181}