1#![no_std]
91extern crate no_std_compat as std;
92
93use std::prelude::v1::*;
94
95#[cfg(not(any(feature = "framework_axum", feature = "framework_flow")))]
101compile_error!(
102 "At least one framework feature must be enabled: 'framework_axum' or 'framework_flow'"
103);
104
105#[cfg(all(feature = "framework_axum", feature = "framework_flow"))]
107compile_error!(
108 "Both 'framework_axum' and 'framework_flow' features cannot be enabled simultaneously. \
109 \n\nChoose ONE framework:\
110 \n 1. Axum (default): --features framework_axum\
111 \n 2. Flow (new): --no-default-features --features framework_flow,std"
112);
113
114#[cfg(feature = "framework_axum")]
120mod axum_impl;
121
122#[cfg(feature = "framework_flow")]
123pub mod flow_impl;
124
125#[cfg(any(feature = "framework_axum", feature = "framework_flow"))]
127use std::collections::BTreeMap;
128
129#[cfg(any(feature = "framework_axum", feature = "core"))]
130pub use product_os_http::{
131 header::{HeaderMap, HeaderName, HeaderValue},
132 request::Parts as RequestParts,
133 response::Parts as ResponseParts,
134 Request, Response, StatusCode,
135};
136
137#[cfg(feature = "core")]
138pub use product_os_http_body::{BodyBytes, Bytes};
139
140#[cfg(feature = "middleware")]
141pub use product_os_http_body::*;
142
143#[cfg(feature = "framework_axum")]
144pub use axum::{
145 body::{Body, HttpBody},
146 extract::{
147 ws::{Message, WebSocket, WebSocketUpgrade},
148 ConnectInfo, FromRef, FromRequest, FromRequestParts, Path, Query, State,
149 },
150 handler::Handler,
151 http::Uri,
152 middleware::{from_fn, from_fn_with_state, Next},
153 response::{IntoResponse, Redirect},
154 routing::{any, delete, get, head, options, patch, post, put, trace, MethodRouter},
155 BoxError, Form, Json, Router,
156};
157
158#[cfg(all(feature = "sse", feature = "framework_axum"))]
159pub use axum::response::sse::{Event, Sse};
160
161#[cfg(feature = "framework_axum")]
162pub use crate::extractors::RequestMethod;
163
164#[cfg(all(
166 feature = "framework_flow",
167 not(feature = "framework_axum"),
168 not(feature = "flow_axum_compat")
169))]
170pub use flow_impl::core::body::Body;
171#[cfg(all(
172 feature = "framework_flow",
173 not(feature = "framework_axum"),
174 not(feature = "flow_axum_compat")
175))]
176pub use flow_impl::core::Handler;
177#[cfg(all(
178 feature = "framework_flow",
179 not(feature = "framework_axum"),
180 not(feature = "flow_axum_compat")
181))]
182pub use flow_impl::core::{FromRequest, FromRequestParts, IntoResponse};
183#[cfg(all(
184 feature = "framework_flow",
185 not(feature = "framework_axum"),
186 not(feature = "flow_axum_compat")
187))]
188pub use flow_impl::extractors::form::StreamingForm as Form;
189#[cfg(all(
190 feature = "framework_flow",
191 not(feature = "framework_axum"),
192 not(feature = "flow_axum_compat")
193))]
194pub use flow_impl::extractors::json::StreamingJson as Json;
195#[cfg(all(
196 feature = "framework_flow",
197 not(feature = "framework_axum"),
198 not(feature = "flow_axum_compat")
199))]
200pub use flow_impl::extractors::path::Path;
201#[cfg(all(
202 feature = "framework_flow",
203 not(feature = "framework_axum"),
204 not(feature = "flow_axum_compat")
205))]
206pub use flow_impl::extractors::query::Query;
207#[cfg(all(
208 feature = "framework_flow",
209 not(feature = "framework_axum"),
210 not(feature = "flow_axum_compat")
211))]
212pub use flow_impl::extractors::state::State;
213#[cfg(all(
214 feature = "framework_flow",
215 not(feature = "framework_axum"),
216 not(feature = "flow_axum_compat")
217))]
218pub use flow_impl::router::NextService;
219#[cfg(all(
220 feature = "framework_flow",
221 not(feature = "framework_axum"),
222 not(feature = "flow_axum_compat")
223))]
224pub use product_os_http::uri::Uri;
225#[cfg(all(
226 feature = "framework_flow",
227 not(feature = "framework_axum"),
228 not(feature = "flow_axum_compat")
229))]
230pub use product_os_http_body::Body as HttpBody;
231
232#[cfg(all(
233 feature = "framework_flow",
234 not(feature = "framework_axum"),
235 not(feature = "flow_axum_compat")
236))]
237pub type BoxError = std::boxed::Box<dyn core::error::Error + Send + Sync>;
238
239#[cfg(all(
240 feature = "sse",
241 feature = "framework_flow",
242 not(feature = "framework_axum"),
243 not(feature = "flow_axum_compat")
244))]
245pub use flow_impl::sse::{Event, KeepAlive, Sse};
246
247#[cfg(all(
248 feature = "ws",
249 feature = "framework_flow",
250 not(feature = "framework_axum"),
251 not(feature = "flow_axum_compat")
252))]
253pub use flow_impl::ws::{Message, WebSocket};
254
255#[cfg(any(feature = "framework_axum", feature = "core"))]
256pub use product_os_http::uri::Scheme;
257
258#[cfg(all(feature = "flow_axum_compat", not(feature = "framework_axum")))]
262pub use axum::{
263 body::{Body, HttpBody},
264 extract::{
265 ws::{Message, WebSocket, WebSocketUpgrade},
266 ConnectInfo, FromRef, FromRequest, FromRequestParts, State,
267 },
268 http::Uri,
269 response::{IntoResponse, Redirect},
270 BoxError, Form, Json,
271};
272
273#[cfg(all(feature = "flow_axum_compat", not(feature = "framework_axum")))]
276pub use flow_impl::extractors::path::Path;
277#[cfg(all(feature = "flow_axum_compat", not(feature = "framework_axum")))]
278pub use flow_impl::extractors::query::Query;
279
280#[cfg(all(
281 feature = "sse",
282 feature = "flow_axum_compat",
283 not(feature = "framework_axum")
284))]
285pub use axum::response::sse::{Event, Sse};
286
287#[cfg(all(feature = "flow_axum_compat", not(feature = "framework_axum")))]
288pub use flow_impl::core::Handler;
289
290#[cfg(all(feature = "flow_axum_compat", not(feature = "framework_axum")))]
291pub use flow_impl::router::NextService;
292
293#[cfg(all(feature = "flow_axum_compat", not(feature = "framework_axum")))]
294pub use axum::routing::MethodRouter;
295
296#[cfg(all(
297 feature = "debug",
298 any(feature = "framework_axum", feature = "flow_axum_compat")
299))]
300pub use axum_macros::debug_handler;
301
302#[cfg(feature = "core")]
303pub use tower::{
304 make::future::SharedFuture, make::AsService, make::IntoService, make::MakeConnection,
305 make::Shared, util::service_fn, util::ServiceFn, Layer, MakeService, Service, ServiceBuilder,
306 ServiceExt,
307};
308
309#[cfg(feature = "core")]
310pub use product_os_request::Method;
311
312#[cfg(feature = "middleware")]
313pub mod middleware;
314
315#[cfg(feature = "framework_axum")]
316mod default_headers;
317#[cfg(feature = "core")]
318pub mod dual_protocol;
319#[cfg(feature = "framework_axum")]
320mod extractors;
321#[cfg(feature = "framework_axum")]
322mod service_wrapper;
323
324#[cfg(feature = "framework_axum")]
325pub use crate::default_headers::DefaultHeadersLayer;
326#[cfg(feature = "core")]
327pub use crate::dual_protocol::{Protocol, UpgradeHttpLayer};
328
329#[cfg(feature = "middleware")]
330pub use crate::middleware::*;
331
332#[cfg(feature = "framework_flow")]
333pub use flow_impl::extractors::headers::Headers;
334
335#[cfg(all(feature = "framework_axum", not(feature = "framework_flow")))]
336mod axum_request_id;
337#[cfg(all(feature = "framework_axum", not(feature = "framework_flow")))]
338mod axum_trace_context;
339
340#[cfg(all(feature = "framework_axum", not(feature = "framework_flow")))]
341pub use axum_request_id::RequestId;
342#[cfg(all(feature = "framework_axum", not(feature = "framework_flow")))]
343pub use axum_trace_context::TraceContext;
344
345#[cfg(feature = "framework_flow")]
346pub use flow_impl::extractors::trace_context::TraceContext;
347
348#[cfg(all(
349 feature = "framework_flow",
350 not(feature = "framework_axum"),
351 not(feature = "flow_axum_compat")
352))]
353pub use flow_impl::extractors::context::{ClientAddr, ConnectInfo, RequestId};
354
355#[cfg(all(feature = "framework_flow", feature = "flow_axum_compat"))]
356pub use flow_impl::extractors::context::{ClientAddr, RequestId};
357
358use core::fmt;
373
374#[derive(Debug)]
375pub enum ProductOSRouterError {
376 Headers(String),
378 Query(String),
380 Body(String),
382 Authentication(String),
384 Authorization(String),
386 Process(String),
388 Unavailable(String),
390}
391
392impl fmt::Display for ProductOSRouterError {
393 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
394 match self {
395 ProductOSRouterError::Headers(m) => write!(f, "header error: {m}"),
396 ProductOSRouterError::Query(m) => write!(f, "query error: {m}"),
397 ProductOSRouterError::Body(m) => write!(f, "body error: {m}"),
398 ProductOSRouterError::Authentication(m) => write!(f, "authentication error: {m}"),
399 ProductOSRouterError::Authorization(m) => write!(f, "authorization error: {m}"),
400 ProductOSRouterError::Process(m) => write!(f, "process error: {m}"),
401 ProductOSRouterError::Unavailable(m) => write!(f, "unavailable: {m}"),
402 }
403 }
404}
405
406#[cfg(feature = "std")]
407extern crate std as _real_std;
408
409#[cfg(feature = "std")]
410impl _real_std::error::Error for ProductOSRouterError {}
411
412impl ProductOSRouterError {
413 pub fn message(&self) -> &str {
415 match self {
416 ProductOSRouterError::Headers(m) => m,
417 ProductOSRouterError::Query(m) => m,
418 ProductOSRouterError::Body(m) => m,
419 ProductOSRouterError::Authentication(m) => m,
420 ProductOSRouterError::Authorization(m) => m,
421 ProductOSRouterError::Process(m) => m,
422 ProductOSRouterError::Unavailable(m) => m,
423 }
424 }
425}
426
427#[cfg(feature = "core")]
428impl ProductOSRouterError {
429 pub fn status_code(&self) -> StatusCode {
431 match self {
432 ProductOSRouterError::Headers(_) => StatusCode::BAD_REQUEST,
433 ProductOSRouterError::Query(_) => StatusCode::BAD_REQUEST,
434 ProductOSRouterError::Body(_) => StatusCode::BAD_REQUEST,
435 ProductOSRouterError::Authentication(_) => StatusCode::UNAUTHORIZED,
436 ProductOSRouterError::Authorization(_) => StatusCode::FORBIDDEN,
437 ProductOSRouterError::Process(_) => StatusCode::GATEWAY_TIMEOUT,
438 ProductOSRouterError::Unavailable(_) => StatusCode::SERVICE_UNAVAILABLE,
439 }
440 }
441}
442
443#[cfg(feature = "std")]
444impl ProductOSRouterError {
445 fn build_error_response(message: &str, status_code: &StatusCode) -> Response<Body> {
450 let safe_message = message.replace("\"", "'");
451 let status_code_u16 = status_code.as_u16();
452
453 Response::builder()
454 .status(status_code_u16)
455 .header("content-type", "application/json")
456 .body(Body::from(format!("{{\"error\": \"{safe_message}\"}}")))
457 .unwrap_or_else(|_| {
458 Response::builder()
459 .status(StatusCode::INTERNAL_SERVER_ERROR.as_u16())
460 .body(Body::from("{\"error\": \"internal error\"}"))
461 .expect("fallback response must be valid")
462 })
463 }
464
465 pub fn error_response(error: ProductOSRouterError, status_code: &StatusCode) -> Response<Body> {
488 Self::build_error_response(error.message(), status_code)
489 }
490
491 pub fn handle_error(error: &ProductOSRouterError) -> Response<Body> {
513 Self::build_error_response(error.message(), &error.status_code())
514 }
515}
516
517#[cfg(any(feature = "framework_axum", feature = "framework_flow"))]
561pub enum ProductOSRouter<S = ()> {
562 #[cfg(feature = "framework_axum")]
563 Axum(axum_impl::AxumRouter<S>),
564
565 #[cfg(feature = "framework_flow")]
566 Flow(flow_impl::Router<S>),
567}
568
569#[cfg(feature = "framework_axum")]
570impl<S: Clone + Send + Sync + 'static> Clone for ProductOSRouter<S> {
571 fn clone(&self) -> Self {
572 match self {
573 Self::Axum(r) => Self::Axum(r.clone()),
574 }
575 }
576}
577
578#[cfg(feature = "framework_flow")]
579impl<S: Clone + Send + Sync + 'static> Clone for ProductOSRouter<S> {
580 fn clone(&self) -> Self {
581 match self {
582 Self::Flow(r) => Self::Flow(r.clone()),
583 }
584 }
585}
586
587#[cfg(any(feature = "framework_axum", feature = "framework_flow"))]
588impl<S: Clone + Send + Sync + 'static> ProductOSRouter<S> {
589 pub fn new_with_state(state: S) -> Self {
591 #[cfg(feature = "framework_axum")]
592 return Self::Axum(axum_impl::AxumRouter::new_with_state(state));
593
594 #[cfg(feature = "framework_flow")]
595 return Self::Flow(flow_impl::Router::new_with_state(state));
596 }
597}
598
599#[cfg(any(feature = "framework_axum", feature = "framework_flow"))]
600impl ProductOSRouter<()> {
601 pub fn new() -> Self {
614 ProductOSRouter::new_with_state(())
615 }
616}
617
618#[cfg(any(feature = "framework_axum", feature = "framework_flow"))]
619impl Default for ProductOSRouter<()> {
620 fn default() -> Self {
621 Self::new()
622 }
623}
624
625#[cfg(any(feature = "framework_axum", feature = "framework_flow"))]
626impl ProductOSRouter<()> {
627 pub fn param_to_field(path: &str) -> String {
629 #[cfg(feature = "framework_axum")]
630 {
631 axum_impl::AxumRouter::<()>::param_to_field(path)
632 }
633 #[cfg(all(feature = "framework_flow", not(feature = "framework_axum")))]
634 {
635 flow_impl::Router::<()>::param_to_field(path)
636 }
637 }
638
639 pub fn not_implemented() -> Response<Body> {
641 Response::builder()
642 .status(StatusCode::NOT_IMPLEMENTED.as_u16())
643 .header("content-type", "application/json")
644 .body(Body::from("{}"))
645 .unwrap()
646 }
647
648 #[deprecated(
650 since = "0.0.41",
651 note = "Use not_implemented() which correctly returns 501, or build a 404 response explicitly"
652 )]
653 pub fn not_implemented_legacy() -> Response<Body> {
654 Response::builder()
655 .status(StatusCode::NOT_FOUND.as_u16())
656 .header("content-type", "application/json")
657 .body(Body::from("{}"))
658 .unwrap()
659 }
660
661 pub fn add_get_no_state<H, T>(&mut self, path: &str, handler: H)
663 where
664 H: Handler<T, ()> + Send + Sync + 'static,
665 T: 'static,
666 {
667 match self {
668 #[cfg(feature = "framework_axum")]
669 Self::Axum(r) => r.add_get_no_state(path, handler),
670 #[cfg(feature = "framework_flow")]
671 Self::Flow(r) => r.add_get_no_state(path, handler),
672 }
673 }
674
675 pub fn add_post_no_state<H, T>(&mut self, path: &str, handler: H)
677 where
678 H: Handler<T, ()> + Send + Sync + 'static,
679 T: 'static,
680 {
681 match self {
682 #[cfg(feature = "framework_axum")]
683 Self::Axum(r) => r.add_post_no_state(path, handler),
684 #[cfg(feature = "framework_flow")]
685 Self::Flow(r) => r.add_post_no_state(path, handler),
686 }
687 }
688
689 pub fn add_handler_no_state<H, T>(&mut self, path: &str, method: Method, handler: H)
691 where
692 H: Handler<T, ()> + Send + Sync + 'static,
693 T: 'static,
694 {
695 match self {
696 #[cfg(feature = "framework_axum")]
697 Self::Axum(r) => r.add_handler_no_state(path, method, handler),
698 #[cfg(feature = "framework_flow")]
699 Self::Flow(r) => r.add_handler_no_state(path, method, handler),
700 }
701 }
702
703 pub fn add_default_header_no_state(&mut self, header_name: &str, header_value: &str) {
705 match self {
706 #[cfg(feature = "framework_axum")]
707 Self::Axum(r) => r.add_default_header_no_state(header_name, header_value),
708 #[cfg(feature = "framework_flow")]
709 Self::Flow(r) => r.add_default_header_no_state(header_name, header_value),
710 }
711 }
712
713 pub fn set_fallback_handler_no_state<H, T>(&mut self, handler: H)
715 where
716 H: Handler<T, ()> + Send + Sync + 'static,
717 T: 'static,
718 {
719 match self {
720 #[cfg(feature = "framework_axum")]
721 Self::Axum(r) => r.set_fallback_handler_no_state(handler),
722 #[cfg(feature = "framework_flow")]
723 Self::Flow(r) => r.set_fallback_handler_no_state(handler),
724 }
725 }
726
727 #[cfg(feature = "cors")]
729 pub fn add_cors_handler_no_state<H, T>(&mut self, path: &str, method: Method, handler: H)
730 where
731 H: Handler<T, ()> + Send + Sync + 'static,
732 T: 'static,
733 {
734 match self {
735 #[cfg(feature = "framework_axum")]
736 Self::Axum(r) => r.add_cors_handler_no_state(path, method, handler),
737 #[cfg(feature = "framework_flow")]
738 Self::Flow(r) => r.add_cors_handler(path, method, handler),
739 }
740 }
741
742 #[cfg(feature = "sse")]
744 pub fn add_sse_handler_no_state<H, T>(&mut self, path: &str, handler: H)
745 where
746 H: Handler<T, ()> + Send + Sync + 'static,
747 T: 'static,
748 {
749 match self {
750 #[cfg(feature = "framework_axum")]
751 Self::Axum(r) => r.add_sse_handler_no_state(path, handler),
752 #[cfg(feature = "framework_flow")]
753 Self::Flow(r) => r.add_sse_handler(path, handler),
754 }
755 }
756
757 #[cfg(all(
759 feature = "ws",
760 any(feature = "framework_axum", feature = "flow_axum_compat")
761 ))]
762 pub fn add_ws_handler_no_state<H, T>(&mut self, path: &str, handler: H)
763 where
764 H: Handler<T, ()> + Send + Sync + 'static,
765 T: 'static,
766 {
767 match self {
768 #[cfg(feature = "framework_axum")]
769 Self::Axum(r) => r.add_ws_handler_no_state(path, handler),
770 #[cfg(feature = "framework_flow")]
771 Self::Flow(r) => r.add_ws_handler(path, handler),
772 }
773 }
774
775 #[cfg(all(
776 feature = "ws",
777 feature = "framework_flow",
778 not(feature = "framework_axum"),
779 not(feature = "flow_axum_compat")
780 ))]
781 pub fn add_ws_handler_no_state<F, Fut>(&mut self, path: &str, handler: F)
782 where
783 F: Fn(flow_impl::ws::WebSocket) -> Fut + Send + Sync + Clone + 'static,
784 Fut: std::future::Future<Output = ()> + Send + 'static,
785 {
786 match self {
787 Self::Flow(r) => r.add_ws_handler(path, handler),
788 }
789 }
790
791 pub fn add_handlers_no_state<H, T>(&mut self, path: &str, handlers: BTreeMap<Method, H>)
793 where
794 H: Handler<T, ()> + Send + Sync + 'static,
795 T: 'static,
796 {
797 match self {
798 #[cfg(feature = "framework_axum")]
799 Self::Axum(r) => r.add_handlers_no_state(path, handlers),
800 #[cfg(feature = "framework_flow")]
801 Self::Flow(r) => r.add_handlers_no_state(path, handlers),
802 }
803 }
804
805 #[cfg(feature = "cors")]
807 pub fn add_cors_handlers_no_state<H, T>(&mut self, path: &str, handlers: BTreeMap<Method, H>)
808 where
809 H: Handler<T, ()> + Send + Sync + 'static,
810 T: 'static,
811 {
812 match self {
813 #[cfg(feature = "framework_axum")]
814 Self::Axum(r) => r.add_cors_handlers_no_state(path, handlers),
815 #[cfg(feature = "framework_flow")]
816 Self::Flow(r) => r.add_cors_handlers_no_state(path, handlers),
817 }
818 }
819
820 #[cfg(feature = "cors")]
822 pub fn add_cors_middleware_no_state(&mut self) {
823 match self {
824 #[cfg(feature = "framework_axum")]
825 Self::Axum(r) => r.add_cors_middleware_no_state(),
826 #[cfg(feature = "framework_flow")]
827 Self::Flow(r) => r.add_cors_middleware(),
828 }
829 }
830}
831
832#[cfg(any(feature = "framework_axum", feature = "framework_flow"))]
833impl<S> ProductOSRouter<S>
834where
835 S: Clone + Send + Sync + 'static,
836{
837 pub fn get_router(&self) -> ProductOSRouter<S> {
842 self.clone()
843 }
844
845 #[cfg(feature = "framework_axum")]
850 pub fn into_axum_router(self) -> Router {
851 match self {
852 Self::Axum(r) => r.get_router(),
853 }
854 }
855
856 #[cfg(feature = "framework_flow")]
858 pub fn get_state(&self) -> S {
859 match self {
860 Self::Flow(r) => r.get_state(),
861 }
862 }
863
864 pub fn add_get<H, T>(&mut self, path: &str, handler: H)
866 where
867 H: Handler<T, S> + Send + Sync + 'static,
868 T: 'static,
869 {
870 match self {
871 #[cfg(feature = "framework_axum")]
872 Self::Axum(r) => r.add_get(path, handler),
873 #[cfg(feature = "framework_flow")]
874 Self::Flow(r) => r.add_get(path, handler),
875 }
876 }
877
878 pub fn add_post<H, T>(&mut self, path: &str, handler: H)
880 where
881 H: Handler<T, S> + Send + Sync + 'static,
882 T: 'static,
883 {
884 match self {
885 #[cfg(feature = "framework_axum")]
886 Self::Axum(r) => r.add_post(path, handler),
887 #[cfg(feature = "framework_flow")]
888 Self::Flow(r) => r.add_post(path, handler),
889 }
890 }
891
892 pub fn add_handler<H, T>(&mut self, path: &str, method: Method, handler: H)
894 where
895 H: Handler<T, S> + Send + Sync + 'static,
896 T: 'static,
897 {
898 match self {
899 #[cfg(feature = "framework_axum")]
900 Self::Axum(r) => r.add_handler(path, method, handler),
901 #[cfg(feature = "framework_flow")]
902 Self::Flow(r) => r.add_handler(path, method, handler),
903 }
904 }
905
906 pub fn add_default_header(&mut self, header_name: &str, header_value: &str) {
908 match self {
909 #[cfg(feature = "framework_axum")]
910 Self::Axum(r) => r.add_default_header(header_name, header_value),
911 #[cfg(feature = "framework_flow")]
912 Self::Flow(r) => r.add_default_header(header_name, header_value),
913 }
914 }
915
916 #[cfg(feature = "cors")]
918 pub fn add_cors_middleware(&mut self) {
919 match self {
920 #[cfg(feature = "framework_axum")]
921 Self::Axum(r) => r.add_cors_middleware(),
922 #[cfg(feature = "framework_flow")]
923 Self::Flow(r) => r.add_cors_middleware(),
924 }
925 }
926
927 pub fn add_handlers<H, T>(&mut self, path: &str, handlers: BTreeMap<Method, H>)
929 where
930 H: Handler<T, S> + Send + Sync + 'static,
931 T: 'static,
932 {
933 match self {
934 #[cfg(feature = "framework_axum")]
935 Self::Axum(r) => r.add_handlers(path, handlers),
936 #[cfg(feature = "framework_flow")]
937 Self::Flow(r) => r.add_handlers(path, handlers),
938 }
939 }
940
941 #[cfg(feature = "cors")]
943 pub fn add_cors_handlers<H, T>(&mut self, path: &str, handlers: BTreeMap<Method, H>)
944 where
945 H: Handler<T, S> + Send + Sync + 'static,
946 T: 'static,
947 {
948 match self {
949 #[cfg(feature = "framework_axum")]
950 Self::Axum(r) => r.add_cors_handlers(path, handlers),
951 #[cfg(feature = "framework_flow")]
952 Self::Flow(r) => r.add_cors_handlers(path, handlers),
953 }
954 }
955
956 #[cfg(feature = "cors")]
958 pub fn add_cors_handler<H, T>(&mut self, path: &str, method: Method, handler: H)
959 where
960 H: Handler<T, S> + Send + Sync + 'static,
961 T: 'static,
962 {
963 match self {
964 #[cfg(feature = "framework_axum")]
965 Self::Axum(r) => r.add_cors_handler(path, method, handler),
966 #[cfg(feature = "framework_flow")]
967 Self::Flow(r) => r.add_cors_handler(path, method, handler),
968 }
969 }
970
971 #[cfg(all(
973 feature = "ws",
974 any(feature = "framework_axum", feature = "flow_axum_compat")
975 ))]
976 pub fn add_ws_handler<H, T>(&mut self, path: &str, handler: H)
977 where
978 H: Handler<T, S> + Send + Sync + 'static,
979 T: 'static,
980 {
981 match self {
982 #[cfg(feature = "framework_axum")]
983 Self::Axum(r) => r.add_ws_handler(path, handler),
984 #[cfg(feature = "framework_flow")]
985 Self::Flow(r) => r.add_ws_handler(path, handler),
986 }
987 }
988
989 #[cfg(all(
994 feature = "ws",
995 feature = "framework_flow",
996 not(feature = "framework_axum"),
997 not(feature = "flow_axum_compat")
998 ))]
999 pub fn add_ws_handler<F, Fut>(&mut self, path: &str, handler: F)
1000 where
1001 F: Fn(flow_impl::ws::WebSocket) -> Fut + Send + Sync + Clone + 'static,
1002 Fut: std::future::Future<Output = ()> + Send + 'static,
1003 {
1004 match self {
1005 Self::Flow(r) => r.add_ws_handler(path, handler),
1006 }
1007 }
1008
1009 #[cfg(all(
1011 feature = "ws",
1012 feature = "framework_flow",
1013 not(feature = "framework_axum"),
1014 not(feature = "flow_axum_compat")
1015 ))]
1016 pub fn lookup_ws_handler(
1017 &mut self,
1018 path: &str,
1019 ) -> Option<flow_impl::router::WsHandlerCallback> {
1020 match self {
1021 Self::Flow(r) => r.lookup_ws_handler(path),
1022 }
1023 }
1024
1025 #[cfg(feature = "sse")]
1027 pub fn add_sse_handler<H, T>(&mut self, path: &str, handler: H)
1028 where
1029 H: Handler<T, S> + Send + Sync + 'static,
1030 T: 'static,
1031 {
1032 match self {
1033 #[cfg(feature = "framework_axum")]
1034 Self::Axum(r) => r.add_sse_handler(path, handler),
1035 #[cfg(feature = "framework_flow")]
1036 Self::Flow(r) => r.add_sse_handler(path, handler),
1037 }
1038 }
1039
1040 #[cfg(feature = "framework_axum")]
1042 pub fn add_route(&mut self, path: &str, method_router: axum::routing::MethodRouter<S>)
1043 where
1044 S: Clone + Send + Sync + 'static,
1045 {
1046 match self {
1047 Self::Axum(r) => r.add_route(path, method_router),
1048 }
1049 }
1050
1051 #[cfg(feature = "framework_axum")]
1053 pub fn set_fallback(&mut self, service_handler: axum::routing::MethodRouter<S>)
1054 where
1055 S: Clone + Send + Sync + 'static,
1056 {
1057 match self {
1058 Self::Axum(r) => r.set_fallback(service_handler),
1059 }
1060 }
1061
1062 pub fn set_fallback_handler<H, T>(&mut self, handler: H)
1064 where
1065 H: Handler<T, S>,
1066 T: 'static,
1067 {
1068 match self {
1069 #[cfg(feature = "framework_axum")]
1070 Self::Axum(r) => r.set_fallback_handler(handler),
1071 #[cfg(feature = "framework_flow")]
1072 Self::Flow(r) => r.set_fallback_handler(handler),
1073 }
1074 }
1075
1076 #[cfg(feature = "framework_axum")]
1078 pub fn add_middleware<L, ResBody>(&mut self, middleware: L)
1079 where
1080 L: tower::Layer<axum::routing::Route> + Clone + Send + Sync + 'static,
1081 L::Service: tower::Service<Request<Body>, Response = Response<ResBody>>
1082 + Clone
1083 + Send
1084 + Sync
1085 + 'static,
1086 <L::Service as tower::Service<Request<Body>>>::Future: Send,
1087 <L::Service as tower::Service<Request<Body>>>::Error: Into<axum::BoxError>,
1088 ResBody: axum::body::HttpBody<Data = product_os_http_body::Bytes> + Send + 'static,
1089 ResBody::Error: Into<axum::BoxError>,
1090 {
1091 match self {
1092 Self::Axum(r) => r.add_middleware(middleware),
1093 }
1094 }
1095
1096 #[cfg(all(feature = "framework_flow", feature = "flow_axum_compat"))]
1102 pub fn add_middleware<L, ResBody>(&mut self, middleware: L)
1103 where
1104 L: tower::Layer<flow_impl::router::NextService<S>> + Clone + Send + Sync + 'static,
1105 L::Service: tower::Service<Request<Body>, Response = product_os_http::Response<ResBody>>
1106 + Clone
1107 + Send
1108 + Sync
1109 + 'static,
1110 <L::Service as tower::Service<Request<Body>>>::Future: Send + 'static,
1111 <L::Service as tower::Service<Request<Body>>>::Error: Into<axum::BoxError> + Send + 'static,
1112 ResBody: axum::body::HttpBody<Data = product_os_http_body::Bytes> + Send + 'static,
1113 ResBody::Error: Into<axum::BoxError>,
1114 {
1115 match self {
1116 Self::Flow(r) => r.add_middleware_erased(middleware),
1117 }
1118 }
1119
1120 #[cfg(all(
1125 feature = "framework_flow",
1126 not(feature = "flow_axum_compat"),
1127 not(feature = "framework_axum")
1128 ))]
1129 pub fn add_middleware<L>(&mut self, middleware: L)
1130 where
1131 L: tower::Layer<flow_impl::router::NextService<S>> + Clone + Send + Sync + 'static,
1132 L::Service: tower::Service<
1133 Request<Body>,
1134 Response = flow_impl::core::body::Response,
1135 Error = core::convert::Infallible,
1136 > + Clone
1137 + Send
1138 + Sync
1139 + 'static,
1140 <L::Service as tower::Service<Request<Body>>>::Future: Send + 'static,
1141 {
1142 match self {
1143 Self::Flow(r) => r.add_middleware(middleware),
1144 }
1145 }
1146}
1147
1148#[cfg(any(feature = "framework_axum", feature = "framework_flow"))]
1149impl<S: Clone + Send + Sync + 'static> ProductOSRouter<S> {
1150 pub fn add_extension<T: Clone + Send + Sync + 'static>(&mut self, value: T) {
1152 #[cfg(feature = "framework_axum")]
1153 {
1154 match self {
1155 Self::Axum(r) => {
1156 let router = r.take_router().layer(axum::Extension(value));
1157 *r.get_router_mut() = router;
1158 }
1159 }
1160 }
1161 #[cfg(all(feature = "framework_flow", not(feature = "framework_axum")))]
1162 {
1163 match self {
1164 Self::Flow(r) => {
1165 r.add_extension(value);
1166 }
1167 }
1168 }
1169 }
1170}
1171
1172#[cfg(feature = "framework_flow")]
1175impl<S> tower::Service<Request<Body>> for ProductOSRouter<S>
1176where
1177 S: Clone + Send + Sync + 'static,
1178{
1179 type Response = flow_impl::core::body::Response;
1180 type Error = core::convert::Infallible;
1181 type Future = core::pin::Pin<
1182 Box<dyn core::future::Future<Output = Result<Self::Response, Self::Error>> + Send>,
1183 >;
1184
1185 fn poll_ready(
1186 &mut self,
1187 cx: &mut core::task::Context<'_>,
1188 ) -> core::task::Poll<Result<(), Self::Error>> {
1189 match self {
1190 Self::Flow(r) => tower::Service::poll_ready(r, cx),
1191 }
1192 }
1193
1194 fn call(&mut self, req: Request<Body>) -> Self::Future {
1195 match self {
1196 Self::Flow(r) => tower::Service::call(r, req),
1197 }
1198 }
1199}
1200
1201#[cfg(feature = "std")]
1202mod extension_impl {
1203 use crate::{Body, FromRequestParts, Request};
1204 use std::ops::{Deref, DerefMut};
1205 use std::prelude::v1::*;
1206
1207 #[derive(Debug, Clone, Copy, Default)]
1228 pub struct Extension<T>(pub T);
1229
1230 impl<T> Deref for Extension<T> {
1231 type Target = T;
1232
1233 fn deref(&self) -> &Self::Target {
1234 &self.0
1235 }
1236 }
1237
1238 impl<T> DerefMut for Extension<T> {
1239 fn deref_mut(&mut self) -> &mut Self::Target {
1240 &mut self.0
1241 }
1242 }
1243
1244 impl<T, S> FromRequestParts<S> for Extension<T>
1245 where
1246 T: Clone + Send + Sync + 'static,
1247 S: Send + Sync,
1248 {
1249 type Rejection = (product_os_http::StatusCode, &'static str);
1250
1251 fn from_request_parts(
1252 parts: &mut product_os_http::request::Parts,
1253 _state: &S,
1254 ) -> impl core::future::Future<Output = Result<Self, Self::Rejection>> + Send {
1255 let value = parts.extensions.get::<T>().cloned().map(Extension).ok_or((
1256 product_os_http::StatusCode::INTERNAL_SERVER_ERROR,
1257 "Extension not found in request",
1258 ));
1259
1260 async move { value }
1261 }
1262 }
1263
1264 pub fn extension_layer<T>(
1265 value: T,
1266 ) -> tower::util::MapRequestLayer<impl Fn(Request<Body>) -> Request<Body> + Clone>
1267 where
1268 T: Clone + Send + Sync + 'static,
1269 {
1270 tower::util::MapRequestLayer::new(move |mut req: Request<Body>| {
1271 req.extensions_mut().insert(value.clone());
1272 req
1273 })
1274 }
1275}
1276
1277#[cfg(feature = "std")]
1278pub use extension_impl::{extension_layer, Extension};