char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
f4a0f5b
main
1pub mod file; 2 3use std:: collections:: HashMap ; 4use std:: future:: Future ; 5use std:: io; 6use std:: pin:: Pin ; 7use std:: sync:: atomic::{ AtomicBool , AtomicU64 , Ordering }; 8use std:: sync::{ Arc , Mutex , Weak }; 9use std:: task::{ Context , Poll }; 10 11use base64:: Engine as _; 12use bytes:: Bytes ; 13use futures:: channel:: oneshot; 14use futures:: future:: BoxFuture ; 15use http_body_util::{ BodyExt , Full , StreamBody , combinators:: UnsyncBoxBody }; 16use hyper:: body::{ Body as HttpBody , Frame , Incoming , SizeHint }; 17use hyper:: server:: conn:: http1; 18use hyper:: service:: service_fn; 19use hyper::{ Request , Response , StatusCode }; 20use hyper_util:: rt::{ TokioIo , TokioTimer }; 21use sha1:: Digest ; 22use tokio:: sync::{ Mutex as AsyncMutex , mpsc}; 23use tokio:: task:: JoinSet ; 24use tokio_util:: sync:: CancellationToken ; 25use tokio_util:: task:: TaskTracker ; 26use tokio_util:: task:: task_tracker:: TaskTrackerToken ; 27 28pub use avril_net:: Address ; 29use avril_net::{ Endpoint , Listener }; 30 31pub type Error =Box < dyn std:: error:: Error +Send +Sync >; 32type Body =UnsyncBoxBody < Bytes , Error >; 33type Requests =Arc < Mutex < HashMap < u64 , Arc < Exchange >>>>; 34type Upload = mpsc:: Sender < Result < Frame < Bytes >, Error >>; 35pub type Authorize =Arc < dyn Fn ( & Address ) ->Result <(), Error > +Send +Sync >; 36pub type Metadata =( u64 , String , String , Vec <( String , String )>, bool , Endpoint ); 37pub type RespondArgs =( u64 , u16 , Vec <( String , String )>, Option < Bytes >, bool ); 38 39const MAX_ID : u64 =9_007_199_254_740_991 ; 40 41enum BodyKind { 42Inline ( Bytes ), 43GuestStream , 44File ( Arc < file:: FileBody >), 45} 46 47struct Exchange { 48server : Weak < Server >, 49method : hyper:: Method , 50version : hyper:: Version , 51headers : hyper:: HeaderMap , 52upgrade : Mutex < Option < hyper:: upgrade:: OnUpgrade >>, 53pending_upgrade : Mutex < Option < PendingUpgrade >>, 54body : AsyncMutex < Incoming >, 55reply : Mutex < Option < oneshot:: Sender < Response < Body >>>>, 56upload : Mutex < Option < Upload >>, 57done : CancellationToken , 58disconnected : AtomicBool , 59} 60 61impl Exchange { 62fn check ( & self ) ->Result <(), Error > { 63self . server 64. upgrade () 65. ok_or ( "HTTP server is closed" ) ? 66. check () 67} 68} 69 70struct Lifetime { 71id : u64 , 72exchange : Arc < Exchange >, 73requests : Requests , 74complete : bool , 75} 76 77impl Drop for Lifetime { 78fn drop ( & mut self ) { 79self . exchange 80. disconnected 81. store ( !self . complete , Ordering :: Relaxed ); 82self . exchange . done . cancel (); 83self . exchange . upload . lock (). unwrap (). take (); 84self . exchange . pending_upgrade . lock (). unwrap (). take (); 85self . requests . lock (). unwrap (). remove ( & self . id ); 86} 87} 88 89struct PendingUpgrade { 90headers : hyper:: HeaderMap , 91ready : oneshot:: Sender < Lifetime >, 92} 93 94pub struct Upgrade { 95on_upgrade : hyper:: upgrade:: OnUpgrade , 96ready : oneshot:: Receiver < Lifetime >, 97pub canceled : CancellationToken , 98token : TaskTrackerToken , 99} 100 101pub struct Lease { 102_lifetime : Lifetime , 103_token : TaskTrackerToken , 104} 105 106impl Upgrade { 107pub async fn accept ( self ) ->Result <( hyper:: upgrade:: Upgraded , Lease ), Error > { 108let lifetime = tokio:: select!{ 109 _ =self . canceled . cancelled () =>return Err ( "HTTP server aborted" . into ()), 110 ready =self . ready => ready. map_err ( |_|"WebSocket upgrade response was not returned" ) ?, 111}; 112let stream = tokio:: select!{ 113 _ =self . canceled . cancelled () =>return Err ( "HTTP server aborted" . into ()), 114 stream =self . on_upgrade => stream?, 115}; 116Ok (( 117 stream, 118Lease { 119_lifetime : lifetime, 120_token : self . token , 121}, 122)) 123} 124} 125 126struct ResponseBody { 127inner : Body , 128lifetime : Lifetime , 129remaining : Option < u64 >, 130failed : bool , 131} 132 133impl HttpBody for ResponseBody { 134type Data =Bytes ; 135type Error =Error ; 136 137fn poll_frame ( 138mut self : Pin < & mut Self >, 139cx : & mut Context < ' _ >, 140) ->Poll < Option < Result < Frame < Bytes >, Error >>> { 141let result =Pin :: new ( & mut self . inner ). poll_frame ( cx); 142if let Poll :: Ready ( Some ( frame)) =& result{ 143match frame{ 144Ok ( frame) =>{ 145if let ( Some ( remaining), Some ( bytes)) =( self . remaining , frame. data_ref ()) { 146self . remaining = remaining. checked_sub ( bytes. len () as u64 ); 147if self . remaining . is_none () { 148self . failed =true ; 149} 150} 151} 152Err ( _) =>self . failed =true , 153} 154} 155if ( matches! ( result, Poll :: Ready ( None )) ||self . inner . is_end_stream ()) 156 &&self . remaining . is_some_and ( |remaining| remaining !=0 ) 157{ 158self . failed =true ; 159} 160if !self . failed 161 &&( self . remaining ==Some ( 0 ) 162 ||matches! ( result, Poll :: Ready ( None )) 163 ||self . inner . is_end_stream ()) 164{ 165self . lifetime . complete =true ; 166} 167 result 168} 169 170fn is_end_stream ( & self ) ->bool { 171self . inner . is_end_stream () 172} 173fn size_hint ( & self ) ->SizeHint { 174self . inner . size_hint () 175} 176} 177 178impl Drop for ResponseBody { 179fn drop ( & mut self ) { 180// Hyper can stop polling at Content-Length without ever observing EOF. 181if !self . failed &&( self . remaining ==Some ( 0 ) ||self . inner . is_end_stream ()) { 182self . lifetime . complete =true ; 183} 184} 185} 186 187struct FileResponseBody { 188file : Arc < file:: FileBody >, 189request : Arc < Exchange >, 190pending : Option < BoxFuture < ' static , Result <( Bytes , bool ), Error >>>, 191remaining : u64 , 192ended : bool , 193} 194 195impl HttpBody for FileResponseBody { 196type Data =Bytes ; 197type Error =Error ; 198 199fn poll_frame ( 200mut self : Pin < & mut Self >, 201cx : & mut Context < ' _ >, 202) ->Poll < Option < Result < Frame < Bytes >, Error >>> { 203if self . ended { 204return Poll :: Ready ( None ); 205} 206if self . pending . is_none () { 207let file =self . file . clone (); 208let request =self . request . clone (); 209self . pending =Some ( Box :: pin ( async move { 210 request. check () ?; 211let result = tokio:: select!{ 212 biased; 213 _ = request. done . cancelled () =>return Err ( "HTTP request canceled" . into ()), 214 result = file. read () => result?, 215}; 216 request. check () ?; 217Ok (( Bytes :: from ( result. 0 ), result. 1 )) 218})); 219} 220match self . pending . as_mut (). unwrap (). as_mut (). poll ( cx) { 221Poll :: Pending =>Poll :: Pending , 222Poll :: Ready ( result) =>{ 223self . pending =None ; 224match result{ 225Ok (( bytes, done)) =>{ 226self . remaining -= bytes. len () as u64 ; 227self . ended = done; 228Poll :: Ready ( Some ( Ok ( Frame :: data ( bytes)))) 229} 230Err ( error) =>{ 231self . ended =true ; 232self . file . close (); 233Poll :: Ready ( Some ( Err ( error))) 234} 235} 236} 237} 238} 239 240fn is_end_stream ( & self ) ->bool { 241self . ended 242} 243 244fn size_hint ( & self ) ->SizeHint { 245SizeHint :: with_exact ( self . remaining ) 246} 247} 248 249impl Drop for FileResponseBody { 250fn drop ( & mut self ) { 251self . file . close (); 252} 253} 254 255struct Server { 256addr : Address , 257authorize : Authorize , 258upgrades : TaskTracker , 259queue : mpsc:: Sender < Metadata >, 260incoming : AsyncMutex < mpsc:: Receiver < Metadata >>, 261stop : CancellationToken , 262abort : CancellationToken , 263done : CancellationToken , 264error : Mutex < Option < String >>, 265requests : Requests , 266next : Arc < AtomicU64 >, 267} 268 269impl Server { 270fn check ( & self ) ->Result <(), Error > { 271( self . authorize )( & self . addr ) 272} 273 274async fn request ( 275self : Arc < Self >, 276mut request : Request < Incoming >, 277remote : Endpoint , 278) ->Result < Response < Body >, Error > { 279self . check () ?; 280if request. method () == hyper:: Method :: CONNECT { 281return Ok ( Response :: builder () 282. status ( StatusCode :: NOT_IMPLEMENTED ) 283. body ( 284Full :: new ( Bytes :: new ()) 285. map_err ( |never|match never{}) 286. boxed_unsync (), 287) ?); 288} 289let authority = request 290. headers () 291. get ( "host" ) 292. map ( |value| value. to_str ()) 293. transpose () ? 294. map ( str:: to_owned) 295. unwrap_or_else ( ||match & self . addr { 296Address :: Tcp { hostname, port} =>{ 297if hostname. contains ( ':' ) { 298format! ( "[{hostname}]:{port}" ) 299} else { 300format! ( "{hostname}:{port}" ) 301} 302} 303Address :: Unix { ..} =>"localhost" . to_owned (), 304}); 305 authority. parse ::< hyper:: http:: uri:: Authority >() ?; 306let path = request 307. uri () 308. path_and_query () 309. map_or ( "/" , |path| path. as_str ()); 310let path =if path =="*" { "/" } else { path}; 311let url = url:: Url :: parse ( & format! ( "http://{authority}{path}" )) ?; 312if !url. username (). is_empty () || url. password (). is_some () || url. host_str (). is_none () { 313return Err ( "Invalid HTTP request authority" . into ()); 314} 315let id =self 316. next 317. fetch_update ( Ordering :: Relaxed , Ordering :: Relaxed , |id|{ 318( id <=MAX_ID ). then_some ( id +1 ) 319}) 320. map_err ( |_|"HTTP request IDs exhausted" ) ?; 321let headers = request 322. headers () 323. iter () 324. map ( |( name, value) |{ 325( 326 name. to_string (), 327 value 328. as_bytes () 329. iter () 330. map ( |byte| char:: from ( * byte)) 331. collect (), 332) 333}) 334. collect (); 335let has_body = !request. body (). is_end_stream (); 336let upgrade = hyper:: upgrade:: on ( & mut request); 337let original_headers = request. headers (). clone (); 338let version = request. version (); 339let method = request. method (). clone (); 340let ( reply, receive) = oneshot:: channel (); 341let exchange =Arc :: new ( Exchange { 342server : Arc :: downgrade ( & self ), 343method : method. clone (), 344 version, 345headers : original_headers, 346upgrade : Mutex :: new ( Some ( upgrade)), 347pending_upgrade : Mutex :: new ( None ), 348body : AsyncMutex :: new ( request. into_body ()), 349reply : Mutex :: new ( Some ( reply)), 350upload : Mutex :: new ( None ), 351done : CancellationToken :: new (), 352disconnected : AtomicBool :: new ( false ), 353}); 354self . requests . lock (). unwrap (). insert ( id, exchange. clone ()); 355let lifetime =Lifetime { 356 id, 357exchange : exchange. clone (), 358requests : self . requests . clone (), 359complete : false , 360}; 361 tokio:: select!{ 362 biased; 363 _ =self . stop . cancelled () =>return Err ( "HTTP server is shutting down" . into ()), 364 result =self . queue . send (( id, method. to_string (), url. into (), headers, has_body, remote)) =>{ 365 result. map_err ( |_|"HTTP dispatcher stopped" ) ?; 366} 367} 368let response = tokio:: select!{ 369 _ = exchange. done . cancelled () =>return Err ( "HTTP request canceled" . into ()), 370 response = receive => response. map_err ( |_|"HTTP handler stopped" ) ?, 371}; 372if response. status () ==StatusCode :: SWITCHING_PROTOCOLS { 373let pending = exchange 374. pending_upgrade 375. lock () 376. unwrap () 377. take () 378. ok_or ( "WebSocket upgrade was not prepared" ) ?; 379 pending 380. ready 381. send ( lifetime) 382. map_err ( |_|"WebSocket upgrade was canceled" ) ?; 383return Ok ( response); 384} 385 exchange. pending_upgrade . lock (). unwrap (). take (); 386let suppressed = exchange. method == hyper:: Method :: HEAD 387 ||matches! ( response. status (). as_u16 (), 204 |205 |304 ); 388let remaining =if suppressed{ 389Some ( 0 ) 390} else { 391 response 392. headers () 393. get ( "content-length" ) 394. and_then ( |value| value. to_str (). ok () ?. parse (). ok ()) 395}; 396let ( parts, inner) = response. into_parts (); 397Ok ( Response :: from_parts ( 398 parts, 399ResponseBody { 400 inner, 401 lifetime, 402 remaining, 403failed : false , 404} 405. boxed_unsync (), 406)) 407} 408 409async fn serve ( self : Arc < Self >, listener : Listener ) ->Result <(), Error > { 410let mut connections =JoinSet :: new (); 411loop { 412 tokio:: select!{ 413 biased; 414 _ =self . stop . cancelled () =>break , 415Some ( _) = connections. join_next (), if !connections. is_empty () =>{}, 416 accepted = listener. accept () =>{ 417let avril_net:: Accepted { socket, remote, ..} =match accepted{ 418Ok ( accepted) => accepted, 419Err ( error) =>{ 420if matches! ( error. kind (), io:: ErrorKind :: ConnectionAborted | io:: ErrorKind :: ConnectionReset | io:: ErrorKind :: Interrupted ) { 421continue ; 422} 423let exhausted = error. kind () == io:: ErrorKind :: OutOfMemory ; 424# [ cfg ( unix )] 425let exhausted = exhausted ||matches! ( error. raw_os_error (), Some ( libc:: EMFILE | libc:: ENFILE | libc:: ENOBUFS | libc:: ENOMEM )); 426# [ cfg ( windows )] 427let exhausted = exhausted ||matches! ( error. raw_os_error (), Some ( 10024 |10055 )); 428if !exhausted{ 429return Err ( error. into ()); 430} 431 tokio:: select!{ 432 _ =self . stop . cancelled () =>break , 433 _ = tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 100 )) =>{}, 434} 435continue ; 436} 437}; 438self . check () ?; 439let server =self . clone (); 440 connections. spawn ( async move { 441let service_server = server. clone (); 442let connection = http1:: Builder :: new (). timer ( TokioTimer :: new ()). serve_connection ( TokioIo :: new ( socket), service_fn ( move |request|{ 443 service_server. clone (). request ( request, remote. clone ()) 444})). with_upgrades (); 445 tokio:: pin!( connection); 446 tokio:: select!{ 447 biased; 448 _ = server. abort . cancelled () =>{}, 449 _ = server. stop . cancelled () =>{ 450 connection. as_mut (). graceful_shutdown (); 451 tokio:: select!{ 452 _ = server. abort . cancelled () =>{}, 453 _ =& mut connection =>{}, 454} 455}, 456 _ =& mut connection =>{}, 457} 458}); 459} 460} 461} 462drop ( listener); 463while connections. join_next (). await . is_some () {} 464self . upgrades . close (); 465self . upgrades . wait (). await ; 466Ok (()) 467} 468} 469 470pub struct Engine { 471runtime : tokio:: runtime:: Handle , 472servers : Mutex < HashMap < u64 , Arc < Server >>>, 473requests : Requests , 474next_server : AtomicU64 , 475next_request : Arc < AtomicU64 >, 476} 477 478impl Drop for Engine { 479fn drop ( & mut self ) { 480for serverin self . servers . get_mut (). unwrap (). values () { 481 server. stop . cancel (); 482 server. abort . cancel (); 483} 484} 485} 486 487impl Engine { 488fn server ( & self , id : u64 ) ->Result < Arc < Server >, Error > { 489self . servers 490. lock () 491. unwrap () 492. get ( & id) 493. cloned () 494. ok_or_else ( ||"HTTP server is closed" . into ()) 495} 496 497fn request ( & self , id : u64 ) ->Result < Arc < Exchange >, Error > { 498self . requests 499. lock () 500. unwrap () 501. get ( & id) 502. cloned () 503. ok_or_else ( ||"HTTP request is closed" . into ()) 504} 505 506fn run < T : Send +' static , F : Future < Output =Result < T , Error >> +Send +' static >( 507& self , 508future : F , 509) ->impl Future < Output =Result < T , io:: Error >> +use <T , F >{ 510let handle =self . runtime . spawn ( future); 511async move { 512// Dropping the handle detaches the task rather than aborting it. 513 handle 514. await 515. map_err ( |_| io:: Error :: other ( "HTTP worker stopped" )) ? 516. map_err ( io:: Error :: other) 517} 518} 519 520pub fn upgrade ( 521& self , 522id : u64 , 523protocol : Option < & str >, 524) ->Result <( Upgrade , Vec <( String , String )>), Error > { 525let request =self . request ( id) ?; 526 request. check () ?; 527let token = |name, token : & str |{ 528 request. headers . get_all ( name). iter (). any ( |value|{ 529 value. to_str (). is_ok_and ( |value|{ 530 value 531. split ( ',' ) 532. any ( |value| value. trim (). eq_ignore_ascii_case ( token)) 533}) 534}) 535}; 536let single = |name|{ 537let mut values = request. headers . get_all ( name). iter (); 538let value = values 539. next () 540. ok_or ( "Missing WebSocket handshake header" ) ? 541. to_str () ?; 542if values. next (). is_some () { 543return Err ( "Duplicate WebSocket handshake header" . into ()); 544} 545Ok ::< _ , Error >( value) 546}; 547if request. method != hyper:: Method :: GET 548 || request. version != hyper:: Version :: HTTP_11 549 || !token ( "connection" , "upgrade" ) 550 || !token ( "upgrade" , "websocket" ) 551 ||single ( "sec-websocket-version" ) ? !="13" 552{ 553return Err ( "Invalid WebSocket upgrade request" . into ()); 554} 555let key =single ( "sec-websocket-key" ) ?; 556if base64:: engine:: general_purpose:: STANDARD . decode ( key) ?. len () !=16 { 557return Err ( "Invalid WebSocket key" . into ()); 558} 559if let Some ( protocol) = protocol 560 &&( protocol. is_empty () 561 || !protocol 562. bytes () 563. all ( |byte| byte. is_ascii_alphanumeric () ||b"!#$%&'*+-.^_`|~" . contains ( & byte)) 564 || !request 565. headers 566. get_all ( "sec-websocket-protocol" ) 567. iter () 568. any ( |value|{ 569 value. to_str (). is_ok_and ( |value|{ 570 value. split ( ',' ). any ( |value| value. trim () == protocol) 571}) 572})) 573{ 574return Err ( "WebSocket protocol was not offered by the client" . into ()); 575} 576let mut hash = sha1:: Sha1 :: new (); 577 hash. update ( key. as_bytes ()); 578 hash. update ( b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11" ); 579let mut response =Response :: builder () 580. status ( 101 ) 581. header ( "connection" , "Upgrade" ) 582. header ( "upgrade" , "websocket" ) 583. header ( 584"sec-websocket-accept" , 585 base64:: engine:: general_purpose:: STANDARD . encode ( hash. finalize ()), 586); 587if let Some ( protocol) = protocol{ 588 response = response. header ( "sec-websocket-protocol" , protocol); 589} 590let response = response. body (()) ?; 591let headers = response 592. headers () 593. iter () 594. map ( |( name, value) |( name. to_string (), value. to_str (). unwrap (). to_owned ())) 595. collect (); 596let server = request. server . upgrade (). ok_or ( "HTTP server is closed" ) ?; 597let on_upgrade = request 598. upgrade 599. lock () 600. unwrap () 601. take () 602. ok_or ( "WebSocket upgrade already prepared" ) ?; 603let ( ready, receive) = oneshot:: channel (); 604* request. pending_upgrade . lock (). unwrap () =Some ( PendingUpgrade { 605headers : response. into_parts (). 0 . headers , 606 ready, 607}); 608Ok (( 609Upgrade { 610 on_upgrade, 611ready : receive, 612canceled : server. abort . clone (), 613token : server. upgrades . token (), 614}, 615 headers, 616)) 617} 618 619pub fn next ( 620& self , 621id : u64 , 622) ->impl Future < Output =Result < Option < Metadata >, io:: Error >> +use <>{ 623let server =self . server ( id); 624self . run ( async move { 625let server = server?; 626 tokio:: select!{ 627 biased; 628 _ = server. stop . cancelled () =>Ok ( server. incoming . lock (). await . try_recv (). ok ()), 629 item =async { server. incoming . lock (). await . recv (). await } =>Ok ( item), 630} 631}) 632} 633 634pub fn finished ( 635self : & Arc < Self >, 636id : u64 , 637) ->impl Future < Output =Result <(), io:: Error >> +use <>{ 638let server =self . server ( id); 639let pending =self . run ( async move { 640let server = server?; 641 server. done . cancelled (). await ; 642let error = server. error . lock (). unwrap (). clone (); 643if let Some ( error) = error{ 644Err ( error. into ()) 645} else { 646Ok (()) 647} 648}); 649let engine =self . clone (); 650async move { 651let result = pending. await ; 652 engine. servers . lock (). unwrap (). remove ( & id); 653 result 654} 655} 656 657pub fn stop_all ( & self , force : bool ) { 658for serverin self . servers . lock (). unwrap (). values () { 659 server. stop . cancel (); 660if force{ 661 server. abort . cancel (); 662} 663} 664} 665 666pub fn stop ( & self , id : u64 , force : bool ) { 667if let Ok ( server) =self . server ( id) { 668 server. stop . cancel (); 669if force{ 670 server. abort . cancel (); 671} 672} 673} 674 675pub fn read ( & self , id : u64 ) ->impl Future < Output =Result < Option < Bytes >, io:: Error >> +use <>{ 676let request =self . request ( id); 677self . run ( async move { 678let request = request?; 679 request. check () ?; 680 tokio:: select!{ 681 _ = request. done . cancelled () =>Err ( "HTTP request canceled" . into ()), 682 result =async { 683let mut body = request. body . lock (). await ; 684while let Some ( frame) = body. frame (). await { 685if let Ok ( data) = frame?. into_data () { return Ok ( Some ( data)); } 686} 687Ok ( None ) 688} => result, 689} 690}) 691} 692 693pub fn write ( 694& self , 695id : u64 , 696bytes : Option < Bytes >, 697) ->impl Future < Output =Result < bool , io:: Error >> +use <>{ 698let request =self . request ( id); 699self . run ( async move { 700let Ok ( request) = requestelse { 701return Ok ( false ); 702}; 703 request. check () ?; 704if let Some ( bytes) = bytes{ 705let Some ( upload) = request. upload . lock (). unwrap (). clone () else { 706return Ok ( false ); 707}; 708 tokio:: select!{ 709 _ = request. done . cancelled () =>Ok ( false ), 710 result = upload. send ( Ok ( Frame :: data ( bytes))) =>Ok ( result. is_ok ()), 711} 712} else { 713Ok ( request. upload . lock (). unwrap (). take (). is_some ()) 714} 715}) 716} 717 718pub fn wait ( & self , id : u64 ) ->impl Future < Output =Result < bool , io:: Error >> +use <>{ 719let request =self . request ( id); 720self . run ( async move { 721let request = request?; 722 request. done . cancelled (). await ; 723Ok ( request. disconnected . load ( Ordering :: Relaxed )) 724}) 725} 726 727pub fn cancel ( & self , id : u64 ) { 728if let Ok ( request) =self . request ( id) { 729 request. disconnected . store ( true , Ordering :: Relaxed ); 730 request. done . cancel (); 731 request. pending_upgrade . lock (). unwrap (). take (); 732} 733} 734 735pub fn new ( runtime : tokio:: runtime:: Handle ) ->Self { 736Self { 737 runtime, 738servers : Mutex :: new ( HashMap :: new ()), 739requests : Arc :: new ( Mutex :: new ( HashMap :: new ())), 740next_server : AtomicU64 :: new ( 1 ), 741next_request : Arc :: new ( AtomicU64 :: new ( 1 )), 742} 743} 744 745pub fn listen ( & self , address : Address , authorize : Authorize ) ->Result <( u64 , Address ), Error > { 746authorize ( & address) ?; 747let ( listener, addr) =Listener :: bind ( & self . runtime , & address) ?; 748let addr =Address :: from ( addr); 749authorize ( & addr) ?; 750let id =self 751. next_server 752. fetch_update ( Ordering :: Relaxed , Ordering :: Relaxed , |id|{ 753( id <=MAX_ID ). then_some ( id +1 ) 754}) 755. map_err ( |_|"HTTP server IDs exhausted" ) ?; 756let ( queue, incoming) = mpsc:: channel ( 64 ); 757let server =Arc :: new ( Server { 758addr : addr. clone (), 759 authorize, 760upgrades : TaskTracker :: new (), 761 queue, 762incoming : AsyncMutex :: new ( incoming), 763stop : CancellationToken :: new (), 764abort : CancellationToken :: new (), 765done : CancellationToken :: new (), 766error : Mutex :: new ( None ), 767requests : self . requests . clone (), 768next : self . next_request . clone (), 769}); 770self . servers . lock (). unwrap (). insert ( id, server. clone ()); 771self . runtime . spawn ( async move { 772if let Err ( error) = server. clone (). serve ( listener). await { 773* server. error . lock (). unwrap () =Some ( error. to_string ()); 774 server. abort . cancel (); 775 server. upgrades . close (); 776 server. upgrades . wait (). await ; 777} 778 server. stop . cancel (); 779 server. done . cancel (); 780}); 781Ok (( id, addr)) 782} 783 784pub fn respond ( & self , args : RespondArgs ) ->Result < bool , Error > { 785let ( id, status, headers, bytes, streaming) = args; 786let body =if streaming{ 787BodyKind :: GuestStream 788} else { 789BodyKind :: Inline ( bytes. unwrap_or_default ()) 790}; 791self . respond_inner ( id, status, headers, body) 792} 793 794pub fn respond_file ( 795& self , 796id : u64 , 797status : u16 , 798headers : Vec <( String , String )>, 799file : Arc < file:: FileBody >, 800) ->Result < bool , Error > { 801self . respond_inner ( id, status, headers, BodyKind :: File ( file)) 802} 803 804fn respond_inner ( 805& self , 806id : u64 , 807status : u16 , 808headers : Vec <( String , String )>, 809body : BodyKind , 810) ->Result < bool , Error > { 811let request =self . request ( id) ?; 812 request. check () ?; 813if status ==101 { 814let mut response =Response :: new ( 815Full :: new ( Bytes :: new ()) 816. map_err ( |never|match never{}) 817. boxed_unsync (), 818); 819* response. status_mut () =StatusCode :: SWITCHING_PROTOCOLS ; 820* response. headers_mut () = request 821. pending_upgrade 822. lock () 823. unwrap () 824. as_ref () 825. ok_or ( "WebSocket upgrade was not prepared" ) ? 826. headers 827. clone (); 828 request 829. reply 830. lock () 831. unwrap () 832. take () 833. ok_or ( "HTTP request already answered" ) ? 834. send ( response) 835. map_err ( |_|"HTTP client disconnected" ) ?; 836return Ok ( false ); 837} 838if !( 200 ..=599 ). contains ( & status) { 839return Err ( "Invalid HTTP response status" . into ()); 840} 841let mut response =Response :: builder (). status ( status); 842for ( name, value) in headers{ 843if [ 844"connection" , 845"transfer-encoding" , 846"upgrade" , 847"trailer" , 848"keep-alive" , 849"proxy-connection" , 850] 851. contains ( & name. to_ascii_lowercase (). as_str ()) 852{ 853return Err ( format! ( "Unsupported HTTP response header: {name}" ). into ()); 854} 855let value = value 856. chars () 857. map ( |c| u8:: try_from ( cas u32 )) 858. collect ::< Result < Vec < _ >, _ >>() ?; 859 response = response. header ( name, value); 860} 861let suppressed = request. method == hyper:: Method :: HEAD ||matches! ( status, 204 |205 |304 ); 862if !matches! ( body, BodyKind :: GuestStream ) 863 && !matches! ( status, 204 |304 ) 864 && !response 865. headers_ref () 866. is_some_and ( |headers| headers. contains_key ( "content-length" )) 867{ 868 response = response. header ( 869"content-length" , 870if status ==205 { 8710 872} else { 873match & body{ 874BodyKind :: Inline ( bytes) => bytes. len () as u64 , 875BodyKind :: File ( file) => file. len (), 876BodyKind :: GuestStream =>0 , 877} 878}, 879); 880} 881if let Some ( length) = response 882. headers_ref () 883. and_then ( |headers| headers. get ( "content-length" )) 884{ 885let length = length. to_str () ?; 886if length. is_empty () || !length. bytes (). all ( |byte| byte. is_ascii_digit ()) { 887return Err ( "Invalid response Content-Length" . into ()); 888} 889let length = length. parse ::< u64 >() ?; 890let mismatch =match & body{ 891BodyKind :: Inline ( bytes) => !suppressed && length != bytes. len () as u64 , 892BodyKind :: File ( file) => !suppressed && length != file. len (), 893BodyKind :: GuestStream =>false , 894}; 895if status ==204 ||( status ==205 && length !=0 ) || mismatch{ 896return Err ( "Response Content-Length does not match the body" . into ()); 897} 898} 899let guest_streaming =matches! ( body, BodyKind :: GuestStream ) && !suppressed; 900let body =match body{ 901BodyKind :: File ( file) if !suppressed =>FileResponseBody { 902remaining : file. len (), 903 file, 904request : request. clone (), 905pending : None , 906ended : false , 907} 908. boxed_unsync (), 909BodyKind :: GuestStream if !suppressed =>{ 910let ( send, receive) = mpsc:: channel ( 1 ); 911* request. upload . lock (). unwrap () =Some ( send); 912let done = request. done . clone (); 913let stream = futures:: stream:: unfold ( 914( receive, done, false ), 915 |( mut receive, done, ended) |async move { 916if ended{ 917return None ; 918} 919 tokio:: select!{ 920 biased; 921 _ = done. cancelled () =>Some (( Err ( "HTTP request canceled" . into ()), ( receive, done, true ))), 922 frame = receive. recv () => frame. map ( |frame|( frame, ( receive, done, false ))), 923} 924}, 925); 926StreamBody :: new ( stream). boxed_unsync () 927} 928BodyKind :: Inline ( bytes) =>Full :: new ( if suppressed{ Bytes :: new () } else { bytes}) 929. map_err ( |never|match never{}) 930. boxed_unsync (), 931BodyKind :: File ( _) |BodyKind :: GuestStream =>Full :: new ( Bytes :: new ()) 932. map_err ( |never|match never{}) 933. boxed_unsync (), 934}; 935let response = response. body ( body) ?; 936 request 937. reply 938. lock () 939. unwrap () 940. take () 941. ok_or ( "HTTP request already answered" ) ? 942. send ( response) 943. map_err ( |_|"HTTP client disconnected" ) ?; 944Ok ( guest_streaming) 945} 946}