Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
S
spring-boot
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DEMO
spring-boot
Commits
1e801723
Commit
1e801723
authored
Oct 02, 2015
by
Phillip Webb
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'gh-4018'
parents
5cbb81c6
d4c2959c
Changes
19
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
739 additions
and
280 deletions
+739
-280
ServerProperties.java
...ingframework/boot/autoconfigure/web/ServerProperties.java
+79
-19
ServerPropertiesTests.java
...amework/boot/autoconfigure/web/ServerPropertiesTests.java
+75
-10
appendix-application-properties.adoc
...cs/src/main/asciidoc/appendix-application-properties.adoc
+1
-0
howto.adoc
spring-boot-docs/src/main/asciidoc/howto.adoc
+53
-60
CloudFoundryVcapEnvironmentPostProcessor.java
.../boot/cloud/CloudFoundryVcapEnvironmentPostProcessor.java
+241
-0
CloudPlatform.java
...in/java/org/springframework/boot/cloud/CloudPlatform.java
+88
-0
package-info.java
...ain/java/org/springframework/boot/cloud/package-info.java
+3
-3
VcapEnvironmentPostProcessor.java
...ework/boot/cloudfoundry/VcapEnvironmentPostProcessor.java
+5
-169
JettyEmbeddedServletContainerFactory.java
.../embedded/jetty/JettyEmbeddedServletContainerFactory.java
+38
-0
UndertowEmbeddedServletContainer.java
...t/embedded/undertow/UndertowEmbeddedServletContainer.java
+14
-1
UndertowEmbeddedServletContainerFactory.java
...ded/undertow/UndertowEmbeddedServletContainerFactory.java
+12
-1
spring.factories
spring-boot/src/main/resources/META-INF/spring.factories
+2
-2
CloudPlatformTests.java
...va/org/springframework/boot/cloud/CloudPlatformTests.java
+75
-0
CloudFoundryVcapEnvironmentPostProcessorTests.java
...oundry/CloudFoundryVcapEnvironmentPostProcessorTests.java
+5
-4
AbstractEmbeddedServletContainerFactoryTests.java
...mbedded/AbstractEmbeddedServletContainerFactoryTests.java
+24
-10
ExampleServlet.java
...springframework/boot/context/embedded/ExampleServlet.java
+2
-1
JettyEmbeddedServletContainerFactoryTests.java
...dded/jetty/JettyEmbeddedServletContainerFactoryTests.java
+7
-0
TomcatEmbeddedServletContainerFactoryTests.java
...ed/tomcat/TomcatEmbeddedServletContainerFactoryTests.java
+8
-0
UndertowEmbeddedServletContainerFactoryTests.java
...ndertow/UndertowEmbeddedServletContainerFactoryTests.java
+7
-0
No files found.
spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java
View file @
1e801723
...
...
@@ -38,6 +38,7 @@ import org.apache.coyote.AbstractProtocol;
import
org.apache.coyote.ProtocolHandler
;
import
org.apache.coyote.http11.AbstractHttp11Protocol
;
import
org.springframework.boot.autoconfigure.web.ServerProperties.Session.Cookie
;
import
org.springframework.boot.cloud.CloudPlatform
;
import
org.springframework.boot.context.embedded.Compression
;
import
org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer
;
import
org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer
;
...
...
@@ -47,6 +48,7 @@ import org.springframework.boot.context.embedded.InitParameterConfiguringServlet
import
org.springframework.boot.context.embedded.JspServlet
;
import
org.springframework.boot.context.embedded.ServletContextInitializer
;
import
org.springframework.boot.context.embedded.Ssl
;
import
org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory
;
import
org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer
;
import
org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer
;
import
org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory
;
...
...
@@ -54,7 +56,9 @@ import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServle
import
org.springframework.boot.context.properties.ConfigurationProperties
;
import
org.springframework.boot.context.properties.DeprecatedConfigurationProperty
;
import
org.springframework.boot.context.properties.NestedConfigurationProperty
;
import
org.springframework.context.EnvironmentAware
;
import
org.springframework.core.Ordered
;
import
org.springframework.core.env.Environment
;
import
org.springframework.util.StringUtils
;
/**
...
...
@@ -69,7 +73,8 @@ import org.springframework.util.StringUtils;
* @author Marcos Barbero
*/
@ConfigurationProperties
(
prefix
=
"server"
,
ignoreUnknownFields
=
true
)
public
class
ServerProperties
implements
EmbeddedServletContainerCustomizer
,
Ordered
{
public
class
ServerProperties
implements
EmbeddedServletContainerCustomizer
,
EnvironmentAware
,
Ordered
{
/**
* Server HTTP port.
...
...
@@ -102,6 +107,11 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
*/
private
final
Map
<
String
,
String
>
contextParameters
=
new
HashMap
<
String
,
String
>();
/**
* If X-Forwarded-* headers should be applied to the HttpRequest.
*/
private
Boolean
useForwardHeaders
;
private
Session
session
=
new
Session
();
@NestedConfigurationProperty
...
...
@@ -115,13 +125,22 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
private
final
Tomcat
tomcat
=
new
Tomcat
();
private
final
Jetty
jetty
=
new
Jetty
();
private
final
Undertow
undertow
=
new
Undertow
();
private
Environment
environment
;
@Override
public
int
getOrder
()
{
return
0
;
}
@Override
public
void
setEnvironment
(
Environment
environment
)
{
this
.
environment
=
environment
;
}
@Override
public
void
customize
(
ConfigurableEmbeddedServletContainer
container
)
{
if
(
getPort
()
!=
null
)
{
...
...
@@ -150,11 +169,16 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
container
.
setCompression
(
getCompression
());
}
if
(
container
instanceof
TomcatEmbeddedServletContainerFactory
)
{
getTomcat
()
.
customizeTomcat
(
(
TomcatEmbeddedServletContainerFactory
)
container
);
getTomcat
()
.
customizeTomcat
(
this
,
(
TomcatEmbeddedServletContainerFactory
)
container
);
}
if
(
container
instanceof
JettyEmbeddedServletContainerFactory
)
{
getJetty
().
customizeJetty
(
this
,
(
JettyEmbeddedServletContainerFactory
)
container
);
}
if
(
container
instanceof
UndertowEmbeddedServletContainerFactory
)
{
getUndertow
().
customizeUndertow
(
getUndertow
().
customizeUndertow
(
this
,
(
UndertowEmbeddedServletContainerFactory
)
container
);
}
container
.
addInitializers
(
new
SessionConfiguringInitializer
(
this
.
session
));
...
...
@@ -267,6 +291,22 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
return
this
.
contextParameters
;
}
public
Boolean
isUseForwardHeaders
()
{
return
this
.
useForwardHeaders
;
}
public
void
setUseForwardHeaders
(
Boolean
useForwardHeaders
)
{
this
.
useForwardHeaders
=
useForwardHeaders
;
}
protected
final
boolean
getOrDeduceUseForwardHeaders
()
{
if
(
this
.
useForwardHeaders
!=
null
)
{
return
this
.
useForwardHeaders
;
}
CloudPlatform
platform
=
CloudPlatform
.
getActive
(
this
.
environment
);
return
(
platform
==
null
?
false
:
platform
.
isUsingForwardHeaders
());
}
/**
* Get the session timeout.
* @return the session timeout
...
...
@@ -320,6 +360,10 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
return
this
.
tomcat
;
}
private
Jetty
getJetty
()
{
return
this
.
jetty
;
}
public
Undertow
getUndertow
()
{
return
this
.
undertow
;
}
...
...
@@ -488,9 +532,8 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
/**
* Header that holds the incoming protocol, usually named "X-Forwarded-Proto".
* Configures a RemoteIpValve only if remoteIpHeader is also set.
*/
private
String
protocolHeader
=
"x-forwarded-proto"
;
private
String
protocolHeader
;
/**
* Value of the protocol header that indicates that the incoming request uses SSL.
...
...
@@ -500,13 +543,12 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
/**
* Name of the HTTP header used to override the original port value.
*/
private
String
portHeader
=
"
x-forwarded-p
ort"
;
private
String
portHeader
=
"
X-Forwarded-P
ort"
;
/**
* Name of the http header from which the remote ip is extracted. Configures a
* RemoteIpValve only if protocolHeader is also set.
* Name of the http header from which the remote ip is extracted..
*/
private
String
remoteIpHeader
=
"x-forwarded-for"
;
private
String
remoteIpHeader
;
/**
* Tomcat base directory. If not specified a temporary directory will be used.
...
...
@@ -659,12 +701,13 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
this
.
uriEncoding
=
uriEncoding
;
}
void
customizeTomcat
(
TomcatEmbeddedServletContainerFactory
factory
)
{
void
customizeTomcat
(
ServerProperties
serverProperties
,
TomcatEmbeddedServletContainerFactory
factory
)
{
if
(
getBasedir
()
!=
null
)
{
factory
.
setBaseDirectory
(
getBasedir
());
}
customizeBackgroundProcessorDelay
(
factory
);
customize
Headers
(
factory
);
customize
RemoteIpValve
(
serverProperties
,
factory
);
if
(
this
.
maxThreads
>
0
)
{
customizeMaxThreads
(
factory
);
}
...
...
@@ -691,14 +734,20 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
});
}
private
void
customize
Headers
(
TomcatEmbeddedServletContainerFactory
factory
)
{
String
remoteIpHeader
=
getRemoteIpHeader
();
private
void
customize
RemoteIpValve
(
ServerProperties
properties
,
TomcatEmbeddedServletContainerFactory
factory
)
{
String
protocolHeader
=
getProtocolHeader
();
if
(
StringUtils
.
hasText
(
remoteIpHeader
)
&&
StringUtils
.
hasText
(
protocolHeader
))
{
String
remoteIpHeader
=
getRemoteIpHeader
();
// For back compatibility the valve is also enabled if protocol-header is set
if
(
StringUtils
.
hasText
(
protocolHeader
)
||
StringUtils
.
hasText
(
remoteIpHeader
)
||
properties
.
getOrDeduceUseForwardHeaders
())
{
RemoteIpValve
valve
=
new
RemoteIpValve
();
valve
.
setRemoteIpHeader
(
remoteIpHeader
);
valve
.
setProtocolHeader
(
protocolHeader
);
valve
.
setProtocolHeader
(
StringUtils
.
hasLength
(
protocolHeader
)
?
protocolHeader
:
"X-Forwarded-Proto"
);
if
(
StringUtils
.
hasLength
(
remoteIpHeader
))
{
valve
.
setRemoteIpHeader
(
remoteIpHeader
);
}
// The internal proxies default to a white list of "safe" internal IP
// addresses
valve
.
setInternalProxies
(
getInternalProxies
());
...
...
@@ -822,6 +871,15 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
}
private
static
class
Jetty
{
void
customizeJetty
(
ServerProperties
serverProperties
,
JettyEmbeddedServletContainerFactory
factory
)
{
factory
.
setUseForwardHeaders
(
serverProperties
.
getOrDeduceUseForwardHeaders
());
}
}
public
static
class
Undertow
{
/**
...
...
@@ -958,7 +1016,8 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
getAccesslog
().
setDir
(
accessLogDir
);
}
void
customizeUndertow
(
UndertowEmbeddedServletContainerFactory
factory
)
{
void
customizeUndertow
(
ServerProperties
serverProperties
,
UndertowEmbeddedServletContainerFactory
factory
)
{
factory
.
setBufferSize
(
this
.
bufferSize
);
factory
.
setBuffersPerRegion
(
this
.
buffersPerRegion
);
factory
.
setIoThreads
(
this
.
ioThreads
);
...
...
@@ -967,6 +1026,7 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord
factory
.
setAccessLogDirectory
(
this
.
accesslog
.
dir
);
factory
.
setAccessLogPattern
(
this
.
accesslog
.
pattern
);
factory
.
setAccessLogEnabled
(
this
.
accesslog
.
enabled
);
factory
.
setUseForwardHeaders
(
serverProperties
.
getOrDeduceUseForwardHeaders
());
}
public
static
class
Accesslog
{
...
...
spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ServerPropertiesTests.java
View file @
1e801723
...
...
@@ -39,7 +39,10 @@ import org.springframework.beans.MutablePropertyValues;
import
org.springframework.boot.bind.RelaxedDataBinder
;
import
org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer
;
import
org.springframework.boot.context.embedded.ServletContextInitializer
;
import
org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory
;
import
org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory
;
import
org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory
;
import
org.springframework.mock.env.MockEnvironment
;
import
static
org
.
hamcrest
.
Matchers
.
equalTo
;
import
static
org
.
hamcrest
.
Matchers
.
instanceOf
;
...
...
@@ -50,6 +53,7 @@ import static org.mockito.BDDMockito.given;
import
static
org
.
mockito
.
Mockito
.
atLeastOnce
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
never
;
import
static
org
.
mockito
.
Mockito
.
spy
;
import
static
org
.
mockito
.
Mockito
.
verify
;
/**
...
...
@@ -58,6 +62,7 @@ import static org.mockito.Mockito.verify;
* @author Dave Syer
* @author Stephane Nicoll
* @author Andy Wilkinson
* @author Phillip Webb
*/
public
class
ServerPropertiesTests
{
...
...
@@ -239,10 +244,8 @@ public class ServerPropertiesTests {
Map
<
String
,
String
>
map
=
new
HashMap
<
String
,
String
>();
map
.
put
(
"server.display-name"
,
"MyBootApp"
);
bindProperties
(
map
);
TomcatEmbeddedServletContainerFactory
container
=
new
TomcatEmbeddedServletContainerFactory
();
this
.
properties
.
customize
(
container
);
assertEquals
(
"MyBootApp"
,
container
.
getDisplayName
());
}
...
...
@@ -252,27 +255,44 @@ public class ServerPropertiesTests {
map
.
put
(
"server.tomcat.remote_ip_header"
,
""
);
map
.
put
(
"server.tomcat.protocol_header"
,
""
);
bindProperties
(
map
);
TomcatEmbeddedServletContainerFactory
container
=
new
TomcatEmbeddedServletContainerFactory
();
this
.
properties
.
customize
(
container
);
assertEquals
(
0
,
container
.
getValves
().
size
());
}
@Test
public
void
defaultTomcatRemoteIpValve
()
throws
Exception
{
// Since 1.3.0 no need to explicitly set header names
Map
<
String
,
String
>
map
=
new
HashMap
<
String
,
String
>();
// Since 1.1.7 you need to specify at least the protocol
map
.
put
(
"server.tomcat.protocol_header"
,
"X-Forwarded-Proto"
);
map
.
put
(
"server.tomcat.remote_ip_header"
,
"X-Forwarded-For"
);
bindProperties
(
map
);
testRemoteIpValveConfigured
();
}
@Test
public
void
setUseForwardHeadersTomcat
()
throws
Exception
{
// Since 1.3.0 no need to explicitly set header names if use-forward-header=true
this
.
properties
.
setUseForwardHeaders
(
true
);
testRemoteIpValveConfigured
();
}
@Test
public
void
deduceUseForwardHeadersTomcat
()
throws
Exception
{
this
.
properties
.
setEnvironment
(
new
MockEnvironment
().
withProperty
(
"DYNO"
,
"-"
));
testRemoteIpValveConfigured
();
}
private
void
testRemoteIpValveConfigured
()
{
TomcatEmbeddedServletContainerFactory
container
=
new
TomcatEmbeddedServletContainerFactory
();
this
.
properties
.
customize
(
container
);
assertEquals
(
1
,
container
.
getValves
().
size
());
Valve
valve
=
container
.
getValves
().
iterator
().
next
();
assertThat
(
valve
,
instanceOf
(
RemoteIpValve
.
class
));
RemoteIpValve
remoteIpValve
=
(
RemoteIpValve
)
valve
;
assertEquals
(
"
x-forwarded-p
roto"
,
remoteIpValve
.
getProtocolHeader
());
assertEquals
(
"
X-Forwarded-P
roto"
,
remoteIpValve
.
getProtocolHeader
());
assertEquals
(
"https"
,
remoteIpValve
.
getProtocolHeaderHttpsValue
());
assertEquals
(
"x-forwarded-for"
,
remoteIpValve
.
getRemoteIpHeader
());
assertEquals
(
"X-Forwarded-For"
,
remoteIpValve
.
getRemoteIpHeader
());
String
expectedInternalProxies
=
"10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|"
// 10/8
+
"192\\.168\\.\\d{1,3}\\.\\d{1,3}|"
// 192.168/16
+
"169\\.254\\.\\d{1,3}\\.\\d{1,3}|"
// 169.254/16
...
...
@@ -280,7 +300,6 @@ public class ServerPropertiesTests {
+
"172\\.1[6-9]{1}\\.\\d{1,3}\\.\\d{1,3}|"
// 172.16/12
+
"172\\.2[0-9]{1}\\.\\d{1,3}\\.\\d{1,3}|"
+
"172\\.3[0-1]{1}\\.\\d{1,3}\\.\\d{1,3}"
;
assertEquals
(
expectedInternalProxies
,
remoteIpValve
.
getInternalProxies
());
}
...
...
@@ -308,6 +327,52 @@ public class ServerPropertiesTests {
assertEquals
(
"192.168.0.1"
,
remoteIpValve
.
getInternalProxies
());
}
@Test
public
void
defaultUseForwardHeadersUndertow
()
throws
Exception
{
UndertowEmbeddedServletContainerFactory
container
=
spy
(
new
UndertowEmbeddedServletContainerFactory
());
this
.
properties
.
customize
(
container
);
verify
(
container
).
setUseForwardHeaders
(
false
);
}
@Test
public
void
setUseForwardHeadersUndertow
()
throws
Exception
{
this
.
properties
.
setUseForwardHeaders
(
true
);
UndertowEmbeddedServletContainerFactory
container
=
spy
(
new
UndertowEmbeddedServletContainerFactory
());
this
.
properties
.
customize
(
container
);
verify
(
container
).
setUseForwardHeaders
(
true
);
}
@Test
public
void
deduceUseForwardHeadersUndertow
()
throws
Exception
{
this
.
properties
.
setEnvironment
(
new
MockEnvironment
().
withProperty
(
"DYNO"
,
"-"
));
UndertowEmbeddedServletContainerFactory
container
=
spy
(
new
UndertowEmbeddedServletContainerFactory
());
this
.
properties
.
customize
(
container
);
verify
(
container
).
setUseForwardHeaders
(
true
);
}
@Test
public
void
defaultUseForwardHeadersJetty
()
throws
Exception
{
JettyEmbeddedServletContainerFactory
container
=
spy
(
new
JettyEmbeddedServletContainerFactory
());
this
.
properties
.
customize
(
container
);
verify
(
container
).
setUseForwardHeaders
(
false
);
}
@Test
public
void
setUseForwardHeadersJetty
()
throws
Exception
{
this
.
properties
.
setUseForwardHeaders
(
true
);
JettyEmbeddedServletContainerFactory
container
=
spy
(
new
JettyEmbeddedServletContainerFactory
());
this
.
properties
.
customize
(
container
);
verify
(
container
).
setUseForwardHeaders
(
true
);
}
@Test
public
void
deduceUseForwardHeadersJetty
()
throws
Exception
{
this
.
properties
.
setEnvironment
(
new
MockEnvironment
().
withProperty
(
"DYNO"
,
"-"
));
JettyEmbeddedServletContainerFactory
container
=
spy
(
new
JettyEmbeddedServletContainerFactory
());
this
.
properties
.
customize
(
container
);
verify
(
container
).
setUseForwardHeaders
(
true
);
}
private
void
bindProperties
(
Map
<
String
,
String
>
map
)
{
new
RelaxedDataBinder
(
this
.
properties
,
"server"
).
bind
(
new
MutablePropertyValues
(
map
));
...
...
spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
View file @
1e801723
...
...
@@ -83,6 +83,7 @@ content into your application; rather pick only the properties that you need.
server.jsp-servlet.registered=true # Whether or not the JSP servlet is registered
server.servlet-path= # the servlet path, defaults to '/'
server.display-name= # the display name of the application
server.use-forward-headers= # if X-Forwarded-* headers should be used (default is off unless running in a known cloud)
server.session.persistent=false # true if session should be saved across restarts
server.session.timeout= # session timeout in seconds
server.session.tracking-modes= # tracking modes (one or more of "cookie" ,"url", "ssl")
...
...
spring-boot-docs/src/main/asciidoc/howto.adoc
View file @
1e801723
...
...
@@ -491,6 +491,59 @@ sample project for an example.
[[howto-use-behind-a-proxy-server]]
[[howto-use-tomcat-behind-a-proxy-server]]
=== Use behind a front-end proxy server
Your application might need to send `302` redirects or render content with absolute links
back to itself. When running behind a proxy, the caller wants a link to the proxy, and not
to the physical address of the machine hosting your app. Typically such situations are
handled via a contract with the proxy, which will add headers to tell the back end how to
construct links to itself.
If the proxy adds conventional `X-Forwarded-For` and `X-Forwarded-Proto` headers (most do
this out of the box) the absolute links should be rendered correctly as long as
`server.use-forward-headers` is set to `true` in your `application.properties`.
NOTE: If your application is running in Cloud Foundry or Heroku the
`server.use-forward-headers` property will default to `true` if not specified. In all
other instances it defaults to `false`.
[[howto-customize-tomcat-behind-a-proxy-server]]
==== Customize Tomcat's proxy configuration
If you are using Tomcat you can additionally configure the names of the headers used to
carry "`forwarded`" information:
[indent=0]
----
server.tomcat.remote-ip-header=x-your-remote-ip-header
server.tomcat.protocol-header=x-your-protocol-header
----
Tomcat is also configured with a default regular expression that matches internal
proxies that are to be trusted. By default, IP addresses in `10/8`, `192.168/16`,
`169.254/16` and `127/8` are trusted. You can customize the valve's configuration by
adding an entry to `application.properties`, e.g.
[indent=0]
----
server.tomcat.internal-proxies=192\\.168\\.\\d{1,3}\\.\\d{1,3}
----
NOTE: The double backslashes are only required when you're using a properties file for
configuration. If you are using YAML, single backslashes are sufficient and a value
that's equivalent to the one shown above would be `192\.168\.\d{1,3}\.\d{1,3}`.
NOTE: You can trust all proxies by setting the `internal-proxies` to empty (but don't do
this in production).
You can take complete control of the configuration of Tomcat's `RemoteIpValve` by
switching the automatic one off (i.e. set `server.use-forward-headers=false`) and adding
a new valve instance in a `TomcatEmbeddedServletContainerFactory` bean.
[[howto-configure-tomcat]]
=== Configure Tomcat
Generally you can follow the advice from
...
...
@@ -544,66 +597,6 @@ HTTPS connector:
[[howto-use-tomcat-behind-a-proxy-server]]
=== Use Tomcat behind a front-end proxy server
Your app might need to send 302 redirects, or render UI templates with
absolute links to itself, or hypermedia links back to itself in the
case of a RESTful service. If the app is behind a proxy, the caller
wants a link to the proxy not to the physical address of the app, so
something has to be done in the backend. Typically this is handled via
a contract with the proxy, which will add headers to tell the back end
how to construct links to itself. If the proxy adds conventional
headers (most do this out of the box) the absolute links should be
rendered correctly by default using the Tomcat server.
Spring Boot using Tomcat automatically adds a `RemoteIpValve`. This
transparently takes the standard `x-forwarded-for` and
`x-forwarded-proto` headers and uses them to change local URLs created
in the `HttpServletRequest`. You can configure the header names in
Spring Boot and the valve is switched on unless one or both of these
properties is empty. These values are the defaults and are the
conventional values used by most proxies, so you don't need to set
them unless you need different values:
[indent=0]
----
server.tomcat.remote-ip-header=x-forwarded-for
server.tomcat.protocol-header=x-forwarded-proto
----
If your proxy uses different headers you can customize the valve's configuration by adding
some entries to `application.properties`, e.g.
[indent=0]
----
server.tomcat.remote-ip-header=x-your-remote-ip-header
server.tomcat.protocol-header=x-your-protocol-header
----
The valve is also configured with a default regular expression that matches internal
proxies that are to be trusted. By default, IP addresses in 10/8, 192.168/16, 169.254/16
and 127/8 are trusted. You can customize the valve's configuration by adding an entry
to `application.properties`, e.g.
[indent=0]
----
server.tomcat.internal_proxies=192\\.168\\.\\d{1,3}\\.\\d{1,3}
----
NOTE: The double backslashes are only required when you're using a properties file for
configuration. If you are using YAML, single backslashes are sufficient and a value
that's equivalent to the one shown above would be `192\.168\.\d{1,3}\.\d{1,3}`.
NOTE: You can trust all proxies by setting the `internal_proxies` to empty (but don't do
this in production).
You can take complete control of the configuration of the
`RemoteIpValve` by switching the automatic one off (i.e. set one of
the headers to empty) and adding a new valve instance in a
`TomcatEmbeddedServletContainerFactory` bean.
[[howto-use-jetty-instead-of-tomcat]]
=== Use Jetty instead of Tomcat
The Spring Boot starters (`spring-boot-starter-web` in particular) use Tomcat as an
...
...
spring-boot/src/main/java/org/springframework/boot/cloud/CloudFoundryVcapEnvironmentPostProcessor.java
0 → 100644
View file @
1e801723
/*
* Copyright 2010-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
cloud
;
import
java.util.Collection
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map.Entry
;
import
java.util.Properties
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.boot.context.config.ConfigFileEnvironmentPostProcessor
;
import
org.springframework.boot.env.EnvironmentPostProcessor
;
import
org.springframework.boot.json.JsonParser
;
import
org.springframework.boot.json.JsonParserFactory
;
import
org.springframework.core.Ordered
;
import
org.springframework.core.env.CommandLinePropertySource
;
import
org.springframework.core.env.ConfigurableEnvironment
;
import
org.springframework.core.env.Environment
;
import
org.springframework.core.env.MutablePropertySources
;
import
org.springframework.core.env.PropertiesPropertySource
;
import
org.springframework.util.StringUtils
;
/**
* An {@link EnvironmentPostProcessor} that knows where to find VCAP (a.k.a. Cloud
* Foundry) meta data in the existing environment. It parses out the VCAP_APPLICATION and
* VCAP_SERVICES meta data and dumps it in a form that is easily consumed by
* {@link Environment} users. If the app is running in Cloud Foundry then both meta data
* items are JSON objects encoded in OS environment variables. VCAP_APPLICATION is a
* shallow hash with basic information about the application (name, instance id, instance
* index, etc.), and VCAP_SERVICES is a hash of lists where the keys are service labels
* and the values are lists of hashes of service instance meta data. Examples are:
*
* <pre class="code">
* VCAP_APPLICATION: {"instance_id":"2ce0ac627a6c8e47e936d829a3a47b5b","instance_index":0,
* "version":"0138c4a6-2a73-416b-aca0-572c09f7ca53","name":"foo",
* "uris":["foo.cfapps.io"], ...}
* VCAP_SERVICES: {"rds-mysql-1.0":[{"name":"mysql","label":"rds-mysql-1.0","plan":"10mb",
* "credentials":{"name":"d04fb13d27d964c62b267bbba1cffb9da","hostname":"mysql-service-public.clqg2e2w3ecf.us-east-1.rds.amazonaws.com",
* "host":"mysql-service-public.clqg2e2w3ecf.us-east-1.rds.amazonaws.com","port":3306,"user":"urpRuqTf8Cpe6",
* "username":"urpRuqTf8Cpe6","password":"pxLsGVpsC9A5S"}
* }]}
* </pre>
*
* These objects are flattened into properties. The VCAP_APPLICATION object goes straight
* to {@code vcap.application.*} in a fairly obvious way, and the VCAP_SERVICES object is
* unwrapped so that it is a hash of objects with key equal to the service instance name
* (e.g. "mysql" in the example above), and value equal to that instances properties, and
* then flattened in the same way. E.g.
*
* <pre class="code">
* vcap.application.instance_id: 2ce0ac627a6c8e47e936d829a3a47b5b
* vcap.application.version: 0138c4a6-2a73-416b-aca0-572c09f7ca53
* vcap.application.name: foo
* vcap.application.uris[0]: foo.cfapps.io
*
* vcap.services.mysql.name: mysql
* vcap.services.mysql.label: rds-mysql-1.0
* vcap.services.mysql.credentials.name: d04fb13d27d964c62b267bbba1cffb9da
* vcap.services.mysql.credentials.port: 3306
* vcap.services.mysql.credentials.host: mysql-service-public.clqg2e2w3ecf.us-east-1.rds.amazonaws.com
* vcap.services.mysql.credentials.username: urpRuqTf8Cpe6
* vcap.services.mysql.credentials.password: pxLsGVpsC9A5S
* ...
* </pre>
*
* N.B. this initializer is mainly intended for informational use (the application and
* instance ids are particularly useful). For service binding you might find that Spring
* Cloud is more convenient and more robust against potential changes in Cloud Foundry.
*
* @author Dave Syer
* @author Andy Wilkinson
*/
public
class
CloudFoundryVcapEnvironmentPostProcessor
implements
EnvironmentPostProcessor
,
Ordered
{
private
static
final
Log
logger
=
LogFactory
.
getLog
(
CloudFoundryVcapEnvironmentPostProcessor
.
class
);
private
static
final
String
VCAP_APPLICATION
=
"VCAP_APPLICATION"
;
private
static
final
String
VCAP_SERVICES
=
"VCAP_SERVICES"
;
// Before ConfigFileApplicationListener so values there can use these ones
private
int
order
=
ConfigFileEnvironmentPostProcessor
.
DEFAULT_ORDER
-
1
;
private
final
JsonParser
parser
=
JsonParserFactory
.
getJsonParser
();
public
void
setOrder
(
int
order
)
{
this
.
order
=
order
;
}
@Override
public
int
getOrder
()
{
return
this
.
order
;
}
@Override
public
void
postProcessEnvironment
(
ConfigurableEnvironment
environment
,
SpringApplication
application
)
{
if
(
CloudPlatform
.
CLOUD_FOUNDRY
.
isActive
(
environment
))
{
Properties
properties
=
new
Properties
();
addWithPrefix
(
properties
,
getPropertiesFromApplication
(
environment
),
"vcap.application."
);
addWithPrefix
(
properties
,
getPropertiesFromServices
(
environment
),
"vcap.services."
);
MutablePropertySources
propertySources
=
environment
.
getPropertySources
();
if
(
propertySources
.
contains
(
CommandLinePropertySource
.
COMMAND_LINE_PROPERTY_SOURCE_NAME
))
{
propertySources
.
addAfter
(
CommandLinePropertySource
.
COMMAND_LINE_PROPERTY_SOURCE_NAME
,
new
PropertiesPropertySource
(
"vcap"
,
properties
));
}
else
{
propertySources
.
addFirst
(
new
PropertiesPropertySource
(
"vcap"
,
properties
));
}
}
}
private
void
addWithPrefix
(
Properties
properties
,
Properties
other
,
String
prefix
)
{
for
(
String
key
:
other
.
stringPropertyNames
())
{
String
prefixed
=
prefix
+
key
;
properties
.
setProperty
(
prefixed
,
other
.
getProperty
(
key
));
}
}
private
Properties
getPropertiesFromApplication
(
Environment
environment
)
{
Properties
properties
=
new
Properties
();
try
{
String
property
=
environment
.
getProperty
(
VCAP_APPLICATION
,
"{}"
);
Map
<
String
,
Object
>
map
=
this
.
parser
.
parseMap
(
property
);
extractPropertiesFromApplication
(
properties
,
map
);
}
catch
(
Exception
ex
)
{
logger
.
error
(
"Could not parse VCAP_APPLICATION"
,
ex
);
}
return
properties
;
}
private
Properties
getPropertiesFromServices
(
Environment
environment
)
{
Properties
properties
=
new
Properties
();
try
{
String
property
=
environment
.
getProperty
(
VCAP_SERVICES
,
"{}"
);
Map
<
String
,
Object
>
map
=
this
.
parser
.
parseMap
(
property
);
extractPropertiesFromServices
(
properties
,
map
);
}
catch
(
Exception
ex
)
{
logger
.
error
(
"Could not parse VCAP_SERVICES"
,
ex
);
}
return
properties
;
}
private
void
extractPropertiesFromApplication
(
Properties
properties
,
Map
<
String
,
Object
>
map
)
{
if
(
map
!=
null
)
{
flatten
(
properties
,
map
,
""
);
}
}
private
void
extractPropertiesFromServices
(
Properties
properties
,
Map
<
String
,
Object
>
map
)
{
if
(
map
!=
null
)
{
for
(
Object
services
:
map
.
values
())
{
@SuppressWarnings
(
"unchecked"
)
List
<
Object
>
list
=
(
List
<
Object
>)
services
;
for
(
Object
object
:
list
)
{
@SuppressWarnings
(
"unchecked"
)
Map
<
String
,
Object
>
service
=
(
Map
<
String
,
Object
>)
object
;
String
key
=
(
String
)
service
.
get
(
"name"
);
if
(
key
==
null
)
{
key
=
(
String
)
service
.
get
(
"label"
);
}
flatten
(
properties
,
service
,
key
);
}
}
}
}
@SuppressWarnings
(
"unchecked"
)
private
void
flatten
(
Properties
properties
,
Map
<
String
,
Object
>
input
,
String
path
)
{
for
(
Entry
<
String
,
Object
>
entry
:
input
.
entrySet
())
{
String
key
=
getFullKey
(
path
,
entry
.
getKey
());
Object
value
=
entry
.
getValue
();
if
(
value
instanceof
Map
)
{
// Need a compound key
flatten
(
properties
,
(
Map
<
String
,
Object
>)
value
,
key
);
}
else
if
(
value
instanceof
Collection
)
{
// Need a compound key
Collection
<
Object
>
collection
=
(
Collection
<
Object
>)
value
;
properties
.
put
(
key
,
StringUtils
.
collectionToCommaDelimitedString
(
collection
));
int
count
=
0
;
for
(
Object
item
:
collection
)
{
String
itemKey
=
"["
+
(
count
++)
+
"]"
;
flatten
(
properties
,
Collections
.
singletonMap
(
itemKey
,
item
),
key
);
}
}
else
if
(
value
instanceof
String
)
{
properties
.
put
(
key
,
value
);
}
else
if
(
value
instanceof
Number
)
{
properties
.
put
(
key
,
value
.
toString
());
}
else
if
(
value
instanceof
Boolean
)
{
properties
.
put
(
key
,
value
.
toString
());
}
else
{
properties
.
put
(
key
,
value
==
null
?
""
:
value
);
}
}
}
private
String
getFullKey
(
String
path
,
String
key
)
{
if
(!
StringUtils
.
hasText
(
path
))
{
return
key
;
}
if
(
key
.
startsWith
(
"["
))
{
return
path
+
key
;
}
return
path
+
"."
+
key
;
}
}
spring-boot/src/main/java/org/springframework/boot/cloud/CloudPlatform.java
0 → 100644
View file @
1e801723
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
cloud
;
import
org.springframework.core.env.Environment
;
/**
* Simple detection for well known cloud platforms. For more advanced cloud provider
* integration consider the Spring Clould project.
*
* @author Phillip Webb
* @since 1.3.0
* @see "http://cloud.spring.io"
*/
public
enum
CloudPlatform
{
/**
* Cloud Foundry platform.
*/
CLOUD_FOUNDRY
{
@Override
public
boolean
isActive
(
Environment
environment
)
{
return
environment
.
containsProperty
(
"VCAP_APPLICATION"
)
||
environment
.
containsProperty
(
"VCAP_SERVICES"
);
}
},
/**
* Heroku platform.
*/
HEROKU
{
@Override
public
boolean
isActive
(
Environment
environment
)
{
return
environment
.
containsProperty
(
"DYNO"
);
}
};
/**
* Determines if the platform is active (i.e. the application is running in it).
* @param environment the environment
* @return if the platform is active.
*/
public
abstract
boolean
isActive
(
Environment
environment
);
/**
* Returns if the platform is behind a load balancer and uses
* {@literal X-Forwarded-For} headers.
* @return if {@literal X-Forwarded-For} headers are used
*/
public
boolean
isUsingForwardHeaders
()
{
return
true
;
}
/**
* Returns the active {@link CloudPlatform} or {@code null} if one cannot be deduced.
* @param environment the environment
* @return the {@link CloudPlatform} or {@code null}
*/
public
static
CloudPlatform
getActive
(
Environment
environment
)
{
if
(
environment
!=
null
)
{
for
(
CloudPlatform
cloudPlatform
:
values
())
{
if
(
cloudPlatform
.
isActive
(
environment
))
{
return
cloudPlatform
;
}
}
}
return
null
;
}
}
spring-boot/src/main/java/org/springframework/boot/cloud
foundry
/package-info.java
→
spring-boot/src/main/java/org/springframework/boot/cloud/package-info.java
View file @
1e801723
/*
* Copyright 2012-201
4
the original author or authors.
* Copyright 2012-201
5
the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
...
...
@@ -15,7 +15,7 @@
*/
/**
*
Support for Cloud Foundry PAAS based deployment
.
*
Low level support for Cloud deployments
.
*/
package
org
.
springframework
.
boot
.
cloud
foundry
;
package
org
.
springframework
.
boot
.
cloud
;
spring-boot/src/main/java/org/springframework/boot/cloudfoundry/VcapEnvironmentPostProcessor.java
View file @
1e801723
...
...
@@ -16,27 +16,9 @@
package
org
.
springframework
.
boot
.
cloudfoundry
;
import
java.util.Collection
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map.Entry
;
import
java.util.Properties
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.boot.context.config.ConfigFileEnvironmentPostProcessor
;
import
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor
;
import
org.springframework.boot.env.EnvironmentPostProcessor
;
import
org.springframework.boot.json.JsonParser
;
import
org.springframework.boot.json.JsonParserFactory
;
import
org.springframework.core.Ordered
;
import
org.springframework.core.env.CommandLinePropertySource
;
import
org.springframework.core.env.ConfigurableEnvironment
;
import
org.springframework.core.env.Environment
;
import
org.springframework.core.env.MutablePropertySources
;
import
org.springframework.core.env.PropertiesPropertySource
;
import
org.springframework.util.StringUtils
;
/**
* An {@link EnvironmentPostProcessor} that knows where to find VCAP (a.k.a. Cloud
...
...
@@ -87,156 +69,10 @@ import org.springframework.util.StringUtils;
*
* @author Dave Syer
* @author Andy Wilkinson
* @deprecated since 1.3.0 in favor of CloudFoundryVcapEnvironmentPostProcessor
*/
public
class
VcapEnvironmentPostProcessor
implements
EnvironmentPostProcessor
,
Ordered
{
private
static
final
Log
logger
=
LogFactory
.
getLog
(
VcapEnvironmentPostProcessor
.
class
);
private
static
final
String
VCAP_APPLICATION
=
"VCAP_APPLICATION"
;
private
static
final
String
VCAP_SERVICES
=
"VCAP_SERVICES"
;
// Before ConfigFileApplicationListener so values there can use these ones
private
int
order
=
ConfigFileEnvironmentPostProcessor
.
DEFAULT_ORDER
-
1
;
private
final
JsonParser
parser
=
JsonParserFactory
.
getJsonParser
();
public
void
setOrder
(
int
order
)
{
this
.
order
=
order
;
}
@Override
public
int
getOrder
()
{
return
this
.
order
;
}
@Override
public
void
postProcessEnvironment
(
ConfigurableEnvironment
environment
,
SpringApplication
application
)
{
if
(!
environment
.
containsProperty
(
VCAP_APPLICATION
)
&&
!
environment
.
containsProperty
(
VCAP_SERVICES
))
{
return
;
}
Properties
properties
=
new
Properties
();
addWithPrefix
(
properties
,
getPropertiesFromApplication
(
environment
),
"vcap.application."
);
addWithPrefix
(
properties
,
getPropertiesFromServices
(
environment
),
"vcap.services."
);
MutablePropertySources
propertySources
=
environment
.
getPropertySources
();
if
(
propertySources
.
contains
(
CommandLinePropertySource
.
COMMAND_LINE_PROPERTY_SOURCE_NAME
))
{
propertySources
.
addAfter
(
CommandLinePropertySource
.
COMMAND_LINE_PROPERTY_SOURCE_NAME
,
new
PropertiesPropertySource
(
"vcap"
,
properties
));
}
else
{
propertySources
.
addFirst
(
new
PropertiesPropertySource
(
"vcap"
,
properties
));
}
}
private
void
addWithPrefix
(
Properties
properties
,
Properties
other
,
String
prefix
)
{
for
(
String
key
:
other
.
stringPropertyNames
())
{
String
prefixed
=
prefix
+
key
;
properties
.
setProperty
(
prefixed
,
other
.
getProperty
(
key
));
}
}
private
Properties
getPropertiesFromApplication
(
Environment
environment
)
{
Properties
properties
=
new
Properties
();
try
{
Map
<
String
,
Object
>
map
=
this
.
parser
.
parseMap
(
environment
.
getProperty
(
VCAP_APPLICATION
,
"{}"
));
extractPropertiesFromApplication
(
properties
,
map
);
}
catch
(
Exception
ex
)
{
logger
.
error
(
"Could not parse VCAP_APPLICATION"
,
ex
);
}
return
properties
;
}
private
Properties
getPropertiesFromServices
(
Environment
environment
)
{
Properties
properties
=
new
Properties
();
try
{
Map
<
String
,
Object
>
map
=
this
.
parser
.
parseMap
(
environment
.
getProperty
(
VCAP_SERVICES
,
"{}"
));
extractPropertiesFromServices
(
properties
,
map
);
}
catch
(
Exception
ex
)
{
logger
.
error
(
"Could not parse VCAP_SERVICES"
,
ex
);
}
return
properties
;
}
private
void
extractPropertiesFromApplication
(
Properties
properties
,
Map
<
String
,
Object
>
map
)
{
if
(
map
!=
null
)
{
flatten
(
properties
,
map
,
""
);
}
}
private
void
extractPropertiesFromServices
(
Properties
properties
,
Map
<
String
,
Object
>
map
)
{
if
(
map
!=
null
)
{
for
(
Object
services
:
map
.
values
())
{
@SuppressWarnings
(
"unchecked"
)
List
<
Object
>
list
=
(
List
<
Object
>)
services
;
for
(
Object
object
:
list
)
{
@SuppressWarnings
(
"unchecked"
)
Map
<
String
,
Object
>
service
=
(
Map
<
String
,
Object
>)
object
;
String
key
=
(
String
)
service
.
get
(
"name"
);
if
(
key
==
null
)
{
key
=
(
String
)
service
.
get
(
"label"
);
}
flatten
(
properties
,
service
,
key
);
}
}
}
}
@SuppressWarnings
(
"unchecked"
)
private
void
flatten
(
Properties
properties
,
Map
<
String
,
Object
>
input
,
String
path
)
{
for
(
Entry
<
String
,
Object
>
entry
:
input
.
entrySet
())
{
String
key
=
getFullKey
(
path
,
entry
.
getKey
());
Object
value
=
entry
.
getValue
();
if
(
value
instanceof
Map
)
{
// Need a compound key
flatten
(
properties
,
(
Map
<
String
,
Object
>)
value
,
key
);
}
else
if
(
value
instanceof
Collection
)
{
// Need a compound key
Collection
<
Object
>
collection
=
(
Collection
<
Object
>)
value
;
properties
.
put
(
key
,
StringUtils
.
collectionToCommaDelimitedString
(
collection
));
int
count
=
0
;
for
(
Object
item
:
collection
)
{
String
itemKey
=
"["
+
(
count
++)
+
"]"
;
flatten
(
properties
,
Collections
.
singletonMap
(
itemKey
,
item
),
key
);
}
}
else
if
(
value
instanceof
String
)
{
properties
.
put
(
key
,
value
);
}
else
if
(
value
instanceof
Number
)
{
properties
.
put
(
key
,
value
.
toString
());
}
else
if
(
value
instanceof
Boolean
)
{
properties
.
put
(
key
,
value
.
toString
());
}
else
{
properties
.
put
(
key
,
value
==
null
?
""
:
value
);
}
}
}
private
String
getFullKey
(
String
path
,
String
key
)
{
if
(!
StringUtils
.
hasText
(
path
))
{
return
key
;
}
if
(
key
.
startsWith
(
"["
))
{
return
path
+
key
;
}
return
path
+
"."
+
key
;
}
@Deprecated
public
class
VcapEnvironmentPostProcessor
extends
CloudFoundryVcapEnvironmentPostProcessor
{
}
spring-boot/src/main/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactory.java
View file @
1e801723
...
...
@@ -30,7 +30,9 @@ import java.util.Set;
import
org.eclipse.jetty.http.HttpVersion
;
import
org.eclipse.jetty.http.MimeTypes
;
import
org.eclipse.jetty.server.AbstractConnector
;
import
org.eclipse.jetty.server.ConnectionFactory
;
import
org.eclipse.jetty.server.Connector
;
import
org.eclipse.jetty.server.ForwardedRequestCustomizer
;
import
org.eclipse.jetty.server.HttpConfiguration
;
import
org.eclipse.jetty.server.HttpConnectionFactory
;
import
org.eclipse.jetty.server.SecureRequestCustomizer
;
...
...
@@ -97,6 +99,8 @@ public class JettyEmbeddedServletContainerFactory extends
private
List
<
Configuration
>
configurations
=
new
ArrayList
<
Configuration
>();
private
boolean
useForwardHeaders
;
private
List
<
JettyServerCustomizer
>
jettyServerCustomizers
=
new
ArrayList
<
JettyServerCustomizer
>();
private
ResourceLoader
resourceLoader
;
...
...
@@ -153,6 +157,9 @@ public class JettyEmbeddedServletContainerFactory extends
for
(
JettyServerCustomizer
customizer
:
getServerCustomizers
())
{
customizer
.
customize
(
server
);
}
if
(
this
.
useForwardHeaders
)
{
new
ForwardHeadersCustomizer
().
customize
(
server
);
}
return
getJettyEmbeddedServletContainer
(
server
);
}
...
...
@@ -449,6 +456,15 @@ public class JettyEmbeddedServletContainerFactory extends
this
.
resourceLoader
=
resourceLoader
;
}
/**
* Set if x-forward-* headers should be processed.
* @param useForwardHeaders if x-forward headers should be used
* @since 1.3.0
*/
public
void
setUseForwardHeaders
(
boolean
useForwardHeaders
)
{
this
.
useForwardHeaders
=
useForwardHeaders
;
}
/**
* Sets {@link JettyServerCustomizer}s that will be applied to the {@link Server}
* before it is started. Calling this method will replace any existing configurations.
...
...
@@ -669,4 +685,26 @@ public class JettyEmbeddedServletContainerFactory extends
}
/**
* {@link JettyServerCustomizer} to add {@link ForwardedRequestCustomizer}. Only
* supported with Jetty 9 (hence the inner class)
*/
private
static
class
ForwardHeadersCustomizer
implements
JettyServerCustomizer
{
@Override
public
void
customize
(
Server
server
)
{
ForwardedRequestCustomizer
customizer
=
new
ForwardedRequestCustomizer
();
for
(
Connector
connector
:
server
.
getConnectors
())
{
for
(
ConnectionFactory
connectionFactory
:
connector
.
getConnectionFactories
())
{
if
(
connectionFactory
instanceof
HttpConfiguration
.
ConnectionFactory
)
{
((
HttpConfiguration
.
ConnectionFactory
)
connectionFactory
)
.
getHttpConfiguration
().
addCustomizer
(
customizer
);
}
}
}
}
}
}
spring-boot/src/main/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainer.java
View file @
1e801723
...
...
@@ -71,6 +71,8 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine
private
final
String
contextPath
;
private
final
boolean
useForwardHeaders
;
private
final
boolean
autoStart
;
private
final
Compression
compression
;
...
...
@@ -81,9 +83,16 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine
public
UndertowEmbeddedServletContainer
(
Builder
builder
,
DeploymentManager
manager
,
String
contextPath
,
int
port
,
boolean
autoStart
,
Compression
compression
)
{
this
(
builder
,
manager
,
contextPath
,
port
,
false
,
autoStart
,
compression
);
}
public
UndertowEmbeddedServletContainer
(
Builder
builder
,
DeploymentManager
manager
,
String
contextPath
,
int
port
,
boolean
useForwardHeaders
,
boolean
autoStart
,
Compression
compression
)
{
this
.
builder
=
builder
;
this
.
manager
=
manager
;
this
.
contextPath
=
contextPath
;
this
.
useForwardHeaders
=
useForwardHeaders
;
this
.
autoStart
=
autoStart
;
this
.
compression
=
compression
;
}
...
...
@@ -105,7 +114,11 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine
private
Undertow
createUndertowServer
()
{
try
{
HttpHandler
httpHandler
=
this
.
manager
.
start
();
this
.
builder
.
setHandler
(
getContextHandler
(
httpHandler
));
httpHandler
=
getContextHandler
(
httpHandler
);
if
(
this
.
useForwardHeaders
)
{
httpHandler
=
Handlers
.
proxyPeerAddress
(
httpHandler
);
}
this
.
builder
.
setHandler
(
httpHandler
);
return
this
.
builder
.
build
();
}
catch
(
ServletException
ex
)
{
...
...
spring-boot/src/main/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactory.java
View file @
1e801723
...
...
@@ -121,6 +121,8 @@ public class UndertowEmbeddedServletContainerFactory extends
private
boolean
accessLogEnabled
=
false
;
private
boolean
useForwardHeaders
;
/**
* Create a new {@link UndertowEmbeddedServletContainerFactory} instance.
*/
...
...
@@ -220,7 +222,7 @@ public class UndertowEmbeddedServletContainerFactory extends
int
port
=
getPort
();
Builder
builder
=
createBuilder
(
port
);
return
new
UndertowEmbeddedServletContainer
(
builder
,
manager
,
getContextPath
(),
port
,
port
>=
0
,
getCompression
());
port
,
this
.
useForwardHeaders
,
port
>=
0
,
getCompression
());
}
private
Builder
createBuilder
(
int
port
)
{
...
...
@@ -519,6 +521,15 @@ public class UndertowEmbeddedServletContainerFactory extends
return
this
.
accessLogEnabled
;
}
/**
* Set if x-forward-* headers should be processed.
* @param useForwardHeaders if x-forward headers should be used
* @since 1.3.0
*/
public
void
setUseForwardHeaders
(
boolean
useForwardHeaders
)
{
this
.
useForwardHeaders
=
useForwardHeaders
;
}
/**
* Undertow {@link ResourceManager} for JAR resources.
*/
...
...
spring-boot/src/main/resources/META-INF/spring.factories
View file @
1e801723
...
...
@@ -28,5 +28,5 @@ org.springframework.boot.logging.LoggingApplicationListener
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloudfoundry.VcapEnvironmentPostProcessor,\
org.springframework.boot.context.config.ConfigFileEnvironmentPostProcessor
\ No newline at end of file
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.context.config.ConfigFileEnvironmentPostProcessor
spring-boot/src/test/java/org/springframework/boot/cloud/CloudPlatformTests.java
0 → 100644
View file @
1e801723
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
cloud
;
import
org.junit.Test
;
import
org.springframework.core.env.Environment
;
import
org.springframework.mock.env.MockEnvironment
;
import
static
org
.
hamcrest
.
Matchers
.
equalTo
;
import
static
org
.
hamcrest
.
Matchers
.
nullValue
;
import
static
org
.
junit
.
Assert
.
assertThat
;
/**
* Tests for {@link CloudPlatform}.
*
* @author Phillip Webb
*/
public
class
CloudPlatformTests
{
@Test
public
void
getActiveWhenEnvironmentIsNullShouldReturnNull
()
throws
Exception
{
CloudPlatform
platform
=
CloudPlatform
.
getActive
(
null
);
assertThat
(
platform
,
nullValue
());
}
@Test
public
void
getActiveWhenNotInCloudShouldReturnNull
()
throws
Exception
{
Environment
environment
=
new
MockEnvironment
();
CloudPlatform
platform
=
CloudPlatform
.
getActive
(
environment
);
assertThat
(
platform
,
nullValue
());
}
@Test
public
void
getActiveWhenHasVcapApplicationShouldReturnCloudFoundry
()
throws
Exception
{
Environment
environment
=
new
MockEnvironment
().
withProperty
(
"VCAP_APPLICATION"
,
"---"
);
CloudPlatform
platform
=
CloudPlatform
.
getActive
(
environment
);
assertThat
(
platform
,
equalTo
(
CloudPlatform
.
CLOUD_FOUNDRY
));
assertThat
(
platform
.
isActive
(
environment
),
equalTo
(
true
));
}
@Test
public
void
getActiveWhenHasVcapServicesShouldReturnCloudFoundry
()
throws
Exception
{
Environment
environment
=
new
MockEnvironment
().
withProperty
(
"VCAP_SERVICES"
,
"---"
);
CloudPlatform
platform
=
CloudPlatform
.
getActive
(
environment
);
assertThat
(
platform
,
equalTo
(
CloudPlatform
.
CLOUD_FOUNDRY
));
assertThat
(
platform
.
isActive
(
environment
),
equalTo
(
true
));
}
@Test
public
void
getActiveWhenHasDynoShouldReturnHeroku
()
throws
Exception
{
Environment
environment
=
new
MockEnvironment
().
withProperty
(
"DYNO"
,
"---"
);
CloudPlatform
platform
=
CloudPlatform
.
getActive
(
environment
);
assertThat
(
platform
,
equalTo
(
CloudPlatform
.
HEROKU
));
assertThat
(
platform
.
isActive
(
environment
),
equalTo
(
true
));
}
}
spring-boot/src/test/java/org/springframework/boot/cloud
foundry/
VcapEnvironmentPostProcessorTests.java
→
spring-boot/src/test/java/org/springframework/boot/cloud
/cloudfoundry/CloudFoundry
VcapEnvironmentPostProcessorTests.java
View file @
1e801723
...
...
@@ -14,9 +14,10 @@
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
cloudfoundry
;
package
org
.
springframework
.
boot
.
cloud
.
cloud
foundry
;
import
org.junit.Test
;
import
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor
;
import
org.springframework.boot.test.EnvironmentTestUtils
;
import
org.springframework.context.ConfigurableApplicationContext
;
import
org.springframework.context.annotation.AnnotationConfigApplicationContext
;
...
...
@@ -25,14 +26,14 @@ import static org.junit.Assert.assertEquals;
import
static
org
.
junit
.
Assert
.
assertNull
;
/**
* Tests for {@link VcapEnvironmentPostProcessor}.
* Tests for {@link
CloudFoundry
VcapEnvironmentPostProcessor}.
*
* @author Dave Syer
* @author Andy Wilkinson
*/
public
class
VcapEnvironmentPostProcessorTests
{
public
class
CloudFoundry
VcapEnvironmentPostProcessorTests
{
private
final
VcapEnvironmentPostProcessor
initializer
=
new
VcapEnvironmentPostProcessor
();
private
final
CloudFoundryVcapEnvironmentPostProcessor
initializer
=
new
CloudFoundry
VcapEnvironmentPostProcessor
();
private
final
ConfigurableApplicationContext
context
=
new
AnnotationConfigApplicationContext
();
...
...
spring-boot/src/test/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactoryTests.java
View file @
1e801723
...
...
@@ -638,8 +638,9 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
return
"http://localhost:"
+
port
+
resourcePath
;
}
protected
String
getResponse
(
String
url
)
throws
IOException
,
URISyntaxException
{
ClientHttpResponse
response
=
getClientResponse
(
url
);
protected
String
getResponse
(
String
url
,
String
...
headers
)
throws
IOException
,
URISyntaxException
{
ClientHttpResponse
response
=
getClientResponse
(
url
,
headers
);
try
{
return
StreamUtils
.
copyToString
(
response
.
getBody
(),
Charset
.
forName
(
"UTF-8"
));
}
...
...
@@ -649,9 +650,9 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
}
protected
String
getResponse
(
String
url
,
HttpComponentsClientHttpRequestFactory
requestFactory
)
throws
IOException
,
URISyntaxException
{
ClientHttpResponse
response
=
getClientResponse
(
url
,
requestFactory
);
HttpComponentsClientHttpRequestFactory
requestFactory
,
String
...
headers
)
throws
IOException
,
URISyntaxException
{
ClientHttpResponse
response
=
getClientResponse
(
url
,
requestFactory
,
headers
);
try
{
return
StreamUtils
.
copyToString
(
response
.
getBody
(),
Charset
.
forName
(
"UTF-8"
));
}
...
...
@@ -660,8 +661,8 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
}
}
protected
ClientHttpResponse
getClientResponse
(
String
url
)
throws
IOException
,
URISyntaxException
{
protected
ClientHttpResponse
getClientResponse
(
String
url
,
String
...
headers
)
throws
IOException
,
URISyntaxException
{
return
getClientResponse
(
url
,
new
HttpComponentsClientHttpRequestFactory
()
{
@Override
...
...
@@ -669,19 +670,32 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
return
AbstractEmbeddedServletContainerFactoryTests
.
this
.
httpClientContext
;
}
});
}
,
headers
);
}
protected
ClientHttpResponse
getClientResponse
(
String
url
,
HttpComponentsClientHttpRequestFactory
requestFactory
)
throws
IOException
,
URISyntaxException
{
HttpComponentsClientHttpRequestFactory
requestFactory
,
String
...
headers
)
throws
IOException
,
URISyntaxException
{
ClientHttpRequest
request
=
requestFactory
.
createRequest
(
new
URI
(
url
),
HttpMethod
.
GET
);
request
.
getHeaders
().
add
(
"Cookie"
,
"JSESSIONID="
+
"123"
);
for
(
String
header
:
headers
)
{
String
[]
parts
=
header
.
split
(
":"
);
request
.
getHeaders
().
add
(
parts
[
0
],
parts
[
1
]);
}
ClientHttpResponse
response
=
request
.
execute
();
return
response
;
}
protected
void
assertForwardHeaderIsUsed
(
EmbeddedServletContainerFactory
factory
)
throws
IOException
,
URISyntaxException
{
this
.
container
=
factory
.
getEmbeddedServletContainer
(
new
ServletRegistrationBean
(
new
ExampleServlet
(
true
),
"/hello"
));
this
.
container
.
start
();
assertThat
(
getResponse
(
getLocalUrl
(
"/hello"
),
"X-Forwarded-For:140.211.11.130"
),
containsString
(
"remoteaddr=140.211.11.130"
));
}
protected
abstract
AbstractEmbeddedServletContainerFactory
getFactory
();
protected
abstract
Object
getJspServlet
();
...
...
spring-boot/src/test/java/org/springframework/boot/context/embedded/ExampleServlet.java
View file @
1e801723
/*
* Copyright 2012-201
3
the original author or authors.
* Copyright 2012-201
5
the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
...
...
@@ -47,6 +47,7 @@ public class ExampleServlet extends GenericServlet {
String
content
=
"Hello World"
;
if
(
this
.
echoRequestInfo
)
{
content
+=
" scheme="
+
request
.
getScheme
();
content
+=
" remoteaddr="
+
request
.
getRemoteAddr
();
}
response
.
getWriter
().
write
(
content
);
}
...
...
spring-boot/src/test/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactoryTests.java
View file @
1e801723
...
...
@@ -183,6 +183,13 @@ public class JettyEmbeddedServletContainerFactoryTests extends
assertThat
(
getJspServlet
().
getInitParameters
(),
is
(
equalTo
(
initParameters
)));
}
@Test
public
void
useForwardHeaders
()
throws
Exception
{
JettyEmbeddedServletContainerFactory
factory
=
getFactory
();
factory
.
setUseForwardHeaders
(
true
);
assertForwardHeaderIsUsed
(
factory
);
}
@Override
@SuppressWarnings
(
"serial"
)
// Workaround for Jetty issue - https://bugs.eclipse.org/bugs/show_bug.cgi?id=470646
...
...
spring-boot/src/test/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactoryTests.java
View file @
1e801723
...
...
@@ -35,6 +35,7 @@ import org.apache.catalina.Valve;
import
org.apache.catalina.Wrapper
;
import
org.apache.catalina.connector.Connector
;
import
org.apache.catalina.startup.Tomcat
;
import
org.apache.catalina.valves.RemoteIpValve
;
import
org.apache.coyote.http11.AbstractHttp11JsseProtocol
;
import
org.junit.Test
;
import
org.mockito.InOrder
;
...
...
@@ -333,6 +334,13 @@ public class TomcatEmbeddedServletContainerFactoryTests extends
assertThat
(
jspServlet
.
findInitParameter
(
"a"
),
is
(
equalTo
(
"alpha"
)));
}
@Test
public
void
useForwardHeaders
()
throws
Exception
{
TomcatEmbeddedServletContainerFactory
factory
=
getFactory
();
factory
.
addContextValves
(
new
RemoteIpValve
());
assertForwardHeaderIsUsed
(
factory
);
}
@Override
protected
Wrapper
getJspServlet
()
{
Container
context
=
((
TomcatEmbeddedServletContainer
)
this
.
container
).
getTomcat
()
...
...
spring-boot/src/test/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactoryTests.java
View file @
1e801723
...
...
@@ -149,6 +149,13 @@ public class UndertowEmbeddedServletContainerFactoryTests extends
assertEquals
(
"/"
,
contextPath
.
get
());
}
@Test
public
void
useForwardHeaders
()
throws
Exception
{
UndertowEmbeddedServletContainerFactory
factory
=
getFactory
();
factory
.
setUseForwardHeaders
(
true
);
assertForwardHeaderIsUsed
(
factory
);
}
@Override
protected
Object
getJspServlet
()
{
return
null
;
// Undertow does not support JSPs
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment