Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.arangodb.shaded.vertx.core.http.impl.HttpUtils Maven / Gradle / Ivy
/*
* Copyright (c) 2011-2019 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*/
package com.arangodb.shaded.vertx.core.http.impl;
import com.arangodb.shaded.netty.buffer.ByteBuf;
import com.arangodb.shaded.netty.buffer.Unpooled;
import com.arangodb.shaded.netty.channel.Channel;
import com.arangodb.shaded.netty.handler.codec.http.*;
import com.arangodb.shaded.netty.handler.codec.http2.Http2Settings;
import com.arangodb.shaded.netty.util.AsciiString;
import com.arangodb.shaded.netty.util.CharsetUtil;
import com.arangodb.shaded.vertx.core.AsyncResult;
import com.arangodb.shaded.vertx.core.Future;
import com.arangodb.shaded.vertx.core.Handler;
import com.arangodb.shaded.vertx.core.MultiMap;
import com.arangodb.shaded.vertx.core.buffer.Buffer;
import com.arangodb.shaded.vertx.core.file.AsyncFile;
import com.arangodb.shaded.vertx.core.file.FileSystem;
import com.arangodb.shaded.vertx.core.file.OpenOptions;
import com.arangodb.shaded.vertx.core.http.HttpClosedException;
import com.arangodb.shaded.vertx.core.http.HttpServerRequest;
import com.arangodb.shaded.vertx.core.http.HttpServerResponse;
import com.arangodb.shaded.vertx.core.http.StreamPriority;
import com.arangodb.shaded.vertx.core.impl.VertxInternal;
import com.arangodb.shaded.vertx.core.spi.tracing.TagExtractor;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import static com.arangodb.shaded.netty.handler.codec.http.HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED;
import static com.arangodb.shaded.netty.handler.codec.http.HttpHeaderValues.MULTIPART_FORM_DATA;
import static com.arangodb.shaded.netty.handler.codec.http.HttpResponseStatus.METHOD_NOT_ALLOWED;
import static com.arangodb.shaded.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import static com.arangodb.shaded.vertx.core.http.Http2Settings.*;
/**
* Various http utils.
*
* @author Norman Maurer
*/
public final class HttpUtils {
static final HttpClosedException CONNECTION_CLOSED_EXCEPTION = new HttpClosedException("Connection was closed");
static final HttpClosedException STREAM_CLOSED_EXCEPTION = new HttpClosedException("Stream was closed");
static final int SC_SWITCHING_PROTOCOLS = 101;
static final int SC_BAD_GATEWAY = 502;
static final TagExtractor SERVER_REQUEST_TAG_EXTRACTOR = new TagExtractor() {
@Override
public int len(HttpServerRequest req) {
return 2;
}
@Override
public String name(HttpServerRequest req, int index) {
switch (index) {
case 0:
return "http.url";
case 1:
return "http.method";
}
throw new IndexOutOfBoundsException("Invalid tag index " + index);
}
@Override
public String value(HttpServerRequest req, int index) {
switch (index) {
case 0:
return req.absoluteURI();
case 1:
return req.method().name();
}
throw new IndexOutOfBoundsException("Invalid tag index " + index);
}
};
static final TagExtractor SERVER_RESPONSE_TAG_EXTRACTOR = new TagExtractor() {
@Override
public int len(HttpServerResponse resp) {
return 1;
}
@Override
public String name(HttpServerResponse resp, int index) {
if (index == 0) {
return "http.status_code";
}
throw new IndexOutOfBoundsException("Invalid tag index " + index);
}
@Override
public String value(HttpServerResponse resp, int index) {
if (index == 0) {
return "" + resp.getStatusCode();
}
throw new IndexOutOfBoundsException("Invalid tag index " + index);
}
};
static final TagExtractor CLIENT_HTTP_REQUEST_TAG_EXTRACTOR = new TagExtractor() {
@Override
public int len(HttpRequestHead req) {
return 2;
}
@Override
public String name(HttpRequestHead req, int index) {
switch (index) {
case 0:
return "http.url";
case 1:
return "http.method";
}
throw new IndexOutOfBoundsException("Invalid tag index " + index);
}
@Override
public String value(HttpRequestHead req, int index) {
switch (index) {
case 0:
return req.absoluteURI;
case 1:
return req.method.name();
}
throw new IndexOutOfBoundsException("Invalid tag index " + index);
}
};
static final TagExtractor CLIENT_RESPONSE_TAG_EXTRACTOR = new TagExtractor() {
@Override
public int len(HttpResponseHead resp) {
return 1;
}
@Override
public String name(HttpResponseHead resp, int index) {
if (index == 0) {
return "http.status_code";
}
throw new IndexOutOfBoundsException("Invalid tag index " + index);
}
@Override
public String value(HttpResponseHead resp, int index) {
if (index == 0) {
return "" + resp.statusCode;
}
throw new IndexOutOfBoundsException("Invalid tag index " + index);
}
};
static final StreamPriority DEFAULT_STREAM_PRIORITY = new StreamPriority() {
@Override
public StreamPriority setWeight(short weight) {
throw new UnsupportedOperationException("Unmodifiable stream priority");
}
@Override
public StreamPriority setDependency(int dependency) {
throw new UnsupportedOperationException("Unmodifiable stream priority");
}
@Override
public StreamPriority setExclusive(boolean exclusive) {
throw new UnsupportedOperationException("Unmodifiable stream priority");
}
};
private HttpUtils() {
}
private static int indexOfSlash(CharSequence str, int start) {
for (int i = start; i < str.length(); i++) {
if (str.charAt(i) == '/') {
return i;
}
}
return -1;
}
private static boolean matches(CharSequence path, int start, String what) {
return matches(path, start, what, false);
}
private static boolean matches(CharSequence path, int start, String what, boolean exact) {
if (exact) {
if (path.length() - start != what.length()) {
return false;
}
}
if (path.length() - start >= what.length()) {
for (int i = 0; i < what.length(); i++) {
if (path.charAt(start + i) != what.charAt(i)) {
return false;
}
}
return true;
}
return false;
}
/**
* Normalizes a path as per = 0x41 && unescaped <= 0x5A) ||
(unescaped >= 0x61 && unescaped <= 0x7A) ||
// DIGIT
(unescaped >= 0x30 && unescaped <= 0x39) ||
// HYPHEN
(unescaped == 0x2D) ||
// PERIOD
(unescaped == 0x2E) ||
// UNDERSCORE
(unescaped == 0x5F) ||
// TILDE
(unescaped == 0x7E)) {
path.setCharAt(start, (char) unescaped);
path.delete(start + 1, start + 3);
}
} else {
throw new IllegalArgumentException("Invalid position for escape character: " + start);
}
}
/**
* Removed dots as per /
if (obuf.length() == 0 || obuf.charAt(obuf.length() - 1) != '/') {
obuf.append('/');
}
}
int pos = indexOfSlash(path, i);
if (pos != -1) {
obuf.append(path, i, pos);
i = pos;
} else {
obuf.append(path, i, path.length());
break;
}
}
}
return obuf.toString();
}
/**
* Resolve an URI reference as per rfc3986
*/
public static URI resolveURIReference(URI base, String ref) throws URISyntaxException {
URI _ref = URI.create(ref);
String scheme;
String authority;
String path;
String query;
if (_ref.getScheme() != null) {
scheme = _ref.getScheme();
authority = _ref.getAuthority();
path = removeDots(_ref.getRawPath());
query = _ref.getRawQuery();
} else {
if (_ref.getAuthority() != null) {
authority = _ref.getAuthority();
path = _ref.getRawPath();
query = _ref.getRawQuery();
} else {
if (_ref.getRawPath().length() == 0) {
path = base.getRawPath();
if (_ref.getRawQuery() != null) {
query = _ref.getRawQuery();
} else {
query = base.getRawQuery();
}
} else {
if (_ref.getRawPath().startsWith("/")) {
path = removeDots(_ref.getRawPath());
} else {
// Merge paths
String mergedPath;
String basePath = base.getRawPath();
if (base.getAuthority() != null && basePath.length() == 0) {
mergedPath = "/" + _ref.getRawPath();
} else {
int index = basePath.lastIndexOf('/');
if (index > -1) {
mergedPath = basePath.substring(0, index + 1) + _ref.getRawPath();
} else {
mergedPath = _ref.getRawPath();
}
}
path = removeDots(mergedPath);
}
query = _ref.getRawQuery();
}
authority = base.getAuthority();
}
scheme = base.getScheme();
}
return new URI(scheme, authority, path, query, _ref.getFragment());
}
/**
* Extract the path out of the uri.
*/
static String parsePath(String uri) {
if (uri.length() == 0) {
return "";
}
int i;
if (uri.charAt(0) == '/') {
i = 0;
} else {
i = uri.indexOf("://");
if (i == -1) {
i = 0;
} else {
i = uri.indexOf('/', i + 3);
if (i == -1) {
// contains no /
return "/";
}
}
}
int queryStart = uri.indexOf('?', i);
if (queryStart == -1) {
queryStart = uri.length();
if (i == 0) {
return uri;
}
}
return uri.substring(i, queryStart);
}
/**
* Extract the query out of a uri or returns the empty string if no query was found.
*/
static String parseQuery(String uri) {
int i = uri.indexOf('?');
if (i == -1) {
return null;
} else {
return uri.substring(i + 1);
}
}
static String absoluteURI(String serverOrigin, HttpServerRequest req) throws URISyntaxException {
String absoluteURI;
URI uri = new URI(req.uri());
String scheme = uri.getScheme();
if (scheme != null && (scheme.equals("http") || scheme.equals("https"))) {
absoluteURI = uri.toString();
} else {
String host = req.host();
if (host != null) {
absoluteURI = req.scheme() + "://" + host + uri;
} else {
// Fall back to the server origin
absoluteURI = serverOrigin + uri;
}
}
return absoluteURI;
}
static MultiMap params(String uri, Charset charset) {
QueryStringDecoder queryStringDecoder = new QueryStringDecoder(uri, charset);
Map> prms = queryStringDecoder.parameters();
MultiMap params = MultiMap.caseInsensitiveMultiMap();
if (!prms.isEmpty()) {
for (Map.Entry> entry: prms.entrySet()) {
params.add(entry.getKey(), entry.getValue());
}
}
return params;
}
public static void fromVertxInitialSettings(boolean server, io.vertx.core.http.Http2Settings vertxSettings, Http2Settings nettySettings) {
if (vertxSettings != null) {
if (!server && vertxSettings.isPushEnabled() != DEFAULT_ENABLE_PUSH) {
nettySettings.pushEnabled(vertxSettings.isPushEnabled());
}
if (vertxSettings.getHeaderTableSize() != DEFAULT_HEADER_TABLE_SIZE) {
nettySettings.put('\u0001', (Long)vertxSettings.getHeaderTableSize());
}
if (vertxSettings.getInitialWindowSize() != DEFAULT_INITIAL_WINDOW_SIZE) {
nettySettings.initialWindowSize(vertxSettings.getInitialWindowSize());
}
if (vertxSettings.getMaxConcurrentStreams() != DEFAULT_MAX_CONCURRENT_STREAMS) {
nettySettings.maxConcurrentStreams(vertxSettings.getMaxConcurrentStreams());
}
if (vertxSettings.getMaxFrameSize() != DEFAULT_MAX_FRAME_SIZE) {
nettySettings.maxFrameSize(vertxSettings.getMaxFrameSize());
}
if (vertxSettings.getMaxHeaderListSize() != DEFAULT_MAX_HEADER_LIST_SIZE) {
nettySettings.maxHeaderListSize(vertxSettings.getMaxHeaderListSize());
}
Map extraSettings = vertxSettings.getExtraSettings();
if (extraSettings != null) {
extraSettings.forEach((code, setting) -> {
nettySettings.put((char)(int)code, setting);
});
}
}
}
public static Http2Settings fromVertxSettings(com.arangodb.shaded.vertx.core.http.Http2Settings settings) {
Http2Settings converted = new Http2Settings();
converted.pushEnabled(settings.isPushEnabled());
converted.maxFrameSize(settings.getMaxFrameSize());
converted.initialWindowSize(settings.getInitialWindowSize());
converted.headerTableSize(settings.getHeaderTableSize());
converted.maxConcurrentStreams(settings.getMaxConcurrentStreams());
converted.maxHeaderListSize(settings.getMaxHeaderListSize());
if (settings.getExtraSettings() != null) {
settings.getExtraSettings().forEach((key, value) -> {
converted.put((char)(int)key, value);
});
}
return converted;
}
public static com.arangodb.shaded.vertx.core.http.Http2Settings toVertxSettings(Http2Settings settings) {
io.vertx.core.http.Http2Settings converted = new io.vertx.core.http.Http2Settings();
Boolean pushEnabled = settings.pushEnabled();
if (pushEnabled != null) {
converted.setPushEnabled(pushEnabled);
}
Long maxConcurrentStreams = settings.maxConcurrentStreams();
if (maxConcurrentStreams != null) {
converted.setMaxConcurrentStreams(maxConcurrentStreams);
}
Long maxHeaderListSize = settings.maxHeaderListSize();
if (maxHeaderListSize != null) {
converted.setMaxHeaderListSize(maxHeaderListSize);
}
Integer maxFrameSize = settings.maxFrameSize();
if (maxFrameSize != null) {
converted.setMaxFrameSize(maxFrameSize);
}
Integer initialWindowSize = settings.initialWindowSize();
if (initialWindowSize != null) {
converted.setInitialWindowSize(initialWindowSize);
}
Long headerTableSize = settings.headerTableSize();
if (headerTableSize != null) {
converted.setHeaderTableSize(headerTableSize);
}
settings.forEach((key, value) -> {
if (key > 6) {
converted.set(key, value);
}
});
return converted;
}
static Http2Settings decodeSettings(String base64Settings) {
try {
Http2Settings settings = new Http2Settings();
Buffer buffer = Buffer.buffer(Base64.getUrlDecoder().decode(base64Settings));
int pos = 0;
int len = buffer.length();
while (pos < len) {
int i = buffer.getUnsignedShort(pos);
pos += 2;
long j = buffer.getUnsignedInt(pos);
pos += 4;
settings.put((char)i, (Long)j);
}
return settings;
} catch (Exception ignore) {
}
return null;
}
public static String encodeSettings(com.arangodb.shaded.vertx.core.http.Http2Settings settings) {
Buffer buffer = Buffer.buffer();
fromVertxSettings(settings).forEach((c, l) -> {
buffer.appendUnsignedShort(c);
buffer.appendUnsignedInt(l);
});
return Base64.getUrlEncoder().encodeToString(buffer.getBytes());
}
public static ByteBuf generateWSCloseFrameByteBuf(short statusCode, String reason) {
if (reason != null)
return Unpooled.copiedBuffer(
Unpooled.copyShort(statusCode), // First two bytes are reserved for status code
Unpooled.copiedBuffer(reason, StandardCharsets.UTF_8)
);
else
return Unpooled.copyShort(statusCode);
}
static void sendError(Channel ch, HttpResponseStatus status) {
sendError(ch, status, status.reasonPhrase());
}
static void sendError(Channel ch, HttpResponseStatus status, CharSequence err) {
FullHttpResponse resp = new DefaultFullHttpResponse(HTTP_1_1, status);
if (status.code() == METHOD_NOT_ALLOWED.code()) {
// SockJS requires this
resp.headers().set(com.arangodb.shaded.vertx.core.http.HttpHeaders.ALLOW, io.vertx.core.http.HttpHeaders.GET);
}
if (err != null) {
resp.content().writeBytes(err.toString().getBytes(CharsetUtil.UTF_8));
HttpUtil.setContentLength(resp, err.length());
} else {
HttpUtil.setContentLength(resp, 0);
}
ch.writeAndFlush(resp);
}
static String getWebSocketLocation(HttpServerRequest req, boolean ssl) throws Exception {
String prefix;
if (ssl) {
prefix = "wss://";
} else {
prefix = "ws://";
}
URI uri = new URI(req.uri());
String path = uri.getRawPath();
String loc = prefix + req.headers().get(HttpHeaderNames.HOST) + path;
String query = uri.getRawQuery();
if (query != null) {
loc += "?" + query;
}
return loc;
}
/**
* @return convert the {@code sequence} to a lower case instance
*/
public static CharSequence toLowerCase(CharSequence sequence) {
StringBuilder buffer = null;
int len = sequence.length();
for (int index = 0; index < len; index++) {
char c = sequence.charAt(index);
if (c >= 'A' && c <= 'Z') {
if (buffer == null) {
buffer = new StringBuilder(sequence);
}
buffer.setCharAt(index, (char)(c + ('a' - 'A')));
}
}
if (buffer != null) {
return buffer.toString();
} else {
return sequence;
}
}
static HttpVersion toNettyHttpVersion(com.arangodb.shaded.vertx.core.http.HttpVersion version) {
switch (version) {
case HTTP_1_0: {
return HttpVersion.HTTP_1_0;
}
case HTTP_1_1: {
return HttpVersion.HTTP_1_1;
}
default:
throw new IllegalArgumentException("Unsupported HTTP version: " + version);
}
}
static com.arangodb.shaded.vertx.core.http.HttpMethod toVertxMethod(String method) {
return io.vertx.core.http.HttpMethod.valueOf(method);
}
private static final AsciiString TIMEOUT_EQ = AsciiString.of("timeout=");
public static int parseKeepAliveHeaderTimeout(CharSequence value) {
int len = value.length();
int pos = 0;
while (pos < len) {
int idx = AsciiString.indexOf(value, ',', pos);
int next;
if (idx == -1) {
idx = next = len;
} else {
next = idx + 1;
}
while (pos < idx && value.charAt(pos) == ' ') {
pos++;
}
int to = idx;
while (to > pos && value.charAt(to -1) == ' ') {
to--;
}
if (AsciiString.regionMatches(value, true, pos, TIMEOUT_EQ, 0, TIMEOUT_EQ.length())) {
pos += TIMEOUT_EQ.length();
if (pos < to) {
int ret = 0;
while (pos < to) {
int ch = value.charAt(pos++);
if (ch >= '0' && ch < '9') {
ret = ret * 10 + (ch - '0');
} else {
ret = -1;
break;
}
}
if (ret > -1) {
return ret;
}
}
}
pos = next;
}
return -1;
}
private static final Consumer HEADER_VALUE_VALIDATOR = HttpUtils::validateHeaderValue;
public static void validateHeader(CharSequence name, CharSequence value) {
validateHeaderName(name);
if (value != null) {
validateHeaderValue(value);
}
}
public static void validateHeader(CharSequence name, Iterable values) {
validateHeaderName(name);
values.forEach(value -> {
if (value != null) {
HEADER_VALUE_VALIDATOR.accept(value);
}
});
}
public static void validateHeaderValue(CharSequence seq) {
int state = 0;
// Start looping through each of the character
for (int index = 0; index < seq.length(); index++) {
state = validateValueChar(seq, state, seq.charAt(index));
}
if (state != 0) {
throw new IllegalArgumentException("a header value must not end with '\\r' or '\\n':" + seq);
}
}
private static final int HIGHEST_INVALID_VALUE_CHAR_MASK = ~0x1F;
private static int validateValueChar(CharSequence seq, int state, char character) {
/*
* State:
* 0: Previous character was neither CR nor LF
* 1: The previous character was CR
* 2: The previous character was LF
*/
if ((character & HIGHEST_INVALID_VALUE_CHAR_MASK) == 0 || character == 0x7F) { // 0x7F is "DEL".
// The only characters allowed in the range 0x00-0x1F are : HTAB, LF and CR
switch (character) {
case 0x09: // Horizontal tab - HTAB
case 0x0a: // Line feed - LF
case 0x0d: // Carriage return - CR
break;
default:
throw new IllegalArgumentException("a header value contains a prohibited character '" + (int) character + "': " + seq);
}
}
// Check the CRLF (HT | SP) pattern
switch (state) {
case 0:
switch (character) {
case '\r':
return 1;
case '\n':
return 2;
}
break;
case 1:
switch (character) {
case '\n':
return 2;
default:
throw new IllegalArgumentException("only '\\n' is allowed after '\\r': " + seq);
}
case 2:
switch (character) {
case '\t':
case ' ':
return 0;
default:
throw new IllegalArgumentException("only ' ' and '\\t' are allowed after '\\n': " + seq);
}
}
return state;
}
private static final boolean[] VALID_H_NAME_ASCII_CHARS;
static {
VALID_H_NAME_ASCII_CHARS = new boolean[Byte.MAX_VALUE + 1];
Arrays.fill(VALID_H_NAME_ASCII_CHARS, true);
VALID_H_NAME_ASCII_CHARS[' '] = false;
VALID_H_NAME_ASCII_CHARS['"'] = false;
VALID_H_NAME_ASCII_CHARS['('] = false;
VALID_H_NAME_ASCII_CHARS[')'] = false;
VALID_H_NAME_ASCII_CHARS[','] = false;
VALID_H_NAME_ASCII_CHARS['/'] = false;
VALID_H_NAME_ASCII_CHARS[':'] = false;
VALID_H_NAME_ASCII_CHARS[';'] = false;
VALID_H_NAME_ASCII_CHARS['<'] = false;
VALID_H_NAME_ASCII_CHARS['>'] = false;
VALID_H_NAME_ASCII_CHARS['='] = false;
VALID_H_NAME_ASCII_CHARS['?'] = false;
VALID_H_NAME_ASCII_CHARS['@'] = false;
VALID_H_NAME_ASCII_CHARS['['] = false;
VALID_H_NAME_ASCII_CHARS[']'] = false;
VALID_H_NAME_ASCII_CHARS['\\'] = false;
VALID_H_NAME_ASCII_CHARS['{'] = false;
VALID_H_NAME_ASCII_CHARS['}'] = false;
VALID_H_NAME_ASCII_CHARS[0x7f] = false;
// control characters are not valid
for (int i = 0; i < 0x20; i++) {
VALID_H_NAME_ASCII_CHARS[i] = false;
}
}
public static void validateHeaderName(CharSequence value) {
if (value instanceof AsciiString) {
// no need to check for ASCII-ness anymore
validateHeaderName((AsciiString) value);
} else {
validateHeaderName0(value);
}
}
private static void validateHeaderName(AsciiString value) {
final int len = value.length();
final int off = value.arrayOffset();
final byte[] asciiChars = value.array();
for (int i = 0; i < len; i++) {
// Check to see if the character is not an ASCII character, or invalid
byte c = asciiChars[off + i];
if (c < 0) {
throw new IllegalArgumentException("a header name cannot contain non-ASCII character: " + value);
}
if (!VALID_H_NAME_ASCII_CHARS[c & 0x7F]) {
throw new IllegalArgumentException("a header name cannot contain some prohibited characters, such as : " + value);
}
}
}
private static void validateHeaderName0(CharSequence value) {
for (int i = 0; i < value.length(); i++) {
final char c = value.charAt(i);
// Check to see if the character is not an ASCII character, or invalid
if (c > 0x7f) {
throw new IllegalArgumentException("a header name cannot contain non-ASCII character: " + value);
}
if (!VALID_H_NAME_ASCII_CHARS[c & 0x7F]) {
throw new IllegalArgumentException("a header name cannot contain some prohibited characters, such as : " + value);
}
}
}
public static boolean isValidMultipartContentType(String contentType) {
return MULTIPART_FORM_DATA.regionMatches(true, 0, contentType, 0, MULTIPART_FORM_DATA.length())
|| APPLICATION_X_WWW_FORM_URLENCODED.regionMatches(true, 0, contentType, 0, APPLICATION_X_WWW_FORM_URLENCODED.length());
}
public static boolean isValidMultipartMethod(HttpMethod method) {
return method.equals(HttpMethod.POST) || method.equals(HttpMethod.PUT) || method.equals(HttpMethod.PATCH)
|| method.equals(HttpMethod.DELETE);
}
static void resolveFile(VertxInternal vertx, String filename, long offset, long length, Handler> resultHandler) {
File file_ = vertx.resolveFile(filename);
if (!file_.exists()) {
resultHandler.handle(Future.failedFuture(new FileNotFoundException()));
return;
}
//We open the fileName using a RandomAccessFile to make sure that this is an actual file that can be read.
//i.e is not a directory
try(RandomAccessFile raf = new RandomAccessFile(file_, "r")) {
FileSystem fs = vertx.fileSystem();
fs.open(filename, new OpenOptions().setCreate(false).setWrite(false), ar -> {
if (ar.succeeded()) {
AsyncFile file = ar.result();
long contentLength = Math.min(length, file_.length() - offset);
file.setReadPos(offset);
file.setReadLength(contentLength);
}
resultHandler.handle(ar);
});
} catch (IOException e) {
resultHandler.handle(Future.failedFuture(e));
}
}
static boolean isConnectOrUpgrade(com.arangodb.shaded.vertx.core.http.HttpMethod method, MultiMap headers) {
return method == io.vertx.core.http.HttpMethod.CONNECT || (method == io.vertx.core.http.HttpMethod.GET && headers.contains(com.arangodb.shaded.vertx.core.http.HttpHeaders.CONNECTION, io.vertx.core.http.HttpHeaders.UPGRADE, true));
}
}