Skip to content

Commit

Permalink
Reorganise stuff into separate echo servers
Browse files Browse the repository at this point in the history
TODO fix localhost hostname matching
  • Loading branch information
LeafHacker committed Sep 18, 2019
1 parent c02df8d commit e7b3dd1
Show file tree
Hide file tree
Showing 9 changed files with 160 additions and 128 deletions.
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
14 changes: 0 additions & 14 deletions src/router.go

This file was deleted.

25 changes: 14 additions & 11 deletions src/web/s3proxy.go → src/s3proxy/server.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package web

import (
"github.com/ImpactDevelopment/ImpactServer/src/util"
"github.com/labstack/echo/middleware"
"net/http"
"net/url"
"strings"
"time"

"github.com/aws/aws-sdk-go/aws"
Expand All @@ -13,17 +15,18 @@ import (

var awsSess = session.Must(session.NewSession(&aws.Config{Region: aws.String("us-east-1")}))

func S3Proxy(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
hostStr := c.Request().Host
if strings.HasPrefix(hostStr, "static.") {
return S3Handle(c)
}
return next(c)
}
func Server() (e *echo.Echo) {
e = echo.New()

e.Match([]string{http.MethodHead, http.MethodGet}, "/*", proxyHandler)

e.Use(middleware.Logger())
e.Use(middleware.Recover())

return
}

func S3Handle(c echo.Context) error {
func proxyHandler(c echo.Context) error {
file := c.Request().URL.Path

s3Req, _ := s3.New(awsSess).GetObjectRequest(&s3.GetObjectInput{
Expand All @@ -41,6 +44,6 @@ func S3Handle(c echo.Context) error {
return err
}

doProxy(c, target)
util.Proxy(c, target)
return nil
}
49 changes: 26 additions & 23 deletions src/server.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package main

import (
"net/http"
"os"
"strconv"

mid "github.com/ImpactDevelopment/ImpactServer/src/middleware"
"github.com/ImpactDevelopment/ImpactServer/src/s3proxy"
"github.com/ImpactDevelopment/ImpactServer/src/web"
"github.com/labstack/echo"
"github.com/labstack/echo/middleware"
"net/http"
"os"
"strconv"
)

var port = 3000
Expand All @@ -20,36 +21,38 @@ func init() {
}

func main() {
// Echo is cool https://echo.labstack.com
server := echo.New()
AddMiddleware(server)
Router(server)

// Fall back to static files, after none of the routes have matched
server.Use(middleware.StaticWithConfig(middleware.StaticConfig{
Root: "static", // Root directory from where the static content is served.
Browse: false, // Don't enable directory browsing.
HTML5: false, // Don't forward everything to root (would allow client-side routing)
}))
hosts := map[string]*echo.Echo{
"impactclient.net": web.Server(),
"files.impactclient.net": s3proxy.Server(),
}

// Start the server
server.Logger.Fatal(StartServer(server, port))
}
e := echo.New()

func AddMiddleware(e *echo.Echo) {
// Enforce URL style
// We don't need to do any http->https stuff here 'cos cloudflare
e.Pre(middleware.NonWWWRedirect())
e.Pre(middleware.RemoveTrailingSlash())
e.Pre(mid.RemoveIndexHTML(http.StatusMovedPermanently))

// Compression not required because the CDN does that for us
e.Any("/*", func(c echo.Context) (err error) {
req := c.Request()
res := c.Response()
host := hosts[req.Host]

// Log all the things TODO formatting https://echo.labstack.com/middleware/logger
e.Use(middleware.Logger())
if host == nil {
err = echo.ErrNotFound
} else {
host.ServeHTTP(res, req)
}

return
})

// Don't crash
e.Use(middleware.Logger())
e.Use(middleware.Recover())

// Start the server
e.Logger.Fatal(StartServer(e, port))
}

func StartServer(e *echo.Echo, port int) error {
Expand Down
30 changes: 30 additions & 0 deletions src/util/proxy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package util

import (
"github.com/labstack/echo"
"net/http"
"net/http/httputil"
"net/url"
)

// var func to allow overriding in tests
var serveProxy = func(proxy *httputil.ReverseProxy, req *http.Request, res http.ResponseWriter) {
proxy.ServeHTTP(res, req)
}

func Proxy(c echo.Context, target *url.URL) {
proxy := &httputil.ReverseProxy{
Director: func(req *http.Request) {
// Change the URL
req.URL = target
req.Header.Set("X-Forwarded-Host", req.Host)
req.Host = target.Host

// Don't send our cookies to github
req.Header.Del(echo.HeaderCookie)
req.Header.Del(echo.HeaderAuthorization)
},
}

serveProxy(proxy, c.Request(), c.Response())
}
62 changes: 62 additions & 0 deletions src/util/proxy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package util

import (
"github.com/labstack/echo"
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
"net/http/httputil"
"net/url"
"testing"
)

func TestProxy(t *testing.T) {
// Override serveProxy and store what's passed into it
var (
servedCount = 0
servedProxy *httputil.ReverseProxy
servedReq *http.Request
servedRes http.ResponseWriter
)
serveProxy = func(proxy *httputil.ReverseProxy, req *http.Request, res http.ResponseWriter) {
servedCount++
servedProxy = proxy
servedReq = req
servedRes = res
}

// Setup the request
e := echo.New()
req := httptest.NewRequest(http.MethodGet, "http://foobar.host/changelog", nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
c.SetPath("/changelog")

target, _ := url.Parse("https://impactdevelopment.github.io/Impact/changelog")

// Run the handler
Proxy(c, target)
// Basic checks
assert.Equal(t, 1, servedCount)
assert.NotNil(t, servedProxy)
assert.NotNil(t, servedReq)
assert.NotNil(t, servedRes)

// Request should be unchanged
assert.Equal(t, "", servedReq.Header.Get("X-Forwarded-Host"))
assert.Equal(t, "foobar.host", servedReq.Host)
assert.Equal(t, "foobar.host", servedReq.URL.Host)
assert.Equal(t, "/changelog", servedReq.URL.Path)
assert.Equal(t, "", servedReq.URL.RawQuery)
assert.Equal(t, "http://foobar.host/changelog", servedReq.URL.String())

// The Director function should mutate the request
servedProxy.Director(servedReq)
assert.Equal(t, "foobar.host", servedReq.Header.Get("X-Forwarded-Host"))
assert.Equal(t, "impactdevelopment.github.io", servedReq.Host)
assert.Equal(t, "https", servedReq.URL.Scheme)
assert.Equal(t, "impactdevelopment.github.io", servedReq.URL.Host)
assert.Equal(t, "/Impact/changelog", servedReq.URL.Path)
assert.Equal(t, "", servedReq.URL.RawQuery)
assert.Equal(t, target.String(), servedReq.URL.String())
}
30 changes: 4 additions & 26 deletions src/web/changelog.go
Original file line number Diff line number Diff line change
@@ -1,49 +1,27 @@
package web

import (
"github.com/ImpactDevelopment/ImpactServer/src/util"
"net/http"
"net/http/httputil"
"net/url"

"github.com/labstack/echo"
)

const github = "https://impactdevelopment.github.io"

func Changelog(c echo.Context) error {
func changelog(c echo.Context) error {
// Forward to the changelog hosted by github

target, err := url.Parse(github + "/Impact/changelog")
if err != nil {
return err //wtf
}
doProxy(c, target)
util.Proxy(c, target)
return nil
}

func doProxy(c echo.Context, target *url.URL) {
proxy := &httputil.ReverseProxy{
Director: func(req *http.Request) {
// Change the URL
req.URL = target
req.Header.Set("X-Forwarded-Host", req.Host)
req.Host = target.Host

// Don't send our cookies to github
req.Header.Del(echo.HeaderCookie)
req.Header.Del(echo.HeaderAuthorization)
},
}

serveProxy(proxy, c.Request(), c.Response())
}

// var func to allow overriding in tests
var serveProxy = func(proxy *httputil.ReverseProxy, req *http.Request, res http.ResponseWriter) {
proxy.ServeHTTP(res, req)
}

func ImpactRedirect(c echo.Context) error {
func impactRedirect(c echo.Context) error {
address := c.Request().URL

// Echo tends to set the Request URL to just the path+query
Expand Down
56 changes: 2 additions & 54 deletions src/web/changelog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package web
import (
"net/http"
"net/http/httptest"
"net/http/httputil"
"testing"

"github.com/labstack/echo"
Expand All @@ -14,57 +13,6 @@ func TestConst(t *testing.T) {
assert.Equal(t, "https://impactdevelopment.github.io", github)
}

func TestChangelog(t *testing.T) {
// Override serveProxy and store what's passed into it
var (
servedCount = 0
servedProxy *httputil.ReverseProxy
servedReq *http.Request
servedRes http.ResponseWriter
)
serveProxy = func(proxy *httputil.ReverseProxy, req *http.Request, res http.ResponseWriter) {
servedCount++
servedProxy = proxy
servedReq = req
servedRes = res
}

// Setup the request
e := echo.New()
req := httptest.NewRequest(http.MethodGet, "http://foobar.host/changelog", nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
c.SetPath("/changelog")

// Run the handler
err := Changelog(c)
if assert.NoError(t, err) {
// Basic checks
assert.Equal(t, 1, servedCount)
assert.NotNil(t, servedProxy)
assert.NotNil(t, servedReq)
assert.NotNil(t, servedRes)

// Request should be unchanged
assert.Equal(t, "", servedReq.Header.Get("X-Forwarded-Host"))
assert.Equal(t, "foobar.host", servedReq.Host)
assert.Equal(t, "foobar.host", servedReq.URL.Host)
assert.Equal(t, "/changelog", servedReq.URL.Path)
assert.Equal(t, "", servedReq.URL.RawQuery)
assert.Equal(t, "http://foobar.host/changelog", servedReq.URL.String())

// The Director function should mutate the request
servedProxy.Director(servedReq)
assert.Equal(t, "foobar.host", servedReq.Header.Get("X-Forwarded-Host"))
assert.Equal(t, "impactdevelopment.github.io", servedReq.Host)
assert.Equal(t, "https", servedReq.URL.Scheme)
assert.Equal(t, "impactdevelopment.github.io", servedReq.URL.Host)
assert.Equal(t, "/Impact/changelog", servedReq.URL.Path)
assert.Equal(t, "", servedReq.URL.RawQuery)
assert.Equal(t, github+"/Impact/changelog", servedReq.URL.String())
}
}

func TestImpactRedirect(t *testing.T) {
const route = "/Impact/"
const path = "assets/css/style.css?v=foobar"
Expand All @@ -74,7 +22,7 @@ func TestImpactRedirect(t *testing.T) {
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
c.SetPath(route + "*")
err := ImpactRedirect(c)
err := impactRedirect(c)

if assert.NoError(t, err) {
// Expect 302
Expand All @@ -93,7 +41,7 @@ func TestChangelogRedirect(t *testing.T) {
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
c.SetPath(route + "*")
err := ImpactRedirect(c)
err := impactRedirect(c)

if assert.NoError(t, err) {
// Expect 301
Expand Down
Loading

0 comments on commit e7b3dd1

Please sign in to comment.