Skip to content

Commit

Permalink
fix(chore): include and choose tags (#10)
Browse files Browse the repository at this point in the history
* feat: pass some headers to child requests

* fix(chore): include and choose tags

Co-authored-by: Dalibor Karlović <dalibor.karlovic@sigwin.hr>
  • Loading branch information
darkweak and dkarlovi authored Nov 23, 2022
1 parent 8f1e394 commit 9298fae
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 10 deletions.
3 changes: 1 addition & 2 deletions esi/choose.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ func (c *chooseTag) Process(b []byte, req *http.Request) ([]byte, int) {
for _, v := range tagIdxs {
if validateTest(v[1], req) {
res = Parse(v[2], req)

break
return res, c.length
}
}

Expand Down
36 changes: 35 additions & 1 deletion esi/include.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ var (
altAttribute = regexp.MustCompile(`alt="?(.+?)"?( |/>)`)
)

// safe to pass to any origin
var headersSafe = []string{
"Accept",
"Accept-Language",
}

// safe to pass only to same-origin (same scheme, same host, same port)
var headersUnsafe = []string{
"Cookie",
"Authorization",
}

type includeTag struct {
*baseTag
src string
Expand Down Expand Up @@ -42,6 +54,15 @@ func sanitizeURL(u string, reqUrl *url.URL) string {
return reqUrl.ResolveReference(parsed).String()
}

func addHeaders(headers []string, req *http.Request, rq *http.Request) {
for _, h := range headers {
v := req.Header.Get(h)
if v != "" {
rq.Header.Add(h, v)
}
}
}

// Input (e.g. include src="https://domain.com/esi-include" alt="https://domain.com/alt-esi-include" />)
// With or without the alt
// With or without a space separator before the closing
Expand All @@ -59,18 +80,31 @@ func (i *includeTag) Process(b []byte, req *http.Request) ([]byte, int) {
}

rq, _ := http.NewRequest(http.MethodGet, sanitizeURL(i.src, req.URL), nil)
addHeaders(headersSafe, req, rq)
if rq.URL.Scheme == req.URL.Scheme && rq.URL.Host == req.URL.Host {
addHeaders(headersUnsafe, req, rq)
}

client := &http.Client{}
response, err := client.Do(rq)

if err != nil || response.StatusCode >= 400 {
if (err != nil || response.StatusCode >= 400) && i.alt != "" {
rq, _ = http.NewRequest(http.MethodGet, sanitizeURL(i.alt, req.URL), nil)
addHeaders(headersSafe, req, rq)
if rq.URL.Scheme == req.URL.Scheme && rq.URL.Host == req.URL.Host {
addHeaders(headersUnsafe, req, rq)
}
response, err = client.Do(rq)

if err != nil || response.StatusCode >= 400 {
return nil, len(b)
}
}

if response == nil {
return nil, i.length
}

defer response.Body.Close()
x, _ := io.ReadAll(response.Body)
b = Parse(x, req)
Expand Down
13 changes: 13 additions & 0 deletions fixtures/full.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,18 @@
-->
<esi:include src="/chained-esi-include-1" />
<esi:include src="http://inexistent.abc/something" alt="//domain.com:9080/alt-esi-include" />
<esi:choose>
<esi:when test="$(HTTP_COOKIE{group})=='Advanced'">
<span><esi:include src="http://domain.com:9080/chained-esi-include-1"/></span>
</esi:when>
<esi:when test="$(HTTP_COOKIE{group})=='Basic User'">
<esi:include src="https://google.com"/>
</esi:when>
<esi:otherwise>
<div>
<esi:include src="http://domain.com/esi-include"/>
</div>
</esi:otherwise>
</esi:choose>
</body>
</html>
14 changes: 7 additions & 7 deletions middleware/caddy/esi.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,25 +46,25 @@ func (e *ESI) ServeHTTP(rw http.ResponseWriter, r *http.Request, next caddyhttp.
defer bufPool.Put(buf)
cw := writer.NewWriter(buf, rw, r)
go func(w *writer.Writer) {
w.Header().Del("Content-Length")
if w.Rq.ProtoMajor == 1 {
w.Header().Set("Content-Encoding", "chunked")
}
var i = 0
for {
if len(cw.AsyncBuf) <= i {
if len(w.AsyncBuf) <= i {
continue
}
rs := <-cw.AsyncBuf[i]
rs := <-w.AsyncBuf[i]
if rs == nil {
cw.Done <- true
w.Done <- true
break
}
_, _ = rw.Write(rs)
i++
}
}(cw)
next.ServeHTTP(cw, r)
cw.Header().Del("Content-Length")
if cw.Rq.ProtoMajor == 1 {
cw.Header().Set("Content-Encoding", "chunked")
}
cw.AsyncBuf = append(cw.AsyncBuf, make(chan []byte))
go func(w *writer.Writer, iteration int) {
w.AsyncBuf[iteration] <- nil
Expand Down
5 changes: 5 additions & 0 deletions middleware/caddy/esi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ const expectedOutput = `<html>
<h1>CHAINED 2</h1>
<h1>ALTERNATE ESI INCLUDE</h1>
<div>
</div>
</body>
</html>
`
Expand Down

0 comments on commit 9298fae

Please sign in to comment.