Skip to content

Commit

Permalink
[Feature/extensions] Pass REST params and content to extensions (#4633)
Browse files Browse the repository at this point in the history
* Pass REST params and content to extensions 

Signed-off-by: Daniel Widdis <[email protected]>
  • Loading branch information
dbwiddis authored Sep 30, 2022
1 parent a4f4e72 commit 54b4ad0
Show file tree
Hide file tree
Showing 6 changed files with 537 additions and 230 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- Adding create component extension point support for AD ([#4517](https:/opensearch-project/OpenSearch/pull/4517))
- Add getSettings support for AD([#4519](https:/opensearch-project/OpenSearch/pull/4519))
- Fixed javadoc warning for build failure([#4581](https:/opensearch-project/OpenSearch/pull/4581))
- Pass REST params and content to extensions ([#4633](https:/opensearch-project/OpenSearch/pull/4633))

## [2.x]
### Added
Expand Down
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);
}
}

This file was deleted.

Loading

0 comments on commit 54b4ad0

Please sign in to comment.