blob: a7ed63fa856b5275d30a21695869c0125b703df2 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.sidecar.models;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.vertx.core.Future;
import io.vertx.core.http.HttpHeaders;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.net.SocketAddress;
import static java.util.concurrent.TimeUnit.MICROSECONDS;
import static org.apache.cassandra.sidecar.utils.RequestUtils.extractHostAddressWithoutPort;
/**
* Wrapper around HttpServerResponse
*/
public class HttpResponse
{
private final String host;
private final HttpServerRequest request;
private final HttpServerResponse response;
public HttpResponse(HttpServerRequest request, HttpServerResponse response)
{
this.request = request;
this.response = response;
this.host = extractHostAddressWithoutPort(request.host());
}
public void setRetryAfterHeader(long microsToWait)
{
response.setStatusCode(HttpResponseStatus.TOO_MANY_REQUESTS.code());
response.putHeader(HttpHeaderNames.RETRY_AFTER, Long.toString(MICROSECONDS.toSeconds(microsToWait))).end();
}
public void setTooManyRequestsStatus()
{
response.setStatusCode(HttpResponseStatus.TOO_MANY_REQUESTS.code()).end();
}
public void setRangeNotSatisfiable(String msg)
{
response.setStatusCode(HttpResponseStatus.REQUESTED_RANGE_NOT_SATISFIABLE.code()).setStatusMessage(msg).end();
}
public void setPartialContentStatus(Range range)
{
response.setStatusCode(HttpResponseStatus.PARTIAL_CONTENT.code())
.putHeader(HttpHeaderNames.CONTENT_RANGE, contentRangeHeader(range));
}
private String contentRangeHeader(Range r)
{
return "bytes " + r.start() + "-" + r.end() + "/" + r.length();
}
public void setBadRequestStatus(String msg)
{
response.setStatusCode(HttpResponseStatus.BAD_REQUEST.code()).setStatusMessage(msg).end();
}
public void setNotFoundStatus(String msg)
{
response.setStatusCode(HttpResponseStatus.NOT_FOUND.code()).setStatusMessage(msg).end();
}
public void setInternalErrorStatus(String msg)
{
response.setStatusCode(HttpResponseStatus.INTERNAL_SERVER_ERROR.code()).setStatusMessage(msg).end();
}
/**
* Send a range in a file asynchronously
*
* @param fileName file to send
* @param fileLength the size of the file to send
* @param range range to send
* @return a future completed with the body result
*/
public Future<Void> sendFile(String fileName, long fileLength, Range range)
{
// notify client we support range requests
response.putHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
if (range.length() != fileLength)
{
setPartialContentStatus(range);
}
return response.putHeader(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_OCTET_STREAM)
.putHeader(HttpHeaderNames.CONTENT_LENGTH, Long.toString(range.length()))
.sendFile(fileName, range.start(), range.length());
}
/**
* @return the remote address for this connection, possibly {@code null} (e.g a server bound on a domain socket).
*/
public SocketAddress remoteAddress()
{
return request.remoteAddress();
}
/**
* @return the request host without the port
*/
public String host()
{
return host;
}
}