Reputation: 778
I am creating a simple service using HttpServer. The service works correctly when I use strings without special characters.
public static void main (String arg []) throws Exception {
HttpServer server = HttpServer.create(new InetSocketAddress(serverPort), 0);
server.createContext("/notification", new MyHandler());
server.setExecutor(null); // creates a default executor
server.start();
}
static class MyHandler implements HttpHandler {
public void handle(HttpExchange t) throws IOException {
String response;
response = "with special characters éáã "; // it doesn't work
response = "without special characters"; // it works!
String encoding = "UTF-8";
System.out.println(response);
t.getResponseHeaders().set("Content-Type", "application/json; charset=" + encoding);
t.sendResponseHeaders(200, response.length());
byte[] bytes = response.getBytes(StandardCharsets.UTF_8);
OutputStream os = t.getResponseBody();
os.write(bytes);
os.flush();
os.close();
}
}
When my UTF-8 string has special characters, it return this error:
java.io.IOException: too many bytes to write to stream at sun.net.httpserver.FixedLengthOutputStream.write(FixedLengthOutputStream.java:76) at java.io.FilterOutputStream.write(FilterOutputStream.java:97) at sun.net.httpserver.PlaceholderOutputStream.write(ExchangeImpl.java:439) at InternalServer$MyHandler.handle(InternalServer.java:86) at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:79) at sun.net.httpserver.AuthFilter.doFilter(AuthFilter.java:83) at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:82) at sun.net.httpserver.ServerImpl$Exchange$LinkHandler.handle(ServerImpl.java:675) at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:79) at sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:647) at sun.net.httpserver.ServerImpl$DefaultExecutor.execute(ServerImpl.java:158) at sun.net.httpserver.ServerImpl$Dispatcher.handle(ServerImpl.java:431) at sun.net.httpserver.ServerImpl$Dispatcher.run(ServerImpl.java:396) at java.lang.Thread.run(Thread.java:748)
Upvotes: 0
Views: 804
Reputation: 718678
Here is the problem.
t.sendResponseHeaders(200, response.length());
The second parameter to sendResponseHeaders
must be the exact size of the content you are going to send in bytes. But you are passing the length of a string in characters.
In UTF-8, any character that is larger than U+0080 will be encoded as 2 or more bytes. Your second example string contains characters that are larger than U+0080, so when it is encoded in UTF-8, the character count and byte count are different. You will be setting the incorrect content length in the response header
It looks like the output stream provided by HttpExchange
is checking that you do not send more bytes than you set in the response header. (That would be an HTTP protocol violation.)
Solution:
...
byte[] bytes = response.getBytes(StandardCharsets.UTF_8);
t.sendResponseHeaders(200, bytes.length);
...
It is also possible to pass 0
as the content length. That will cause the body to be sent using chunked transfer encoding.
Upvotes: 2