Part 3.


Former-commit-id: 229b86baca4043c69517968318d9a962d2e026d0
This commit is contained in:
Gerasimos (Makis) Maropoulos 2017-03-24 02:25:00 +02:00
parent 7c5d7cae05
commit 7a6cf4c5aa
18 changed files with 558 additions and 24 deletions

View File

@ -23,6 +23,10 @@ Developers should read the official [documentation](https://godoc.org/gopkg.in/k
* [Favicon](beginner/favicon/main.go)
* [File Server](beginner/file-server/main.go)
* [Send Files](beginner/send-files/main.go)
* [Stream Writer](beginner/stream-writer/main.go)
* [Listen UNIX Socket](beginner/listen-unix/main.go)
* [Listen TLS](beginner/listen-tls/main.go)
* [Listen Letsencrypt (Automatic Certifications)](beginner/listen-letsencrypt/main.go)
* [Level: Intermediate](intermediate)
* [Send An E-mail](intermediate/e-mail/main.go)
* [Upload/Read Files](intermediate/upload-files/main.go)
@ -34,6 +38,8 @@ Developers should read the official [documentation](https://godoc.org/gopkg.in/k
* [Localization and Internationalization](intermediate/i18n/main.go)
* [Recovery](intermediate/recover/main.go)
* [Graceful Shutdown](intermediate/graceful-shutdown/main.go)
* [Custom TCP Listener](intermediate/custom-listener/main.go)
* [Custom HTTP Server](intermediate/custom-httpserver/main.go)
* [View Engine](intermediate/view)
* [Overview](intermediate/view/overview/main.go)
* [Embedding Templates Into Executable](intermediate/embedding-templates-into-app)
@ -58,10 +64,15 @@ Developers should read the official [documentation](https://godoc.org/gopkg.in/k
* [Secure](intermediate/websockets/secure/main.go)
* [Custom Go Client](intermediate/websockets/custom-go-client/main.go)
* [Level: Advanced](advanced)
* [Transactions](advanced/transactions/main.go)
* [HTTP Testing](advanced/httptest/main_test.go)
* [Watch & Compile Typescript source files](advanced/typescript/main.go)
* [Cloud Editor](advanced/cloud-editor/main.go)
* [Online Visitors](advanced/online-visitors/main.go)
* [URL Shortener using BoltDB](advanced/url-shortener/main.go)
* [Subdomains](advanced/subdomains)
* [Single](advanced/subdomains/single/main.go)
* [Multi](advanced/subdomains/multi/main.go)
* [Wildcard](advanced/subdomains/wildcard/main.go)
> Take look at the [community examples](https://github.com/iris-contrib/examples) too!

View File

@ -0,0 +1,28 @@
# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
# 102.54.94.97 rhino.acme.com # source server
# 38.25.63.10 x.acme.com # x client host
# localhost name resolution is handled within DNS itself.
127.0.0.1 localhost
::1 localhost
#-IRIS-For development machine, you have to configure your dns also for online, search google how to do it if you don't know
127.0.0.1 domain.local
127.0.0.1 system.domain.local
127.0.0.1 dashboard.domain.local
#-END IRIS-

View File

@ -0,0 +1,39 @@
package main
import (
"gopkg.in/kataras/iris.v6"
"gopkg.in/kataras/iris.v6/adaptors/httprouter"
)
func main() {
app := iris.New()
app.Adapt(iris.DevLogger())
// subdomains works with all available routers, like other features too.
app.Adapt(httprouter.New())
/*
* Setup static files
*/
app.StaticWeb("/assets", "./public/assets")
app.StaticWeb("/upload_resources", "./public/upload_resources")
dashboard := app.Party("dashboard.")
{
dashboard.Get("/", func(ctx *iris.Context) {
ctx.Writef("HEY FROM dashboard")
})
}
system := app.Party("system.")
{
system.Get("/", func(ctx *iris.Context) {
ctx.Writef("HEY FROM system")
})
}
app.Get("/", func(ctx *iris.Context) {
ctx.Writef("HEY FROM frontend /")
})
/* test this on firefox, because the domain is not real (because of .local), on firefox this will fail, but you can test it with other domain */
app.Listen("domain.local:80") // for beginners: look ../hosts file
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

@ -0,0 +1,27 @@
# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
# 102.54.94.97 rhino.acme.com # source server
# 38.25.63.10 x.acme.com # x client host
# localhost name resolution is handled within DNS itself.
127.0.0.1 localhost
::1 localhost
#-IRIS-For development machine, you have to configure your dns also for online, search google how to do it if you don't know
127.0.0.1 mydomain.com
127.0.0.1 admin.mydomain.com
#-END IRIS-

View File

@ -0,0 +1,43 @@
// Package main register static subdomains, simple as parties, check ./hosts if you use windows
package main
import (
"gopkg.in/kataras/iris.v6"
"gopkg.in/kataras/iris.v6/adaptors/httprouter"
)
func main() {
app := iris.New()
app.Adapt(iris.DevLogger())
// subdomains works with all available routers, like other features too.
app.Adapt(httprouter.New())
// no order, you can register subdomains at the end also.
admin := app.Party("admin.")
{
// admin.mydomain.com
admin.Get("/", func(c *iris.Context) {
c.Writef("INDEX FROM admin.mydomain.com")
})
// admin.mydomain.com/hey
admin.Get("/hey", func(c *iris.Context) {
c.Writef("HEY FROM admin.mydomain.com/hey")
})
// admin.mydomain.com/hey2
admin.Get("/hey2", func(c *iris.Context) {
c.Writef("HEY SECOND FROM admin.mydomain.com/hey")
})
}
// mydomain.com/
app.Get("/", func(c *iris.Context) {
c.Writef("INDEX FROM no-subdomain hey")
})
// mydomain.com/hey
app.Get("/hey", func(c *iris.Context) {
c.Writef("HEY FROM no-subdomain hey")
})
app.Listen("mydomain.com:80") // for beginners: look ../hosts file
}

View File

@ -0,0 +1,30 @@
# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
# 102.54.94.97 rhino.acme.com # source server
# 38.25.63.10 x.acme.com # x client host
# localhost name resolution is handled within DNS itself.
127.0.0.1 localhost
::1 localhost
#-IRIS-For development machine, you have to configure your dns also for online, search google how to do it if you don't know
127.0.0.1 mydomain.com
127.0.0.1 username1.mydomain.com
127.0.0.1 username2.mydomain.com
127.0.0.1 username3.mydomain.com
127.0.0.1 username4.mydomain.com
127.0.0.1 username5.mydomain.com
#-END IRIS-

View File

@ -0,0 +1,71 @@
// Package main an example on how to catch dynamic subdomains - wildcard.
// On the first example (subdomains_1) we saw how to create routes for static subdomains, subdomains you know that you will have.
// Here we will see an example how to catch unknown subdomains, dynamic subdomains, like username.mydomain.com:8080.
package main
import (
"gopkg.in/kataras/iris.v6"
"gopkg.in/kataras/iris.v6/adaptors/httprouter"
)
// register a dynamic-wildcard subdomain to your server machine(dns/...) first, check ./hosts if you use windows.
// run this file and try to redirect: http://username1.mydomain.com:8080/ , http://username2.mydomain.com:8080/ , http://username1.mydomain.com/something, http://username1.mydomain.com/something/sadsadsa
func main() {
app := iris.New()
app.Adapt(iris.DevLogger())
// subdomains works with all available routers, like other features too.
app.Adapt(httprouter.New())
/* Keep note that you can use both type of subdomains (named and wildcard(*.) )
admin.mydomain.com, and for other the Party(*.) but this is not this example's purpose
admin := app.Party("admin.")
{
// admin.mydomain.com
admin.Get("/", func(ctx *iris.Context) {
ctx.Writef("INDEX FROM admin.mydomain.com")
})
// admin.mydomain.com/hey
admin.Get("/hey", func(ctx *iris.Context) {
ctx.Writef("HEY FROM admin.mydomain.com/hey")
})
// admin.mydomain.com/hey2
admin.Get("/hey2", func(ctx *iris.Context) {
ctx.Writef("HEY SECOND FROM admin.mydomain.com/hey")
})
}*/
// no order, you can register subdomains at the end also.
dynamicSubdomains := app.Party("*.")
{
dynamicSubdomains.Get("/", dynamicSubdomainHandler)
dynamicSubdomains.Get("/something", dynamicSubdomainHandler)
dynamicSubdomains.Get("/something/:param1", dynamicSubdomainHandlerWithParam)
}
app.Get("/", func(ctx *iris.Context) {
ctx.Writef("Hello from mydomain.com path: %s", ctx.Path())
})
app.Get("/hello", func(ctx *iris.Context) {
ctx.Writef("Hello from mydomain.com path: %s", ctx.Path())
})
app.Listen("mydomain.com:8080") // for beginners: look ../hosts file
}
func dynamicSubdomainHandler(ctx *iris.Context) {
username := ctx.Subdomain()
ctx.Writef("Hello from dynamic subdomain path: %s, here you can handle the route for dynamic subdomains, handle the user: %s", ctx.Path(), username)
// if http://username4.mydomain.com:8080/ prints:
// Hello from dynamic subdomain path: /, here you can handle the route for dynamic subdomains, handle the user: username4
}
func dynamicSubdomainHandlerWithParam(ctx *iris.Context) {
username := ctx.Subdomain()
ctx.Writef("Hello from dynamic subdomain path: %s, here you can handle the route for dynamic subdomains, handle the user: %s", ctx.Path(), username)
ctx.Writef("THE PARAM1 is: %s", ctx.Param("param1"))
}

View File

@ -0,0 +1,56 @@
package main
import (
"gopkg.in/kataras/iris.v6"
"gopkg.in/kataras/iris.v6/adaptors/httprouter"
)
func main() {
app := iris.New()
app.Adapt(iris.DevLogger())
// subdomains works with all available routers, like other features too.
app.Adapt(httprouter.New())
app.Get("/", func(ctx *iris.Context) {
ctx.BeginTransaction(func(t *iris.Transaction) {
// OPTIONAl STEP: , if true then the next transictions will not be executed if this transiction fails
// t.SetScope(iris.RequestTransactionScope)
// OPTIONAL STEP:
// create a new custom type of error here to keep track of the status code and reason message
err := iris.NewTransactionErrResult()
// we should use t.Context if we want to rollback on any errors lives inside this function clojure.
t.Context.Text(iris.StatusOK, "Blablabla this should not be sent to the client because we will fill the err with a message and status")
// virtualize a fake error here, for the shake of the example
fail := true
if fail {
err.StatusCode = iris.StatusInternalServerError
// NOTE: if empty reason then the default or the custom http error will be fired (like ctx.EmitError)
err.Reason = "Error: Virtual failure!!"
}
// OPTIONAl STEP:
// but useful if we want to post back an error message to the client if the transaction failed.
// if the reason is empty then the transaction completed succesfuly,
// otherwise we rollback the whole response writer's body,
// headers and cookies, status code and everything lives inside this transaction
t.Complete(err)
})
ctx.BeginTransaction(func(t *iris.Transaction) {
t.Context.HTML(iris.StatusOK,
"<h1>This will sent at all cases because it lives on different transaction and it doesn't fails</h1>")
// * if we don't have any 'throw error' logic then no need of scope.Complete()
})
// OPTIONAL, depends on the usage:
// at any case, what ever happens inside the context's transactions send this to the client
ctx.HTML(iris.StatusOK, "<h1>Let's add a second html message to the response, "+
"if the transaction was failed and it was request scoped then this message would "+
"not been shown. But it has a transient scope(default) so, it is visible as expected!</h1>")
})
app.Listen(":8080")
}

View File

@ -0,0 +1,35 @@
// Package main provide one-line integration with letsencrypt.org
package main
import (
"gopkg.in/kataras/iris.v6"
"gopkg.in/kataras/iris.v6/adaptors/httprouter"
)
func main() {
app := iris.New()
// output startup banner and error logs on os.Stdout
app.Adapt(iris.DevLogger())
// set the router, you can choose gorillamux too
app.Adapt(httprouter.New())
app.Get("/", func(ctx *iris.Context) {
ctx.Writef("Hello from SECURE SERVER!")
})
app.Get("/test2", func(ctx *iris.Context) {
ctx.Writef("Welcome to secure server from /test2!")
})
app.Get("/redirect", func(ctx *iris.Context) {
ctx.Redirect("/test2")
})
// This will provide you automatic certification & key from letsencrypt.org's servers
// it also starts a second 'http://' server which will redirect all 'http://$PATH' requests to 'https://$PATH'
// NOTE: may not work on local addresses like this,
// use it on a real domain, because
// it uses the "golang.org/x/crypto/acme/autocert" package.
app.ListenLETSENCRYPT("localhost:443")
}

View File

@ -0,0 +1,37 @@
package main
import (
"gopkg.in/kataras/iris.v6"
"gopkg.in/kataras/iris.v6/adaptors/httprouter"
)
const host = "127.0.0.1:443"
func main() {
app := iris.New()
// output startup banner and error logs on os.Stdout
app.Adapt(iris.DevLogger())
// set the router, you can choose gorillamux too
app.Adapt(httprouter.New())
app.Get("/", func(ctx *iris.Context) {
ctx.Writef("Hello from the SECURE server")
})
app.Get("/mypath", func(ctx *iris.Context) {
ctx.Writef("Hello from the SECURE server on path /mypath")
})
// start a secondary server (HTTP) on port 80, this is a non-blocking func
// redirects all http to the main server which is tls/ssl on port :443
iris.Proxy(":80", "https://"+host)
// start the MAIN server (HTTPS) on port 443, this is a blocking func
app.ListenTLS(host, "mycert.cert", "mykey.key")
// now if you navigate to http://127.0.0.1/mypath it will
// send you back to https://127.0.0.1:443/mypath (https://127.0.0.1/mypath)
//
// go to the listen-letsencrypt example to view how you can integrate your server
// to get automatic certification and key from the letsencrypt.org 's servers.
}

View File

@ -0,0 +1,22 @@
package main
import (
"gopkg.in/kataras/iris.v6"
"gopkg.in/kataras/iris.v6/adaptors/httprouter"
)
const host = "127.0.0.1:443"
func main() {
app := iris.New()
// output startup banner and error logs on os.Stdout
app.Adapt(iris.DevLogger())
// set the router, you can choose gorillamux too
app.Adapt(httprouter.New())
app.Get("/", func(ctx *iris.Context) {
ctx.Writef("Hello from the server")
})
app.ListenUNIX("/tmp/srv.sock", 0666)
}

View File

@ -0,0 +1,56 @@
package main
import (
"fmt" // just an optional helper
"io"
"time" // showcase the delay
"gopkg.in/kataras/iris.v6"
"gopkg.in/kataras/iris.v6/adaptors/httprouter"
)
func main() {
app := iris.New()
// output startup banner and error logs on os.Stdout
app.Adapt(iris.DevLogger())
// set the router, you can choose gorillamux too
app.Adapt(httprouter.New())
timeWaitForCloseStream := 4 * time.Second
app.Get("/", func(ctx *iris.Context) {
i := 0
// goroutine in order to no block and just wait,
// goroutine is OPTIONAL and not a very good option but it depends on the needs
// Look the streaming_simple_2 for an alternative code style
// Send the response in chunks and wait for a second between each chunk.
go ctx.StreamWriter(func(w io.Writer) bool {
i++
fmt.Fprintf(w, "this is a message number %d\n", i) // write
time.Sleep(time.Second) // imaginary delay
if i == 4 {
return false // close and flush
}
return true // continue write
})
// when this handler finished the client should be see the stream writer's contents
// simulate a job here...
time.Sleep(timeWaitForCloseStream)
})
app.Get("/alternative", func(ctx *iris.Context) {
// Send the response in chunks and wait for a second between each chunk.
ctx.StreamWriter(func(w io.Writer) bool {
for i := 1; i <= 4; i++ {
fmt.Fprintf(w, "this is a message number %d\n", i) // write
time.Sleep(time.Second)
}
// when this handler finished the client should be see the stream writer's contents
return false // stop and flush the contents
})
})
app.Listen(":8080")
}

View File

@ -0,0 +1,33 @@
package main
import (
"net/http"
"gopkg.in/kataras/iris.v6"
"gopkg.in/kataras/iris.v6/adaptors/httprouter"
)
func main() {
app := iris.New()
// output startup banner and error logs on os.Stdout
app.Adapt(iris.DevLogger())
// set the router, you can choose gorillamux too
app.Adapt(httprouter.New())
app.Get("/", func(ctx *iris.Context) {
ctx.Writef("Hello from the server")
})
app.Get("/mypath", func(ctx *iris.Context) {
ctx.Writef("Hello from %s", ctx.Path())
})
// call .Boot before use the 'app' as an http.Handler on a custom http.Server
app.Boot()
// create our custom fasthttp server and assign the Handler/Router
fsrv := &http.Server{Handler: app, Addr: ":8080"}
fsrv.ListenAndServe()
// navigate to http://127.0.0.1:8080/mypath
}

View File

@ -0,0 +1,33 @@
package main
import (
"net"
"gopkg.in/kataras/iris.v6"
"gopkg.in/kataras/iris.v6/adaptors/httprouter"
)
func main() {
app := iris.New()
// output startup banner and error logs on os.Stdout
app.Adapt(iris.DevLogger())
// set the router, you can choose gorillamux too
app.Adapt(httprouter.New())
app.Get("/", func(ctx *iris.Context) {
ctx.Writef("Hello from the server")
})
app.Get("/mypath", func(ctx *iris.Context) {
ctx.Writef("Hello from %s", ctx.Path())
})
// create our custom listener
ln, err := net.Listen("tcp4", ":8080")
if err != nil {
panic(err)
}
// use of the custom listener
app.Serve(ln)
}

31
addr.go
View File

@ -37,18 +37,18 @@ func TCPKeepAlive(addr string) (net.Listener, error) {
}
// UNIX returns a new unix(file) Listener
func UNIX(addr string, mode os.FileMode) (net.Listener, error) {
if errOs := os.Remove(addr); errOs != nil && !os.IsNotExist(errOs) {
return nil, errRemoveUnix.Format(addr, errOs.Error())
func UNIX(socketFile string, mode os.FileMode) (net.Listener, error) {
if errOs := os.Remove(socketFile); errOs != nil && !os.IsNotExist(errOs) {
return nil, errRemoveUnix.Format(socketFile, errOs.Error())
}
listener, err := net.Listen("unix", addr)
listener, err := net.Listen("unix", socketFile)
if err != nil {
return nil, errPortAlreadyUsed.AppendErr(err)
}
if err = os.Chmod(addr, mode); err != nil {
return nil, errChmod.Format(mode, addr, err.Error())
if err = os.Chmod(socketFile, mode); err != nil {
return nil, errChmod.Format(mode, socketFile, err.Error())
}
return listener, nil
@ -84,14 +84,16 @@ func CERT(addr string, cert tls.Certificate) (net.Listener, error) {
}
// LETSENCRYPT returns a new Automatic TLS Listener using letsencrypt.org service
// receives two parameters, the first is the domain of the server
// and the second is optionally, the cache directory, if you skip it then the cache directory is "./certcache"
// receives three parameters,
// the first is the host of the server,
// second can be the server name(domain) or empty if skip verification is the expected behavior (not recommended)
// and the third is optionally, the cache directory, if you skip it then the cache directory is "./certcache"
// if you want to disable cache directory then simple give it a value of empty string ""
//
// does NOT supports localhost domains for testing.
//
// this is the recommended function to use when you're ready for production state
func LETSENCRYPT(addr string, cacheDirOptional ...string) (net.Listener, error) {
func LETSENCRYPT(addr string, serverName string, cacheDirOptional ...string) (net.Listener, error) {
if portIdx := strings.IndexByte(addr, ':'); portIdx == -1 {
addr += ":443"
}
@ -109,15 +111,22 @@ func LETSENCRYPT(addr string, cacheDirOptional ...string) (net.Listener, error)
m := autocert.Manager{
Prompt: autocert.AcceptTOS,
} // HostPolicy is missing, if user wants it, then she/he should manually
// configure the autocertmanager and use the `iris.Default.Serve` to pass that listener
if cacheDir == "" {
// then the user passed empty by own will, then I guess she/he doesnt' want any cache directory
} else {
m.Cache = autocert.DirCache(cacheDir)
}
tlsConfig := &tls.Config{GetCertificate: m.GetCertificate}
// use InsecureSkipVerify or ServerName to a value
if serverName == "" {
// if server name is invalid then bypass it
tlsConfig.InsecureSkipVerify = true
} else {
tlsConfig.ServerName = serverName
}
tlsLn := tls.NewListener(ln, tlsConfig)
return tlsLn, nil

30
iris.go
View File

@ -579,6 +579,7 @@ func (s *Framework) Listen(addr string) {
ln, err := TCPKeepAlive(addr)
if err != nil {
s.handlePanic(err)
return
}
s.Must(s.Serve(ln))
@ -620,14 +621,14 @@ func (s *Framework) ListenTLS(addr string, certFile, keyFile string) {
// ListenLETSENCRYPT starts a server listening at the specific nat address
// using key & certification taken from the letsencrypt.org 's servers
// it's also starts a second 'http' server to redirect all 'http://$ADDR_HOSTNAME:80' to the' https://$ADDR'
// it creates a cache file to store the certifications, for performance reasons, this file by-default is "./letsencrypt.cache"
// it creates a cache file to store the certifications, for performance reasons, this file by-default is "./certcache"
// if you skip the second parameter then the cache file is "./letsencrypt.cache"
// if you want to disable cache then simple pass as second argument an empty empty string ""
//
// Note: HTTP/2 Push is not working with LETSENCRYPT, you have to use ListenTLS to enable HTTP/2
// Because net/http's author didn't exported the functions to tell the server that is using HTTP/2...
//
// example: https://github.com/iris-contrib/examples/blob/master/letsencrypt/main.go
// example: https://github.com/kataras/iris/blob/v6/_examples/beginner/listen-letsencrypt/main.go
func (s *Framework) ListenLETSENCRYPT(addr string, cacheFileOptional ...string) {
addr = ParseHost(addr)
@ -643,9 +644,10 @@ func (s *Framework) ListenLETSENCRYPT(addr string, cacheFileOptional ...string)
}
}
ln, err := LETSENCRYPT(addr, cacheFileOptional...)
ln, err := LETSENCRYPT(addr, addr, cacheFileOptional...)
if err != nil {
s.handlePanic(err)
return
}
// starts a second server which listening on HOST:80 to redirect all requests to the HTTPS://HOST:PORT
@ -653,21 +655,23 @@ func (s *Framework) ListenLETSENCRYPT(addr string, cacheFileOptional ...string)
s.Must(s.Serve(ln))
}
// ListenUNIX starts the process of listening to the new requests using a 'socket file', this works only on unix
//
// ListenUNIX starts the process of listening to the new requests using a 'socket file',
// Note: this works only on unix
//
// If you need to manually monitor any error please use `.Serve` instead.
func (s *Framework) ListenUNIX(addr string, mode os.FileMode) {
// *on unix listen we don't parse the host, because sometimes it causes problems to the user
if s.Config.VHost == "" {
s.Config.VHost = addr
// this will be set as the front-end listening addr
}
ln, err := UNIX(addr, mode)
//
// example: https://github.com/kataras/iris/blob/v6/_examples/beginner/listen-unix/main.go
func (s *Framework) ListenUNIX(socketFile string, mode os.FileMode) {
ln, err := UNIX(socketFile, mode)
if err != nil {
s.handlePanic(err)
return
}
// *on unix listen we don't parse the host, because sometimes it causes problems to the user
if s.Config.VHost == "" {
s.Config.VHost = ln.Addr().String()
// this will be set as the front-end listening addr
}
s.Must(s.Serve(ln))
}