mirror of
https://github.com/mjl-/mox.git
synced 2024-12-26 16:33:47 +03:00
8b0706e02d
you can already get most http to https redirects through DontRedirectPlainHTTP in WebHandler, but that needs handlers for all paths. now you can just set up a redirect for a domain and all its path to baseurl https://domain (leaving other webdirect fields empty). when the request comes in with plain http, the redirect to https is done. that next request will also evaluate the same redirect rule. but it will not cause a match because it would redirect to the same scheme,host,path. so next webhandlers get a chance to serve. also clarify in webhandlers docs that also account & admin built-in handlers run first. related to issue #16
121 lines
4.9 KiB
Go
121 lines
4.9 KiB
Go
package http
|
|
|
|
import (
|
|
"bytes"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/mjl-/mox/mox-"
|
|
)
|
|
|
|
func TestWebserver(t *testing.T) {
|
|
os.RemoveAll("../testdata/webserver/data")
|
|
mox.ConfigStaticPath = "../testdata/webserver/mox.conf"
|
|
mox.ConfigDynamicPath = filepath.Join(filepath.Dir(mox.ConfigStaticPath), "domains.conf")
|
|
mox.MustLoadConfig(false)
|
|
|
|
srv := &serve{Webserver: true}
|
|
|
|
test := func(method, target string, reqhdrs map[string]string, expCode int, expContent string, expHeaders map[string]string) {
|
|
t.Helper()
|
|
|
|
req := httptest.NewRequest(method, target, nil)
|
|
for k, v := range reqhdrs {
|
|
req.Header.Add(k, v)
|
|
}
|
|
rw := httptest.NewRecorder()
|
|
rw.Body = &bytes.Buffer{}
|
|
srv.ServeHTTP(rw, req)
|
|
resp := rw.Result()
|
|
if resp.StatusCode != expCode {
|
|
t.Fatalf("got statuscode %d, expected %d", resp.StatusCode, expCode)
|
|
}
|
|
if expContent != "" {
|
|
s := rw.Body.String()
|
|
if s != expContent {
|
|
t.Fatalf("got response data %q, expected %q", s, expContent)
|
|
}
|
|
}
|
|
for k, v := range expHeaders {
|
|
if xv := resp.Header.Get(k); xv != v {
|
|
t.Fatalf("got %q for header %q, expected %q", xv, k, v)
|
|
}
|
|
}
|
|
}
|
|
|
|
test("GET", "http://redir.mox.example", nil, http.StatusPermanentRedirect, "", map[string]string{"Location": "https://mox.example/"})
|
|
|
|
// http to https redirect, and stay on https afterwards without redirect loop.
|
|
test("GET", "http://schemeredir.example", nil, http.StatusPermanentRedirect, "", map[string]string{"Location": "https://schemeredir.example/"})
|
|
test("GET", "https://schemeredir.example", nil, http.StatusNotFound, "", nil)
|
|
|
|
test("GET", "http://mox.example/static/", nil, http.StatusOK, "", map[string]string{"X-Test": "mox"}) // index.html
|
|
test("GET", "http://mox.example/static/dir/", nil, http.StatusOK, "", map[string]string{"X-Test": "mox"}) // listing
|
|
test("GET", "http://mox.example/static/dir", nil, http.StatusTemporaryRedirect, "", map[string]string{"Location": "/static/dir/"}) // redirect to dir
|
|
test("GET", "http://mox.example/static/bogus", nil, http.StatusNotFound, "", nil)
|
|
|
|
test("GET", "http://mox.example/nolist/", nil, http.StatusOK, "", nil) // index.html
|
|
test("GET", "http://mox.example/nolist/dir/", nil, http.StatusForbidden, "", nil) // no listing
|
|
|
|
test("GET", "http://mox.example/tls/", nil, http.StatusPermanentRedirect, "", map[string]string{"Location": "https://mox.example/tls/"}) // redirect to tls
|
|
|
|
test("GET", "http://mox.example/baseurl/x?y=2", nil, http.StatusPermanentRedirect, "", map[string]string{"Location": "https://tls.mox.example/baseurl/x?q=1&y=2#fragment"})
|
|
test("GET", "http://mox.example/pathonly/old/x?q=2", nil, http.StatusTemporaryRedirect, "", map[string]string{"Location": "http://mox.example/pathonly/new/x?q=2"})
|
|
test("GET", "http://mox.example/baseurlpath/old/x?y=2", nil, http.StatusPermanentRedirect, "", map[string]string{"Location": "//other.mox.example/baseurlpath/new/x?q=1&y=2#fragment"})
|
|
|
|
test("GET", "http://mox.example/strip/x", nil, http.StatusBadGateway, "", nil) // no server yet
|
|
test("GET", "http://mox.example/nostrip/x", nil, http.StatusBadGateway, "", nil) // no server yet
|
|
|
|
badForwarded := map[string]string{
|
|
"Forwarded": "bad",
|
|
"X-Forwarded-For": "bad",
|
|
"X-Forwarded-Proto": "bad",
|
|
"X-Forwarded-Host": "bad",
|
|
"X-Forwarded-Ext": "bad",
|
|
}
|
|
|
|
// Server that echoes path, and forwarded request headers.
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
for k, v := range badForwarded {
|
|
if r.Header.Get(k) == v {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
}
|
|
|
|
for k, vl := range r.Header {
|
|
if k == "Forwarded" || k == "X-Forwarded" || strings.HasPrefix(k, "X-Forwarded-") {
|
|
w.Header()[k] = vl
|
|
}
|
|
}
|
|
w.Write([]byte(r.URL.Path))
|
|
}))
|
|
defer server.Close()
|
|
|
|
serverURL, err := url.Parse(server.URL)
|
|
if err != nil {
|
|
t.Fatalf("parsing url: %v", err)
|
|
}
|
|
serverURL.Path = "/a"
|
|
|
|
// warning: it is not normally allowed to access the dynamic config without lock. don't propagate accesses like this!
|
|
mox.Conf.Dynamic.WebHandlers[len(mox.Conf.Dynamic.WebHandlers)-2].WebForward.TargetURL = serverURL
|
|
mox.Conf.Dynamic.WebHandlers[len(mox.Conf.Dynamic.WebHandlers)-1].WebForward.TargetURL = serverURL
|
|
|
|
test("GET", "http://mox.example/strip/x", badForwarded, http.StatusOK, "/a/x", map[string]string{
|
|
"X-Test": "mox",
|
|
"X-Forwarded-For": "192.0.2.1", // IP is hardcoded in Go's src/net/http/httptest/httptest.go
|
|
"X-Forwarded-Proto": "http",
|
|
"X-Forwarded-Host": "mox.example",
|
|
"X-Forwarded-Ext": "",
|
|
})
|
|
test("GET", "http://mox.example/nostrip/x", map[string]string{"X-OK": "ok"}, http.StatusOK, "/a/nostrip/x", map[string]string{"X-Test": "mox"})
|
|
|
|
test("GET", "http://mox.example/bogus", nil, http.StatusNotFound, "", nil) // path not registered.
|
|
test("GET", "http://bogus.mox.example/static/", nil, http.StatusNotFound, "", nil) // domain not registered.
|
|
}
|