Closed ralscha closed 8 years ago
Thanks for the sample that reproduces the problem. The ISO-8859-1
response can be reproduced with a simple curl request:
curl -v localhost:8080/start -H 'Origin: foo'
Isn't that related to #5459 ?
I'm not sure yet. It seems likely, however I'd expect Tomcat and Undertow to be affected too.
When CORS is involved, DefaultCorsProcessor.handleInternal
calls ServletServerHttpResponse.flush()
which, in turn, calls ServletServerHttpResponse.writeHeaders()
. As part of writing the headers, getCharacterEncoding()
is called on the HttpServletResponse
. Jetty's implementation is:
@Override
public String getCharacterEncoding()
{
if (_characterEncoding == null)
_characterEncoding = StringUtil.__ISO_8859_1;
return _characterEncoding;
}
When the call is made, _characterEncoding
is null
so it's set to iso-8859-1
. Without the Origin
header, DefaultCorsProcessor
doesn't really get involved, flush()
isn't called, and the character encoding isn't initialized with the unwanted value.
As @snicoll suspected, this is a side-effect of #5459. In 1.4.0.M3 and later, responses can be set to UTF-8 by forcing the response's content type:
spring.http.encoding.force-response=true
The will set the charset of every response to UTF-8
which may or may not be desirable. If it's undesirable, one more focussed solution is a custom SseEmitter
subclass. For example:
@Controller
public class SseController {
@CrossOrigin
@RequestMapping("/start")
public SseEmitter start() {
return new Utf8SseEmitter();
}
private static final class Utf8SseEmitter extends SseEmitter {
private static final MediaType UTF8_TEXT_STREAM = new MediaType("text", "stream", Charset.forName("UTF-8"));
@Override
protected void extendResponse(ServerHttpResponse outputMessage) {
HttpHeaders headers = outputMessage.getHeaders();
if (headers.getContentType() == null) {
headers.setContentType(UTF8_TEXT_STREAM);
}
}
}
}
I'm not convinced that this should be necessary, though.
@bclozel Given that the spec states that text/stream
must use UTF-8
, would it make sense for SseEmitter
to specify the UTF-8
charset by default as I have done above in Utf8SseEmitter
?
This has been fixed in SPR-14407 and should be available shortly as a Spring Framework 4.3.1 SNAPSHOT version.
Thanks @wilkinsona !
Duplicates #6197
There is a problem in 1.4.0.M3 and 1.4.0.BUILD-SNAPSHOT, Jetty, EventSource (SseEmitter) and CORS. With this setup spring boot sends a wrong Content-Type response header back to the client.
Content-Type: text/event-stream; charset=ISO-8859-1
Chrome 51 complains with this error message
EventSource's response has a charset ("iso-8859-1") that is not UTF-8. Aborting the connection.
When the request is not sent with CORS the server sends this header
Content-Type: text/event-stream
which is okay for Chrome. Event streams must always be encoded using UTF-8Here is a github repository that demonstrates the problem: https://github.com/ralscha/sse-encoding
Requests to http://localhost:8080 work fine but when you do a CORS request (for example by opening index.html directly from filesystem) Chrome will complain with the above-mentioned error message.
This problem does not occur with Spring Boot 1.4.0.M2 and it does not occur with Tomcat and Undertow with 1.4.0.M3 and 1.4.0.BUILD-SNAPSHOT