diff options
author | Morten Tokle <mortent@verizonmedia.com> | 2021-05-20 15:42:13 +0200 |
---|---|---|
committer | Morten Tokle <mortent@verizonmedia.com> | 2021-05-20 16:06:53 +0200 |
commit | 156c15e72404e9ffec6ffdb2103d151e5a528705 (patch) | |
tree | 71aad894694f049b24748a813b662d401c87b948 /configserver | |
parent | 864eb3da782e9795826ec78add953a76eeb2ea17 (diff) |
Parse content type header
Diffstat (limited to 'configserver')
3 files changed, 42 insertions, 9 deletions
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationApiHandler.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationApiHandler.java index 8bc792a179d..5b520b10fcf 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationApiHandler.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationApiHandler.java @@ -16,6 +16,8 @@ import com.yahoo.vespa.config.server.http.SessionHandler; import com.yahoo.vespa.config.server.http.Utils; import com.yahoo.vespa.config.server.session.PrepareParams; import com.yahoo.vespa.config.server.tenant.TenantRepository; +import com.yahoo.vespa.model.content.Content; +import org.apache.hc.core5.http.ContentType; import org.eclipse.jetty.http.MultiPartFormInputStream; import javax.servlet.http.Part; @@ -70,7 +72,8 @@ public class ApplicationApiHandler extends SessionHandler { PrepareParams prepareParams; CompressedApplicationInputStream compressedStream; boolean multipartRequest = Optional.ofNullable(request.getHeader(HttpHeaders.Names.CONTENT_TYPE)) - .map(val -> val.equalsIgnoreCase(MULTIPART_FORM_DATA)) + .map(ContentType::parse) + .map(contentType -> contentType.getMimeType().equalsIgnoreCase(MULTIPART_FORM_DATA)) .orElse(false); if(multipartRequest) { try { diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionCreateHandler.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionCreateHandler.java index a3e82c51dfa..61f099fb8ea 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionCreateHandler.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionCreateHandler.java @@ -9,6 +9,7 @@ import com.yahoo.config.provision.InstanceName; import com.yahoo.config.provision.TenantName; import com.yahoo.container.jdisc.HttpRequest; import com.yahoo.container.jdisc.HttpResponse; +import com.yahoo.jdisc.HeaderFields; import com.yahoo.jdisc.application.UriPattern; import com.yahoo.vespa.config.server.ApplicationRepository; import com.yahoo.vespa.config.server.deploy.DeployHandlerLogger; @@ -16,6 +17,8 @@ import com.yahoo.vespa.config.server.TimeoutBudget; import com.yahoo.vespa.config.server.http.BadRequestException; import com.yahoo.vespa.config.server.http.SessionHandler; import com.yahoo.vespa.config.server.http.Utils; +import com.yahoo.vespa.model.content.Content; +import org.apache.hc.core5.http.ContentType; import java.net.URI; import java.time.Duration; @@ -93,9 +96,12 @@ public class SessionCreateHandler extends SessionHandler { String header = request.getHeader(ApplicationApiHandler.contentTypeHeader); if (header == null) { throw new BadRequestException("Request contains no " + ApplicationApiHandler.contentTypeHeader + " header"); - } else if (!supportedContentTypes.contains(header)) { - throw new BadRequestException("Request contains invalid " + ApplicationApiHandler.contentTypeHeader + " header, only '[" - + String.join(", ", supportedContentTypes) + "' are supported"); + } else { + ContentType contentType = ContentType.parse(header); + if (!supportedContentTypes.contains(contentType.getMimeType())) { + throw new BadRequestException("Request contains invalid " + ApplicationApiHandler.contentTypeHeader + " header (" + contentType.getMimeType() + "), only '[" + + String.join(", ", supportedContentTypes) + "]' are supported"); + } } } } diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionCreateHandlerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionCreateHandlerTest.java index 83d6ac5b288..5d7322070e7 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionCreateHandlerTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionCreateHandlerTest.java @@ -16,19 +16,24 @@ import com.yahoo.vespa.config.server.http.SessionHandlerTest; import com.yahoo.vespa.config.server.session.Session; import com.yahoo.vespa.config.server.tenant.TenantRepository; import com.yahoo.vespa.config.server.tenant.TestTenantRepository; +import org.apache.hc.core5.http.ContentType; import org.junit.Before; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import static com.yahoo.jdisc.Response.Status.BAD_REQUEST; @@ -43,6 +48,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; /** * @author hmusum @@ -171,6 +177,22 @@ public class SessionCreateHandlerTest extends SessionHandlerTest { assertIllegalFromParameter("http://host:4013/application/v2/tenant/" + tenant + "/application/foo/environment/prod/region/baz/instance"); } + @Test + public void require_that_content_type_is_parsed_correctly() throws FileNotFoundException { + HttpRequest request = post(new ByteArrayInputStream("foo".getBytes(StandardCharsets.UTF_8)), + Map.of("Content-Type", "multipart/form-data; charset=ISO-8859-1; boundary=g5gJAzUWl_t6"), + Collections.emptyMap()); + + // Valid header should validate ok + SessionCreateHandler.validateDataAndHeader(request, List.of(ContentType.MULTIPART_FORM_DATA.getMimeType())); + + // Accepting only application/json should fail: + try { + SessionCreateHandler.validateDataAndHeader(request, List.of(ContentType.APPLICATION_JSON.getMimeType())); + fail("Request contained invalid content type, but validated ok"); + } catch (Exception expected) {} + } + private SessionCreateHandler createHandler() { return new SessionCreateHandler(SessionCreateHandler.testOnlyContext(), applicationRepository, @@ -178,7 +200,7 @@ public class SessionCreateHandlerTest extends SessionHandlerTest { } private HttpRequest post() throws FileNotFoundException { - return post(null, postHeaders, new HashMap<>()); + return post((InputStream) null, postHeaders, new HashMap<>()); } private HttpRequest post(File file) throws FileNotFoundException { @@ -186,10 +208,12 @@ public class SessionCreateHandlerTest extends SessionHandlerTest { } private HttpRequest post(File file, Map<String, String> headers, Map<String, String> parameters) throws FileNotFoundException { + return post(file == null ? null : new FileInputStream(file), headers, parameters); + } + + private HttpRequest post(InputStream data, Map <String, String > headers, Map < String, String > parameters) throws FileNotFoundException { HttpRequest request = HttpRequest.createTestRequest("http://" + hostname + ":" + port + "/application/v2/tenant/" + tenant + "/session", - POST, - file == null ? null : new FileInputStream(file), - parameters); + POST, data, parameters); for (Map.Entry<String, String> entry : headers.entrySet()) { request.getJDiscRequest().headers().put(entry.getKey(), entry.getValue()); } @@ -197,6 +221,6 @@ public class SessionCreateHandlerTest extends SessionHandlerTest { } private HttpRequest post(Map<String, String> parameters) throws FileNotFoundException { - return post(null, new HashMap<>(), parameters); + return post((InputStream) null, new HashMap<>(), parameters); } } |