/**
* Copyright 2016 LinkedIn Corp. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
package com.github.ambry.rest;
import com.github.ambry.router.AsyncWritableChannel;
import com.github.ambry.router.Callback;
import com.github.ambry.router.ReadableStreamChannel;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import javax.net.ssl.SSLSession;
/**
* RestRequest represents a HTTP request as a generic object that can be understood by all the layers in a RESTful
* frontend.
* <p/>
* It contains metadata about the request including the {@link RestMethod} desired, the original URI and associated
* arguments (in the form of parameters or headers). It also contains all the content associated with the request
* and this content can be streamed out through the read operations.
* <p/>
* Implementations are expected to be thread-safe.
* <p/>
* NOTE: Most of the operations performed in the REST front end are async. Therefore any reference counted objects
* inside an implementation of this interface have to be retained for the life of the object. They can be released on
* {@link #close()}.
*/
public interface RestRequest extends ReadableStreamChannel {
/**
* Gets the generic {@link RestMethod} that this request desires.
* @return RestMethod the {@link RestMethod} defined by the request.
*/
public RestMethod getRestMethod();
/**
* Return the path (the parts of the URI after the domain excluding query parameters).
* @return path String that represents part of the uri excluding domain and query parameters.
*/
public String getPath();
/**
* Return the request URI.
* @return the URI defined by the request.
*/
public String getUri();
/**
* Gets all the arguments passed as a part of the request.
* <p/>
* The implementation can decide what constitute as arguments. It can be specific parts of the URI, query parameters,
* header values etc. or a combination of any of these.
* @return the arguments and their values (if any) as a map.
*/
public Map<String, Object> getArgs();
/**
* If this request was over HTTPS, gets the {@link SSLSession} associated with the request.
* @return The {@link SSLSession} for the request and response, or {@code null} if SSL was not used.
*/
public SSLSession getSSLSession();
/**
* Prepares the request for reading.
* <p/>
* Any CPU bound tasks (decoding, decryption) can be performed in this method as it is expected to be called in a CPU
* bound thread. Calling this from an I/O bound thread will impact throughput.
* @throws RestServiceException if request channel is closed or if the request could not be prepared for reading.
*/
public void prepare() throws RestServiceException;
/**
* Closes this request channel and releases all of the resources associated with it. Also records some metrics via
* the {@link RestRequestMetricsTracker} instance attached to this RestRequest.
* <p/>
* Expected to be called once the request is "completed" i.e. either a response is completely sent out or an error
* state is reached from which a response cannot be sent.
* <p/>
* {@inheritDoc}
* @throws IOException if there is an I/O error while closing the request channel.
*/
@Override
public void close() throws IOException;
/**
* Gets the {@link RestRequestMetricsTracker} instance attached to this RestRequest.
* @return the {@link RestRequestMetricsTracker} instance attached to this RestRequest.
*/
public RestRequestMetricsTracker getMetricsTracker();
/**
* Set the digest algorithm to use on the data that is being streamed from the request. Once the data is emptied,
* the digest can be obtained via {@link #getDigest()}.
* <p/>
* This function is ideally called before {@link #readInto(AsyncWritableChannel, Callback)}. After a call to
* {@link #readInto(AsyncWritableChannel, Callback)}, some content may have been consumed and getting a digest may no
* longer be possible. The safety of doing otherwise depends on the implementation.
* @param digestAlgorithm the digest algorithm to use.
* @throws NoSuchAlgorithmException if the {@code digestAlgorithm} does not exist or is not supported.
* @throws IllegalStateException if {@link #readInto(AsyncWritableChannel, Callback)} has already been called.
*/
public void setDigestAlgorithm(String digestAlgorithm) throws NoSuchAlgorithmException;
/**
* Gets the digest as specified by the digest algorithm set through {@link #setDigestAlgorithm(String)}. If none was
* set, returns {@code null}.
* <p/>
* This function is ideally called after the data is emptied completely. Otherwise, the complete digest may not
* have been calculated yet. The safety of doing otherwise depends on the implementation.
* <p/>
* "Emptying the data" refers to awaiting on the future or getting the callback after a
* {@link #readInto(AsyncWritableChannel, Callback)} call.
* @return the digest as computed by the digest algorithm set through {@link #setDigestAlgorithm(String)}. If none
* was set, {@code null}.
* @throws IllegalStateException if called before the data has been emptied.
*/
public byte[] getDigest();
}