diff --git a/HISTORY.md b/HISTORY.md
index 39a44971..e653e25b 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -359,6 +359,10 @@ Response:
Other Improvements:
+- New [apps](https://github.com/kataras/iris/tree/master/apps) subpackage. [Example of usage](https://github.com/kataras/iris/tree/master/_examples/routing/subdomains/redirect/multi-instances).
+
+![apps image example](https://user-images.githubusercontent.com/22900943/90459288-8a54f400-e109-11ea-8dea-20631975c9fc.png)
+
- Fix `AutoTLS` when used with `iris.TLSNoRedirect` [*](https://github.com/kataras/iris/issues/1577). The `AutoTLS` runner can be customized through the new `iris.AutoTLSNoRedirect` instead, read its go documentation. Example of having both TLS and non-TLS versions of the same application without conflicts with letsencrypt `./well-known` path:
![](https://iris-go.com/images/github/autotls-1.png)
diff --git a/_examples/apidoc/yaag/go.mod b/_examples/apidoc/yaag/go.mod
index e1c27c2f..e0c9281a 100644
--- a/_examples/apidoc/yaag/go.mod
+++ b/_examples/apidoc/yaag/go.mod
@@ -4,5 +4,5 @@ go 1.15
require (
github.com/betacraft/yaag v1.0.1-0.20200719063524-47d781406108
- github.com/kataras/iris/v12 v12.1.9-0.20200812051831-0edf0affb0bd
+ github.com/kataras/iris/v12 vv12.1.9-0.20200817185317-589c8c6242ce
)
diff --git a/_examples/database/mongodb/go.mod b/_examples/database/mongodb/go.mod
index 511a8000..6e3205a6 100644
--- a/_examples/database/mongodb/go.mod
+++ b/_examples/database/mongodb/go.mod
@@ -4,6 +4,6 @@ go 1.15
require (
github.com/joho/godotenv v1.3.0
- github.com/kataras/iris/v12 v12.1.9-0.20200812051831-0edf0affb0bd
+ github.com/kataras/iris/v12 vv12.1.9-0.20200817185317-589c8c6242ce
go.mongodb.org/mongo-driver v1.3.4
)
diff --git a/_examples/database/mysql/go.mod b/_examples/database/mysql/go.mod
index 3e7d3e76..d25896ab 100644
--- a/_examples/database/mysql/go.mod
+++ b/_examples/database/mysql/go.mod
@@ -4,6 +4,6 @@ go 1.15
require (
github.com/go-sql-driver/mysql v1.5.0
- github.com/kataras/iris/v12 v12.1.9-0.20200812051831-0edf0affb0bd
+ github.com/kataras/iris/v12 vv12.1.9-0.20200817185317-589c8c6242ce
github.com/mailgun/groupcache/v2 v2.1.0
)
diff --git a/_examples/kafka-api/go.mod b/_examples/kafka-api/go.mod
index 101fed8b..b6519424 100644
--- a/_examples/kafka-api/go.mod
+++ b/_examples/kafka-api/go.mod
@@ -4,5 +4,5 @@ go 1.15
require (
github.com/Shopify/sarama v1.26.4
- github.com/kataras/iris/v12 v12.1.9-0.20200812051831-0edf0affb0bd
+ github.com/kataras/iris/v12 vv12.1.9-0.20200817185317-589c8c6242ce
)
diff --git a/_examples/logging/rollbar/go.mod b/_examples/logging/rollbar/go.mod
index 6a3e5ca1..a5e37ffb 100644
--- a/_examples/logging/rollbar/go.mod
+++ b/_examples/logging/rollbar/go.mod
@@ -3,6 +3,6 @@ module github.com/kataras/iris/examples/logging/rollbar
go 1.15
require (
- github.com/kataras/iris/v12 v12.1.9-0.20200812051831-0edf0affb0bd
+ github.com/kataras/iris/v12 vv12.1.9-0.20200817185317-589c8c6242ce
github.com/rollbar/rollbar-go v1.2.0
)
diff --git a/_examples/mvc/overview/go.mod b/_examples/mvc/overview/go.mod
index cb0cb9cd..8d8ffd70 100644
--- a/_examples/mvc/overview/go.mod
+++ b/_examples/mvc/overview/go.mod
@@ -2,4 +2,4 @@ module app
go 1.15
-require github.com/kataras/iris/v12 v12.1.9-0.20200812051831-0edf0affb0bd
+require github.com/kataras/iris/v12 vv12.1.9-0.20200817185317-589c8c6242ce
diff --git a/_examples/routing/subdomains/redirect/hosts b/_examples/routing/subdomains/redirect/hosts
index c4c06478..b4cd51fe 100644
--- a/_examples/routing/subdomains/redirect/hosts
+++ b/_examples/routing/subdomains/redirect/hosts
@@ -1,4 +1,5 @@
127.0.0.1 mydomain.com
127.0.0.1 www.mydomain.com
+127.0.0.1 otherdomain.com
# Windows: Drive:/Windows/system32/drivers/etc/hosts, on Linux: /etc/hosts
\ No newline at end of file
diff --git a/_examples/routing/subdomains/redirect/main_test.go b/_examples/routing/subdomains/redirect/main_test.go
deleted file mode 100644
index 9e4410cf..00000000
--- a/_examples/routing/subdomains/redirect/main_test.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package main
-
-import (
- "fmt"
- "strings"
- "testing"
-
- "github.com/kataras/iris/v12/httptest"
-)
-
-func TestSubdomainRedirectWWW(t *testing.T) {
- app := newApp()
- root := strings.TrimSuffix(addr, ":80")
-
- e := httptest.New(t, app)
-
- tests := []struct {
- path string
- response string
- }{
- {"/", fmt.Sprintf("This is the www.%s endpoint.", root)},
- {"/users", fmt.Sprintf("This is the www.%s/users endpoint.", root)},
- {"/users/login", fmt.Sprintf("This is the www.%s/users/login endpoint.", root)},
- }
-
- for _, test := range tests {
- e.GET(test.path).Expect().Status(httptest.StatusOK).Body().Equal(test.response)
- e.GET(test.path).WithURL("www.mydomain.com").Expect().Status(httptest.StatusOK).Body().Equal(test.response)
- }
-}
diff --git a/_examples/routing/subdomains/redirect/multi-instances/go.mod b/_examples/routing/subdomains/redirect/multi-instances/go.mod
new file mode 100644
index 00000000..b3957171
--- /dev/null
+++ b/_examples/routing/subdomains/redirect/multi-instances/go.mod
@@ -0,0 +1,7 @@
+module github.com/kataras/iris/_examples/routing/subdomains/redirect/multi-instances
+
+go 1.15
+
+require github.com/kataras/iris/v12 v12.1.9-0.20200817185317-589c8c6242ce
+
+replace github.com/kataras/iris/v12 => ../../../../../
\ No newline at end of file
diff --git a/_examples/routing/subdomains/redirect/multi-instances/main.go b/_examples/routing/subdomains/redirect/multi-instances/main.go
index 2c0bffa8..d3e59279 100644
--- a/_examples/routing/subdomains/redirect/multi-instances/main.go
+++ b/_examples/routing/subdomains/redirect/multi-instances/main.go
@@ -1,82 +1,70 @@
package main
import (
- "net/http"
+ _ "github.com/kataras/iris/_examples/routing/subdomains/redirect/multi-instances/other"
+ _ "github.com/kataras/iris/_examples/routing/subdomains/redirect/multi-instances/root"
"github.com/kataras/iris/v12"
+ "github.com/kataras/iris/v12/apps"
)
+// In this example, you wanna use three different applications exposed as one.
+// The first one is the "other" package, the second is the "root",
+// the third is the switcher application which will expose the above.
+// Unlike the previous example, on this one we will NOT redirect,
+// the Hosts switcher will just pass the request to the matched Application to handle.
+// This is NOT an alternative of your favorite load balancer.
+// Read the comments carefully, if you need more information
+// you can head over to the "apps" package's godocs and tests.
func main() {
- app := iris.New()
-
- hosts := map[string]*iris.Application{
- "mydomain.com": createRoot("www.mydomain.com"), // redirects to www.
- "www.mydomain.com": createWWW(),
- "test.mydomain.com": createTest(),
- }
- for _, r := range hosts {
- r.Build()
- }
-
- app.Downgrade(func(w http.ResponseWriter, r *http.Request) {
- host := r.Host
- if host == "" {
- host = r.URL.Host
- }
-
- if router, ok := hosts[host]; ok {
- router.ServeHTTP(w, r)
- return
- }
-
- http.NotFound(w, r)
+ // The `apps.Hosts` switch provider:
+ // The pattern. A regexp for matching the host part of incoming requests.
+ // The target. An iris.Application instance (created by iris.New())
+ // OR
+ // You can use the Application's name (app.SetName("myapp")).
+ // Example:
+ // package rootdomain
+ // func init() {
+ // app := iris.New().SetName("root app")
+ // ...
+ // }
+ // On the main package add an empty import statement: ` _ import "rootdomain"`
+ // And set the "root app" as the key to reference that application (of the same program).
+ // Thats the target we wanna use now ^ (see ../hosts file).
+ // OR
+ // An external host or a local running in the same machine but different port or host behind proxy.
+ switcher := apps.Switch(apps.Hosts{
+ {"^(www.)?mydomain.com$", "root app"},
+ {"^otherdomain.com$", "other app"},
})
+ // The registration order matters, so we can register a fallback server (when host no match)
+ // using "*". However, you have alternatives by using the Switch Iris Application value
+ // (let's call it "switcher"):
+ // 1. Handle the not founds, e.g. switcher.OnErrorCode(404, ...)
+ // 2. Use the switcher.WrapRouter, e.g. to log the flow of a request of all hosts exposed.
+ // 3. Just register routes to match, e.g. switcher.Get("/", ...)
+ switcher.Get("/", fallback)
+ // OR
+ // Change the response code to 502
+ // instead of 404 and write a message:
+ // switcher.OnErrorCode(iris.StatusNotFound, fallback)
- app.Listen(":80")
+ // The switcher is a common Iris Application, so you have access to the Iris features.
+ // And it should be listening to a host:port in order to match and serve its apps.
+ //
+ // http://mydomain.com (OK)
+ // http://www.mydomain.com (OK)
+ // http://mydomain.com/dsa (404)
+ // http://no.mydomain.com (502 Bad Host)
+ //
+ // http://otherdomain.com (OK)
+ // http://www.otherdomain.com (502 Bad Host)
+ // http://otherdomain.com/dsa (404 JSON)
+ // ...
+ switcher.Listen(":80")
}
-func createRoot(redirectTo string) *iris.Application {
- app := iris.New()
- app.Downgrade(func(w http.ResponseWriter, r *http.Request) {
- fullScheme := "http://"
- if r.TLS != nil {
- fullScheme = "https://"
- }
-
- http.Redirect(w, r, fullScheme+redirectTo+r.URL.RequestURI(), iris.StatusMovedPermanently)
- })
-
- return app
-}
-
-func createWWW() *iris.Application {
- app := iris.New()
- app.Get("/", index)
-
- users := app.Party("/users")
- users.Get("/", usersIndex)
- users.Get("/login", getLogin)
-
- return app
-}
-
-func createTest() *iris.Application {
- app := iris.New()
- app.Get("/", func(ctx iris.Context) {
- ctx.WriteString("Test Index")
- })
-
- return app
-}
-
-func index(ctx iris.Context) {
- ctx.Writef("This is the www.mydomain.com endpoint.")
-}
-
-func usersIndex(ctx iris.Context) {
- ctx.Writef("This is the www.mydomain.com/users endpoint.")
-}
-
-func getLogin(ctx iris.Context) {
- ctx.Writef("This is the www.mydomain.com/users/login endpoint.")
+func fallback(ctx iris.Context) {
+ ctx.StatusCode(iris.StatusBadGateway)
+ ctx.Writef("Bad Host %s", ctx.Host())
}
diff --git a/_examples/routing/subdomains/redirect/multi-instances/other/server.go b/_examples/routing/subdomains/redirect/multi-instances/other/server.go
new file mode 100644
index 00000000..7452a406
--- /dev/null
+++ b/_examples/routing/subdomains/redirect/multi-instances/other/server.go
@@ -0,0 +1,30 @@
+package other
+
+import (
+ "time"
+
+ "github.com/kataras/iris/v12"
+)
+
+func init() {
+ app := iris.New()
+ app.SetName("other app")
+
+ app.OnAnyErrorCode(handleErrors)
+ app.Get("/", index)
+}
+
+func index(ctx iris.Context) {
+ ctx.HTML("Other Index (App Name: %s | Host: %s)",
+ ctx.Application().String(), ctx.Host())
+}
+
+func handleErrors(ctx iris.Context) {
+ errCode := ctx.GetStatusCode()
+ ctx.JSON(iris.Map{
+ "Server": ctx.Application().String(),
+ "Code": errCode,
+ "Message": iris.StatusText(errCode),
+ "Timestamp": time.Now().Unix(),
+ })
+}
diff --git a/_examples/routing/subdomains/redirect/multi-instances/root/server.go b/_examples/routing/subdomains/redirect/multi-instances/root/server.go
new file mode 100644
index 00000000..79aa9792
--- /dev/null
+++ b/_examples/routing/subdomains/redirect/multi-instances/root/server.go
@@ -0,0 +1,15 @@
+package root
+
+import "github.com/kataras/iris/v12"
+
+func init() {
+ app := iris.New()
+ app.SetName("root app")
+
+ app.Get("/", index)
+}
+
+func index(ctx iris.Context) {
+ ctx.HTML("Main Root Index (App Name: %s | Host: %s)",
+ ctx.Application().String(), ctx.Host())
+}
diff --git a/_examples/sessions/database/redis/go.mod b/_examples/sessions/database/redis/go.mod
index 549a5828..90822d02 100644
--- a/_examples/sessions/database/redis/go.mod
+++ b/_examples/sessions/database/redis/go.mod
@@ -2,5 +2,5 @@ module app
go 1.15
-require github.com/kataras/iris/v12 v12.1.9-0.20200812051831-0edf0affb0bd
+require github.com/kataras/iris/v12 vv12.1.9-0.20200817185317-589c8c6242ce
diff --git a/_examples/websocket/socketio/go.mod b/_examples/websocket/socketio/go.mod
index 61b7561a..673a246e 100644
--- a/_examples/websocket/socketio/go.mod
+++ b/_examples/websocket/socketio/go.mod
@@ -4,5 +4,5 @@ go 1.15
require (
github.com/googollee/go-socket.io v1.4.3-0.20191109153049-7451e2f8c2e0
- github.com/kataras/iris/v12 v12.1.9-0.20200812051831-0edf0affb0bd
+ github.com/kataras/iris/v12 vv12.1.9-0.20200817185317-589c8c6242ce
)
diff --git a/apps/switch.go b/apps/switch.go
index 5d7aa233..73aa8cfc 100644
--- a/apps/switch.go
+++ b/apps/switch.go
@@ -1,6 +1,8 @@
package apps
import (
+ "strings"
+
"github.com/kataras/iris/v12"
)
@@ -33,11 +35,18 @@ func Switch(providers ...SwitchProvider) *iris.Application {
panic("iris: switch: empty providers")
}
+ var friendlyAddrs []string
var cases []SwitchCase
for _, p := range providers {
for _, c := range p.GetSwitchCases() {
cases = append(cases, c)
}
+
+ if fp, ok := p.(FriendlyNameProvider); ok {
+ if friendlyName := fp.GetFriendlyName(); friendlyName != "" {
+ friendlyAddrs = append(friendlyAddrs, friendlyName)
+ }
+ }
}
if len(cases) == 0 {
@@ -61,7 +70,7 @@ func Switch(providers ...SwitchProvider) *iris.Application {
app.UseRouter(func(ctx iris.Context) {
for _, c := range cases {
if c.Filter(ctx) {
- c.App.ServeHTTP(ctx.ResponseWriter().Naive(), ctx.Request())
+ c.App.ServeHTTP(ctx.ResponseWriter(), ctx.Request())
// if c.App.Downgraded() {
// c.App.ServeHTTP(ctx.ResponseWriter(), ctx.Request())
@@ -81,6 +90,12 @@ func Switch(providers ...SwitchProvider) *iris.Application {
ctx.Next()
})
+ // Configure the switcher's supervisor.
+ app.ConfigureHost(func(su *iris.Supervisor) {
+ if len(friendlyAddrs) > 0 {
+ su.FriendlyAddr = strings.Join(friendlyAddrs, ", ")
+ }
+ })
return app
}
@@ -88,8 +103,8 @@ type (
// SwitchCase contains the filter
// and the matched Application instance.
SwitchCase struct {
- Filter iris.Filter
- App *iris.Application
+ Filter iris.Filter // Filter runs against the Switcher.
+ App *iris.Application // App is the main target application responsible to handle the request.
}
// A SwitchProvider should return the switch cases.
@@ -100,6 +115,12 @@ type (
GetSwitchCases() []SwitchCase
}
+ // FriendlyNameProvider can be optionally implemented by providers
+ // to customize the Switcher's Supervisor.FriendlyAddr field (Startup log).
+ FriendlyNameProvider interface {
+ GetFriendlyName() string
+ }
+
// Join returns a new slice which joins different type of switch cases.
Join []SwitchProvider
)
diff --git a/apps/switch_hosts.go b/apps/switch_hosts.go
index f143d4f7..36bfd858 100644
--- a/apps/switch_hosts.go
+++ b/apps/switch_hosts.go
@@ -5,6 +5,7 @@ import (
"net/http"
"net/url"
"regexp"
+ "strings"
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/context"
@@ -53,6 +54,18 @@ func (hosts Hosts) GetSwitchCases() []SwitchCase {
return cases
}
+// GetFriendlyName implements the FriendlyNameProvider.
+func (hosts Hosts) GetFriendlyName() string {
+ var patterns []string
+ for _, host := range hosts {
+ if strings.TrimSpace(host.Pattern) != "" {
+ patterns = append(patterns, host.Pattern)
+ }
+ }
+
+ return strings.Join(patterns, ", ")
+}
+
func hostApp(host Host) *iris.Application {
if host.Target == nil {
return nil
diff --git a/core/host/supervisor.go b/core/host/supervisor.go
index 546f35d2..1551cdb5 100644
--- a/core/host/supervisor.go
+++ b/core/host/supervisor.go
@@ -30,8 +30,9 @@ type Configurator func(su *Supervisor)
//
// Interfaces are separated to return relative functionality to them.
type Supervisor struct {
- Server *http.Server
- friendlyAddr string // e.g mydomain.com instead of :443 when AutoTLS is used, see `WriteStartupLogOnServe` task.
+ Server *http.Server
+ // FriendlyAddr can be set to customize the "Now Listening on: {FriendlyAddr}".
+ FriendlyAddr string // e.g mydomain.com instead of :443 when AutoTLS is used, see `WriteStartupLogOnServe` task.
disableHTTP1ToHTTP2Redirection bool
closedManually uint32 // future use, accessed atomically (non-zero means we've called the Shutdown)
closedByInterruptHandler uint32 // non-zero means that the end-developer interrupted it by-purpose.
@@ -350,7 +351,7 @@ func (su *Supervisor) ListenAndServeAutoTLS(domain string, email string, cacheDi
if strings.TrimSpace(domain) != "" {
domains := strings.Split(domain, " ")
- su.friendlyAddr = domains[0]
+ su.FriendlyAddr = strings.Join(domains, ", ")
hostPolicy = autocert.HostWhitelist(domains...)
}
diff --git a/core/host/task.go b/core/host/task.go
index 3fd10652..7a4f030d 100644
--- a/core/host/task.go
+++ b/core/host/task.go
@@ -23,7 +23,7 @@ import (
func WriteStartupLogOnServe(w io.Writer) func(TaskHost) {
return func(h TaskHost) {
guessScheme := netutil.ResolveScheme(h.Supervisor.manuallyTLS || h.Supervisor.Fallback != nil)
- addr := h.Supervisor.friendlyAddr
+ addr := h.Supervisor.FriendlyAddr
if addr == "" {
addr = h.Supervisor.Server.Addr
}