Skip to content

Commit 76c5f91

Browse files
authored
Merge pull request #2714 from hongwei1/refactor/hostname-parsing-improvement
Add bind_address property for http4s server configuration
2 parents 80a563a + f9edb6f commit 76c5f91

File tree

5 files changed

+93
-20
lines changed

5 files changed

+93
-20
lines changed

obp-api/src/main/resources/props/sample.props.template

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ db.url=jdbc:h2:./lift_proto.db;NON_KEYWORDS=VALUE;DB_CLOSE_ON_EXIT=FALSE
287287
## This is needed for oauth to work. it's important to access the api over this url, e.g.
288288
## If this is 127.0.0.1 do NOT use localhost to access it.
289289
## (this needs to be a URL)
290+
## IMPORTANT: hostname is also used as fallback for local_provider_name - do not change unless necessary
290291
hostname=http://127.0.0.1
291292

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

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

302310
#The start of the api path (before the version)
303311
#It is *strongly* recommended not to change this - since Apps will be expecting the api at /obp/+version

obp-api/src/main/scala/bootstrap/http4s/Http4sServer.scala

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,24 @@ package bootstrap.http4s
22

33
import cats.effect._
44
import code.api.util.APIUtil
5-
import code.api.util.http4s.Http4sApp
5+
import code.api.util.http4s.{Http4sApp, Http4sConfigUtil}
66
import com.comcast.ip4s._
7-
import org.http4s.Uri
87
import org.http4s.ember.server._
98

109
object Http4sServer extends IOApp {
1110

1211
//Start OBP relevant objects and settings; this step MUST be executed first
1312
// new bootstrap.http4s.Http4sBoot().boot
1413
new bootstrap.liftweb.Boot().boot
15-
16-
// Parse hostname - support both "127.0.0.1" and "http://127.0.0.1" formats
17-
private def parseHostname(hostnameValue: String): String = {
18-
val trimmed = hostnameValue.trim
19-
// Try to parse as URI first
20-
Uri.fromString(trimmed).toOption
21-
.flatMap(_.host.map(_.renderString))
22-
.getOrElse(trimmed) // If not a valid URI, use as-is
23-
}
24-
25-
val host = parseHostname(code.api.Constant.HostName)
14+
15+
// Get bind address: use bind_address prop if set, otherwise parse from hostname
16+
// Note: hostname prop must remain unchanged as it may be used for local_provider_name fallback
17+
val host = Http4sConfigUtil.parseHostname(APIUtil.getPropsValue("bind_address",code.api.Constant.HostName))
2618
val port = APIUtil.getPropsAsIntValue("dev.port",8080)
2719

2820
// Use shared httpApp configuration (same as tests)
2921
val httpApp = Http4sApp.httpApp
30-
22+
3123
override def run(args: List[String]): IO[ExitCode] = EmberServerBuilder
3224
.default[IO]
3325
.withHost(Host.fromString(host).get)

obp-api/src/main/scala/code/api/util/http4s/Http4sSupport.scala

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,3 +436,35 @@ object ResourceDocMatcher {
436436
)
437437
}
438438
}
439+
440+
/**
441+
* Http4s configuration utilities.
442+
*/
443+
object Http4sConfigUtil {
444+
445+
/**
446+
* Parse hostname from a string that may be either a plain host or a full URI.
447+
*
448+
* Supports both formats:
449+
* - Plain host: "127.0.0.1" or "localhost"
450+
* - Full URI: "http://127.0.0.1:8080" or "https://example.com"
451+
*
452+
* @param hostnameValue The hostname or URI string to parse
453+
* @return The extracted hostname/IP address
454+
*
455+
* Examples:
456+
* {{{
457+
* parseHostname("127.0.0.1") // Returns: "127.0.0.1"
458+
* parseHostname("http://127.0.0.1:8080") // Returns: "127.0.0.1"
459+
* parseHostname("https://api.example.com") // Returns: "api.example.com"
460+
* parseHostname("localhost") // Returns: "localhost"
461+
* }}}
462+
*/
463+
def parseHostname(hostnameValue: String): String = {
464+
val trimmed = hostnameValue.trim
465+
// Try to parse as URI first
466+
Uri.fromString(trimmed).toOption
467+
.flatMap(_.host.map(_.renderString))
468+
.getOrElse(trimmed) // If not a valid URI, use as-is
469+
}
470+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package code.api.util.http4s
2+
3+
import org.scalatest.{FlatSpec, Matchers}
4+
5+
class Http4sConfigUtilTest extends FlatSpec with Matchers {
6+
7+
"parseHostname" should "extract hostname from plain IP address" in {
8+
Http4sConfigUtil.parseHostname("127.0.0.1") shouldBe "127.0.0.1"
9+
}
10+
11+
it should "extract hostname from HTTP URI" in {
12+
Http4sConfigUtil.parseHostname("http://127.0.0.1:8080") shouldBe "127.0.0.1"
13+
}
14+
15+
it should "extract hostname from HTTPS URI" in {
16+
Http4sConfigUtil.parseHostname("https://api.example.com") shouldBe "api.example.com"
17+
}
18+
19+
it should "handle localhost" in {
20+
Http4sConfigUtil.parseHostname("localhost") shouldBe "localhost"
21+
}
22+
23+
it should "handle URI with path" in {
24+
Http4sConfigUtil.parseHostname("http://example.com/path") shouldBe "example.com"
25+
}
26+
27+
it should "trim whitespace" in {
28+
Http4sConfigUtil.parseHostname(" 127.0.0.1 ") shouldBe "127.0.0.1"
29+
}
30+
31+
it should "handle URI with port" in {
32+
Http4sConfigUtil.parseHostname("http://localhost:8080") shouldBe "localhost"
33+
}
34+
35+
it should "handle domain names" in {
36+
Http4sConfigUtil.parseHostname("example.com") shouldBe "example.com"
37+
}
38+
39+
it should "handle full URL with protocol, port and path" in {
40+
Http4sConfigUtil.parseHostname("https://api.example.com:443/v1/endpoint") shouldBe "api.example.com"
41+
}
42+
}

release_notes.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@
33
### Most recent changes at top of file
44
```
55
Date Commit Action
6-
12/12/2025 f2e7b827 Http4s runner configuration
7-
Added http4s.host and http4s.port to props sample template:
8-
- http4s.host=127.0.0.1
9-
- http4s.port=8086
10-
These properties control the bind address of bootstrap.http4s.Http4sServer
11-
when running via the obp-http4s-runner fat JAR.
6+
27/02/2026 24035862 Http4s server bind address configuration
7+
Added bind_address property for http4s server configuration:
8+
- bind_address: Optional property to specify the network binding address
9+
- Falls back to parsing hostname property if not set
10+
- Maintains backward compatibility with existing hostname configuration
1211
11/12/2025 3c2df942 BREAKING CHANGE: Migration from Akka to Apache Pekko™ 1.1.2
1312
Replaced Akka 2.5.32 with Apache Pekko™ 1.1.2 to address Akka licensing changes.
1413
Updated all imports from com.typesafe.akka to org.apache.pekko.

0 commit comments

Comments
 (0)