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

updtes from using the library #19

Merged
merged 2 commits into from
Jun 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package run.cosy.akka.http.messages

import akka.http.scaladsl.model.*
import akka.http.scaladsl.model.Uri.Authority
import akka.http.scaladsl.model.headers.Host
import akka.http.scaladsl.settings.ParserSettings.ConflictingContentTypeHeaderProcessingMode.NoContentType
import cats.Id
Expand All @@ -25,12 +26,7 @@ import run.cosy.akka.http.AkkaTp
import run.cosy.akka.http.AkkaTp.HT
import run.cosy.http.Http
import run.cosy.http.Http.{Request, Response}
import run.cosy.http.auth.{
AttributeException,
HTTPHeaderParseException,
ParsingExc,
SelectorException
}
import run.cosy.http.auth.*
import run.cosy.http.headers.Rfc8941.{Param, Params}
import run.cosy.http.headers.{ParsingException, Rfc8941}
import run.cosy.http.messages.*
Expand All @@ -39,7 +35,7 @@ import java.nio.charset.StandardCharsets
import scala.collection.immutable.ListMap
import scala.util.{Failure, Success, Try}

class RequestSelectorFnsAkka(using sc: ServerContext)
class RequestSelectorFnsAkka(using sc: ServerContext = NoServerContext)
extends ReqFns[HT]:

override val method: RequestFn =
Expand All @@ -48,11 +44,18 @@ class RequestSelectorFnsAkka(using sc: ServerContext)
override val authority: RequestFn =
RequestAkka { req =>
try
Right(req.effectiveUri(
sc.secure,
sc.defaultHost.map(Host(_))
.getOrElse(Host.empty)
).authority.toString().toLowerCase(java.util.Locale.ROOT).nn)
sc match
case NoServerContext =>
// we can arbitrarily have secured connection be true, because we will ignore it when selecting the host
val euri = req.effectiveUri(true, Host.empty)
// an exception will have been thrown above if not absolute uri
Right(euri.authority.toString())
case asc: AServerContext =>
Right(req.effectiveUri(
asc.secure,
asc.defaultHost.map(Host(_))
.getOrElse(Host.empty)
).authority.toString())
catch
case urlEx: IllegalUriException =>
Left(
Expand Down Expand Up @@ -93,19 +96,41 @@ class RequestSelectorFnsAkka(using sc: ServerContext)
case head :: tail => Right(NonEmptyList(head, tail))
}

val schemes = List("https", "http")
override val scheme: RequestFn =
RequestAkka { req =>
Right(req.effectiveUri(
securedConnection = sc.secure,
defaultHostHeader = sc.defaultHost.map(Host(_)).getOrElse(Host.empty)
).scheme)
if schemes.contains(req.uri.scheme) then Right(req.uri.scheme)
else
sc match
case NoServerContext => Left(
MissingContextException("No scheme in Uri and no context information available")
)
case asc: AServerContext => Right(if asc.secure then "https" else "http")
}

override val targetUri: RequestFn = RequestAkka { req =>
Right(req.effectiveUri(
securedConnection = sc.secure,
defaultHostHeader = sc.defaultHost.map(Host(_)).getOrElse(Host.empty)
).toString())
try
sc match
case NoServerContext =>
// the request has to be absolute, because even with Host header we won't know scheme
if !schemes.contains(req.uri.scheme) then
Left(MissingContextException(
"No authority in request, and no context to fill in missing request"
))
else
Right(req.effectiveUri(
req.uri.scheme == "https",
Host.empty
).toString())
case asc: AServerContext =>
Right(req.effectiveUri(
asc.secure,
asc.defaultHost.map(Host(_))
.getOrElse(Host.empty)
).toString())
catch
case urlEx: IllegalUriException =>
Left(SelectorException("cannot calculate effectuve url for request. " + urlEx.getMessage))
}

case class RequestAkka(
Expand All @@ -116,7 +141,7 @@ class RequestSelectorFnsAkka(using sc: ServerContext)

end RequestSelectorFnsAkka

class ResponseSelectorFnsAkka(using sc: ServerContext)
class ResponseSelectorFnsAkka(using sc: AServerContext)
extends ResFns[HT]:

override val status: ResponseFn = ResponseAkka { resp =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import run.cosy.http.messages.*
//todo: this double use of "using" is really not good
class AkkaSigCreationTests extends SigCreationTest[HT](
AkkaMsgInterpreter,
new ReqSelectors(using new RequestSelectorFnsAkka(using ServerContext("bblfish.net", true)))
new ReqSelectors(using new RequestSelectorFnsAkka(using AServerContext("bblfish.net", true)))
):
given ME: cats.effect.Sync[SyncIO] = SyncIO.syncForSyncIO

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import run.cosy.http.auth.VerifySignatureTests
import run.cosy.http.messages.*
import run.cosy.akka.http.messages.RequestSelectorFnsAkka

given ServerContext = ServerContext("bblfish.net", true)
given ReqFns[HT] = new RequestSelectorFnsAkka
given AServerContext = AServerContext("bblfish.net", true)
given ReqFns[HT] = new RequestSelectorFnsAkka
import scala.concurrent.Future

class AkkaVerifySigTests extends VerifySignatureTests[HT](AkkaMsgInterpreter):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import run.cosy.akka.http.AkkaTp
import run.cosy.akka.http.AkkaTp.HT
import run.cosy.akka.http.messages.RequestSelectorFnsAkka

given ServerContext = ServerContext("bblfish.net", true)
given AServerContext = AServerContext("bblfish.net", true)
given TestHttpMsgInterpreter[HT] = AkkaMsgInterpreter //this needs the above

given ReqFns[HT] = new RequestSelectorFnsAkka
Expand All @@ -31,8 +31,8 @@ class AkkaHeaderSelectorSuite extends HeaderSuite(
)

class AkkaAtRequestSelectorSuite extends AtRequestSelectorSuite[HT]:
def sel(using ServerContext): AtReqSelectors[HT] =
new AtReqSelectors[HT](using new RequestSelectorFnsAkka()) {}
def sel(sc: ServerContext): AtReqSelectors[HT] =
new AtReqSelectors[HT](using new RequestSelectorFnsAkka(using sc)) {}
def interp: TestHttpMsgInterpreter[HT] = AkkaMsgInterpreter
def platform: HttpMsgPlatform = HttpMsgPlatform.Akka

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import run.cosy.http4s.messages.{Http4sMsgInterpreter, SelectorFnsH4}
//todo: this double use of "using" is really not good
class JS_H4SigCreationTests extends run.cosy.http.auth.SigCreationTest[HT](
Http4sMsgInterpreter,
new ReqSelectors(using new SelectorFnsH4(using ServerContext("bblfish.net", true)))
new ReqSelectors(using new SelectorFnsH4(using AServerContext("bblfish.net", true)))
):
given ME: cats.effect.Sync[IO] = IO.asyncForIO

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ import run.cosy.http4s.Http4sTp
import run.cosy.http4s.Http4sTp.HT
import run.cosy.http4s.messages.{Http4sMsgInterpreter, SelectorFnsH4}

given ServerContext = ServerContext("bblfish.net", true)
given ReqFns[HT] = new SelectorFnsH4
given AServerContext = AServerContext("bblfish.net", true)
given ReqFns[HT] = new SelectorFnsH4

// to get this to work, we need to first work out how to generically switch between IO and SyncIO
class H4VerifySigTests extends VerifySignatureTests[HT](Http4sMsgInterpreter):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import run.cosy.http.messages.{
ReqComponentDB,
ReqFns,
ReqSelectors,
ServerContext,
AServerContext,
TestHttpMsgInterpreter
}
import run.cosy.http4s.Http4sTp
Expand All @@ -35,7 +35,7 @@ import run.cosy.http4s.messages.SelectorFnsH4
//todo: this double use of "using" is really not good
class H4SigCreationTests extends run.cosy.http.auth.SigCreationTest[HT](
Http4sMsgInterpreter,
new ReqSelectors(using new SelectorFnsH4(using ServerContext("bblfish.net", true)))
new ReqSelectors(using new SelectorFnsH4(using AServerContext("bblfish.net", true)))
):
given ME: cats.effect.Sync[SyncIO] = SyncIO.syncForSyncIO

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ import run.cosy.http4s.Http4sTp
import run.cosy.http4s.Http4sTp.HT
import run.cosy.http4s.messages.{Http4sMsgInterpreter, SelectorFnsH4}

given ServerContext = ServerContext("bblfish.net", true)
given ReqFns[HT] = new SelectorFnsH4
given AServerContext = AServerContext("bblfish.net", true)
given ReqFns[HT] = new SelectorFnsH4

class H4VerifySigTests extends VerifySignatureTests(Http4sMsgInterpreter):
override val thisPlatform: RunPlatform = RunPlatform.JVM
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ object Http4sTp extends Http:
extension [R <: Http.Message[HT]](msg: R)
def addHeaders(headers: Seq[Http.Header[HT]]): R =
val m = msg.asInstanceOf[org.http4s.Message[F]]
m.withHeaders((m.headers ++ Headers(headers)))
m.withHeaders((m.headers.transform(l => l ++ headers)))
.asInstanceOf[R]

def addHeader(name: String, value: String): R =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,27 @@
package run.cosy.http4s.messages

import cats.data.NonEmptyList
import run.cosy.http.messages.{
AtReqSelectorFns,
HeaderId,
ReqFns,
ResFns,
SelectorFn,
ServerContext
}
import org.http4s.headers.Host
import org.http4s.{Query, Uri, Message as H4Message, Request as H4Request, Response as H4Response}
import org.typelevel.ci.CIString
import run.cosy.http.Http
import run.cosy.http.auth.{
AttributeException,
ParsingExc,
SelectorException,
MissingContextException
}
import run.cosy.http.headers.Rfc8941
import run.cosy.http.messages.Parameters.nameTk
import run.cosy.http.messages.*
import run.cosy.http4s.Http4sTp
import run.cosy.http4s.Http4sTp.HT as H4
import run.cosy.platform
import run.cosy.http.headers.Rfc8941
import run.cosy.http.auth.{AttributeException, ParsingExc, SelectorException}
import run.cosy.http4s.messages.SelectorFnsH4.getHeaders
import run.cosy.platform

import scala.util.Try
import scala.util.{Failure, Success}
import org.typelevel.ci.CIString
import scala.util.{Failure, Success, Try}

class SelectorFnsH4(using sc: ServerContext) extends ReqFns[H4]:
class SelectorFnsH4(using sc: ServerContext = NoServerContext) extends ReqFns[H4]:
val SF = SelectorFnsH4

override def method: RequestFn =
Expand Down Expand Up @@ -103,7 +100,7 @@ class SelectorFnsH4(using sc: ServerContext) extends ReqFns[H4]:

end SelectorFnsH4

class ResponseSelectorFnsH4(using sc: ServerContext) extends ResFns[H4]:
class ResponseSelectorFnsH4(using sc: AServerContext) extends ResFns[H4]:
val SF = SelectorFnsH4

override def responseHeaders(name: HeaderId): ResponseFn = ResponseSelH4(res =>
Expand All @@ -125,19 +122,21 @@ object SelectorFnsH4:
case None => Left(SelectorException(s"no header in request named $name"))
case Some(nel) => Right(nel)

def defaultAuthorityOpt(scheme: Option[Uri.Scheme])(
using sc: ServerContext
): Option[Uri.Authority] = sc.defaultHost.map(h =>
Uri.Authority(
None,
Uri.RegName(h),
// we assume that if the ports are the default one then we have the corresponding security values
// otherwise we just don't know... (a bit awkward. It may be better to fail)
if sc.secure && sc.port == 443 then None
else if (!sc.secure) && sc.port == 80 then None
else Some(sc.port)
)
)
def defaultAuthorityOpt(using sc: ServerContext): Option[Uri.Authority] =
sc match
case NoServerContext => None
case asc: AServerContext =>
asc.defaultHost.map(h =>
Uri.Authority(
None,
Uri.RegName(h),
// we assume that if the ports are the default one then we have the corresponding security values
// otherwise we just don't know... (a bit awkward. It may be better to fail)
if asc.secure && asc.port == 443 then None
else if (!asc.secure) && asc.port == 80 then None
else Some(asc.port)
)
)

def normaliseAuthority(auth: Uri.Authority, schema: Option[Uri.Scheme]): Uri.Authority =
schema match
Expand All @@ -149,14 +148,15 @@ object SelectorFnsH4:
def authorityFor[F[_]](req: H4Request[F])(using sc: ServerContext): Option[Uri.Authority] =
req.uri.authority
.map(a => normaliseAuthority(a, req.uri.scheme))
.orElse {
req.headers.get[Host]
.map(h => Uri.Authority(None, Uri.RegName(h.host), h.port))
.orElse(defaultAuthorityOpt(req.uri.scheme))
}
.orElse(req.headers.get[Host]
.map(h => Uri.Authority(None, Uri.RegName(h.host), h.port))
.orElse(defaultAuthorityOpt))

def defaultScheme(using sc: ServerContext): Uri.Scheme =
if sc.secure then Uri.Scheme.https else Uri.Scheme.http
def defaultScheme(using sc: ServerContext): Option[Uri.Scheme] =
sc match
case NoServerContext => None
case asc: AServerContext =>
Some(if asc.secure then Uri.Scheme.https else Uri.Scheme.http)

def effectiveUriFor[F[_]](req: H4Request[F])(using
sc: ServerContext
Expand All @@ -166,10 +166,10 @@ object SelectorFnsH4:
then Right(uri)
else
val newUri = uri.copy(
scheme = uri.scheme.orElse(Some(defaultScheme)),
scheme = uri.scheme.orElse(defaultScheme),
authority = authorityFor(req)
)
if newUri.authority.isDefined
if newUri.authority.isDefined && newUri.scheme.isDefined
then Right(newUri)
else Left(SelectorException(s"cannot create effective Uri for req. Got: <$newUri>"))
end effectiveUriFor
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class TestUsingHttp4SMsgs extends CatsEffectSuite:
import msgSig.*
import Http4sTp.{*, given}

given ServerContext = ServerContext("bblfish.net", true)
given AServerContext = AServerContext("bblfish.net", true)

given ReqFns[HT] = new SelectorFnsH4
val sel = new ReqSelectors[HT]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import run.cosy.http4s.Http4sTp
import run.cosy.http4s.Http4sTp.HT
import run.cosy.http4s.messages.SelectorFnsH4

given ServerContext = ServerContext("bblfish.net", true)
given AServerContext = AServerContext("bblfish.net", true)
given TestHttpMsgInterpreter[HT] = Http4sMsgInterpreter

given ReqFns[HT] = new SelectorFnsH4
Expand Down
2 changes: 2 additions & 0 deletions ietfSig/shared/src/main/scala/run/cosy/http/Http.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ trait HttpOps[H <: Http]:
def headerSeq: Seq[Http.Header[H]]

extension [R <: Http.Message[H]](msg: R)
// add the headers without removing duplicates, this limits the useage
// of this lib outside of httpSig. (reason: see http4s implementation)
def addHeaders(headers: Seq[Http.Header[H]]): R
// here we do really add a header to existing ones.
// note http4s
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ case class KeyIdException(msg: String) extends AuthExc(msg)

sealed class ParsingExc(msg: String) extends AuthExc(msg)
case class InvalidSigException(msg: String) extends ParsingExc(msg)
case class SelectorException(msg: String) extends ParsingExc(msg)
class SelectorException(msg: String) extends ParsingExc(msg)
class MissingContextException(msg: String) extends SelectorException(msg)
case class AttributeException(msg: String) extends ParsingExc(msg)
case class CharacterCodingExc(msg: String) extends ParsingExc(msg)
case class HttpSigParsingExc(msg: String) extends ParsingExc(msg)
Expand Down
Loading