2016-07-21 17:57:38 +01:00
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
2017-07-21 18:14:19 +01:00
package server
2016-07-21 17:57:38 +01:00
import (
2021-03-16 13:58:27 -04:00
"crypto/tls"
2016-07-21 17:57:38 +01:00
"fmt"
"net/http"
"strings"
"github.com/codegangsta/negroni"
"github.com/documize/community/core/api/plugins"
2021-08-18 19:39:51 -04:00
"github.com/documize/community/core/asset"
2016-07-21 17:57:38 +01:00
"github.com/documize/community/core/database"
2017-07-21 14:53:32 +01:00
"github.com/documize/community/core/env"
2018-09-27 15:14:48 +01:00
"github.com/documize/community/domain/store"
2017-07-21 18:14:19 +01:00
"github.com/documize/community/server/routing"
2019-04-11 14:45:36 +01:00
"github.com/gorilla/handlers"
2016-07-21 17:57:38 +01:00
"github.com/gorilla/mux"
)
var testHost string // used during automated testing
2017-07-21 18:14:19 +01:00
// Start router to handle all HTTP traffic.
2018-09-27 15:14:48 +01:00
func Start ( rt * env . Runtime , s * store . Store , ready chan struct { } ) {
2017-07-21 18:21:34 +01:00
// decide which mode to serve up
2017-07-24 16:24:21 +01:00
switch rt . Flags . SiteMode {
case env . SiteModeOffline :
2017-07-21 18:14:19 +01:00
rt . Log . Info ( "Serving OFFLINE web server" )
2017-07-24 16:24:21 +01:00
case env . SiteModeSetup :
2017-07-21 18:14:19 +01:00
rt . Log . Info ( "Serving SETUP web server" )
2017-08-29 17:55:41 +01:00
dbHandler := database . Handler { Runtime : rt , Store : s }
routing . Add ( rt , routing . RoutePrefixPrivate , "setup" , [ ] string { "POST" , "OPTIONS" } , nil , dbHandler . Setup )
2017-07-24 16:24:21 +01:00
case env . SiteModeBadDB :
2017-07-21 18:14:19 +01:00
rt . Log . Info ( "Serving BAD DATABASE web server" )
2016-07-21 17:57:38 +01:00
default :
2017-08-09 16:18:03 +01:00
err := plugins . Setup ( s )
if err != nil {
2017-08-29 17:55:41 +01:00
rt . Log . Error ( "plugin setup failed" , err )
2017-08-09 16:18:03 +01:00
}
2018-09-14 13:00:58 +01:00
rt . Log . Info ( "Web Server: starting up" )
2016-07-21 17:57:38 +01:00
}
2017-07-24 16:24:21 +01:00
// define middleware
2017-07-26 10:50:26 +01:00
cm := middleware { Runtime : rt , Store : s }
2017-07-24 16:24:21 +01:00
2017-07-21 18:21:34 +01:00
// define API endpoints
2017-07-26 10:50:26 +01:00
routing . RegisterEndpoints ( rt , s )
2017-07-21 18:21:34 +01:00
// wire up API endpoints
2016-07-21 17:57:38 +01:00
router := mux . NewRouter ( )
// "/api/public/..."
2017-07-21 18:14:19 +01:00
router . PathPrefix ( routing . RoutePrefixPublic ) . Handler ( negroni . New (
2017-07-24 16:24:21 +01:00
negroni . HandlerFunc ( cm . cors ) ,
2017-07-21 18:14:19 +01:00
negroni . Wrap ( routing . BuildRoutes ( rt , routing . RoutePrefixPublic ) ) ,
2016-07-21 17:57:38 +01:00
) )
// "/api/..."
2017-07-21 18:14:19 +01:00
router . PathPrefix ( routing . RoutePrefixPrivate ) . Handler ( negroni . New (
2017-08-02 15:26:31 +01:00
negroni . HandlerFunc ( cm . Authorize ) ,
2017-07-21 18:14:19 +01:00
negroni . Wrap ( routing . BuildRoutes ( rt , routing . RoutePrefixPrivate ) ) ,
2016-07-21 17:57:38 +01:00
) )
// "/..."
2017-07-21 18:14:19 +01:00
router . PathPrefix ( routing . RoutePrefixRoot ) . Handler ( negroni . New (
2017-07-24 16:24:21 +01:00
negroni . HandlerFunc ( cm . cors ) ,
2017-07-21 18:14:19 +01:00
negroni . Wrap ( routing . BuildRoutes ( rt , routing . RoutePrefixRoot ) ) ,
2016-07-21 17:57:38 +01:00
) )
2019-04-11 14:45:36 +01:00
// Look out for reverse proxy headers.
router . Use ( handlers . ProxyHeaders )
2016-07-21 17:57:38 +01:00
n := negroni . New ( )
2021-08-18 19:39:51 -04:00
sfs , err := asset . GetPublicFileSystem ( rt . Assets )
if err != nil {
rt . Log . Error ( "!!!!!!!!!! Cannot load public file system" , err )
}
n . Use ( negroni . NewStatic ( sfs ) )
2017-07-24 16:24:21 +01:00
n . Use ( negroni . HandlerFunc ( cm . cors ) )
2016-07-21 17:57:38 +01:00
n . UseHandler ( router )
2017-08-10 11:14:29 +01:00
// tell caller we are ready to serve HTTP
ready <- struct { } { }
2017-07-21 18:21:34 +01:00
// start server
2017-07-24 16:24:21 +01:00
if ! rt . Flags . SSLEnabled ( ) {
2018-09-14 13:00:58 +01:00
rt . Log . Info ( "Web Server: binding non-SSL server on " + rt . Flags . HTTPPort )
2017-08-10 12:38:05 +01:00
if rt . Flags . SiteMode == env . SiteModeSetup {
rt . Log . Info ( "***" )
rt . Log . Info ( fmt . Sprintf ( "*** Go to http://localhost:%s/setup in your web browser and complete setup wizard ***" , rt . Flags . HTTPPort ) )
rt . Log . Info ( "***" )
}
2017-07-24 16:24:21 +01:00
n . Run ( testHost + ":" + rt . Flags . HTTPPort )
2016-07-21 17:57:38 +01:00
} else {
2017-07-24 16:24:21 +01:00
if rt . Flags . ForceHTTPPort2SSL != "" {
2018-09-14 13:00:58 +01:00
rt . Log . Info ( "Web Server: binding non-SSL server on " + rt . Flags . ForceHTTPPort2SSL + " and redirecting to SSL server on " + rt . Flags . HTTPPort )
2016-07-21 17:57:38 +01:00
go func ( ) {
2017-07-24 16:24:21 +01:00
err := http . ListenAndServe ( ":" + rt . Flags . ForceHTTPPort2SSL , http . HandlerFunc (
2016-07-21 17:57:38 +01:00
func ( w http . ResponseWriter , req * http . Request ) {
2017-05-19 11:36:28 +01:00
w . Header ( ) . Set ( "Connection" , "close" )
2017-07-24 16:24:21 +01:00
var host = strings . Replace ( req . Host , rt . Flags . ForceHTTPPort2SSL , rt . Flags . HTTPPort , 1 ) + req . RequestURI
2016-07-21 17:57:38 +01:00
http . Redirect ( w , req , "https://" + host , http . StatusMovedPermanently )
} ) )
if err != nil {
2017-07-24 16:24:21 +01:00
rt . Log . Error ( "ListenAndServe on " + rt . Flags . ForceHTTPPort2SSL , err )
2016-07-21 17:57:38 +01:00
}
} ( )
}
2017-08-10 12:38:05 +01:00
if rt . Flags . SiteMode == env . SiteModeSetup {
rt . Log . Info ( "***" )
rt . Log . Info ( fmt . Sprintf ( "*** Go to https://localhost:%s/setup in your web browser and complete setup wizard ***" , rt . Flags . HTTPPort ) )
rt . Log . Info ( "***" )
}
2022-10-10 17:40:36 -04:00
cfg := & tls . Config { }
if rt . Flags . TLSVersion == "1.0" {
cfg . MinVersion = tls . VersionTLS10
}
if rt . Flags . TLSVersion == "1.1" {
cfg . MinVersion = tls . VersionTLS11
}
if rt . Flags . TLSVersion == "1.2" {
cfg . MinVersion = tls . VersionTLS12
2021-03-16 13:58:27 -04:00
}
2022-10-10 17:40:36 -04:00
if rt . Flags . TLSVersion == "1.3" {
cfg . MinVersion = tls . VersionTLS13
}
rt . Log . Info ( "Web Server: starting SSL server on " + rt . Flags . HTTPPort + " with " + rt . Flags . SSLCertFile + " " + rt . Flags . SSLKeyFile + " TLS: " + rt . Flags . TLSVersion )
2021-03-16 13:58:27 -04:00
server := & http . Server { Addr : ":" + rt . Flags . HTTPPort , Handler : n , TLSConfig : cfg }
2016-07-21 17:57:38 +01:00
server . SetKeepAlivesEnabled ( true )
2017-07-21 14:53:32 +01:00
2017-07-24 16:24:21 +01:00
if err := server . ListenAndServeTLS ( rt . Flags . SSLCertFile , rt . Flags . SSLKeyFile ) ; err != nil {
rt . Log . Error ( "ListenAndServeTLS on " + rt . Flags . HTTPPort , err )
2016-07-21 17:57:38 +01:00
}
}
}