Skip to content

Commit

Permalink
Validate charset if exist when parse media type from Content-Type
Browse files Browse the repository at this point in the history
  • Loading branch information
liketic committed Nov 9, 2017
1 parent 3209a35 commit bc424b3
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 4 deletions.
21 changes: 18 additions & 3 deletions core/src/main/java/org/elasticsearch/rest/RestController.java
Original file line number Diff line number Diff line change
Expand Up @@ -286,9 +286,7 @@ private boolean hasContentTypeOrCanAutoDetect(final RestRequest restRequest, fin
}
}
} else if (restHandler != null && restHandler.supportsContentStream() && restRequest.header("Content-Type") != null) {
final String lowercaseContentType = restRequest.header("Content-Type").toLowerCase(Locale.ROOT);
final String[] elements = lowercaseContentType.split(";");
final String lowercaseMediaType = elements[0].trim();
final String lowercaseMediaType = parseMediaType(restRequest.header("Content-Type"));

// we also support newline delimited JSON: http://specs.okfnlabs.org/ndjson/
if (lowercaseMediaType.equals("application/x-ndjson")) {
Expand All @@ -311,6 +309,23 @@ private boolean hasContentTypeOrCanAutoDetect(final RestRequest restRequest, fin
return true;
}

private String parseMediaType(String rawContentType) {
final String contentType = rawContentType.toLowerCase(Locale.ROOT);
int firstSemiColonIndex = contentType.indexOf(';');
if (firstSemiColonIndex == -1) {
return contentType;
}
final String mediaType = contentType.substring(0, firstSemiColonIndex).trim();
final String charsetCandidate = contentType.substring(firstSemiColonIndex + 1);

String[] keyValue = charsetCandidate.split("=", 2);
if (keyValue.length != 2 || !keyValue[0].trim().equalsIgnoreCase("charset")
|| !keyValue[1].trim().equalsIgnoreCase("utf-8")) {
deprecationLogger.deprecated("Content-Type [" + rawContentType + "] contains unrecognized [" + charsetCandidate + "]");
}
return mediaType;
}

private boolean autoDetectXContentType(RestRequest restRequest) {
deprecationLogger.deprecated("Content type detection for rest requests is deprecated. Specify the content type using " +
"the [Content-Type] header.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ public boolean supportsContentStream() {
}

public void testDispatchWithContentStream() {
final String mimeType = randomFrom("application/json", "application/smile", "application/x-ndjson; charset=UTF-8");
final String mimeType = randomFrom("application/json", "application/smile");
String content = randomAlphaOfLengthBetween(1, BREAKER_LIMIT.bytesAsInt());
FakeRestRequest fakeRestRequest = new FakeRestRequest.Builder(NamedXContentRegistry.EMPTY)
.withContent(new BytesArray(content), null).withPath("/foo")
Expand All @@ -418,6 +418,50 @@ public boolean supportsContentStream() {
assertTrue(channel.getSendResponseCalled());
}

public void testContentTypeNotOnlyMediaType() {
restController.registerHandler(RestRequest.Method.GET, "/foo", new RestHandler() {
@Override
public void handleRequest(RestRequest request, RestChannel channel, NodeClient client) throws Exception {
channel.sendResponse(new BytesRestResponse(RestStatus.OK, BytesRestResponse.TEXT_CONTENT_TYPE, BytesArray.EMPTY));
}

@Override
public boolean supportsContentStream() {
return true;
}
});

String goodMimeType = randomFrom("application/x-ndjson",
"application/x-ndjson; charset=UTF-8",
"application/x-ndjson; charset=utf-8",
"application/x-ndjson;charset=UTF-8");
String content = randomAlphaOfLengthBetween(1, BREAKER_LIMIT.bytesAsInt());
FakeRestRequest fakeRestRequest = new FakeRestRequest.Builder(NamedXContentRegistry.EMPTY)
.withContent(new BytesArray(content), null).withPath("/foo")
.withHeaders(Collections.singletonMap("Content-Type", Collections.singletonList(goodMimeType))).build();
AssertingChannel channel = new AssertingChannel(fakeRestRequest, true, RestStatus.OK);

assertFalse(channel.getSendResponseCalled());
restController.dispatchRequest(fakeRestRequest, channel, new ThreadContext(Settings.EMPTY));
assertTrue(channel.getSendResponseCalled());

String badMimeType = randomFrom("application/x-ndjson; charset=utf-8; unknown",
"application/x-ndjson; charset=unknown",
"application/x-ndjson;charset=UTF-16",
"application/x-ndjson; unknown");
content = randomAlphaOfLengthBetween(1, BREAKER_LIMIT.bytesAsInt());
fakeRestRequest = new FakeRestRequest.Builder(NamedXContentRegistry.EMPTY)
.withContent(new BytesArray(content), null).withPath("/foo")
.withHeaders(Collections.singletonMap("Content-Type", Collections.singletonList(badMimeType))).build();
channel = new AssertingChannel(fakeRestRequest, true, RestStatus.OK);

assertFalse(channel.getSendResponseCalled());
restController.dispatchRequest(fakeRestRequest, channel, new ThreadContext(Settings.EMPTY));
assertTrue(channel.getSendResponseCalled());
assertWarnings("Content-Type [" + badMimeType + "] contains unrecognized ["
+ badMimeType.substring(badMimeType.indexOf(";") + 1).toLowerCase(Locale.ROOT) + "]");
}

public void testDispatchWithContentStreamAutoDetect() {
FakeRestRequest fakeRestRequest = new FakeRestRequest.Builder(NamedXContentRegistry.EMPTY)
.withContent(new BytesArray("{}"), null).withPath("/foo").build();
Expand Down

0 comments on commit bc424b3

Please sign in to comment.