Skip to content
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
8 changes: 8 additions & 0 deletions obp-api/src/main/resources/props/sample.props.template
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ db.url=jdbc:h2:./lift_proto.db;NON_KEYWORDS=VALUE;DB_CLOSE_ON_EXIT=FALSE
## This is needed for oauth to work. it's important to access the api over this url, e.g.
## If this is 127.0.0.1 do NOT use localhost to access it.
## (this needs to be a URL)
## IMPORTANT: hostname is also used as fallback for local_provider_name - do not change unless necessary
hostname=http://127.0.0.1

# Used as the base URL for password reset and email validation links sent via email.
Expand All @@ -298,6 +299,13 @@ portal_external_url=http://localhost:5174
## To start the server, use: java -jar obp-api/target/obp-api.jar
dev.port=8080

## Bind address for http4s server (optional)
## If not set, the server will parse and use the host from the hostname property above
## Use this if you need to bind to a different address than what's in hostname
## Example: bind_address=0.0.0.0 (to listen on all interfaces)
## Example: bind_address=127.0.0.1 (to listen only on localhost)
#bind_address=127.0.0.1


#The start of the api path (before the version)
#It is *strongly* recommended not to change this - since Apps will be expecting the api at /obp/+version
Expand Down
20 changes: 6 additions & 14 deletions obp-api/src/main/scala/bootstrap/http4s/Http4sServer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,24 @@ package bootstrap.http4s

import cats.effect._
import code.api.util.APIUtil
import code.api.util.http4s.Http4sApp
import code.api.util.http4s.{Http4sApp, Http4sConfigUtil}
import com.comcast.ip4s._
import org.http4s.Uri
import org.http4s.ember.server._

object Http4sServer extends IOApp {

//Start OBP relevant objects and settings; this step MUST be executed first
// new bootstrap.http4s.Http4sBoot().boot
new bootstrap.liftweb.Boot().boot

// Parse hostname - support both "127.0.0.1" and "http://127.0.0.1" formats
private def parseHostname(hostnameValue: String): String = {
val trimmed = hostnameValue.trim
// Try to parse as URI first
Uri.fromString(trimmed).toOption
.flatMap(_.host.map(_.renderString))
.getOrElse(trimmed) // If not a valid URI, use as-is
}

val host = parseHostname(code.api.Constant.HostName)

// Get bind address: use bind_address prop if set, otherwise parse from hostname
// Note: hostname prop must remain unchanged as it may be used for local_provider_name fallback
val host = Http4sConfigUtil.parseHostname(APIUtil.getPropsValue("bind_address",code.api.Constant.HostName))
val port = APIUtil.getPropsAsIntValue("dev.port",8080)

// Use shared httpApp configuration (same as tests)
val httpApp = Http4sApp.httpApp

override def run(args: List[String]): IO[ExitCode] = EmberServerBuilder
.default[IO]
.withHost(Host.fromString(host).get)
Expand Down
32 changes: 32 additions & 0 deletions obp-api/src/main/scala/code/api/util/http4s/Http4sSupport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -436,3 +436,35 @@ object ResourceDocMatcher {
)
}
}

/**
* Http4s configuration utilities.
*/
object Http4sConfigUtil {

/**
* Parse hostname from a string that may be either a plain host or a full URI.
*
* Supports both formats:
* - Plain host: "127.0.0.1" or "localhost"
* - Full URI: "http://127.0.0.1:8080" or "https://example.com"
*
* @param hostnameValue The hostname or URI string to parse
* @return The extracted hostname/IP address
*
* Examples:
* {{{
* parseHostname("127.0.0.1") // Returns: "127.0.0.1"
* parseHostname("http://127.0.0.1:8080") // Returns: "127.0.0.1"
* parseHostname("https://api.example.com") // Returns: "api.example.com"
* parseHostname("localhost") // Returns: "localhost"
* }}}
*/
def parseHostname(hostnameValue: String): String = {
val trimmed = hostnameValue.trim
// Try to parse as URI first
Uri.fromString(trimmed).toOption
.flatMap(_.host.map(_.renderString))
.getOrElse(trimmed) // If not a valid URI, use as-is
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package code.api.util.http4s

import org.scalatest.{FlatSpec, Matchers}

class Http4sConfigUtilTest extends FlatSpec with Matchers {

"parseHostname" should "extract hostname from plain IP address" in {
Http4sConfigUtil.parseHostname("127.0.0.1") shouldBe "127.0.0.1"
}

it should "extract hostname from HTTP URI" in {
Http4sConfigUtil.parseHostname("http://127.0.0.1:8080") shouldBe "127.0.0.1"
}

it should "extract hostname from HTTPS URI" in {
Http4sConfigUtil.parseHostname("https://api.example.com") shouldBe "api.example.com"
}

it should "handle localhost" in {
Http4sConfigUtil.parseHostname("localhost") shouldBe "localhost"
}

it should "handle URI with path" in {
Http4sConfigUtil.parseHostname("http://example.com/path") shouldBe "example.com"
}

it should "trim whitespace" in {
Http4sConfigUtil.parseHostname(" 127.0.0.1 ") shouldBe "127.0.0.1"
}

it should "handle URI with port" in {
Http4sConfigUtil.parseHostname("http://localhost:8080") shouldBe "localhost"
}

it should "handle domain names" in {
Http4sConfigUtil.parseHostname("example.com") shouldBe "example.com"
}

it should "handle full URL with protocol, port and path" in {
Http4sConfigUtil.parseHostname("https://api.example.com:443/v1/endpoint") shouldBe "api.example.com"
}
}
11 changes: 5 additions & 6 deletions release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
### Most recent changes at top of file
```
Date Commit Action
12/12/2025 f2e7b827 Http4s runner configuration
Added http4s.host and http4s.port to props sample template:
- http4s.host=127.0.0.1
- http4s.port=8086
These properties control the bind address of bootstrap.http4s.Http4sServer
when running via the obp-http4s-runner fat JAR.
27/02/2026 24035862 Http4s server bind address configuration
Added bind_address property for http4s server configuration:
- bind_address: Optional property to specify the network binding address
- Falls back to parsing hostname property if not set
- Maintains backward compatibility with existing hostname configuration
11/12/2025 3c2df942 BREAKING CHANGE: Migration from Akka to Apache Pekko™ 1.1.2
Replaced Akka 2.5.32 with Apache Pekko™ 1.1.2 to address Akka licensing changes.
Updated all imports from com.typesafe.akka to org.apache.pekko.
Expand Down