Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
spring-cloud-netflix
Project
Overview
Details
Activity
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
openSource
spring-cloud-netflix
Commits
043732ae
Commit
043732ae
authored
Feb 12, 2015
by
Dave Syer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
More careful handling of multipart data in proxy
To write file data the message converter needs the file content to be provided in the form of an HttpEntity per file. Fixes gh-197 again
parent
2d8085cc
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
73 additions
and
25 deletions
+73
-25
FormBodyWrapperFilter.java
...cloud/netflix/zuul/filters/pre/FormBodyWrapperFilter.java
+30
-12
Servlet30WrapperFilter.java
...loud/netflix/zuul/filters/pre/Servlet30WrapperFilter.java
+12
-2
FormZuulProxyApplicationTests.java
...ork/cloud/netflix/zuul/FormZuulProxyApplicationTests.java
+31
-11
No files found.
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/FormBodyWrapperFilter.java
View file @
043732ae
...
@@ -25,6 +25,7 @@ import java.util.Map.Entry;
...
@@ -25,6 +25,7 @@ import java.util.Map.Entry;
import
javax.servlet.ServletInputStream
;
import
javax.servlet.ServletInputStream
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletRequest
;
import
org.springframework.http.HttpEntity
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpOutputMessage
;
import
org.springframework.http.HttpOutputMessage
;
import
org.springframework.http.InvalidMediaTypeException
;
import
org.springframework.http.InvalidMediaTypeException
;
...
@@ -34,6 +35,8 @@ import org.springframework.util.Assert;
...
@@ -34,6 +35,8 @@ import org.springframework.util.Assert;
import
org.springframework.util.LinkedMultiValueMap
;
import
org.springframework.util.LinkedMultiValueMap
;
import
org.springframework.util.MultiValueMap
;
import
org.springframework.util.MultiValueMap
;
import
org.springframework.util.ReflectionUtils
;
import
org.springframework.util.ReflectionUtils
;
import
org.springframework.web.multipart.MultipartFile
;
import
org.springframework.web.multipart.MultipartRequest
;
import
com.netflix.zuul.ZuulFilter
;
import
com.netflix.zuul.ZuulFilter
;
import
com.netflix.zuul.context.RequestContext
;
import
com.netflix.zuul.context.RequestContext
;
...
@@ -152,22 +155,36 @@ public class FormBodyWrapperFilter extends ZuulFilter {
...
@@ -152,22 +155,36 @@ public class FormBodyWrapperFilter extends ZuulFilter {
}
}
private
synchronized
void
buildContentData
()
{
private
synchronized
void
buildContentData
()
{
MultiValueMap
<
String
,
String
>
builder
=
new
LinkedMultiValueMap
<
String
,
String
>();
for
(
Entry
<
String
,
String
[]>
entry
:
this
.
request
.
getParameterMap
()
.
entrySet
())
{
for
(
String
value
:
entry
.
getValue
())
{
builder
.
add
(
entry
.
getKey
(),
value
);
}
}
FormHttpOutputMessage
data
=
new
FormHttpOutputMessage
();
data
.
getHeaders
().
setContentType
(
MediaType
.
valueOf
(
this
.
request
.
getContentType
()));
try
{
try
{
MultiValueMap
<
String
,
Object
>
builder
=
new
LinkedMultiValueMap
<
String
,
Object
>();
for
(
Entry
<
String
,
String
[]>
entry
:
this
.
request
.
getParameterMap
()
.
entrySet
())
{
for
(
String
value
:
entry
.
getValue
())
{
builder
.
add
(
entry
.
getKey
(),
value
);
}
}
if
(
this
.
request
instanceof
MultipartRequest
)
{
MultipartRequest
multi
=
(
MultipartRequest
)
this
.
request
;
for
(
Entry
<
String
,
MultipartFile
>
part
:
multi
.
getFileMap
()
.
entrySet
())
{
MultipartFile
file
=
part
.
getValue
();
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
setContentDispositionFormData
(
file
.
getName
(),
file
.
getOriginalFilename
());
headers
.
setContentType
(
MediaType
.
valueOf
(
file
.
getContentType
()));
HttpEntity
<
byte
[]>
entity
=
new
HttpEntity
<
byte
[]>(
file
.
getBytes
(),
headers
);
builder
.
set
(
part
.
getKey
(),
entity
);
}
}
FormHttpOutputMessage
data
=
new
FormHttpOutputMessage
();
this
.
contentType
=
MediaType
.
valueOf
(
this
.
request
.
getContentType
());
data
.
getHeaders
().
setContentType
(
this
.
contentType
);
this
.
converter
.
write
(
builder
,
this
.
contentType
,
data
);
this
.
converter
.
write
(
builder
,
this
.
contentType
,
data
);
// copy new content type including multipart boundary
this
.
contentType
=
data
.
getHeaders
().
getContentType
();
this
.
contentType
=
data
.
getHeaders
().
getContentType
();
this
.
contentLength
=
new
Long
(
data
.
getHeaders
().
getContentLength
())
.
intValue
();
this
.
contentData
=
data
.
getInput
();
this
.
contentData
=
data
.
getInput
();
this
.
contentLength
=
this
.
contentData
.
length
;
}
}
catch
(
Exception
e
)
{
catch
(
Exception
e
)
{
throw
new
IllegalStateException
(
"Cannot convert form data"
,
e
);
throw
new
IllegalStateException
(
"Cannot convert form data"
,
e
);
...
@@ -190,6 +207,7 @@ public class FormBodyWrapperFilter extends ZuulFilter {
...
@@ -190,6 +207,7 @@ public class FormBodyWrapperFilter extends ZuulFilter {
}
}
public
byte
[]
getInput
()
throws
IOException
{
public
byte
[]
getInput
()
throws
IOException
{
this
.
output
.
flush
();
return
this
.
output
.
toByteArray
();
return
this
.
output
.
toByteArray
();
}
}
...
...
spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/Servlet30WrapperFilter.java
View file @
043732ae
...
@@ -136,12 +136,22 @@ public class Servlet30WrapperFilter extends ZuulFilter {
...
@@ -136,12 +136,22 @@ public class Servlet30WrapperFilter extends ZuulFilter {
@Override
@Override
public
boolean
isAsyncStarted
()
{
public
boolean
isAsyncStarted
()
{
return
this
.
request
.
isAsyncStarted
();
try
{
return
this
.
request
.
isAsyncStarted
();
}
catch
(
Throwable
e
)
{
return
false
;
}
}
}
@Override
@Override
public
boolean
isAsyncSupported
()
{
public
boolean
isAsyncSupported
()
{
return
this
.
request
.
isAsyncSupported
();
try
{
return
this
.
request
.
isAsyncSupported
();
}
catch
(
Throwable
e
)
{
return
false
;
}
}
}
@Override
@Override
...
...
spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/FormZuulProxyApplicationTests.java
View file @
043732ae
...
@@ -16,11 +16,11 @@
...
@@ -16,11 +16,11 @@
package
org
.
springframework
.
cloud
.
netflix
.
zuul
;
package
org
.
springframework
.
cloud
.
netflix
.
zuul
;
import
java.io.IOException
;
import
java.util.Arrays
;
import
java.util.Arrays
;
import
org.junit.Test
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.junit.runner.RunWith
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.boot.autoconfigure.EnableAutoConfiguration
;
import
org.springframework.boot.autoconfigure.EnableAutoConfiguration
;
...
@@ -28,7 +28,6 @@ import org.springframework.boot.test.IntegrationTest;
...
@@ -28,7 +28,6 @@ import org.springframework.boot.test.IntegrationTest;
import
org.springframework.boot.test.SpringApplicationConfiguration
;
import
org.springframework.boot.test.SpringApplicationConfiguration
;
import
org.springframework.boot.test.TestRestTemplate
;
import
org.springframework.boot.test.TestRestTemplate
;
import
org.springframework.cloud.netflix.ribbon.RibbonClient
;
import
org.springframework.cloud.netflix.ribbon.RibbonClient
;
import
org.springframework.cloud.netflix.zuul.filters.ProxyRouteLocator
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.http.HttpEntity
;
import
org.springframework.http.HttpEntity
;
...
@@ -42,10 +41,11 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
...
@@ -42,10 +41,11 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import
org.springframework.test.context.web.WebAppConfiguration
;
import
org.springframework.test.context.web.WebAppConfiguration
;
import
org.springframework.util.LinkedMultiValueMap
;
import
org.springframework.util.LinkedMultiValueMap
;
import
org.springframework.util.MultiValueMap
;
import
org.springframework.util.MultiValueMap
;
import
org.springframework.web.bind.annotation.RequestBody
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMethod
;
import
org.springframework.web.bind.annotation.RequestMethod
;
import
org.springframework.web.bind.annotation.RequestParam
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.multipart.MultipartFile
;
import
com.netflix.appinfo.EurekaInstanceConfig
;
import
com.netflix.appinfo.EurekaInstanceConfig
;
import
com.netflix.loadbalancer.BaseLoadBalancer
;
import
com.netflix.loadbalancer.BaseLoadBalancer
;
...
@@ -65,12 +65,6 @@ public class FormZuulProxyApplicationTests {
...
@@ -65,12 +65,6 @@ public class FormZuulProxyApplicationTests {
@Value
(
"${local.server.port}"
)
@Value
(
"${local.server.port}"
)
private
int
port
;
private
int
port
;
@Autowired
private
ProxyRouteLocator
routes
;
@Autowired
private
RoutesEndpoint
endpoint
;
@Test
@Test
public
void
postWithForm
()
{
public
void
postWithForm
()
{
MultiValueMap
<
String
,
String
>
form
=
new
LinkedMultiValueMap
<
String
,
String
>();
MultiValueMap
<
String
,
String
>
form
=
new
LinkedMultiValueMap
<
String
,
String
>();
...
@@ -100,6 +94,23 @@ public class FormZuulProxyApplicationTests {
...
@@ -100,6 +94,23 @@ public class FormZuulProxyApplicationTests {
}
}
@Test
@Test
public
void
postWithMultipartFile
()
{
MultiValueMap
<
String
,
Object
>
form
=
new
LinkedMultiValueMap
<
String
,
Object
>();
HttpHeaders
part
=
new
HttpHeaders
();
part
.
setContentType
(
MediaType
.
TEXT_PLAIN
);
part
.
setContentDispositionFormData
(
"file"
,
"foo.txt"
);
form
.
set
(
"foo"
,
new
HttpEntity
<
byte
[]>(
"bar"
.
getBytes
(),
part
));
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
setContentType
(
MediaType
.
MULTIPART_FORM_DATA
);
ResponseEntity
<
String
>
result
=
new
TestRestTemplate
().
exchange
(
"http://localhost:"
+
this
.
port
+
"/simple/file"
,
HttpMethod
.
POST
,
new
HttpEntity
<
MultiValueMap
<
String
,
Object
>>(
form
,
headers
),
String
.
class
);
assertEquals
(
HttpStatus
.
OK
,
result
.
getStatusCode
());
assertEquals
(
"Posted! bar"
,
result
.
getBody
());
}
@Test
public
void
postWithUTF8Form
()
{
public
void
postWithUTF8Form
()
{
MultiValueMap
<
String
,
String
>
form
=
new
LinkedMultiValueMap
<
String
,
String
>();
MultiValueMap
<
String
,
String
>
form
=
new
LinkedMultiValueMap
<
String
,
String
>();
form
.
set
(
"foo"
,
"bar"
);
form
.
set
(
"foo"
,
"bar"
);
...
@@ -124,10 +135,18 @@ public class FormZuulProxyApplicationTests {
...
@@ -124,10 +135,18 @@ public class FormZuulProxyApplicationTests {
class
FormZuulProxyApplication
{
class
FormZuulProxyApplication
{
@RequestMapping
(
value
=
"/"
,
method
=
RequestMethod
.
POST
)
@RequestMapping
(
value
=
"/"
,
method
=
RequestMethod
.
POST
)
public
String
delete
(
@RequestBody
MultiValueMap
<
String
,
String
>
form
)
{
public
String
accept
(
@RequestParam
MultiValueMap
<
String
,
String
>
form
)
throws
IOException
{
return
"Posted! "
+
form
;
return
"Posted! "
+
form
;
}
}
// TODO: Why does this not work if you add @RequestParam as above?
@RequestMapping
(
value
=
"/file"
,
method
=
RequestMethod
.
POST
)
public
String
file
(
@RequestParam
(
required
=
false
)
MultipartFile
file
)
throws
IOException
{
return
"Posted! "
+
(
file
==
null
?
""
:
new
String
(
file
.
getBytes
()));
}
@Bean
@Bean
public
ZuulFilter
sampleFilter
()
{
public
ZuulFilter
sampleFilter
()
{
return
new
ZuulFilter
()
{
return
new
ZuulFilter
()
{
...
@@ -156,7 +175,7 @@ class FormZuulProxyApplication {
...
@@ -156,7 +175,7 @@ class FormZuulProxyApplication {
}
}
public
static
void
main
(
String
[]
args
)
{
public
static
void
main
(
String
[]
args
)
{
SpringApplication
.
run
(
Sample
ZuulProxyApplication
.
class
,
args
);
SpringApplication
.
run
(
Form
ZuulProxyApplication
.
class
,
args
);
}
}
}
}
...
@@ -170,6 +189,7 @@ class FormRibbonClientConfiguration {
...
@@ -170,6 +189,7 @@ class FormRibbonClientConfiguration {
BaseLoadBalancer
balancer
=
new
BaseLoadBalancer
();
BaseLoadBalancer
balancer
=
new
BaseLoadBalancer
();
balancer
.
setServersList
(
Arrays
.
asList
(
new
Server
(
"localhost"
,
instance
balancer
.
setServersList
(
Arrays
.
asList
(
new
Server
(
"localhost"
,
instance
.
getNonSecurePort
())));
.
getNonSecurePort
())));
// balancer.setServersList(Arrays.asList(new Server("localhost", 8000)));
return
balancer
;
return
balancer
;
}
}
...
...
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