Giter Club home page Giter Club logo

xitca-web's People

Contributors

aliemjay avatar fakeshadow avatar somewheve avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

xitca-web's Issues

how to drop a connection as fast as possible? (in the event of ddos attack)

so now i hv
req.body().socket_addr().to_string()

how do i drop the connection as soon as possible?

    let res = Response::builder()
        .status(200)
        // possible redirect browser to http/3 service.
        .header("Alt-Svc", "h3=\":443\"; ma=86400")
        .header(CONTENT_TYPE, TEXT_UTF8)
        .body(remote_addr.into())?;
    Ok(res)
    

what am i supposed to return? are there any documentations i can reference?

Enable borrowed Json and Form extractors

pub trait FromRequest<'a, Req>: Sized {

This requires FromRequest to have a mutable state to extract body and be able to reference it later.
Maybe change FromRequet to something similar to:

pub trait FromRequest<'a, Req>: Sized {
    type Type<'b>: FromRequest<'b, Req, Error = Self::Error>;

    type Stash: Default + 'static;
    type Error;
    type Future: Future<Output = Result<Self, Self::Error>>
    where
        Req: 'a;

    fn from_request(req: &'a Req, stash: &'a mut Self::Stash) -> Self::Future;
}

too many file descriptors. possible to do one that share 1 file descriptor? (feature request)

everything's great but for one last area not sure if it'll be an easy update, using one file descriptor like uWebsocket:
https://unetworkingab.medium.com/5-million-http-3-requests-per-second-d8f0074a5367

can this be part of the roadmap?

2024-03-05T02:38:16.911057Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)
2024-03-05T02:38:16.911130Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)
2024-03-05T02:38:16.911130Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)
2024-03-05T02:38:16.911165Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)
2024-03-05T02:38:16.911169Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)

Xitca Return a router to Main App

I am trying to implement a Xitca router with state but I am having trouble.
I have an axum implementation as below in system.rs

const NAME: &str = "Nigiginc HTTP\n";
const PONG: &str = "pong\n";

pub fn router(state: Arc<AppState>, metrics_config:
&HttpMetricsConfig) -> Router {
    let mut router = Router::new()
        .route("/", get(|| async { NAME }))
        .route("/ping", get(|| async { PONG }))
        .route("/stats", get(get_stats));
    if metrics_config.enabled {
        router = router.route(&metrics_config.endpoint, get(get_metrics));
    }

    router.with_state(state)
}

then in main.rs i have

let app_state = build_app_state(&config, system).await;
    let mut app = Router::new()
        .merge(system::router(app_state.clone(), &config.metrics))
        .merge(users::router(app_state.clone()))
        .layer(middleware::from_fn_with_state(app_state.clone(), jwt_auth));

So the question is can i return a router from another file and merger
the router in the main where Xitca server is started?

`shutdown_timeout` setter on `HttpServer`

There is pretty configurable param shutdown_timeout on HttpServer.builder, but pub setter on HttpServer struct/impl is missing.

Just need to copy from builder this pub method to HttpServer:

/// Workers still alive after the timeout are force dropped.
///
/// By default shutdown timeout sets to 30 seconds.
pub fn shutdown_timeout(mut self, secs: u64) -> Self {
    self.shutdown_timeout = Duration::from_secs(secs);
    self
}

And change self.shutdown_timeout to self.builder.shutdown_timeout ofc

Im not pretty sure about that (infrastructure is huge), so in format of issue. U can use this issue as a note)))

BTW, thx for the project

new to xitca web, how to compile this?

(base) root@ubuntu:/usr/local/src/xitca-web/examples# cargo run --bin xitca-http-multi-services
warning: profiles for the non root package will be ignored, specify profiles at the workspace root:
package:   /usr/local/src/xitca-web/examples/cloudflare-worker/Cargo.toml
workspace: /usr/local/src/xitca-web/examples/Cargo.toml
    Finished dev [unoptimized + debuginfo] target(s) in 0.13s
     Running `target/debug/xitca-http-multi-services`
Error: Custom { kind: Other, error: ErrorStack([Error { code: 2147483650, library: "system library", function: "file_ctrl", file: "../crypto/bio/bss_file.c", line: 297, data: "calling fopen(../cert/key.pem, r)" }, Error { code: 268959746, library: "BIO routines", function: "file_ctrl", reason: "system lib", file: "../crypto/bio/bss_file.c", line: 300 }, Error { code: 168296450, library: "SSL routines", function: "SSL_CTX_use_PrivateKey_file", reason: "system lib", file: "../ssl/ssl_rsa.c", line: 367 }]) }

rustls-ring-crypto for server

It would be nice to have a rustls-ring-crypto feature on the server side, not just for the client crate.
This would enable the use of rustls without having to install build tools to build either openssl or aws-lc.

how to get remote ip address

this from chatgpt doesnt work :D

async fn handler_h2(
    req: Request<RequestExt<h2::RequestBody>>,
) -> Result<Response<ResponseBody>, Box<dyn std::error::Error>> {
    // Extract the remote IP address from the request
    let remote_ip = req.connection_info().remote_addr().unwrap_or_else(|| "Unknown".to_string());

    let res = Response::builder()
        .status(200)
        .header("Alt-Svc", "h3=\":8081\"; ma=86400")
        .header(CONTENT_TYPE, TEXT_UTF8)
        // Include the remote IP address in the response body
        .body(format!("Hello from Http/2! Your IP is {}", remote_ip).into())?;
    Ok(res)
}

thread per core friendly h2 protocol

h2 being a great http2 protocol crate is too high level and mostly aiming for work-stealing use case. Ideally a thread per core h2 low level protocol crate would be better suit for xitca-web

Any examples or documentation?

Hello,

I'm asking for examples or documentation. Want to use this crate for implementing an API with some middleware for logging and to intercept calls and validate a token in the headers and allow or deny the calls. Can you please let me know if this is something I could do with this crate? I've been looking for any examples but I haven't find any.

Thanks,
Jorge

[Feature Request] More granular app state

I imagine the following api for the same granularity and modularity of actix-web app state, but statically checked.

This can leverage the current BorrowReq trait.

#[derive(XitcaState)]
struct MyState {
    #[state]
    my_str: String,
    #[state]
    config: PayloadExtractionConfig,
}

impl MyState {
    async fn construct() -> Self {
        todo!()
    }
}

fn main() {
    App::with_async_state(MyState::construct)
        .at("/", get(handler_service(handler)));
}


async fn handler(
    _: Bytes, // Extractor that depends on PayloadExtractConfig
    _: StateRef<'_, String>, // granular state extractor
    _: StateReq<'_, MyState>, // should be possible for backward-compatibility
) {
}

how to used?

Thanks for contributing such a good project, there are a few questions to ask.
1、How to start the http and websoket server.
2、whether there is a filter function to do security verification, etc.

can you show an example of Router /hello hello world text for xitca multi http2/3?

not sure how to combine xitca-web with xitca-server

i'll try to write an example and hope you have something like
https://github.com/cloudwego/hertz-examples

in future. i can contribute examples too then.

this is how i'm doing it now:

async fn handler_h1(req: Request<RequestExt<h1::RequestBody>>) -> Result<Response<ResponseBody>, Infallible> {
    let path = req.uri().path();
    let response_body = if path == "/hello" {
        "Hello World from Http/1!"
    } else {
        "Not Found"
    };

    Ok(Response::builder()
        .header(CONTENT_TYPE, TEXT_UTF8)
        .body(response_body.into())
        .unwrap())

}

Experiments with borrowed Query and Path extractors

impl<'a, 'r, S, T> FromRequest<'a, WebRequest<'r, S>> for Query<T>
where
    S: 'static,
    T: Universe,
    T: Deserialize<'a>,
{
    type Type<'b> = Query<T::Type<'b>>;

Where Universe is the infamous trait:

trait Universe {
    type Type<'a>: 'a;
}

But this requires every type to be deserialized to impl Universe; an ergonomic hurdle but mybe overcome by a homebrew derive(XitcaDeserialize) that implements both serde::Deserialize and Universe and should also be applicable to Path extractor.

Originally posted by @aliemjay in #201 (comment)

i saw the techempower benchmark, is it really thread per core?

went through techempower benchmark code, saw thread per core. is this the same as glommio or monoio? i dont see anything mentioning glommio or monoio here. how does it compared with them? is it really thread per core? any benchmark to show core utilization for 24 cores and above?

thx

//! show case of axum running on proper thread per core server with io-uring enabled.

mod db;
mod ser;
mod util;

use std::sync::Arc;

use axum::{
    extract::{Json, Query, State},
    http::{
        header::{HeaderValue, SERVER},
        StatusCode,
    },
    response::{Html, IntoResponse, Response},
    routing::{get, Router},
};
use tower_http::set_header::SetResponseHeaderLayer;

use crate::{db::Client, ser::Num, tower_compat::TowerHttp};

fn main() -> std::io::Result<()> {
    let service = TowerHttp::service(|| async {
        let cli = db::create().await?;

Error when not having a slash

Hey there, thank you for this amazing framework!

This errors because no slash at start of the "api" route:

use xitca_web::{handler::handler_service, route::get, App};

fn main() -> std::io::Result<()> {
	async fn test() -> &'static str {
		"hey"
	}

	let nested = App::new().at("/create", get(handler_service(test)));
	let app = App::new().at("api", nested);

	app.serve().bind("localhost:8000")?.run().wait()
}
2024-02-24, 10:13:51 PM  INFO xitca_server::net: 25: Started Tcp listening on: Some(127.0.0.1:8000)
thread 'xitca-server-worker-0' panicked at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xitca-http-0.3.0/src/util/service/router.rs:88:54:
called `Result::unwrap()` on an `Err` value: InvalidCatchAll
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'xitca-server-worker-1' panicked at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xitca-http-0.3.0/src/util/service/router.rs:88:54:
called `Result::unwrap()` on an `Err` value: InvalidCatchAll
thread 'xitca-server-worker-5' panicked at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xitca-http-0.3.0/src/util/service/router.rs:88:54:
called `Result::unwrap()` on an `Err` value: InvalidCatchAll
thread 'xitca-server-worker-2' panicked at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xitca-http-0.3.0/src/util/service/router.rs:88:54:
called `Result::unwrap()` on an `Err` value: InvalidCatchAll
thread 'xitca-server-worker-4' panicked at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xitca-http-0.3.0/src/util/service/router.rs:88:54:
called `Result::unwrap()` on an `Err` value: InvalidCatchAll
thread 'xitca-server-worker-3' panicked at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xitca-http-0.3.0/src/util/service/router.rs:88:54:
called `Result::unwrap()` on an `Err` value: InvalidCatchAll
thread 'xitca-server-worker-7' panicked at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xitca-http-0.3.0/src/util/service/router.rs:88:54:
called `Result::unwrap()` on an `Err` value: InvalidCatchAll
thread 'xitca-server-worker-6' panicked at thread '/home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xitca-http-0.3.0/src/util/service/router.rsxitca-server-worker-8:' panicked at 88/home/.cargo/registry/src/index.crates.io-6f17d22bb
a15001f/xitca-http-0.3.0/src/util/service/router.rs::8854::
54called `Result::unwrap()` on an `Err` value: InvalidCatchAll:

called `Result::unwrap()` on an `Err` value: InvalidCatchAll
thread 'xitca-server-worker-9' panicked at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xitca-http-0.3.0/src/util/service/router.rs:88:54:
called `Result::unwrap()` on an `Err` value: InvalidCatchAll
thread 'xitca-server-worker-10' panicked at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xitca-http-0.3.0/src/util/service/router.rs:88:54:
called `Result::unwrap()` on an `Err` value: InvalidCatchAll
thread 'xitca-server-worker-11' panicked at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xitca-http-0.3.0/src/util/service/router.rs:88:54:
called `Result::unwrap()` on an `Err` value: InvalidCatchAll
thread 'xitca-server-worker-12' panicked at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xitca-http-0.3.0/src/util/service/router.rs:88:54:
called `Result::unwrap()` on an `Err` value: InvalidCatchAll
thread 'xitca-server-worker-13' panicked at thread '/home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xitca-http-0.3.0/src/util/service/router.rsxitca-server-worker-14:' panicked at 88/home/.cargo/registry/src/index.crates.io-6f17d22
bba15001f/xitca-http-0.3.0/src/util/service/router.rs::5488:
:called `Result::unwrap()` on an `Err` value: InvalidCatchAll54
:
called `Result::unwrap()` on an `Err` value: InvalidCatchAll
thread 'xitca-server-worker-15' panicked at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xitca-http-0.3.0/src/util/service/router.rs:88:54:
called `Result::unwrap()` on an `Err` value: InvalidCatchAll
thread 'xitca-server-worker-shared-scope' panicked at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xitca-server-0.1.0/src/server/mod.rs:135:17:
a scoped thread panicked
^C2024-02-24, 10:13:55 PM  INFO xitca_server::server::future: 130: Signal Int received.
thread 'main' panicked at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/xitca-server-0.1.0/src/server/mod.rs:199:39:
called `Result::unwrap()` on an `Err` value: Any { .. }

xitca-postgres & diesel-async

I like the postgres implementation.
Would It make sense to re-use the diesel query-builder like diesel-async does?

it's nice but http/2 or http3 :443 has issues

i realised the cpu is taking up a lot of processing. 4-5x higher than monoio and ntex for no tls / http1.1.

so wasnt sure what's happening.

below is http2 running for
wrk -t 1 -d 10 https://127.0.0.1:443/

i changed the loglevel to WARN.

p.s : your version of thread per core seemed much heavier than monoio / glommio. not sure why but just mentioning.

cargo run --bin xitca-http-multi-services
warning: profiles for the non root package will be ignored, specify profiles at the workspace root:
package:   /usr/local/src/xitca-web/examples/cloudflare-worker/Cargo.toml
workspace: /usr/local/src/xitca-web/examples/Cargo.toml
    Finished dev [unoptimized + debuginfo] target(s) in 0.05s
     Running `/usr/local/src/xitca-web/examples/target/debug/xitca-http-multi-services`
2024-03-02T02:57:39.990808Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)
2024-03-02T02:57:39.990808Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)
2024-03-02T02:57:39.990812Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)
2024-03-02T02:57:39.991418Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)
2024-03-02T02:57:39.991419Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)
2024-03-02T02:57:39.991797Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)
2024-03-02T02:57:39.991797Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)
2024-03-02T02:57:39.991885Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)
2024-03-02T02:57:39.991927Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)
2024-03-02T02:57:39.991931Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)
2024-03-02T02:57:39.991934Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)
2024-03-02T02:57:39.991945Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)
2024-03-02T02:57:40.991795Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)
2024-03-02T02:57:40.991923Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)
2024-03-02T02:57:40.992047Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)
2024-03-02T02:57:40.992131Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)
2024-03-02T02:57:40.992567Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)
2024-03-02T02:57:40.992610Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)
2024-03-02T02:57:40.992712Z ERROR xitca_server::worker: Error accepting connection: Too many open files (os error 24)

possible to do a http2 websocket example? current one is only http1.1

  1. pls help get this up. do also pls put up a section for sponsorship at least for us to buy u coffees. it's really good.
  2. i see greater adoption with actual use case scenario (case studies/simple info of current users) and appreciation page for xitca.

if websocket http2 is available. i can put in example use case for reference with results of production run/use.

thx

Nested Nested Apps don't work

Hey again!

Doing this doesn't work, just returns 404.

use xitca_web::{handler::handler_service, route::get, App};

fn main() {
     async fn test() -> &'static str {
		"hey"
	}

	let nested2 = App::new().at("/create", get(handler_service(test)));
	let nested = App::new().at("/v2", nested2);
	let app = App::new().at("/api", nested);

	app.serve().bind("localhost:8000")?.run().wait()
}

I know I can just send the app and directly add to it, but doing this way makes it way cleaner.
I feel like a good way to just make this work by just collecting all routes and prepending the main route to them, eg.

/api
  /v2
    /create
    /delete

"/v2" gets prepended to "/create" and "/delete".
"/api" gets prepended to "/v2/create" and "/v2/delete".

I haven't checked the router code to determine if this is more efficient or not, but I suppose it is.

how to have websocket, http2/3, router on the same script?

is it possible for you to show a working example of :
websocket, http2/3 and router on the same script?
after 1 whole day doing rust, this is all i have, i have no idea how to add websocket to /ws and how to do recommended "routing".

i also dunno how to do static file like the m/a.css routing

pls help. thx:

//! A Http server returns Hello World String as Response from multiple services.
//!
//! About http/3 discovery:
//! as of writing this comment browsers that support http/3(latest firefox releases for example)
//! can redirect user visiting http/2 service of this example to http/3.
//! visit https://0.0.0.0:443/ after start the example and try to refresh the page until you see
//! "Hello World from Http/3!".

use std::thread;
use std::{convert::Infallible, fs, io, sync::Arc};

use openssl::ssl::{AlpnError, SslAcceptor, SslFiletype, SslMethod};
use quinn::ServerConfig;
use rustls::{Certificate, PrivateKey};
use xitca_http::{
    h1, h2, h3,
    http::{const_header_value::TEXT_HTML_UTF8,const_header_value::TEXT_UTF8, header::CONTENT_TYPE, Request, RequestExt, Response, Version},
    //util::middleware::{Logger, SocketConfig},
    HttpServiceBuilder, ResponseBody,
};

use xitca_service::{fn_service, ServiceExt};
use sailfish::TemplateOnce;

#[derive(TemplateOnce)]
#[template(path = "include.stpl")]
struct IncludeTemplate {
    title: String,
    name: String,
}


fn main() -> io::Result<()> {
    tracing_subscriber::fmt().with_max_level(tracing::Level::INFO).init();

    /*
    let service = Router::new()
        .insert("/hello", get(fn_service(handler)))
        .enclosed(HttpServiceBuilder::new());
    */

    // construct http2 openssl config.
    let acceptor = h2_config()?;

    // construct http3 quic server config
    let config = h3_config()?;

    // construct server
    xitca_server::Builder::new()
        // bind to a http/1 service.
        .bind(
            "http/1",
            "0.0.0.0:80",
            fn_service(handler_h1_redirect)
        //        .enclosed(Logger::new())
                .enclosed(HttpServiceBuilder::h1())
                //.enclosed(SocketConfig::new()),
        )?
        // bind to a http/2 service.
        // *. http/1 and http/2 both use tcp listener so it should be using a separate port.
        .bind(
            "http/2",
            "0.0.0.0:443",
            fn_service(handler_h2).enclosed(HttpServiceBuilder::h2().openssl(acceptor)),
        )?
        // bind to a http/3 service.
        // *. note the service name must be unique.
        //
        // Bind to same service with different bind_xxx API is allowed for reusing one service
        // on multiple socket addresses and protocols.
        .bind_h3(
            "http/3",
            "0.0.0.0:443",
            config,
            fn_service(handler_h3).enclosed(HttpServiceBuilder::h3()),
        )?
        .build()
        .wait()
}


async fn handler_h1_redirect(req: Request<RequestExt<h1::RequestBody>>) -> Result<Response<ResponseBody>, Infallible> {
    // Extract the host from the incoming request.
    // This assumes that the "Host" header is present in the request.
    let host = req.headers().get("Host").and_then(|v| v.to_str().ok()).unwrap_or("");

    // Construct the target HTTPS URL by appending the host to the "https://" scheme.
    let https_url = format!("https://{}{}", host, req.uri());

    Ok(Response::builder()
        .status(301) // or 307 for temporary redirection
        .header("Location", https_url) // Dynamically constructed target HTTPS URL
        .body("Redirecting to HTTPS".into())
        .unwrap())
}

/*
async fn handler(req: Request<RequestExt<RequestBody>>) -> Result<Response<ResponseBody>, Infallible> {
    let remote_addr = req.body().socket_addr();
    Ok(Response::new(ResponseBody::empty()))
}
*/

async fn handler_h2(
    req: Request<RequestExt<h2::RequestBody>>,
) -> Result<Response<ResponseBody>, Box<dyn std::error::Error>> {


    let thread_id = format!("{:?}", thread::current().id());
    let ctx = IncludeTemplate {
        title: "Website".to_owned(),
        //name: "Hanako".to_owned(),
        name: thread_id,
    };
//    println!("{}", ctx.render_once().unwrap());

    //match (req.method(), req.uri().path()) {
     //   (&Method::GET, "/") => Ok(Response::new(Full::new(Bytes::from(ctx.render_once().unwrap())))),
      //  (&Method::GET, "/m/a.css") => Ok(Response::new(Full::new(Bytes::from(ctx.render_once().unwrap())))),


    let remote_addr = format!("{} {}",ctx.render_once().unwrap(),req.body().socket_addr().to_string());


    let res = Response::builder()
        .status(200)
        // possible redirect browser to http/3 service.
        .header("Alt-Svc", "h3=\":443\"; ma=86400")
        .header(CONTENT_TYPE, TEXT_HTML_UTF8)
        .body(remote_addr.into())?;
    Ok(res)
}

async fn handler_h3(
    _: Request<RequestExt<h3::RequestBody>>,
) -> Result<Response<ResponseBody>, Box<dyn std::error::Error>> {
    Response::builder()
        .status(200)
        .version(Version::HTTP_3)
        .header(CONTENT_TYPE, TEXT_UTF8)
        .body("Hello World!".into())
        .map_err(Into::into)
}

fn h2_config() -> io::Result<SslAcceptor> {
    // set up openssl and alpn protocol.
    let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls())?;
    builder.set_private_key_file("../cert/key.pem", SslFiletype::PEM)?;
    builder.set_certificate_chain_file("../cert/cert.pem")?;

    builder.set_alpn_select_callback(|_, protocols| {
        const H2: &[u8] = b"\x02h2";
        const H11: &[u8] = b"\x08http/1.1";

        if protocols.windows(3).any(|window| window == H2) {
            Ok(b"h2")
        } else if protocols.windows(9).any(|window| window == H11) {
            Ok(b"http/1.1")
        } else {
            Err(AlpnError::NOACK)
        }
    });

    builder.set_alpn_protos(b"\x08http/1.1\x02h2")?;

    Ok(builder.build())
}

fn h3_config() -> io::Result<ServerConfig> {
    let cert = fs::read("../cert/cert.pem")?;
    let key = fs::read("../cert/key.pem")?;

    let key = rustls_pemfile::pkcs8_private_keys(&mut &*key).unwrap().remove(0);
    let key = PrivateKey(key);

    let cert = rustls_pemfile::certs(&mut &*cert)
        .unwrap()
        .into_iter()
        .map(Certificate)
        .collect();

    let mut acceptor = rustls::ServerConfig::builder()
        .with_safe_defaults()
        .with_no_client_auth()
        .with_single_cert(cert, key)
        .unwrap();

    acceptor.alpn_protocols = vec![b"h3".to_vec()];

    Ok(ServerConfig::with_crypto(Arc::new(acceptor)))
}

Router

Due to the limitation of GAT feature there is no clear timeline of when it would be object safe. This means traditional Router<Box<dyn Service>> structured router would not work.
It's either the Router contain only one type of service as Router<Service<ChildService1, .., ChildServiceN>> or simple pattern match on route. Either way it needs some heavy proc macro and code generation.

SSL with HttpServer::new

I looked through the examples and saw that SSL can be done with xitca_server::Builder,
but I can't figure out how to make it work with HttpServer::new.

Is this currently supported?

Thanks.

Chatgpt multiple errors unexpected!

Consider removing ServiceFactoryObject trait

It's pointless with the introduction of BuildService trait. Maybe we can replace it with a proper definition for BoxedBuildService:

struct BoxedBuildService<Arg, Svc, InitErr>(Box<dyn BuildService<Arg, Service=Svc, Error = InitError>>);

How to set multiple headers with same name?

Hello,

I tried to find information about how to set multiple headers with same key.

pub async fn zzz(ctx: WebContext<'_>) -> Result<WebResponse, Error> {
  let mut res = ctx.into_response(ResponseBody::empty());
  let headers = res.headers_mut();

  let keys = vec!["access", "refresh"];
  for key in keys {
    let mut cookie = Cookie::new(format!("{key}_key"), "abc");
    let lifetime = 5;
    let t = OffsetDateTime::now_utc() + Duration::from_secs(lifetime);
    cookie.set_path("/");
    cookie.set_expires(t);
    cookie.set_http_only(true);
    headers.append(SET_COOKIE, HeaderValue::from_str(&cookie.to_string())?);
  }
  println!("HEADERS: {headers:?}");
  return Ok(res)
}

Output has single set-cookie header values concatenated with , :

HTTP/1.1 200 OK
set-cookie: access_key=abc; HttpOnly; Secure; Path=/; Max-Age=5, refresh_key=abc; HttpOnly; Secure; Path=/; Max-Age=5
...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.