@@ -6,140 +6,69 @@ package natchez.http4s.syntax
66
77import cats .~>
88import cats .data .{ Kleisli , OptionT }
9- import cats .data .Kleisli .applyK
109import cats .effect .MonadCancel
11- import natchez .{ EntryPoint , Kernel , Span }
1210import org .http4s .HttpRoutes
1311import cats .effect .Resource
1412import org .http4s .server .websocket .WebSocketBuilder2
1513import org .typelevel .ci .CIString
14+ import natchez .EntryPoint
15+ import natchez .Span
1616
17- /**
18- * @define excludedHeaders
19- * All headers except security (Authorization, Cookie, Set-Cookie)
20- * and payload (Content-Length, ContentType, Content-Range, Trailer, Transfer-Encoding)
21- * are passed to Kernel by default.
22- *
23- * @define isKernelHeader should an HTTP header be passed to Kernel or not
24- *
25- * @define spanName compute the span name from the request
26- *
27- * @define spanOptions options used in span creation
28- */
2917trait EntryPointOps [F [_]] { outer =>
3018
3119 def self : EntryPoint [F ]
3220
3321 /**
34- * Given an entry point and HTTP Routes in Kleisli[F, Span[F], *] return routes in F. A new span
35- * is created with by default the URI path as the name, either as a continuation of the incoming trace, if
36- * any, or as a new root.
22+ * Given an entry point and HTTP Routes in Kleisli[F, Span[F], *] return routes in F.
23+ * A span that is injected is a RootsSpan (smilarly to Trace.ioTraceForEntryPoint)
3724 *
38- * @note $excludedHeaders
39- *
40- * @param isKernelHeader $isKernelHeader
41- * @param spanName $spanName
42- * @param spanOptions $spanOptions
4325 */
4426 def liftT (
4527 routes : HttpRoutes [Kleisli [F , Span [F ], * ]],
46- isKernelHeader : CIString => Boolean = name => ! EntryPointOps .ExcludedHeaders .contains(name),
47- spanName : org.http4s.Request [F ] => String = _.uri.path.toString,
48- spanOptions : Span .Options = Span .Options .Defaults ,
4928 )(implicit ev : MonadCancel [F , Throwable ]): HttpRoutes [F ] =
5029 Kleisli { req =>
51- val kernelHeaders = req.headers.headers
52- .collect {
53- case header if isKernelHeader(header.name) => header.name -> header.value
54- }
55- .toMap
56-
57- val kernel = Kernel (kernelHeaders)
58- val spanR = self.continueOrElseRoot(spanName(req), kernel, spanOptions)
59- OptionT {
60- spanR.use { span =>
61- routes.run(req.mapK(lift)).mapK(applyK(span)).map(_.mapK(applyK(span))).value
62- }
63- }
30+ val root = Span .makeRoots(self)
31+ OptionT (routes.run(req.mapK(Kleisli .liftK)).mapK(Kleisli .applyK(root)).map(_.mapK(Kleisli .applyK(root))).value)
6432 }
6533
34+
6635 /**
6736 * Lift an `HttpRoutes`-yielding resource that consumes `Span`s into the bare effect. We do this
6837 * by ignoring any tracing that happens during allocation and freeing of the `HttpRoutes`
6938 * resource. The reasoning is that such a resource typically lives for the lifetime of the
7039 * application and it's of little use to keep a span open that long.
7140 *
72- * @note $excludedHeaders
73- *
74- * @param isKernelHeader $isKernelHeader
7541 */
7642 def liftR (
7743 routes : Resource [Kleisli [F , Span [F ], * ], HttpRoutes [Kleisli [F , Span [F ], * ]]],
78- isKernelHeader : CIString => Boolean = name => ! EntryPointOps .ExcludedHeaders .contains(name)
7944 )(implicit ev : MonadCancel [F , Throwable ]): Resource [F , HttpRoutes [F ]] =
80- routes.map(liftT(_, isKernelHeader) ).mapK(Span .dropTracing)
45+ routes.map(liftT).mapK(Span .dropTracing)
8146
8247 /**
8348 * Given an entry point and a function from `WebSocketBuilder2` to HTTP Routes in
84- * Kleisli[F, Span[F], *] return a function from `WebSocketBuilder2` to routes in F. A new span
85- * is created with the URI path as the name, either as a continuation of the incoming trace, if
86- * any, or as a new root.
87- *
88- * @note $excludedHeaders
89- *
90- * @param isKernelHeader $isKernelHeader
49+ * Kleisli[F, Span[F], *] return a function from `WebSocketBuilder2` to routes in F.
9150 */
9251 def wsLiftT (
93- routes : WebSocketBuilder2 [Kleisli [F , Span [F ], * ]] => HttpRoutes [Kleisli [F , Span [F ], * ]],
94- isKernelHeader : CIString => Boolean = name => ! EntryPointOps .ExcludedHeaders .contains(name),
95- spanName : org.http4s.Request [F ] => String = _.uri.path.toString,
96- spanOptions : Span .Options = Span .Options .Defaults
52+ routes : WebSocketBuilder2 [Kleisli [F , Span [F ], * ]] => HttpRoutes [Kleisli [F , Span [F ], * ]]
9753 )(implicit ev : MonadCancel [F , Throwable ]): WebSocketBuilder2 [F ] => HttpRoutes [F ] = wsb =>
98- liftT(routes(wsb.imapK(lift)(Span .dropTracing)), isKernelHeader, spanName, spanOptions )
54+ liftT(routes(wsb.imapK(lift)(Span .dropTracing)))
9955
10056 /**
10157 * Lift a `WebSocketBuilder2 => HttpRoutes`-yielding resource that consumes `Span`s into the bare
10258 * effect. We do this by ignoring any tracing that happens during allocation and freeing of the
10359 * `HttpRoutes` resource. The reasoning is that such a resource typically lives for the lifetime
10460 * of the application and it's of little use to keep a span open that long.
105- *
106- * @note $excludedHeaders
107- *
108- * @param isKernelHeader $isKernelHeader
10961 */
11062 def wsLiftR (
111- routes : Resource [Kleisli [F , Span [F ], * ], WebSocketBuilder2 [Kleisli [F , Span [F ], * ]] => HttpRoutes [Kleisli [F , Span [F ], * ]]],
112- isKernelHeader : CIString => Boolean = name => ! EntryPointOps .ExcludedHeaders .contains(name),
113- spanName : org.http4s.Request [F ] => String = _.uri.path.toString,
114- spanOptions : Span .Options = Span .Options .Defaults
63+ routes : Resource [Kleisli [F , Span [F ], * ], WebSocketBuilder2 [Kleisli [F , Span [F ], * ]] => HttpRoutes [Kleisli [F , Span [F ], * ]]]
11564 )(implicit ev : MonadCancel [F , Throwable ]): Resource [F , WebSocketBuilder2 [F ] => HttpRoutes [F ]] =
116- routes.map(wsLiftT(_, isKernelHeader, spanName, spanOptions) ).mapK(Span .dropTracing)
65+ routes.map(wsLiftT).mapK(Span .dropTracing)
11766
11867 private val lift : F ~> Kleisli [F , Span [F ], * ] =
11968 Kleisli .liftK
12069}
12170
12271object EntryPointOps {
123- val ExcludedHeaders : Set [CIString ] = {
124- import org .http4s .headers ._
125- import org .typelevel .ci ._
126-
127- val payload = Set (
128- `Content-Length`.name,
129- ci " Content-Type " ,
130- `Content-Range`.name,
131- ci " Trailer " ,
132- `Transfer-Encoding`.name,
133- )
134-
135- val security = Set (
136- Authorization .name,
137- Cookie .name,
138- `Set-Cookie`.name,
139- )
140-
141- payload ++ security
142- }
14372}
14473
14574trait ToEntryPointOps {
0 commit comments