From a6bd4cba833bd576c20ca05badc3aa26ce7f0f91 Mon Sep 17 00:00:00 2001 From: "Juan J. Martinez" Date: Tue, 31 Aug 2021 22:57:23 +0100 Subject: Support to pass env variables to CGIs Env variables are configured per virtual host. --- CHANGES.md | 12 ++++ server/src/net/usebox/gemini/server/Response.scala | 5 +- server/src/net/usebox/gemini/server/Server.scala | 3 +- .../src/net/usebox/gemini/server/ServiceConf.scala | 3 +- server/test/src/ServerSpec.scala | 65 ++++++++++++++++++++++ spacebeans.conf.example | 3 + 6 files changed, 87 insertions(+), 4 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 9ebcb9e..0d0c53e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,17 @@ # What's new? +## Release 1.3.0 - 2021-??-?? + + - Support to provide extra environment variables to CGIs: + +``` +// in virtual host +environment = { "VARIABLE": "VALUE" } +``` + When executing a CGI, SapaceBeans provides a clean environment (other than + the CGI variables). Any required environment variable must be specified + using this configuration token. + ## Release 1.2.0 - 2021-07-20 - Classic CGI support: diff --git a/server/src/net/usebox/gemini/server/Response.scala b/server/src/net/usebox/gemini/server/Response.scala index a6993c4..edb6cdc 100644 --- a/server/src/net/usebox/gemini/server/Response.scala +++ b/server/src/net/usebox/gemini/server/Response.scala @@ -91,7 +91,8 @@ case class Cgi( scriptName: String, host: String, port: String, - remoteAddr: String + remoteAddr: String, + vhEnv: Map[String, String] ) extends Response { private[this] val logger = getLogger @@ -100,7 +101,7 @@ case class Cgi( val responseRe = "([0-9]{2}) (.*)".r - val env = Map( + val env = vhEnv ++ Map( "GATEWAY_INTERFACE" -> "CGI/1.1", "SERVER_SOFTWARE" -> s"${BuildInfo.name}/${BuildInfo.version}", "SERVER_PROTOCOL" -> "GEMINI", diff --git a/server/src/net/usebox/gemini/server/Server.scala b/server/src/net/usebox/gemini/server/Server.scala index 3c78721..f402191 100644 --- a/server/src/net/usebox/gemini/server/Server.scala +++ b/server/src/net/usebox/gemini/server/Server.scala @@ -137,7 +137,8 @@ case class Server(conf: ServiceConf) { scriptName = cgiFile.getFileName().toString(), host = vhost.host, port = conf.port.toString(), - remoteAddr = remoteAddr + remoteAddr = remoteAddr, + vhEnv = vhost.environment.getOrElse(Map()) ) case path if !path.exists() => logger.debug("no resource") diff --git a/server/src/net/usebox/gemini/server/ServiceConf.scala b/server/src/net/usebox/gemini/server/ServiceConf.scala index dc28650..43786af 100644 --- a/server/src/net/usebox/gemini/server/ServiceConf.scala +++ b/server/src/net/usebox/gemini/server/ServiceConf.scala @@ -26,7 +26,8 @@ case class VirtualHost( geminiParams: Option[String] = None, directories: List[Directory] = Nil, userDirectories: Boolean = false, - userDirectoryPath: Option[String] = None + userDirectoryPath: Option[String] = None, + environment: Option[Map[String, String]] = None ) object VirtualHost { diff --git a/server/test/src/ServerSpec.scala b/server/test/src/ServerSpec.scala index 7a2b501..bd909ca 100644 --- a/server/test/src/ServerSpec.scala +++ b/server/test/src/ServerSpec.scala @@ -455,6 +455,7 @@ class ServerSpec extends AnyFlatSpec with Matchers { "cgi", TestData.host, TestData.portStr, + _, _ ) => } @@ -473,6 +474,7 @@ class ServerSpec extends AnyFlatSpec with Matchers { "cgi", TestData.host, TestData.portStr, + _, _ ) => } @@ -491,6 +493,7 @@ class ServerSpec extends AnyFlatSpec with Matchers { "cgi", TestData.host, TestData.portStr, + _, _ ) => } @@ -509,6 +512,7 @@ class ServerSpec extends AnyFlatSpec with Matchers { "cgi", TestData.host, TestData.portStr, + _, _ ) => } @@ -566,6 +570,57 @@ class ServerSpec extends AnyFlatSpec with Matchers { bad.body should include(meta) } + it should "enviroment variables are optional" in { + Server(TestData.cgiConf).handleReq( + "gemini://localhost/dir/cgi/", + "127.0.0.1" + ) should matchPattern { + case Cgi( + _, + _, + _, + _, + "cgi", + TestData.host, + TestData.portStr, + _, + m + ) if m == Map() => + } + } + + it should "pass enviroment variables to the CGI" in { + Server(TestData.cgiEnvConf).handleReq( + "gemini://localhost/dir/cgi/", + "127.0.0.1" + ) should matchPattern { + case Cgi( + _, + _, + _, + _, + "cgi", + TestData.host, + TestData.portStr, + _, + m + ) if m == Map("env1" -> "value") => + } + } + + it should "execute a CGI with the environment variables" in { + val cgi = Server(TestData.cgiEnvConf) + .handleReq( + "gemini://localhost/dir/cgi", + "127.0.0.1" + ) + .asInstanceOf[Cgi] + + cgi.status should be(20) + cgi.meta should be("text/gemini") + cgi.body should include("env1=value") + } + object TestData { val host = "localhost" @@ -607,6 +662,16 @@ class ServerSpec extends AnyFlatSpec with Matchers { ) ) + val cgiEnvConf = cgiConf.copy(virtualHosts = + List( + cgiConf + .virtualHosts(0) + .copy( + environment = Some(Map("env1" -> "value")) + ) + ) + ) + val confUserDir = conf.copy(virtualHosts = List( conf diff --git a/spacebeans.conf.example b/spacebeans.conf.example index 9e92d45..8e24325 100644 --- a/spacebeans.conf.example +++ b/spacebeans.conf.example @@ -29,6 +29,9 @@ virtual-hosts = [ // optional parameters for text/gemini // gemini-params = "charset=utf-8; lang=en" + // optional environment variables to pass to CGIs + // environment = { "VAR1": "VALUE1", "VAR2": "VALUE2" } + // override defaults, set properties per directory // important: directory's path is relative to the root // -- cgit v1.2.3