rupring v0.14.0 ๋ฐฐํฌ

https://github.com/myyrakle/rupring/releases/tag/v0.14.0

์ฐ”๋”์ฐ”๋” ์ข€ ์น˜๋‹ค๊ฐ€ ๊ฐ„๋งŒ์— ๋ฐฐํฌ ํ•œ๋ฒˆ ๋ง์•˜๋‹ค.
์ฃผ์š” ๋ณ€๊ฒฝ์‚ฌํ•ญ๋“ค์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.




1. HTTP2 ์ง€์› ์ œ๊ฑฐ

์ƒ๊ฐํ•ด๋ณด๋‹ˆ๊นŒ, ์‚ฌ์‹ค ์ด๊ฑฐ ์“ธ ์ผ์ด ๋”ฑํžˆ ์—†์–ด์„œ ๊ฑท์–ด๋ƒˆ๋‹ค.

๋Œ€๋ถ€๋ถ„์˜ ์„œ๋ฒ„ ์ธํ”„๋ผ ํ™˜๊ฒฝ์—์„œ๋Š” HTTP1.1๋กœ ์ถฉ๋ถ„ํ•œ ํšจ์œจ์„ฑ์ด ๋‚˜์˜ค๋Š”๋ฐ๋‹ค, ์„œ๋ฒ„๋งˆ๋‹ค TLS ๋ถ™์ด๋Š” ๊ฑด ๊ฑฐ์˜ ๋‡Œ์ ˆ์— ๊ฐ€๊น๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๊ฒŒ๋‹ค๊ฐ€ ์ด๊ฑฐ ํ•˜๋‚˜๋•Œ๋ฌธ์— ์ฝ”๋“œ๋ฒ ์ด์Šค ๊ด€๋ฆฌ๊ฐ€ ๋„ˆ๋ฌด ๋ณต์žกํ•ด์ง€๋Š” ๋ฉด๋„ ์žˆ์—ˆ๋‹ค. ๋‚˜์ค‘์— ๋‹ค์‹œ ์ถ”๊ฐ€ํ•  ์ผ์ด ์ƒ๊ธธ์ง€๋„ ๋ชจ๋ฅด์ง€๋งŒ, ์ผ๋‹จ์€ ๋ฒ„๋ฆฐ๋‹ค.




2. Streaming ๋ฐ SSE ์ง€์›

์ด์ œ SSE๊ฐ€ ๋ฐ”๋กœ ์ง€์›๋œ๋‹ค.
์‚ฌ์šฉ ๊ตฌ์กฐ๋Š” ์ตœ๋Œ€ํ•œ ๋‹จ์ˆœํ•˜๊ณ  ์ง๊ด€์ ์ธ ํ˜•ํƒœ๋กœ ์žก์•„๋ดค๋‹ค.

#[rupring::Get(path = /sse)]
#[tags = [user]]
#[summary = "SSE ํŽ˜์ด์ง€"]
pub fn serve_sse(request: rupring::Request) -> rupring::Response {
    rupring::Response::new()
        .sse_stream(async move |stream_handler|  {
            let mut count = 0;
            loop {
                if stream_handler.is_closed() {
                    println!("Client disconnected, stopping SSE");
                    break;
                }
                let event = rupring::http::sse::Event::new()
                    .event("custom-event")
                    .id("event-id-1")
                    .retry(300)
                    .data(format!("This is custom event number {}", count));
                if let Err(e) = stream_handler.send_event(event).await {
                    eprintln!("Error sending message: {}", e);
                }
                count += 1;
                tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
            }
        })
}

๊ทธ๋ƒฅ ์ด๋Ÿฐ ์‹์œผ๋กœ ์ฝœ๋ฐฑ ๋„ฃ๊ณ  ๋Œ๋ฆฌ๋ฉด ๋œ๋‹ค.
์ปค๋„ฅ์…˜ ์ค‘๋‹จ ๊ฐ์ง€๋Š” ์ง์ ‘ ํ•ด์•ผํ•œ๋‹ค.


๊ทธ๋Ÿฌ๋ฉด ์ด๋ ‡๊ฒŒ ์ž˜ ๋ˆ๋‹ค.




3. ๋ฉ€ํ‹ฐํŒŒํŠธ ํŒŒ์‹ฑ ๊ธฐ๋Šฅ ์ถ”๊ฐ€

์ด์ œ ๋ฉ€ํ‹ฐํŒŒํŠธ ํŒŒ์‹ฑ์„ ์ง์ ‘ ์ง€์›ํ•œ๋‹ค.
๋ฐ”๋กœ ๋ฉ€ํ‹ฐํŒŒํŠธ ํ˜•ํƒœ๋กœ ํŒŒ์ผ์„ ๋ฐ›์•„๋‹ค๊ฐ€ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

#[rupring::Post(path = /multipart-upload)]
#[summary = "๋‹จ์ˆœ ํŒŒ์ผ ์—…๋กœ๋“œ API์ž…๋‹ˆ๋‹ค."]
#[description = "๋ณ„๋‹ค๋ฅธ ๊ธฐ๋Šฅ์€ ์—†์Šต๋‹ˆ๋‹ค."]
#[tags = [root]]
pub fn multipart(mut request: rupring::Request) -> rupring::Response {
    for (i, file) in request.files.iter().enumerate() {
        std::fs::write(format!("{i}.foo"), &file.data).unwrap();
    }

    rupring::Response::new().text("Hello, World!")
}

#[rupring::Get(path = /multipart-upload-page)]
#[summary = "๋‹จ์ˆœ ํŒŒ์ผ ์—…๋กœ๋“œ API์ž…๋‹ˆ๋‹ค."]
#[description = "๋ณ„๋‹ค๋ฅธ ๊ธฐ๋Šฅ์€ ์—†์Šต๋‹ˆ๋‹ค."]
#[tags = [root]]
pub fn multipart_page(request: rupring::Request) -> rupring::Response {
    rupring::Response::new().html(
        r#"
        <html>
            <body>
                <form action="/multipart-upload" method="post" enctype="multipart/form-data">
                    <input type="file" name="file1" />
                    <input type="file" name="file2" />
                    <input type="submit" value="Submit" />
                </form>
            </body>
        </html>
        "#,
    )
}




4. ๊ธฐํƒ€๋“ฑ๋“ฑ

  1. ํŽธ์˜์šฉ Response::download ํ•จ์ˆ˜๊ฐ€ ์ถ”๊ฐ€๋๋‹ค. ์ด๊ฑธ ์“ฐ๋ฉด ๋ฐ”๋กœ content_disposition ํ—ค๋”๋ฅผ ์กฐ์ •ํ•ด์„œ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ฆ‰์‹œ ๋‹ค์šด๋กœ๋“œ๋ฅผ ํ•˜๋„๋ก ๋™์ž‘์„ ์ •์˜ํ•œ๋‹ค.
  2. Response::html ์ˆ์ปท ํ•จ์ˆ˜๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค. ๊ทธ๋ƒฅ text์˜ ํ•œ ์ข…๋ฅ˜์ธ๋ฐ content-type๋งŒ ์•Œ์•„์„œ ์ž˜ ์กฐ์ •ํ•ด์ค€๋‹ค.
  3. Response::cache_control ํ•จ์ˆ˜๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ช…์‹œ์ ์œผ๋กœ ์บ์‹œ ์ •์ฑ…์„ ์กฐ์ ˆํ•  ์ˆ˜ ์žˆ๋‹ค.
  4. ์ฟ ํ‚ค๋ฅผ ์ž๋™์œผ๋กœ ํŒŒ์‹ฑํ•ด์„œ ๋„ฃ์–ด์ฃผ๋Š” ํ”Œ๋ž˜๊ทธ "server.cookie.auto-parsing-enabled"๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค. ์ด๊ฒŒ ์ผœ์ง€๋ฉด request ์ปจํ…์ŠคํŠธ์˜ header์— ์ž๋™์œผ๋กœ ์ฟ ํ‚ค ๊ฐ’์ด ํŒŒ์‹ฑ๋ผ์„œ ๋“ค์–ด๊ฐ„๋‹ค.
  5. URI ๊ธธ์ด ์ œํ•œ ํ”Œ๋ž˜๊ทธ "server.request.uri.max-length"๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค. ์ดˆ๊ณผํ•˜๋ฉด 414๊ฐ€ ๋–จ์–ด์ง„๋‹ค.
  6. ํ—ค๋” ํฌ๊ธฐ ์ œํ•œ ํ”Œ๋ž˜๊ทธ "server.request.header.max-length"์™€ "server.request.header.max-number-of-headers"๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค. ์ดˆ๊ณผํ•˜๋ฉด 400์ด ๋–จ์–ด์ง„๋‹ค.
  7. request body ํฌ๊ธฐ๋ฅผ ์ œํ•œํ•˜๋Š” "server.request.body.max-length" ํ”Œ๋ž˜๊ทธ๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค.
  8. reqeust context์— ip, protocol ๋“ฑ์˜ ๊ฐ’์„ ํฌํ•จํ•˜๋Š” metadata ํ•„๋“œ๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค.
  9. ๊ธฐํƒ€ ๋ฒ„๊ทธ ์ˆ˜์ •