|
16 | 16 | */ |
17 | 17 | package tech.beshu.ror.es.actions.rrauditevent.rest |
18 | 18 |
|
19 | | -import java.util |
20 | | - |
21 | 19 | import org.elasticsearch.ElasticsearchException |
22 | 20 | import org.elasticsearch.client.internal.node.NodeClient |
| 21 | +import org.elasticsearch.common.bytes.BytesReference |
23 | 22 | import org.elasticsearch.common.xcontent.XContentHelper |
| 23 | +import org.elasticsearch.rest.* |
24 | 24 | import org.elasticsearch.rest.BaseRestHandler.RestChannelConsumer |
25 | 25 | import org.elasticsearch.rest.RestHandler.Route |
26 | 26 | import org.elasticsearch.rest.RestRequest.Method.POST |
27 | | -import org.elasticsearch.rest.* |
| 27 | +import org.elasticsearch.xcontent.{DeprecationHandler, NamedXContentRegistry, XContentFactory, XContentParser, XContentParserConfiguration, XContentType} |
28 | 28 | import org.json.JSONObject |
29 | 29 | import squants.information.{Bytes, Information} |
30 | 30 | import tech.beshu.ror.constants |
31 | 31 | import tech.beshu.ror.es.actions.rrauditevent.{RRAuditEventActionType, RRAuditEventRequest} |
32 | 32 |
|
| 33 | +import java.util |
33 | 34 | import scala.jdk.CollectionConverters.* |
34 | | -import scala.util.Try |
| 35 | +import scala.util.{Try, Using} |
35 | 36 |
|
36 | 37 | class RestRRAuditEventAction |
37 | 38 | extends BaseRestHandler with RestHandler { |
38 | 39 |
|
| 40 | + private val strictParserConfig = XContentParserConfiguration.EMPTY |
| 41 | + .withRegistry(NamedXContentRegistry.EMPTY) |
| 42 | + .withDeprecationHandler(DeprecationHandler.THROW_UNSUPPORTED_OPERATION) |
| 43 | + |
39 | 44 | override def routes(): util.List[Route] = List( |
40 | 45 | new Route(POST, constants.AUDIT_EVENT_COLLECTOR_PATH) |
41 | 46 | ).asJava |
@@ -70,12 +75,26 @@ class RestRRAuditEventAction |
70 | 75 |
|
71 | 76 | private def validateBodyJson(request: RestRequest) = Try { |
72 | 77 | if (request.hasContent) { |
73 | | - new JSONObject(XContentHelper.convertToMap(request.requiredContent(), false, request.getXContentType).v2()) |
| 78 | + new JSONObject(asStrictMap(request.requiredContent(), request.getXContentType).asJava) |
74 | 79 | } else { |
75 | 80 | new JSONObject() |
76 | 81 | } |
77 | 82 | }.toEither.left.map(_ => new AuditEventBadRequest) |
78 | 83 |
|
| 84 | + private def asStrictMap(bytes: BytesReference, contentType: XContentType): Map[String, Any] = { |
| 85 | + val map = XContentHelper.convertToMap(bytes, false, contentType).v2().asScala |
| 86 | + if (map.nonEmpty || isExactlyEmptyObject(bytes, contentType)) map.toMap |
| 87 | + else throw new IllegalArgumentException("Malformed request body") |
| 88 | + } |
| 89 | + |
| 90 | + private def isExactlyEmptyObject(bytes: BytesReference, t: XContentType): Boolean = { |
| 91 | + Using.resource(XContentFactory.xContent(t).createParser(strictParserConfig, bytes.streamInput())) { p => |
| 92 | + (p.nextToken() == XContentParser.Token.START_OBJECT) && |
| 93 | + (p.nextToken() == XContentParser.Token.END_OBJECT) && |
| 94 | + p.nextToken() == null // no trailing data |
| 95 | + } |
| 96 | + } |
| 97 | + |
79 | 98 | private class AuditEventBadRequest extends ElasticsearchException("Content malformed") { |
80 | 99 | override def status(): RestStatus = RestStatus.BAD_REQUEST |
81 | 100 | } |
|
0 commit comments