diff --git a/commands/local_server_start.go b/commands/local_server_start.go index 04ddf087..5e24c816 100644 --- a/commands/local_server_start.go +++ b/commands/local_server_start.go @@ -52,6 +52,7 @@ import ( var localWebServerProdWarningMsg = "The local web server is optimized for local development and MUST never be used in a production setup." var localWebServerTlsKeyLogWarningMsg = "Logging TLS master key is enabled. It means TLS connections between the client and this server will be INSECURE. This is NOT recommended unless you are debugging the connections." +var localWebServerAllowsCORSLogWarningMsg = "Cross-origin resource sharing (CORS) is enabled for all requests.\nYou may want to use https://github.com/nelmio/NelmioCorsBundle to have better control over HTTP headers." var localServerStartCmd = &console.Command{ Category: "local", @@ -83,6 +84,7 @@ var localServerStartCmd = &console.Command{ EnvVars: []string{"SSLKEYLOGFILE"}, }, &console.BoolFlag{Name: "no-workers", Usage: "Do not start workers"}, + &console.BoolFlag{Name: "allow-cors", Usage: "Allow Cross-origin resource sharing (CORS) requests"}, }, Action: func(c *console.Context) error { ui := terminal.SymfonyStyle(terminal.Stdout, terminal.Stdin) @@ -188,6 +190,10 @@ var localServerStartCmd = &console.Command{ ui.Warning(localWebServerTlsKeyLogWarningMsg) } + if config.AllowCORS { + ui.Warning(localWebServerAllowsCORSLogWarningMsg) + } + lw, err := pidFile.LogWriter() if err != nil { return err diff --git a/local/http/cors.go b/local/http/cors.go new file mode 100644 index 00000000..56abf2bd --- /dev/null +++ b/local/http/cors.go @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021-present Fabien Potencier + * + * This file is part of Symfony CLI project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package http + +import ( + "net/http" + + "github.com/rs/zerolog" +) + +func corsWrapper(h http.Handler, logger zerolog.Logger) http.Handler { + var corsHeaders = []string{"Access-Control-Allow-Origin", "Access-Control-Allow-Methods", "Access-Control-Allow-Headers"} + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + for _, corsHeader := range corsHeaders { + w.Header().Set(corsHeader, "*") + } + + h.ServeHTTP(w, r) + + for _, corsHeader := range corsHeaders { + if headers, exists := w.Header()[corsHeader]; !exists || len(headers) < 2 { + continue + } + + logger.Warn().Msgf(`Multiple entries detected for header "%s". Only one should be set: you should enable CORS handling in the CLI only if the application does not handle them.`, corsHeader) + } + }) +} diff --git a/local/http/http.go b/local/http/http.go index 859dd25b..650ed678 100644 --- a/local/http/http.go +++ b/local/http/http.go @@ -56,6 +56,7 @@ type Server struct { Appversion string UseGzip bool TlsKeyLogFile string + AllowCORS bool httpserver *http.Server httpsserver *http.Server @@ -98,6 +99,10 @@ func (s *Server) Start(errChan chan error) (int, error) { proxyHandler = gzipWrapper(proxyHandler) } + if s.AllowCORS { + proxyHandler = corsWrapper(proxyHandler, s.Logger) + } + s.httpserver = &http.Server{ Handler: proxyHandler, } diff --git a/local/project/config.go b/local/project/config.go index 307f01bf..82049342 100644 --- a/local/project/config.go +++ b/local/project/config.go @@ -49,6 +49,7 @@ type Config struct { UseGzip bool `yaml:"use_gzip"` TlsKeyLogFile string `yaml:"tls_key_log_file"` NoWorkers bool `yaml:"no_workers"` + AllowCORS bool `yaml:"allow_cors"` } type FileConfig struct { @@ -122,6 +123,9 @@ func NewConfigFromContext(c *console.Context, projectDir string) (*Config, *File if c.IsSet("no-workers") { config.NoWorkers = c.Bool("no-workers") } + if c.IsSet("allow-cors") { + config.AllowCORS = c.Bool("allow-cors") + } return config, fileConfig, nil } diff --git a/local/project/project.go b/local/project/project.go index a4fbbc88..53ad6e9f 100644 --- a/local/project/project.go +++ b/local/project/project.go @@ -63,6 +63,7 @@ func New(c *Config) (*Project, error) { UseGzip: c.UseGzip, Appversion: c.AppVersion, TlsKeyLogFile: c.TlsKeyLogFile, + AllowCORS: c.AllowCORS, }, } if err != nil {