
org.glassfish.grizzly.http2.EncoderUtils Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2014, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package org.glassfish.grizzly.http2;
import static org.glassfish.grizzly.http.util.DataChunk.Type.Buffer;
import static org.glassfish.grizzly.http.util.DataChunk.Type.Bytes;
import java.io.IOException;
import java.util.Map;
import org.glassfish.grizzly.Buffer;
import org.glassfish.grizzly.http.HttpRequestPacket;
import org.glassfish.grizzly.http.HttpResponsePacket;
import org.glassfish.grizzly.http.util.Ascii;
import org.glassfish.grizzly.http.util.BufferChunk;
import org.glassfish.grizzly.http.util.ByteChunk;
import org.glassfish.grizzly.http.util.DataChunk;
import org.glassfish.grizzly.http.util.Header;
import org.glassfish.grizzly.http.util.MimeHeaders;
import org.glassfish.grizzly.memory.Buffers;
import org.glassfish.grizzly.ssl.SSLUtils;
import org.glassfish.grizzly.utils.Charsets;
/**
* HTTP Packet -> HTTP/2 frames encoder utils.
*
* @author Grizzly team
*/
class EncoderUtils extends EncoderDecoderUtilsBase {
private static final String HTTP = "http";
private static final String HTTPS = "https";
@SuppressWarnings("unchecked")
static Buffer encodeResponseHeaders(final Http2Session http2Session, final HttpResponsePacket response, final Map capture)
throws IOException {
assert http2Session.getDeflaterLock().isLocked();
final MimeHeaders headers = response.getHeaders();
headers.removeHeader(Header.Connection);
headers.removeHeader(Header.KeepAlive);
headers.removeHeader(Header.ProxyConnection);
headers.removeHeader(Header.TransferEncoding);
headers.removeHeader(Header.Upgrade);
final HeadersEncoder encoder = http2Session.getHeadersEncoder();
// encoder.encodeHeader(Constants.STATUS_HEADER_BYTES,
// response.getHttpStatus().getStatusBytes(), false);
encoder.encodeHeader(STATUS_HEADER, String.valueOf(response.getHttpStatus().getStatusCode()), capture);
encodeUserHeaders(headers, encoder, capture);
return encoder.flushHeaders();
}
@SuppressWarnings("unchecked")
static Buffer encodeRequestHeaders(final Http2Session http2Session, final HttpRequestPacket request, final Map capture) throws IOException {
assert http2Session.getDeflaterLock().isLocked();
// ----------------- Parse URI scheme and path ----------------
// int schemeStart = -1;
// int schemeLen = -1;
//
// final byte[] requestURI =
// request.getRequestURI().getBytes(DEFAULT_HTTP_CHARACTER_ENCODING);
// final int len = requestURI.length;
//
// final int nonSpaceIdx = skipSpaces(requestURI, 0, len, len);
// final int idx = ByteChunk.indexOf(requestURI, nonSpaceIdx, len, '/');
//
// if (idx > 0 && idx < len - 1 &&
// requestURI[idx - 1] == ':' && requestURI[idx + 1] == '/') {
// schemeStart = nonSpaceIdx;
// schemeLen = idx - schemeStart - 1;
// }
//
//
// final int pathStart = schemeStart == -1 ?
// idx :
// ByteChunk.indexOf(requestURI, idx + 2, len, '/');
// final int pathLen = len - pathStart;
//
// if (pathStart == -1) {
// throw new IllegalStateException("Request URI path is not set");
// }
int schemeStart = -1;
int schemeLen = -1;
final String requestURI = request.getRequestURI().trim();
final int len = requestURI.length();
final int idx = requestURI.indexOf('/');
if (idx > 0 && idx < len - 1 && requestURI.charAt(idx - 1) == ':' && requestURI.charAt(idx + 1) == '/') {
schemeStart = 0;
schemeLen = idx - 1;
}
final int pathStart = schemeStart == -1 ? idx : requestURI.indexOf('/', idx + 2);
final int pathLen = len - pathStart;
if (pathStart == -1) {
throw new IllegalStateException("Request URI path is not set");
}
// ---------------------------------------------------------------
final MimeHeaders headers = request.getHeaders();
String hostHeader = headers.getHeader(Header.Host);
if (hostHeader == null) {
if (schemeStart == -1) {
throw new IllegalStateException("Missing the Host header");
}
hostHeader = requestURI.substring(schemeStart + schemeLen + 3, pathStart);
}
headers.removeHeader(Header.Connection);
// headers.removeHeader(Header.Host);
headers.removeHeader(Header.KeepAlive);
headers.removeHeader(Header.ProxyConnection);
headers.removeHeader(Header.TransferEncoding);
headers.removeHeader(Header.Upgrade);
final HeadersEncoder encoder = http2Session.getHeadersEncoder();
encoder.encodeHeader(METHOD_HEADER, request.getMethod().toString(), capture);
if (schemeLen > 0) {
encoder.encodeHeader(SCHEMA_HEADER, requestURI.substring(0, schemeLen), capture);
} else {
// guess
encoder.encodeHeader(SCHEMA_HEADER, SSLUtils.getSSLEngine(http2Session.getConnection()) == null ? HTTP : HTTPS, capture);
}
encoder.encodeHeader(AUTHORITY_HEADER, hostHeader, capture);
String path = pathLen == requestURI.length() ? requestURI : requestURI.substring(pathStart, pathStart + pathLen);
final DataChunk query = request.getQueryStringDC();
if (!query.isNull()) {
path += '?' + query.toString(Charsets.UTF8_CHARSET);
}
encoder.encodeHeader(PATH_HEADER, path, capture);
encodeUserHeaders(headers, encoder, capture);
return encoder.flushHeaders();
}
static Buffer encodeTrailerHeaders(final Http2Session http2Session, final MimeHeaders trailers, final Map capture) {
assert http2Session.getDeflaterLock().isLocked();
if (trailers == null || trailers.size() == 0) {
return Buffers.EMPTY_BUFFER;
}
final HeadersEncoder encoder = http2Session.getHeadersEncoder();
for (final String name : trailers.names()) {
encoder.encodeHeader(name, trailers.getHeader(name), capture);
}
return encoder.flushHeaders();
}
@SuppressWarnings("unchecked")
private static void encodeUserHeaders(final MimeHeaders headers, final HeadersEncoder encoder, final Map capture) throws IOException {
final int mimeHeadersCount = headers.size();
for (int i = 0; i < mimeHeadersCount; i++) {
if (!headers.setSerialized(i, true)) {
final String nameStr = nameToLowerCase(headers.getName(i));
final DataChunk value = headers.getValue(i);
if (!value.isNull()) {
encoder.encodeHeader(nameStr, value.toString(), capture);
}
}
}
}
@SuppressWarnings("unused")
private static byte[] nameToLowerCaseByteArray(final DataChunk name) {
final int length = name.getLength();
final byte[] lowercase = new byte[length];
if (name.getType() == Bytes) {
final ByteChunk byteChunk = name.getByteChunk();
final byte[] bytes = byteChunk.getBuffer();
final int offs = byteChunk.getStart();
for (int i = 0; i < length; i++) {
lowercase[i] = (byte) Ascii.toLower(bytes[i + offs]);
}
} else if (name.getType() == Buffer) {
final BufferChunk bufferChunk = name.getBufferChunk();
final Buffer buffer = bufferChunk.getBuffer();
final int offs = bufferChunk.getStart();
for (int i = 0; i < length; i++) {
lowercase[i] = (byte) Ascii.toLower(buffer.get(i + offs));
}
} else {
final String s = name.toString();
for (int i = 0; i < length; i++) {
lowercase[i] = (byte) Ascii.toLower(s.charAt(i));
}
}
return lowercase;
}
private static String nameToLowerCase(final DataChunk name) {
final int length = name.getLength();
final StringBuilder sb = new StringBuilder(length);
if (name.getType() == Bytes) {
final ByteChunk byteChunk = name.getByteChunk();
final byte[] bytes = byteChunk.getBuffer();
final int offs = byteChunk.getStart();
for (int i = 0; i < length; i++) {
sb.append((char) Ascii.toLower(bytes[i + offs]));
}
} else if (name.getType() == Buffer) {
final BufferChunk bufferChunk = name.getBufferChunk();
final Buffer buffer = bufferChunk.getBuffer();
final int offs = bufferChunk.getStart();
for (int i = 0; i < length; i++) {
sb.append((char) Ascii.toLower(buffer.get(i + offs)));
}
} else {
final String s = name.toString();
for (int i = 0; i < length; i++) {
sb.append((char) Ascii.toLower(s.charAt(i)));
}
}
return sb.toString();
}
@SuppressWarnings("unused")
private static int valueToByteArray(final DataChunk value, final byte[] dstArray, int arrayOffs) {
final int length = value.getLength();
if (value.getType() == Bytes) {
final ByteChunk byteChunk = value.getByteChunk();
final byte[] bytes = byteChunk.getBuffer();
final int offs = byteChunk.getStart();
System.arraycopy(bytes, offs, dstArray, arrayOffs, length);
} else if (value.getType() == Buffer) {
final BufferChunk bufferChunk = value.getBufferChunk();
final Buffer buffer = bufferChunk.getBuffer();
final int offs = bufferChunk.getStart();
final int oldPos = buffer.position();
final int oldLim = buffer.limit();
Buffers.setPositionLimit(buffer, offs, offs + length);
buffer.get(dstArray, arrayOffs, length);
Buffers.setPositionLimit(buffer, oldPos, oldLim);
} else {
final String s = value.toString();
for (int i = 0; i < length; i++) {
dstArray[arrayOffs + i] = (byte) s.charAt(i);
}
}
return length;
}
@SuppressWarnings("unused")
private static byte[] valueToByteArray(final DataChunk value) {
final int length = value.getLength();
if (value.getType() == Bytes) {
final ByteChunk byteChunk = value.getByteChunk();
final byte[] bytes = byteChunk.getBuffer();
final int offs = byteChunk.getStart();
if (bytes.length == length) {
return bytes;
}
final byte[] dstArray = new byte[length];
System.arraycopy(bytes, offs, dstArray, 0, length);
return dstArray;
} else if (value.getType() == Buffer) {
final BufferChunk bufferChunk = value.getBufferChunk();
final Buffer buffer = bufferChunk.getBuffer();
if (buffer.hasArray() && buffer.array().length == length) {
return buffer.array();
}
final byte[] dstArray = new byte[length];
final int offs = bufferChunk.getStart();
final int oldPos = buffer.position();
final int oldLim = buffer.limit();
Buffers.setPositionLimit(buffer, offs, offs + length);
buffer.get(dstArray);
Buffers.setPositionLimit(buffer, oldPos, oldLim);
return dstArray;
} else {
final byte[] dstArray = new byte[length];
final String s = value.toString();
for (int i = 0; i < length; i++) {
dstArray[i] = (byte) s.charAt(i);
}
return dstArray;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy