Skip to content

Commit

Permalink
add 'DirOptions.PushTargets' for http/2 push on index(es) - #1562
Browse files Browse the repository at this point in the history
Former-commit-id: 5a3f626ba0fbcf10be979b5a800eba51e88602cd
  • Loading branch information
kataras committed Jul 16, 2020
1 parent 38eec57 commit fba8492
Show file tree
Hide file tree
Showing 16 changed files with 275 additions and 99 deletions.
3 changes: 2 additions & 1 deletion HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -429,8 +429,9 @@ Other Improvements:

New Package-level Variables:

- `iris.DirListRich` to override the default look and feel if the `DirOptions.ShowList` was set to true, can be passed to `DirOptions.DirList` field.
- `iris.DirListRichOptions` to pass on `iris.DirListRich` method.
- `iris.DirListRich` to override the default look and feel if the `DirOptions.ShowList` was set to true, can be passed to `DirOptions.DirList` field.
- `DirOptions.PushTargets` for http/2 push on index [*](https://github.com/kataras/iris/tree/master/_examples/file-server/http2push/main.go).
- `iris.Compress` and `iris.CompressReader` middleware to compress responses and decode compressed request data respectfully.
- `iris.B, KB, MB, GB, TB, PB, EB` for byte units.
- `TLSNoRedirect` to disable automatic "http://" to "https://" redirections (see below)
Expand Down
1 change: 1 addition & 0 deletions _examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
* [Profiling](pprof/main.go)
* File Server
* [File Server](file-server/file-server/main.go)
* [HTTP/2 Push Targets](file-server/http2push/main.go)
* [Favicon](file-server/favicon/main.go)
* [Basic](file-server/basic/main.go)
* [Embedding Files Into App Executable File](file-server/embedding-files-into-app/main.go)
Expand Down
3 changes: 1 addition & 2 deletions _examples/file-server/embedding-files-into-app/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import (
// Follow these steps first:
// $ go get -u github.com/go-bindata/go-bindata/...
// $ go-bindata ./assets/...
// $ go build
// $ ./embedding-files-into-app
// $ go run .
// "physical" files are not used, you can delete the "assets" folder and run the example.
//
// See `file-server/embedding-gziped-files-into-app` example as well.
Expand Down
3 changes: 3 additions & 0 deletions _examples/file-server/http2push/assets/css/main.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body {
background-color: black;
}
Binary file not shown.
18 changes: 18 additions & 0 deletions _examples/file-server/http2push/assets/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
<link rel="stylesheet" href="/public/css/main.css" />
<title>File Server</title>
</head>

<body>
<input type="button" onclick="onClick()" value="Click me!" />

<script type="text/javascript" src="/public/js/main.js"></script>
</body>

</html>
5 changes: 5 additions & 0 deletions _examples/file-server/http2push/assets/js/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
console.log("example");

function onClick() {
window.alert("button clicked");
}
35 changes: 35 additions & 0 deletions _examples/file-server/http2push/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package main

import (
"github.com/kataras/iris/v12"
)

var opts = iris.DirOptions{
IndexName: "/index.html",
// Optionally register files (map's absolute values) to be served
// when a specific path (map's key WITHOUT prefix) is requested
// is fired before client asks (HTTP/2 Push).
// E.g. "/" (which serves the `IndexName` if not empty).
//
// Note: Requires running server under TLS,
// that's why we use ListenAndServeTLS below.
PushTargets: map[string][]string{
"/": {
"/public/favicon.ico",
"/public/js/main.js",
"/public/css/main.css",
},
},
Compress: true,
ShowList: true,
}

func main() {
app := iris.New()
app.HandleDir("/public", "./assets", opts)

// Open your browser's Network tools,
// navigate to https://127.0.0.1/public.
// you should see `Initiator` tab: "Push / public".
app.Run(iris.TLS(":443", "mycert.crt", "mykey.key"))
}
31 changes: 31 additions & 0 deletions _examples/file-server/http2push/mycert.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIUfwMd9auWixp19UnXOmyxJ9Jkv7IwDQYJKoZIhvcNAQEL
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDA2MjUwOTUxNDdaFw0yMTA2
MjUwOTUxNDdaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQDlVGyGAQ9uyfNbwZyrtYOSjLpxf5NpNToh2OzU7gy2
OexBji5lmWBQ3oYDG+FjAkbHORPzOMNpeMwje+IjGZBw8x6E+8WoGdSzbrEZ6pUV
wKJGKEuDlx6g6HEmtv3ZwgGe20gvPjjW+oCO888dwK/mbIHrHTq4nO3o0gAdAJwu
amn9BlHU5O4RW7BQ4tLF+j/fBCACWRG1NHXA0AT8eg544GyCdyteAH11oCDsHS8/
DAPsM6t+tZrMCIt9+9dzPdVoOmQNaMMrcz8eJohddRTK6zHe9ixZTt/soayOF7OS
QQeekbr3HPYhD450zRVplLMHx7wnph/+O+Po6bqDnUzdnkqAAwwymQapHMuHXZKN
rhdfKau3rVo1GeXLIRgeWLUoxFSm4TYshrgt+0AidLRH+dCY7MS9Ngga/sAK3vID
gSF75mFgOhY+q7nvY9Ecao6TnoNNRY29hUat4y0VwSyysUy887vHr6lMK5CrAT/l
Ch8fuu20HUCoiLwMJvA6+wpivZkuiIvWY7bVGYsEYrrW+bCNN9wCGYTZEyX++os9
v/38wdOqGUT00ewXkjIUFCWbrnxxSr98kF3w3wPf9K4Y40MNxeR90nyX4zjXGF1/
91msUh+iivsz9mcN9DK83fgTyOsoVLX5cm/L2UBwMacsfjBbN4djOc5IuYMar/VN
GQIDAQABo1MwUTAdBgNVHQ4EFgQUtkf+yAvqgZC8f22iJny9hFEDolMwHwYDVR0j
BBgwFoAUtkf+yAvqgZC8f22iJny9hFEDolMwDwYDVR0TAQH/BAUwAwEB/zANBgkq
hkiG9w0BAQsFAAOCAgEAE2QasBVru618rxupyJgEHw6r4iv7sz1Afz3Q5qJ4oSA9
xVsrVCjr3iHRFSw8Rf670E8Ffk/JjzS65mHw6zeZj/ANBKQWLjRlqzYXeetq5HzG
SIgaG7p1RFvvzz3+leFGzjinZ6sKbfB4OB72o2YN+fO8DsDxgGKll0W4KAazizSe
HY9Pgu437tWnwF16rFO3IL47n5HzYlRoGIPOpzFoNX5+fyn9GlnKEtONF2QBKTjY
rdjvqFRByDiC74d8z/Yx8IiDRn1mTcG90JLR9+c6M7fruha9Y/rJfw+4AhVh5ZDz
Bl9rGPjwEs5zwutYvVAJzs7AVcighYP1lHKoJ7DxBDQeyBsYlUNk2l6bmZgLgGUZ
+2OyWlqc/jD2GdDsIaZ4i7QqhTI/6aYZIf5zUkblKV1aMSaDulKxRv//OwW28Jax
9EEoV7VaFb3sOkB/tZGhusXeQVtdrhahT3KkZLNwmNXoXWKJ5LjeUlFWJyV6JbDe
y/PIWWCwWqyuFCSZS+Cg3RDgAzfSxkI8uVZ+IKKJS3UluDX45lxXtbRrvTQ+oDrA
6ga5c1Vz9C4kn1K5yW4d7QIvg6vPiy7gvl+//sz9oxUM3yswInDBY0HKLgT0Uq9b
YzLDh2RSaHsgHMPy2BKqR+q2N+lpg7inAWuJM1Huq6eHFqhiyQkzsfscBd1Dpm8=
-----END CERTIFICATE-----
52 changes: 52 additions & 0 deletions _examples/file-server/http2push/mykey.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
W2TzuSMYNDu876twbTVQJED3mwOAQ3J7
-----END PRIVATE KEY-----
23 changes: 15 additions & 8 deletions _examples/response-writer/http2push/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
// to need for the page they’re requesting.
package main

import "github.com/kataras/iris/v12"
import (
"net/http"

"github.com/kataras/iris/v12"
)

func main() {
app := iris.New()
Expand All @@ -22,14 +26,17 @@ func pushHandler(ctx iris.Context) {
// If the target is a path, it will inherit the scheme and host of the
// parent request.
target := "/main.js"
err := ctx.ResponseWriter().Push(target, nil)
if err != nil {
if err == iris.ErrPushNotSupported {
ctx.StopWithText(iris.StatusHTTPVersionNotSupported, "HTTP/2 push not supported.")
} else {
ctx.StopWithError(iris.StatusInternalServerError, err)

if pusher, ok := ctx.ResponseWriter().(http.Pusher); ok {
err := pusher.Push(target, nil)
if err != nil {
if err == iris.ErrPushNotSupported {
ctx.StopWithText(iris.StatusHTTPVersionNotSupported, "HTTP/2 push not supported.")
} else {
ctx.StopWithError(iris.StatusInternalServerError, err)
}
return
}
return
}

ctx.HTML(`<html><body><script src="%s"></script></body></html>`, target)
Expand Down
39 changes: 33 additions & 6 deletions context/compress.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ type CompressResponseWriter struct {
CompressWriter
ResponseWriter

http.Pusher
http.Hijacker
http.CloseNotifier

Disabled bool
Encoding string
Level int
Expand Down Expand Up @@ -195,12 +199,15 @@ func AcquireCompressResponseWriter(w ResponseWriter, r *http.Request, level int)
if level == -1 && encoding == BROTLI {
level = 6
}
// Writer exists, encoding matching and it's valid because it has a non nil encWriter;
// just reset to reduce allocations.
if v.Encoding == encoding && v.Level == level && v.CompressWriter != nil {
v.CompressWriter.Reset(w)
return v, nil
}

/*
// Writer exists, encoding matching and it's valid because it has a non nil encWriter;
// just reset to reduce allocations.
if v.Encoding == encoding && v.Level == level && v.CompressWriter != nil {
v.CompressWriter.Reset(w)
return v, nil
}
*/

v.Encoding = encoding

Expand All @@ -213,6 +220,26 @@ func AcquireCompressResponseWriter(w ResponseWriter, r *http.Request, level int)
v.CompressWriter = encWriter

AddCompressHeaders(w.Header(), encoding)

pusher, ok := w.(http.Pusher)
if !ok {
pusher = nil // make sure interface value is nil.
}

hijacker, ok := w.(http.Hijacker)
if !ok {
hijacker = nil
}

closeNotifier, ok := w.(http.CloseNotifier)
if !ok {
closeNotifier = nil
}

v.Pusher = pusher
v.Hijacker = hijacker
v.CloseNotifier = closeNotifier

return v, nil
}

Expand Down
36 changes: 33 additions & 3 deletions context/response_recorder.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package context

import (
"errors"
"net/http"
"sync"
)
Expand Down Expand Up @@ -31,6 +32,10 @@ func releaseResponseRecorder(w *ResponseRecorder) {
// rec := context.Recorder()
type ResponseRecorder struct {
ResponseWriter

http.Hijacker
http.CloseNotifier

// keep track of the body in order to be
// resetable and useful inside custom transactions
chunks []byte
Expand All @@ -50,6 +55,20 @@ func (w *ResponseRecorder) Naive() http.ResponseWriter {
// prepares itself, the response recorder, to record and send response to the client.
func (w *ResponseRecorder) BeginRecord(underline ResponseWriter) {
w.ResponseWriter = underline

hijacker, ok := underline.(http.Hijacker)
if !ok {
hijacker = nil
}

closeNotifier, ok := underline.(http.CloseNotifier)
if !ok {
closeNotifier = nil
}

w.Hijacker = hijacker
w.CloseNotifier = closeNotifier

w.headers = underline.Header()
w.ResetBody()
}
Expand Down Expand Up @@ -236,6 +255,10 @@ func (w *ResponseRecorder) Flush() {
w.ResetBody()
}

// ErrPushNotSupported is returned by the Push method to
// indicate that HTTP/2 Push support is not available.
var ErrPushNotSupported = errors.New("push feature is not supported by this ResponseWriter")

// Push initiates an HTTP/2 server push. This constructs a synthetic
// request using the given target and options, serializes that request
// into a PUSH_PROMISE frame, then dispatches that request using the
Expand All @@ -256,12 +279,19 @@ func (w *ResponseRecorder) Flush() {
//
// Push returns ErrPushNotSupported if the client has disabled push or if push
// is not supported on the underlying connection.
func (w *ResponseRecorder) Push(target string, opts *http.PushOptions) error {
func (w *ResponseRecorder) Push(target string, opts *http.PushOptions) (err error) {
w.FlushResponse()
err := w.ResponseWriter.Push(target, opts)

if pusher, ok := w.ResponseWriter.(http.Pusher); ok {
err = pusher.Push(target, opts)
if err != nil && err.Error() == http.ErrNotSupported.ErrorString {
return ErrPushNotSupported
}
}

// NOTE: we have to reset them even if the push failed.
w.ResetBody()
w.ResetHeaders()

return err
return ErrPushNotSupported
}
Loading

0 comments on commit fba8492

Please sign in to comment.