Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

is it easy to show an example of using websocket with http2 and http3 together? #979

Closed
ouvaa opened this issue Mar 11, 2024 · 9 comments
Closed

Comments

@ouvaa
Copy link

ouvaa commented Mar 11, 2024

@fakeshadow it seems quite difficult to fuse / interface websocket and http2/3 together.

can you help provide an example whereby i can combine them for both?

i cant wrap my head around using xitca web and xitca server together. i'm new to rust.

p.s. : i'm learning rust etc and do mention how i can help contribute to this proj. thx

@fakeshadow
Copy link
Collaborator

fakeshadow commented Mar 11, 2024

There is no websocket over http/3 in existing other than some potential RFC draft. If you need an alternative you can look into WebTransport
You can reference #938 for how to utilize it.

in general xitca-web is just a composer crate between xitca-xxx crates. Below is roughly what it does to bridge a xitca_web::App with xitca-http and xitca-server:

use xitca_http::HttpServiceBuilder;
use xitca_web::{handler::handler_service, route::get, App, service::ServiceExt};

fn main() -> std::io::Result<()> {
    let service = App::new()
        .at("/", get(handler_service(|| async { "" })))
        .finish() // explicit finish app composing.
        .enclosed(HttpServiceBuilder::new()); // apply http layer middleware to app.

   // use xitca-server to run the composed app service with given http middleware.
    xitca_server::Builder::new()
        .bind("xitca-web", "localhost:8080", service)?
        .build()
        .wait()
}

In other word xitca_web::App is just a shortcut and wrapper to produce a application service type that can be applied with xitca-http's middlewares and the final type would be given to xitca-server to run.

@fakeshadow
Copy link
Collaborator

fakeshadow commented Mar 11, 2024

@ouvaa for the question of Router with xitca-http. You can just use xitca_web::App and it's API to compose like the previous example show.
That said there is also Router type for xitca-http which offers lower level API. For example:

[dependencies]
xitca-http = { version = "0.4", features = ["router"] }
xitca-server ="0.2"
xitca-service = "0.1"

use std::convert::Infallible;

use xitca_http::{
    body::RequestBody,
    http::{Request, RequestExt, Response},
    util::service::{route::get, Router},
    HttpServiceBuilder, ResponseBody,
};
use xitca_service::{fn_service, ServiceExt};

fn main() -> std::io::Result<()> {
    let service = Router::new()
        .insert("/", get(fn_service(handler)))
        .enclosed(HttpServiceBuilder::new());

    xitca_server::Builder::new()
        .bind("xitca-http", "localhost:8080", service)?
        .build()
        .wait()
}

async fn handler(
    _: Request<RequestExt<RequestBody>>,
) -> Result<Response<ResponseBody>, Infallible> {
    Ok(Response::new(ResponseBody::empty()))
}

@ouvaa
Copy link
Author

ouvaa commented Mar 11, 2024

@fakeshadow
can you show the example with router for the below? it seems very redundant to have two different handlers for h2 and h3. how to just have 1 router + display logic for both?

async fn handler_h2(
    _: Request<RequestExt<h2::RequestBody>>,
) -> Result<Response<ResponseBody>, Box<dyn std::error::Error>> {
    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("Hello World!".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)
}

@ouvaa
Copy link
Author

ouvaa commented Mar 11, 2024

@fakeshadow i'm new to websocket

i thought it's supposed to do ws:// ... anyway, how to have it do it in http2 then? can you show the example code in full? if you show it here, it'll be easier for chatgpt to help out. currently chatgpt is hallucinating a lot with xitca implementation.

@fakeshadow
Copy link
Collaborator

fakeshadow commented Mar 11, 2024

I recall already told you how. You can just take this example and add http2 feature to it.

xitca-web = { version = "0.4", features = ["websocket"] }

It's just one line change to xitca-web = { version = "0.4", features = ["http2", "websocket"] }

That said typical off the shelf http2 client would have problem to handle clear text http2 so in most case you would have to enable tls to make them work too.
You can use https://docs.rs/xitca-web/latest/xitca_web/struct.HttpServer.html#method.bind_rustls with rustls crate for example.

@fakeshadow
Copy link
Collaborator

fakeshadow commented Mar 11, 2024

@fakeshadow can you show the example with router for the below? it seems very redundant to have two different handlers for h2 and h3. how to just have 1 router + display logic for both?

async fn handler_h2(
    _: Request<RequestExt<h2::RequestBody>>,
) -> Result<Response<ResponseBody>, Box<dyn std::error::Error>> {
    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("Hello World!".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)
}

It seems you are missing the point of the example you are referencing. The multi service example is to show case how you can bind multiple services on multiple ports of your host with different service types. It's not necessary what you have to do to handle multiple http protocols. The example showed in #979 (comment) can be used to handle http/1,http/2 and http/3 automatically with correct configuration.

@ouvaa
Copy link
Author

ouvaa commented Mar 11, 2024

@fakeshadow can you just show how to handle just http/2 and http/3 automatically with the correct configuration?
fyi, i'm doing this for http1.1:

pls just provide the "practical" normal example that people will use daily. it's quite confusing with the http2/http3 example

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(307) // or 301 for permanent redirection
        .header("Location", https_url) // Dynamically constructed target HTTPS URL
        .body("Redirecting to HTTPS".into())
        .unwrap())
}

@fakeshadow
Copy link
Collaborator

The point of xitca-web is about composability. There is no magic solution for everyone and what you believe being "practical" is just your opinion. Sorry I can't help you if you just want some quick "solution" because I don't know exactly what you want.

@fakeshadow
Copy link
Collaborator

I'll go ahead close this issue as #979 (comment) can seen as the answer. For further read please reference the following:
If you need specific feature flag

[features]

If you need tls
pub fn rustls(

If you want to bind to both TCP and UDP
/// Bind to both Tcp and Udp of the same address to enable http/1/2/3 handling

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants