Doug Lauder
2023-03-22 17:22:27 -04:00
коммит произвёл GitHub
родитель b61c096497
Коммит c943ed6859
13276 изменённых файлов: 1695615 добавлений и 223189 удалений

159
server/boards/web/webserver.go Обычный файл
Просмотреть файл

@@ -0,0 +1,159 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package web
import (
"errors"
"fmt"
"net/http"
"net/url"
"os"
"path"
"path/filepath"
"strings"
"text/template"
"github.com/gorilla/mux"
"github.com/mattermost/mattermost-server/v6/server/platform/shared/mlog"
)
// RoutedService defines the interface that is needed for any service to
// register themself in the web server to provide new endpoints. (see
// AddRoutes).
type RoutedService interface {
RegisterRoutes(*mux.Router)
}
// Server is the structure responsible for managing our http web server.
type Server struct {
http.Server
baseURL string
rootPath string
basePrefix string
port int
ssl bool
logger mlog.LoggerIFace
}
// NewServer creates a new instance of the webserver.
func NewServer(rootPath string, serverRoot string, port int, ssl, localOnly bool, logger mlog.LoggerIFace) *Server {
r := mux.NewRouter()
basePrefix := os.Getenv("FOCALBOARD_HTTP_SERVER_BASEPATH")
if basePrefix != "" {
r = r.PathPrefix(basePrefix).Subrouter()
}
var addr string
if localOnly {
addr = fmt.Sprintf(`localhost:%d`, port)
} else {
addr = fmt.Sprintf(`:%d`, port)
}
baseURL := ""
url, err := url.Parse(serverRoot)
if err != nil {
logger.Error("Invalid ServerRoot setting", mlog.Err(err))
}
baseURL = url.Path
ws := &Server{
// (TODO: Add ReadHeaderTimeout)
Server: http.Server{ //nolint:gosec
Addr: addr,
Handler: r,
},
baseURL: baseURL,
rootPath: rootPath,
port: port,
ssl: ssl,
logger: logger,
basePrefix: basePrefix,
}
return ws
}
func (ws *Server) Router() *mux.Router {
return ws.Server.Handler.(*mux.Router)
}
// AddRoutes allows services to register themself in the webserver router and provide new endpoints.
func (ws *Server) AddRoutes(rs RoutedService) {
rs.RegisterRoutes(ws.Router())
}
func (ws *Server) registerRoutes() {
ws.Router().PathPrefix("/static").Handler(http.StripPrefix(ws.basePrefix+"/static/", http.FileServer(http.Dir(filepath.Join(ws.rootPath, "static")))))
ws.Router().PathPrefix("/").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
indexTemplate, err := template.New("index").ParseFiles(path.Join(ws.rootPath, "index.html"))
if err != nil {
ws.logger.Log(errorOrWarn(), "Unable to serve the index.html file", mlog.Err(err))
w.WriteHeader(http.StatusInternalServerError)
return
}
err = indexTemplate.ExecuteTemplate(w, "index.html", map[string]string{"BaseURL": ws.baseURL})
if err != nil {
ws.logger.Log(errorOrWarn(), "Unable to serve the index.html file", mlog.Err(err))
w.WriteHeader(http.StatusInternalServerError)
return
}
})
}
// Start runs the web server and start listening for connections.
func (ws *Server) Start() {
ws.registerRoutes()
if ws.port == -1 {
ws.logger.Debug("server not bind to any port")
return
}
isSSL := ws.ssl && fileExists("./cert/cert.pem") && fileExists("./cert/key.pem")
if isSSL {
ws.logger.Info("https server started", mlog.Int("port", ws.port))
go func() {
if err := ws.ListenAndServeTLS("./cert/cert.pem", "./cert/key.pem"); err != nil {
ws.logger.Fatal("ListenAndServeTLS", mlog.Err(err))
}
}()
return
}
ws.logger.Info("http server started", mlog.Int("port", ws.port))
go func() {
if err := ws.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
ws.logger.Fatal("ListenAndServeTLS", mlog.Err(err))
}
ws.logger.Info("http server stopped")
}()
}
func (ws *Server) Shutdown() error {
return ws.Close()
}
// fileExists returns true if a file exists at the path.
func fileExists(path string) bool {
_, err := os.Stat(path)
if os.IsNotExist(err) {
return false
}
return err == nil
}
// errorOrWarn returns a `warn` level if this server instance is running unit tests, otherwise `error`.
func errorOrWarn() mlog.Level {
unitTesting := strings.ToLower(strings.TrimSpace(os.Getenv("FOCALBOARD_UNIT_TESTING")))
if unitTesting == "1" || unitTesting == "y" || unitTesting == "t" {
return mlog.LvlWarn
}
return mlog.LvlError
}

102
server/boards/web/webserver_test.go Обычный файл
Просмотреть файл

@@ -0,0 +1,102 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package web
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/mattermost/mattermost-server/v6/server/platform/shared/mlog"
)
func Test_NewServer(t *testing.T) {
tests := []struct {
name string
rootPath string
serverRoot string
ssl bool
port int
localOnly bool
logger mlog.LoggerIFace
expectedBaseURL string
expectedServerAddr string
}{
{
name: "should return server with given properties",
rootPath: "./test/path/to/root",
serverRoot: "https://some-fake-server.com/fake-url",
ssl: false,
port: 9999, // fake port number
localOnly: false,
logger: &mlog.Logger{},
expectedBaseURL: "/fake-url",
expectedServerAddr: ":9999",
},
{
name: "should return local server with given properties",
rootPath: "./test/path/to/root",
serverRoot: "https://some-fake-server.com/fake-url",
ssl: false,
port: 3000, // fake port number
localOnly: true,
logger: &mlog.Logger{},
expectedBaseURL: "/fake-url",
expectedServerAddr: "localhost:3000",
},
{
name: "should match Server properties when ssl true",
rootPath: "./test/path/to/root",
serverRoot: "https://some-fake-server.com/fake-url",
ssl: true,
port: 8000, // fake port number
localOnly: false,
logger: &mlog.Logger{},
expectedBaseURL: "/fake-url",
expectedServerAddr: ":8000",
},
{
name: "should return local server when ssl true",
rootPath: "./test/path/to/root",
serverRoot: "https://localhost:8080/fake-url",
ssl: true,
port: 9999, // fake port number
localOnly: true,
logger: &mlog.Logger{},
expectedBaseURL: "/fake-url",
expectedServerAddr: "localhost:9999",
},
{
name: "should return '/' as base url is not good!",
rootPath: "",
serverRoot: "https://localhost:8080/#!@$@#@",
ssl: true,
port: 9999, // fake port number
localOnly: true,
logger: &mlog.Logger{},
expectedBaseURL: "/",
expectedServerAddr: "localhost:9999",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ws := NewServer(test.rootPath, test.serverRoot, test.port, test.ssl, test.localOnly, test.logger)
require.NotNil(t, ws, "The webserver object is nil!")
require.Equal(t, test.expectedBaseURL, ws.baseURL, "baseURL does not match")
require.Equal(t, test.rootPath, ws.rootPath, "rootPath does not match")
require.Equal(t, test.port, ws.port, "rootPath does not match")
require.Equal(t, test.ssl, ws.ssl, "logger pointer does not match")
require.Equal(t, test.logger, ws.logger, "logger pointer does not match")
if test.localOnly == true {
require.Equal(t, test.expectedServerAddr, ws.Server.Addr, "localhost address not as matching!")
} else {
require.Equal(t, test.expectedServerAddr, ws.Server.Addr, "server address not matching!")
}
})
}
}