-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Feature/extensions] Pass REST params and content to extensions (#4633)
* Pass REST params and content to extensions Signed-off-by: Daniel Widdis <[email protected]>
- Loading branch information
Showing
6 changed files
with
537 additions
and
230 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
273 changes: 273 additions & 0 deletions
273
server/src/main/java/org/opensearch/extensions/rest/ExtensionRestRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,273 @@ | ||
/* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* The OpenSearch Contributors require contributions made to | ||
* this file be licensed under the Apache-2.0 license or a | ||
* compatible open source license. | ||
*/ | ||
|
||
package org.opensearch.extensions.rest; | ||
|
||
import org.opensearch.common.bytes.BytesReference; | ||
import org.opensearch.common.io.stream.StreamInput; | ||
import org.opensearch.common.io.stream.StreamOutput; | ||
import org.opensearch.common.xcontent.XContentType; | ||
import org.opensearch.identity.PrincipalIdentifierToken; | ||
import org.opensearch.rest.RestRequest; | ||
import org.opensearch.rest.RestRequest.Method; | ||
import org.opensearch.transport.TransportRequest; | ||
|
||
import java.io.IOException; | ||
import java.util.ArrayList; | ||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
import java.util.Set; | ||
|
||
/** | ||
* Request to execute REST actions on extension node. | ||
* This contains necessary portions of a {@link RestRequest} object, but does not pass the full request for security concerns. | ||
* | ||
* @opensearch.api | ||
*/ | ||
public class ExtensionRestRequest extends TransportRequest { | ||
|
||
private Method method; | ||
private String path; | ||
private Map<String, String> params; | ||
private XContentType xContentType = null; | ||
private BytesReference content; | ||
// The owner of this request object | ||
private PrincipalIdentifierToken principalIdentifierToken; | ||
|
||
// Tracks consumed parameters and content | ||
private final Set<String> consumedParams = new HashSet<>(); | ||
private boolean contentConsumed = false; | ||
|
||
/** | ||
* This object can be instantiated given method, uri, params, content and identifier | ||
* | ||
* @param method of type {@link Method} | ||
* @param path the REST path string (excluding the query) | ||
* @param params the REST params | ||
* @param xContentType the content type, or null for plain text or no content | ||
* @param content the REST request content | ||
* @param principalIdentifier the owner of this request | ||
*/ | ||
public ExtensionRestRequest( | ||
Method method, | ||
String path, | ||
Map<String, String> params, | ||
XContentType xContentType, | ||
BytesReference content, | ||
PrincipalIdentifierToken principalIdentifier | ||
) { | ||
this.method = method; | ||
this.path = path; | ||
this.params = params; | ||
this.xContentType = xContentType; | ||
this.content = content; | ||
this.principalIdentifierToken = principalIdentifier; | ||
} | ||
|
||
/** | ||
* Instantiate this request from input stream | ||
* | ||
* @param in Input stream | ||
* @throws IOException on failure to read the stream | ||
*/ | ||
public ExtensionRestRequest(StreamInput in) throws IOException { | ||
super(in); | ||
method = in.readEnum(RestRequest.Method.class); | ||
path = in.readString(); | ||
params = in.readMap(StreamInput::readString, StreamInput::readString); | ||
if (in.readBoolean()) { | ||
xContentType = in.readEnum(XContentType.class); | ||
} | ||
content = in.readBytesReference(); | ||
principalIdentifierToken = in.readNamedWriteable(PrincipalIdentifierToken.class); | ||
} | ||
|
||
@Override | ||
public void writeTo(StreamOutput out) throws IOException { | ||
super.writeTo(out); | ||
out.writeEnum(method); | ||
out.writeString(path); | ||
out.writeMap(params, StreamOutput::writeString, StreamOutput::writeString); | ||
out.writeBoolean(xContentType != null); | ||
if (xContentType != null) { | ||
out.writeEnum(xContentType); | ||
} | ||
out.writeBytesReference(content); | ||
out.writeNamedWriteable(principalIdentifierToken); | ||
} | ||
|
||
/** | ||
* Gets the REST method | ||
* | ||
* @return This REST request {@link Method} type | ||
*/ | ||
public Method method() { | ||
return method; | ||
} | ||
|
||
/** | ||
* Gets the REST path | ||
* | ||
* @return This REST request's path | ||
*/ | ||
public String path() { | ||
return path; | ||
} | ||
|
||
/** | ||
* Gets the full map of params without consuming them. Rest Handlers should use {@link #param(String)} or {@link #param(String, String)} | ||
* to get parameter values. | ||
* | ||
* @return This REST request's params | ||
*/ | ||
public Map<String, String> params() { | ||
return params; | ||
} | ||
|
||
/** | ||
* Tests whether a parameter named {@code key} exists. | ||
* | ||
* @param key The parameter to test. | ||
* @return True if there is a value for this parameter. | ||
*/ | ||
public boolean hasParam(String key) { | ||
return params.containsKey(key); | ||
} | ||
|
||
/** | ||
* Gets the value of a parameter, consuming it in the process. | ||
* | ||
* @param key The parameter key | ||
* @return The parameter value if it exists, or null. | ||
*/ | ||
public String param(String key) { | ||
consumedParams.add(key); | ||
return params.get(key); | ||
} | ||
|
||
/** | ||
* Gets the value of a parameter, consuming it in the process. | ||
* | ||
* @param key The parameter key | ||
* @param defaultValue A value to return if the parameter value doesn't exist. | ||
* @return The parameter value if it exists, or the default value. | ||
*/ | ||
public String param(String key, String defaultValue) { | ||
consumedParams.add(key); | ||
return params.getOrDefault(key, defaultValue); | ||
} | ||
|
||
/** | ||
* Gets the value of a parameter as a long, consuming it in the process. | ||
* | ||
* @param key The parameter key | ||
* @param defaultValue A value to return if the parameter value doesn't exist. | ||
* @return The parameter value if it exists, or the default value. | ||
*/ | ||
public long paramAsLong(String key, long defaultValue) { | ||
String value = param(key); | ||
if (value == null) { | ||
return defaultValue; | ||
} | ||
try { | ||
return Long.parseLong(value); | ||
} catch (NumberFormatException e) { | ||
throw new IllegalArgumentException("Unable to parse param '" + key + "' value '" + value + "' to a long.", e); | ||
} | ||
} | ||
|
||
/** | ||
* Returns parameters consumed by {@link #param(String)} or {@link #param(String, String)}. | ||
* | ||
* @return a list of consumed parameters. | ||
*/ | ||
public List<String> consumedParams() { | ||
return new ArrayList<>(consumedParams); | ||
} | ||
|
||
/** | ||
* Gets the content type, if any. | ||
* | ||
* @return the content type of the {@link #content()}, or null if the context is plain text or if there is no content. | ||
*/ | ||
public XContentType getXContentType() { | ||
return xContentType; | ||
} | ||
|
||
/** | ||
* Gets the content. | ||
* | ||
* @return This REST request's content | ||
*/ | ||
public BytesReference content() { | ||
contentConsumed = true; | ||
return content; | ||
} | ||
|
||
/** | ||
* Tests whether content exists. | ||
* | ||
* @return True if there is non-empty content. | ||
*/ | ||
public boolean hasContent() { | ||
return content.length() > 0; | ||
} | ||
|
||
/** | ||
* Tests whether content has been consumed. | ||
* | ||
* @return True if the content was consumed. | ||
*/ | ||
public boolean isContentConsumed() { | ||
return contentConsumed; | ||
} | ||
|
||
/** | ||
* @return This REST request issuer's identity token | ||
*/ | ||
public PrincipalIdentifierToken getRequestIssuerIdentity() { | ||
return principalIdentifierToken; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "ExtensionRestRequest{method=" | ||
+ method | ||
+ ", path=" | ||
+ path | ||
+ ", params=" | ||
+ params | ||
+ ", xContentType=" | ||
+ xContentType | ||
+ ", contentLength=" | ||
+ content.length() | ||
+ ", requester=" | ||
+ principalIdentifierToken.getToken() | ||
+ "}"; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object obj) { | ||
if (this == obj) return true; | ||
if (obj == null || getClass() != obj.getClass()) return false; | ||
ExtensionRestRequest that = (ExtensionRestRequest) obj; | ||
return Objects.equals(method, that.method) | ||
&& Objects.equals(path, that.path) | ||
&& Objects.equals(params, that.params) | ||
&& Objects.equals(xContentType, that.xContentType) | ||
&& Objects.equals(content, that.content) | ||
&& Objects.equals(principalIdentifierToken, that.principalIdentifierToken); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(method, path, params, xContentType, content, principalIdentifierToken); | ||
} | ||
} |
95 changes: 0 additions & 95 deletions
95
server/src/main/java/org/opensearch/extensions/rest/RestExecuteOnExtensionRequest.java
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.