mirror of
https://github.com/kataras/iris.git
synced 2025-02-02 15:30:36 +01:00
Add HTTP/2 Example and Websocket wss:// too in the same time :)
Former-commit-id: fd4c12043d6ed739770236e014ccd2f0f4f5a84c
This commit is contained in:
parent
5055546a38
commit
48b470f5da
|
@ -11,7 +11,8 @@ Users already notified for some breaking-changes, this section will help you
|
||||||
to adapt the new changes to your application, it contains an overview of the new features too.
|
to adapt the new changes to your application, it contains an overview of the new features too.
|
||||||
|
|
||||||
- Shutdown with `app.Shutdown(context.Context) error`, no need for any third-parties, with `EventPolicy.Interrupted` and Go's 1.8 Gracefully Shutdown feature you're ready to go!
|
- Shutdown with `app.Shutdown(context.Context) error`, no need for any third-parties, with `EventPolicy.Interrupted` and Go's 1.8 Gracefully Shutdown feature you're ready to go!
|
||||||
- HTTP/2 Go 1.8 `context.Push(target string, opts *http.PushOptions) error` is supported
|
- HTTP/2 Go 1.8 `context.Push(target string, opts *http.PushOptions) error` is supported, example can be found [here](https://github.com/kataras/iris.v6/blob/master/adaptors/websocket/_examples/webocket_secure/main.go)
|
||||||
|
|
||||||
- Router (two lines to add, new features)
|
- Router (two lines to add, new features)
|
||||||
- Template engines (two lines to add, same features as before, except their easier configuration)
|
- Template engines (two lines to add, same features as before, except their easier configuration)
|
||||||
- Basic middleware, that have been written by me, are transfared to the main repository[/middleware](https://github.com/kataras/iris/tree/master/middleware) with a lot of improvements to the `recover middleware` (see the next)
|
- Basic middleware, that have been written by me, are transfared to the main repository[/middleware](https://github.com/kataras/iris/tree/master/middleware) with a lot of improvements to the `recover middleware` (see the next)
|
||||||
|
|
197
adaptors/websocket/_examples/websocket_secure/main.go
Normal file
197
adaptors/websocket/_examples/websocket_secure/main.go
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt" // optional
|
||||||
|
"io/ioutil" // optional
|
||||||
|
"os" // optional
|
||||||
|
"time" // optional
|
||||||
|
|
||||||
|
"gopkg.in/kataras/iris.v6"
|
||||||
|
"gopkg.in/kataras/iris.v6/adaptors/httprouter"
|
||||||
|
"gopkg.in/kataras/iris.v6/adaptors/view"
|
||||||
|
"gopkg.in/kataras/iris.v6/adaptors/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
type clientPage struct {
|
||||||
|
Title string
|
||||||
|
Host string
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := iris.New()
|
||||||
|
app.Adapt(iris.DevLogger()) // enable all (error) logs
|
||||||
|
app.Adapt(httprouter.New()) // select the httprouter as the servemux
|
||||||
|
app.Adapt(view.HTML("./templates", ".html")) // select the html engine to serve templates
|
||||||
|
|
||||||
|
ws := websocket.New(websocket.Config{
|
||||||
|
// the path which the websocket client should listen/registed to,
|
||||||
|
Endpoint: "/my_endpoint",
|
||||||
|
// the client-side javascript static file path
|
||||||
|
// which will be served by Iris.
|
||||||
|
// default is /iris-ws.js
|
||||||
|
// if you change that you have to change the bottom of templates/client.html
|
||||||
|
// script tag:
|
||||||
|
ClientSourcePath: "/iris-ws.js",
|
||||||
|
//
|
||||||
|
// Set the timeouts, 0 means no timeout
|
||||||
|
// websocket has more configuration, go to ../../config.go for more:
|
||||||
|
// WriteTimeout: 0,
|
||||||
|
// ReadTimeout: 0,
|
||||||
|
// by-default all origins are accepted, you can change this behavior by setting:
|
||||||
|
// CheckOrigin: (r *http.Request ) bool {},
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// IDGenerator used to create (and later on, set)
|
||||||
|
// an ID for each incoming websocket connections (clients).
|
||||||
|
// The request is an argument which you can use to generate the ID (from headers for example).
|
||||||
|
// If empty then the ID is generated by DefaultIDGenerator: randomString(64):
|
||||||
|
// IDGenerator func(ctx *iris.Context) string {},
|
||||||
|
})
|
||||||
|
|
||||||
|
app.Adapt(ws) // adapt the websocket server, you can adapt more than one with different Endpoint
|
||||||
|
|
||||||
|
app.StaticWeb("/js", "./static/js") // static route to serve our javascript files
|
||||||
|
|
||||||
|
app.Get("/", func(ctx *iris.Context) {
|
||||||
|
// send our custom javascript source file before client really asks for that
|
||||||
|
// using the new go v1.8's HTTP/2 Push.
|
||||||
|
// Note that you have to listen using ListenTLS/ListenLETSENCRYPT in order this to work.
|
||||||
|
if err := ctx.ResponseWriter.Push("/js/chat.js", nil); err != nil {
|
||||||
|
app.Log(iris.DevMode, err.Error())
|
||||||
|
}
|
||||||
|
ctx.Render("client.html", clientPage{"Client Page", ctx.Host()})
|
||||||
|
})
|
||||||
|
|
||||||
|
var myChatRoom = "room1"
|
||||||
|
|
||||||
|
ws.OnConnection(func(c websocket.Connection) {
|
||||||
|
// Context returns the (upgraded) *iris.Context of this connection
|
||||||
|
// avoid using it, you normally don't need it,
|
||||||
|
// websocket has everything you need to authenticate the user BUT if it's necessary
|
||||||
|
// then you use it to receive user information, for example: from headers.
|
||||||
|
|
||||||
|
// ctx := c.Context()
|
||||||
|
|
||||||
|
// join to a room (optional)
|
||||||
|
c.Join(myChatRoom)
|
||||||
|
|
||||||
|
c.On("chat", func(message string) {
|
||||||
|
if message == "leave" {
|
||||||
|
c.Leave(myChatRoom)
|
||||||
|
c.To(myChatRoom).Emit("chat", "Client with ID: "+c.ID()+" left from the room and cannot send or receive message to/from this room.")
|
||||||
|
c.Emit("chat", "You have left from the room: "+myChatRoom+" you cannot send or receive any messages from others inside that room.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// to all except this connection ->
|
||||||
|
// c.To(websocket.Broadcast).Emit("chat", "Message from: "+c.ID()+"-> "+message)
|
||||||
|
// to all connected clients: c.To(websocket.All)
|
||||||
|
|
||||||
|
// to the client itself ->
|
||||||
|
//c.Emit("chat", "Message from myself: "+message)
|
||||||
|
|
||||||
|
//send the message to the whole room,
|
||||||
|
//all connections are inside this room will receive this message
|
||||||
|
c.To(myChatRoom).Emit("chat", "From: "+c.ID()+": "+message)
|
||||||
|
})
|
||||||
|
|
||||||
|
// or create a new leave event
|
||||||
|
// c.On("leave", func() {
|
||||||
|
// c.Leave(myChatRoom)
|
||||||
|
// })
|
||||||
|
|
||||||
|
c.OnDisconnect(func() {
|
||||||
|
fmt.Printf("Connection with ID: %s has been disconnected!\n", c.ID())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
listenTLS(app)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// a test listenTLS for our localhost
|
||||||
|
func listenTLS(app *iris.Framework) {
|
||||||
|
|
||||||
|
const (
|
||||||
|
testTLSCert = `-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDBTCCAe2gAwIBAgIJAOYzROngkH6NMA0GCSqGSIb3DQEBBQUAMBkxFzAVBgNV
|
||||||
|
BAMMDmxvY2FsaG9zdDo4MDgwMB4XDTE3MDIxNzAzNDM1NFoXDTI3MDIxNTAzNDM1
|
||||||
|
NFowGTEXMBUGA1UEAwwObG9jYWxob3N0OjgwODAwggEiMA0GCSqGSIb3DQEBAQUA
|
||||||
|
A4IBDwAwggEKAoIBAQCfsiVHO14FpKsi0pvBv68oApQm2MO+dCvq87sDU4E0QJhG
|
||||||
|
KV1RCUmQVypChEqdLlUQsopcXSyKwbWoyg1/KNHYO3DHMfePb4bC1UD2HENq7Ph2
|
||||||
|
8QJTEi/CJvUB9hqke/YCoWYdjFiI3h3Hw8q5whGO5XR3R23z69vr5XxoNlcF2R+O
|
||||||
|
TdkzArd0CWTZS27vbgdnyi9v3Waydh/rl+QRtPUgEoCEqOOkMSMldXO6Z9GlUk9b
|
||||||
|
FQHwIuEnlSoVFB5ot5cqebEjJnWMLLP83KOCQekJeHZOyjeTe8W0Fy1DGu5fvFNh
|
||||||
|
xde9e/7XlFE//00vT7nBmJAUV/2CXC8U5lsjLEqdAgMBAAGjUDBOMB0GA1UdDgQW
|
||||||
|
BBQOfENuLn/t0Z4ZY1+RPWaz7RBH+TAfBgNVHSMEGDAWgBQOfENuLn/t0Z4ZY1+R
|
||||||
|
PWaz7RBH+TAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQBG7AEEuIq6
|
||||||
|
rWCE5I2t4IXz0jN7MilqEhUWDbUajl1paYf6Ikx5QhMsFx21p6WEWYIYcnWAKZe2
|
||||||
|
chAgnnGojuxdx0qjiaH4N4xWGHsWhaesnIF1xJepLlX3kJZQURvRxM4wlljlQPIb
|
||||||
|
9tqzKP131K1HDqplAtp7nWQ72m3J0ZfzH0mYIUxuaS/uQIVtgKqdilwy/VE5dRZ9
|
||||||
|
QFIb4G9TnNThXMqgTLjfNr33jVbTuv6fzKHYNbCkP3L10ydEs/ddlREmtsn9nE8Q
|
||||||
|
XCTIYXzA2kr5kWk7d3LkUiSvu3g2S1Ol1YaIKaOQyRveseCGwR4xohLT+dPUW9dL
|
||||||
|
3hDVLlwE3mB3
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
`
|
||||||
|
testTLSKey = `-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEogIBAAKCAQEAn7IlRzteBaSrItKbwb+vKAKUJtjDvnQr6vO7A1OBNECYRild
|
||||||
|
UQlJkFcqQoRKnS5VELKKXF0sisG1qMoNfyjR2DtwxzH3j2+GwtVA9hxDauz4dvEC
|
||||||
|
UxIvwib1AfYapHv2AqFmHYxYiN4dx8PKucIRjuV0d0dt8+vb6+V8aDZXBdkfjk3Z
|
||||||
|
MwK3dAlk2Utu724HZ8ovb91msnYf65fkEbT1IBKAhKjjpDEjJXVzumfRpVJPWxUB
|
||||||
|
8CLhJ5UqFRQeaLeXKnmxIyZ1jCyz/NyjgkHpCXh2Tso3k3vFtBctQxruX7xTYcXX
|
||||||
|
vXv+15RRP/9NL0+5wZiQFFf9glwvFOZbIyxKnQIDAQABAoIBAEzBx4ExW8PCni8i
|
||||||
|
o5LAm2PTuXniflMwa1uGwsCahmOjGI3AnAWzPRSPkNRf2a0q8+AOsMosTphy+umi
|
||||||
|
FFKmQBZ6m35i2earaE6FSbABbbYbKGGi/ccH2sSrDOBgdfXRTzF8eiSBrJw8hnvZ
|
||||||
|
87rNOLtCNnSOdJ7lItODfgRo+fLo4uQenJ8VONYwtwm1ejn8qLXq8O5zF66IYUD6
|
||||||
|
gAzqOiAWumgZL0tEmndeQ+noe4STpJZlOjiCsA12NiJaKDDeDIn5A/pXce+bYNfJ
|
||||||
|
k4yoroyq/JXBkhyuZDvX9vYp5AA+Q68h8/KmsKkifUgSGSHun5/80lYyT/f60TLX
|
||||||
|
PxT9GYECgYEA0s8qck7L29nBBTQ6IPF3GHGmqiRdfH+qhP/Jn4NtoW3XuVe4A15i
|
||||||
|
REq1L8WAiOUIBnBaD8HzbeioqJJYx1pu7x9h/GCNDhdBfwhTjnBe+JjfLqvJKnc0
|
||||||
|
HUT5wj4DVqattxKzUW8kTRBSWtVremzeffDo+EL6dnR7Bc02Ibs4WpUCgYEAwe34
|
||||||
|
Uqhie+/EFr4HjYRUNZSNgYNAJkKHVxk4qGzG5VhvjPafnHUbo+Kk/0QW7eIB+kvR
|
||||||
|
FDO8oKh9wTBrWZEcLJP4jDIKh4y8hZTo9B8EjxFONXVxZlOSYuGjheL8AiLzE7L9
|
||||||
|
C1spaKMM/MyxAXDRHpG/NeEgXM7Kn6kUGwJdNekCgYAshLNiEGHcu8+XWcAs1NFh
|
||||||
|
yB56L9PORuerzpi1pvuv65JzAaNKktQNt/krbXoHbtaTBYb/bOYLf+aeMsmsz9w9
|
||||||
|
g1MeCQXAxAiA2zFKE1D7Ds2S/ZQt8559z+MusgnicrCcyMY1nFL+M0QxCoD4CaWy
|
||||||
|
0v1f8EUUXuTcBMo5tV/hQQKBgDoBBW8jsiFDu7DZscSgOde00QZVzZAkAfsJLisi
|
||||||
|
LfNXGjZdZawUUuoX1iYLpZgNK25D0wtp1hdvjf2Ej/dAMd8bexHjvcaBT7ncqjiq
|
||||||
|
NmDcWjofIIXspTIyLwjStXGmJnJT7N/CqoYDjtTmHGND7Shpi3mAFn/r0isjFUJm
|
||||||
|
2J5RAoGALuGXxzmSRWmkIp11F/Qr3PBFWBWkrRWaH2TRLMhrU/wO8kCsSyo4PmAZ
|
||||||
|
ltOfD7InpDiCu43hcDPQ/29FUbDnmAhvMnmIQuHXGgPF/LhqEhbKPA/o/eZdQVCK
|
||||||
|
QG+tmveBBIYMed5YbWstZu/95lIHF+u8Hl+Z6xgveozfE5yqiUA=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
|
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
// create the key and cert files on the fly, and delete them when this test finished
|
||||||
|
certFile, ferr := ioutil.TempFile("", "cert")
|
||||||
|
|
||||||
|
if ferr != nil {
|
||||||
|
panic(ferr)
|
||||||
|
}
|
||||||
|
|
||||||
|
keyFile, ferr := ioutil.TempFile("", "key")
|
||||||
|
if ferr != nil {
|
||||||
|
panic(ferr)
|
||||||
|
}
|
||||||
|
|
||||||
|
certFile.WriteString(testTLSCert)
|
||||||
|
keyFile.WriteString(testTLSKey)
|
||||||
|
|
||||||
|
// add an event when control+C pressed, to remove the temp cert and key files.
|
||||||
|
app.Adapt(iris.EventPolicy{
|
||||||
|
Interrupted: func(*iris.Framework) {
|
||||||
|
certFile.Close()
|
||||||
|
time.Sleep(50 * time.Millisecond)
|
||||||
|
os.Remove(certFile.Name())
|
||||||
|
|
||||||
|
keyFile.Close()
|
||||||
|
time.Sleep(50 * time.Millisecond)
|
||||||
|
os.Remove(keyFile.Name())
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// https://localhost
|
||||||
|
app.ListenTLS("localhost:443", certFile.Name(), keyFile.Name())
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
var messageTxt;
|
||||||
|
var messages;
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
|
||||||
|
messageTxt = $("#messageTxt");
|
||||||
|
messages = $("#messages");
|
||||||
|
|
||||||
|
/* secure wss because we ListenTLS */
|
||||||
|
w = new Ws("wss://" + HOST + "/my_endpoint");
|
||||||
|
w.OnConnect(function () {
|
||||||
|
console.log("Websocket connection established");
|
||||||
|
});
|
||||||
|
|
||||||
|
w.OnDisconnect(function () {
|
||||||
|
appendMessage($("<div><center><h3>Disconnected</h3></center></div>"));
|
||||||
|
});
|
||||||
|
|
||||||
|
w.On("chat", function (message) {
|
||||||
|
appendMessage($("<div>" + message + "</div>"));
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#sendBtn").click(function () {
|
||||||
|
w.Emit("chat", messageTxt.val().toString());
|
||||||
|
messageTxt.val("");
|
||||||
|
});
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
function appendMessage(messageDiv) {
|
||||||
|
var theDiv = messages[0];
|
||||||
|
var doScroll = theDiv.scrollTop == theDiv.scrollHeight - theDiv.clientHeight;
|
||||||
|
messageDiv.appendTo(messages);
|
||||||
|
if (doScroll) {
|
||||||
|
theDiv.scrollTop = theDiv.scrollHeight - theDiv.clientHeight;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>{{ .Title}}</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="messages"
|
||||||
|
style="border-width: 1px; border-style: solid; height: 400px; width: 375px;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<input type="text" id="messageTxt" />
|
||||||
|
<button type="button" id="sendBtn">Send</button>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var HOST = {{.Host}}
|
||||||
|
</script>
|
||||||
|
<script src="/js/vendor/jquery-2.2.3.min.js"></script>
|
||||||
|
<!-- This is auto-serving by the Iris, you don't need to have this file in your disk-->
|
||||||
|
<script src="/iris-ws.js"></script>
|
||||||
|
<!-- -->
|
||||||
|
<script src="/js/chat.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
123
iris.go
123
iris.go
|
@ -100,8 +100,6 @@ type Framework struct {
|
||||||
// These are setted by user's call to .Adapt
|
// These are setted by user's call to .Adapt
|
||||||
policies Policies
|
policies Policies
|
||||||
|
|
||||||
ln net.Listener // setted on Listten/Serve funcions, available after 'Boot'
|
|
||||||
|
|
||||||
// TLSNextProto optionally specifies a function to take over
|
// TLSNextProto optionally specifies a function to take over
|
||||||
// ownership of the provided TLS connection when an NPN/ALPN
|
// ownership of the provided TLS connection when an NPN/ALPN
|
||||||
// protocol upgrade has occurred. The map key is the protocol
|
// protocol upgrade has occurred. The map key is the protocol
|
||||||
|
@ -210,19 +208,15 @@ func New(setters ...OptionSetter) *Framework {
|
||||||
s.Adapt(EventPolicy{Boot: func(s *Framework) {
|
s.Adapt(EventPolicy{Boot: func(s *Framework) {
|
||||||
// set the host and scheme
|
// set the host and scheme
|
||||||
if s.Config.VHost == "" { // if not setted by Listen functions
|
if s.Config.VHost == "" { // if not setted by Listen functions
|
||||||
if s.ln != nil { // but user called .Serve
|
s.Config.VHost = DefaultServerAddr
|
||||||
// then take the listener's addr
|
|
||||||
s.Config.VHost = s.ln.Addr().String()
|
|
||||||
} else {
|
|
||||||
// if no .Serve or .Listen called, then the user should set the VHost manually,
|
|
||||||
// however set it to a default value here for any case
|
|
||||||
s.Config.VHost = DefaultServerAddr
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// if user didn't specified a scheme then get it from the VHost, which is already setted at before statements
|
// if user didn't specified a scheme then get it from the VHost,
|
||||||
|
// which is already setted at before statements
|
||||||
if s.Config.VScheme == "" {
|
if s.Config.VScheme == "" {
|
||||||
|
// if :443 or :https then returns https:// otherwise http://
|
||||||
s.Config.VScheme = ParseScheme(s.Config.VHost)
|
s.Config.VScheme = ParseScheme(s.Config.VHost)
|
||||||
}
|
}
|
||||||
|
|
||||||
}})
|
}})
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -436,28 +430,21 @@ func (s *Framework) Boot() (firstTime bool) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serve serves incoming connections from the given listener.
|
func (s *Framework) setupServe() (srv *http.Server, deferFn func()) {
|
||||||
//
|
|
||||||
// Serve blocks until the given listener returns permanent error.
|
|
||||||
func (s *Framework) Serve(ln net.Listener) error {
|
|
||||||
if s.ln != nil {
|
|
||||||
return errors.New("server is already started and listening")
|
|
||||||
}
|
|
||||||
|
|
||||||
s.ln = ln
|
|
||||||
s.closedManually = false
|
s.closedManually = false
|
||||||
|
|
||||||
s.Boot()
|
s.Boot()
|
||||||
|
|
||||||
// post any panics to the user defined logger.
|
deferFn = func() {
|
||||||
defer func() {
|
// post any panics to the user defined logger.
|
||||||
if rerr := recover(); rerr != nil {
|
if rerr := recover(); rerr != nil {
|
||||||
if err, ok := rerr.(error); ok {
|
if err, ok := rerr.(error); ok {
|
||||||
s.handlePanic(err)
|
s.handlePanic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}
|
||||||
|
|
||||||
srv := &http.Server{
|
srv = &http.Server{
|
||||||
ReadTimeout: s.Config.ReadTimeout,
|
ReadTimeout: s.Config.ReadTimeout,
|
||||||
WriteTimeout: s.Config.WriteTimeout,
|
WriteTimeout: s.Config.WriteTimeout,
|
||||||
MaxHeaderBytes: s.Config.MaxHeaderBytes,
|
MaxHeaderBytes: s.Config.MaxHeaderBytes,
|
||||||
|
@ -467,21 +454,38 @@ func (s *Framework) Serve(ln net.Listener) error {
|
||||||
ErrorLog: s.policies.LoggerPolicy.ToLogger(log.LstdFlags),
|
ErrorLog: s.policies.LoggerPolicy.ToLogger(log.LstdFlags),
|
||||||
Handler: s.Router,
|
Handler: s.Router,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the grace shutdown, it's just a func no need to make things complicated
|
// Set the grace shutdown, it's just a func no need to make things complicated
|
||||||
// all are managed by net/http now.
|
// all are managed by net/http now.
|
||||||
s.Shutdown = func(ctx context.Context) error {
|
s.Shutdown = func(ctx context.Context) error {
|
||||||
// order matters, look s.handlePanic
|
// order matters, look s.handlePanic
|
||||||
s.closedManually = true
|
s.closedManually = true
|
||||||
err := srv.Shutdown(ctx)
|
err := srv.Shutdown(ctx)
|
||||||
s.ln = nil
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serve serves incoming connections from the given listener.
|
||||||
|
//
|
||||||
|
// Serve blocks until the given listener returns permanent error.
|
||||||
|
func (s *Framework) Serve(ln net.Listener) error {
|
||||||
|
if ln == nil {
|
||||||
|
return errors.New("nil net.Listener on Serve")
|
||||||
|
}
|
||||||
|
|
||||||
|
// if user called .Serve and doesn't uses any nginx-like balancers.
|
||||||
|
if s.Config.VHost == "" {
|
||||||
|
s.Config.VHost = ParseHost(ln.Addr().String())
|
||||||
|
} // Scheme will be checked from Boot state.
|
||||||
|
|
||||||
|
srv, fn := s.setupServe()
|
||||||
|
defer fn()
|
||||||
|
|
||||||
// print the banner and wait for system channel interrupt
|
// print the banner and wait for system channel interrupt
|
||||||
go s.postServe()
|
go s.postServe()
|
||||||
// finally return the error or block here, remember,
|
return srv.Serve(ln)
|
||||||
// until go1.8 these are our best options.
|
|
||||||
return srv.Serve(s.ln)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Framework) postServe() {
|
func (s *Framework) postServe() {
|
||||||
|
@ -507,14 +511,15 @@ func (s *Framework) postServe() {
|
||||||
// If you need to manually monitor any error please use `.Serve` instead.
|
// If you need to manually monitor any error please use `.Serve` instead.
|
||||||
func (s *Framework) Listen(addr string) {
|
func (s *Framework) Listen(addr string) {
|
||||||
addr = ParseHost(addr)
|
addr = ParseHost(addr)
|
||||||
if s.Config.VHost == "" {
|
|
||||||
s.Config.VHost = addr
|
|
||||||
// this will be set as the front-end listening addr
|
|
||||||
}
|
|
||||||
// only here, other Listen functions should throw an error if port is missing.
|
|
||||||
// User should know how to fix them on ListenUNIX/ListenTLS/ListenLETSENCRYPT/Serve,
|
|
||||||
// they are used by more 'advanced' devs, mostly.
|
|
||||||
|
|
||||||
|
// if .Listen called normally and VHost is not setted,
|
||||||
|
// so it's Host is the Real listening addr and user-given
|
||||||
|
if s.Config.VHost == "" {
|
||||||
|
s.Config.VHost = addr // as it is
|
||||||
|
// this will be set as the front-end listening addr
|
||||||
|
} // VScheme will be checked on Boot.
|
||||||
|
|
||||||
|
// this check, only here, other Listen functions should throw an error if port is missing.
|
||||||
if portIdx := strings.IndexByte(addr, ':'); portIdx < 0 {
|
if portIdx := strings.IndexByte(addr, ':'); portIdx < 0 {
|
||||||
// missing port part, add it
|
// missing port part, add it
|
||||||
addr = addr + ":80"
|
addr = addr + ":80"
|
||||||
|
@ -538,16 +543,27 @@ func (s *Framework) Listen(addr string) {
|
||||||
// If you need to manually monitor any error please use `.Serve` instead.
|
// If you need to manually monitor any error please use `.Serve` instead.
|
||||||
func (s *Framework) ListenTLS(addr string, certFile, keyFile string) {
|
func (s *Framework) ListenTLS(addr string, certFile, keyFile string) {
|
||||||
addr = ParseHost(addr)
|
addr = ParseHost(addr)
|
||||||
if s.Config.VHost == "" {
|
|
||||||
s.Config.VHost = addr
|
{
|
||||||
// this will be set as the front-end listening addr
|
// set it before Boot, be-careful VHost and VScheme are used by nginx users too
|
||||||
|
// we don't want to alt them.
|
||||||
|
if s.Config.VHost == "" {
|
||||||
|
s.Config.VHost = addr
|
||||||
|
// this will be set as the front-end listening addr
|
||||||
|
}
|
||||||
|
if s.Config.VScheme == "" {
|
||||||
|
s.Config.VScheme = SchemeHTTPS
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ln, err := TLS(addr, certFile, keyFile)
|
srv, fn := s.setupServe()
|
||||||
if err != nil {
|
// We are doing the same parts as .Serve does but instead we run srv.ListenAndServeTLS
|
||||||
s.handlePanic(err)
|
// because of un-exported net/http.server.go:setupHTTP2_ListenAndServeTLS function which
|
||||||
}
|
// broke our previous flow but no problem :)
|
||||||
s.Must(s.Serve(ln))
|
defer fn()
|
||||||
|
// print the banner and wait for system channel interrupt
|
||||||
|
go s.postServe()
|
||||||
|
s.Must(srv.ListenAndServeTLS(certFile, keyFile))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListenLETSENCRYPT starts a server listening at the specific nat address
|
// ListenLETSENCRYPT starts a server listening at the specific nat address
|
||||||
|
@ -557,16 +573,25 @@ func (s *Framework) ListenTLS(addr string, certFile, keyFile string) {
|
||||||
// if you skip the second parameter then the cache file is "./letsencrypt.cache"
|
// 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 ""
|
// if you want to disable cache then simple pass as second argument an empty empty string ""
|
||||||
//
|
//
|
||||||
// example: https://github.com/iris-contrib/examples/blob/master/letsencrypt/main.go
|
// 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...
|
||||||
//
|
//
|
||||||
// supports localhost domains for testing,
|
// example: https://github.com/iris-contrib/examples/blob/master/letsencrypt/main.go
|
||||||
// NOTE: if you are ready for production then use `$app.Serve(iris.LETSENCRYPTPROD("mydomain.com"))` instead
|
|
||||||
func (s *Framework) ListenLETSENCRYPT(addr string, cacheFileOptional ...string) {
|
func (s *Framework) ListenLETSENCRYPT(addr string, cacheFileOptional ...string) {
|
||||||
addr = ParseHost(addr)
|
addr = ParseHost(addr)
|
||||||
if s.Config.VHost == "" {
|
|
||||||
s.Config.VHost = addr
|
{
|
||||||
// this will be set as the front-end listening addr
|
// set it before Boot, be-careful VHost and VScheme are used by nginx users too
|
||||||
|
// we don't want to alt them.
|
||||||
|
if s.Config.VHost == "" {
|
||||||
|
s.Config.VHost = addr
|
||||||
|
// this will be set as the front-end listening addr
|
||||||
|
}
|
||||||
|
if s.Config.VScheme == "" {
|
||||||
|
s.Config.VScheme = SchemeHTTPS
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ln, err := LETSENCRYPT(addr, cacheFileOptional...)
|
ln, err := LETSENCRYPT(addr, cacheFileOptional...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.handlePanic(err)
|
s.handlePanic(err)
|
||||||
|
|
22
router.go
22
router.go
|
@ -607,9 +607,9 @@ func (router *Router) StaticHandler(reqPath string, systemPath string, showList
|
||||||
// second parameter: the system directory
|
// second parameter: the system directory
|
||||||
// third OPTIONAL parameter: the exception routes
|
// third OPTIONAL parameter: the exception routes
|
||||||
// (= give priority to these routes instead of the static handler)
|
// (= give priority to these routes instead of the static handler)
|
||||||
// for more options look iris.StaticHandler.
|
// for more options look router.StaticHandler.
|
||||||
//
|
//
|
||||||
// iris.StaticWeb("/static", "./static")
|
// router.StaticWeb("/static", "./static")
|
||||||
//
|
//
|
||||||
// As a special case, the returned file server redirects any request
|
// As a special case, the returned file server redirects any request
|
||||||
// ending in "/index.html" to the same path, without the final
|
// ending in "/index.html" to the same path, without the final
|
||||||
|
@ -618,8 +618,22 @@ func (router *Router) StaticHandler(reqPath string, systemPath string, showList
|
||||||
// StaticWeb calls the StaticHandler(reqPath, systemPath, listingDirectories: false, gzip: false ).
|
// StaticWeb calls the StaticHandler(reqPath, systemPath, listingDirectories: false, gzip: false ).
|
||||||
func (router *Router) StaticWeb(reqPath string, systemPath string, exceptRoutes ...RouteInfo) RouteInfo {
|
func (router *Router) StaticWeb(reqPath string, systemPath string, exceptRoutes ...RouteInfo) RouteInfo {
|
||||||
h := router.StaticHandler(reqPath, systemPath, false, false, exceptRoutes...)
|
h := router.StaticHandler(reqPath, systemPath, false, false, exceptRoutes...)
|
||||||
routePath := validateWildcard(reqPath, "file")
|
paramName := "file"
|
||||||
return router.registerResourceRoute(routePath, h)
|
routePath := validateWildcard(reqPath, paramName)
|
||||||
|
handler := func(ctx *Context) {
|
||||||
|
h(ctx)
|
||||||
|
if fname := ctx.Param(paramName); fname != "" {
|
||||||
|
cType := fs.TypeByExtension(fname)
|
||||||
|
if cType != contentBinary && !strings.Contains(cType, "charset") {
|
||||||
|
cType += "; charset=" + ctx.framework.Config.Charset
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.SetContentType(cType)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return router.registerResourceRoute(routePath, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Layout oerrides the parent template layout with a more specific layout for this Party
|
// Layout oerrides the parent template layout with a more specific layout for this Party
|
||||||
|
|
Loading…
Reference in New Issue
Block a user