org.apache.hbase.thirdparty.io.netty.handler.codec.haproxy.HAProxyMessageEncoder Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2020 The Netty Project
*
* The Netty Project 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:
*
* https://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.hbase.thirdparty.io.netty.handler.codec.haproxy;
import org.apache.hbase.thirdparty.io.netty.buffer.ByteBuf;
import org.apache.hbase.thirdparty.io.netty.channel.ChannelHandler.Sharable;
import org.apache.hbase.thirdparty.io.netty.channel.ChannelHandlerContext;
import org.apache.hbase.thirdparty.io.netty.handler.codec.MessageToByteEncoder;
import org.apache.hbase.thirdparty.io.netty.util.CharsetUtil;
import org.apache.hbase.thirdparty.io.netty.util.NetUtil;
import java.util.List;
import static org.apache.hbase.thirdparty.io.netty.handler.codec.haproxy.HAProxyConstants.*;
/**
* Encodes an HAProxy proxy protocol message
*
* @see Proxy Protocol Specification
*/
@Sharable
public final class HAProxyMessageEncoder extends MessageToByteEncoder {
private static final int V2_VERSION_BITMASK = 0x02 << 4;
// Length for source/destination addresses for the UNIX family must be 108 bytes each.
static final int UNIX_ADDRESS_BYTES_LENGTH = 108;
static final int TOTAL_UNIX_ADDRESS_BYTES_LENGTH = UNIX_ADDRESS_BYTES_LENGTH * 2;
public static final HAProxyMessageEncoder INSTANCE = new HAProxyMessageEncoder();
private HAProxyMessageEncoder() {
}
@Override
protected void encode(ChannelHandlerContext ctx, HAProxyMessage msg, ByteBuf out) throws Exception {
switch (msg.protocolVersion()) {
case V1:
encodeV1(msg, out);
break;
case V2:
encodeV2(msg, out);
break;
default:
throw new HAProxyProtocolException("Unsupported version: " + msg.protocolVersion());
}
}
private static void encodeV1(HAProxyMessage msg, ByteBuf out) {
out.writeBytes(TEXT_PREFIX);
out.writeByte((byte) ' ');
out.writeCharSequence(msg.proxiedProtocol().name(), CharsetUtil.US_ASCII);
out.writeByte((byte) ' ');
out.writeCharSequence(msg.sourceAddress(), CharsetUtil.US_ASCII);
out.writeByte((byte) ' ');
out.writeCharSequence(msg.destinationAddress(), CharsetUtil.US_ASCII);
out.writeByte((byte) ' ');
out.writeCharSequence(String.valueOf(msg.sourcePort()), CharsetUtil.US_ASCII);
out.writeByte((byte) ' ');
out.writeCharSequence(String.valueOf(msg.destinationPort()), CharsetUtil.US_ASCII);
out.writeByte((byte) '\r');
out.writeByte((byte) '\n');
}
private static void encodeV2(HAProxyMessage msg, ByteBuf out) {
out.writeBytes(BINARY_PREFIX);
out.writeByte(V2_VERSION_BITMASK | msg.command().byteValue());
out.writeByte(msg.proxiedProtocol().byteValue());
switch (msg.proxiedProtocol().addressFamily()) {
case AF_IPv4:
case AF_IPv6:
byte[] srcAddrBytes = NetUtil.createByteArrayFromIpAddressString(msg.sourceAddress());
byte[] dstAddrBytes = NetUtil.createByteArrayFromIpAddressString(msg.destinationAddress());
// srcAddrLen + dstAddrLen + 4 (srcPort + dstPort) + numTlvBytes
out.writeShort(srcAddrBytes.length + dstAddrBytes.length + 4 + msg.tlvNumBytes());
out.writeBytes(srcAddrBytes);
out.writeBytes(dstAddrBytes);
out.writeShort(msg.sourcePort());
out.writeShort(msg.destinationPort());
encodeTlvs(msg.tlvs(), out);
break;
case AF_UNIX:
out.writeShort(TOTAL_UNIX_ADDRESS_BYTES_LENGTH + msg.tlvNumBytes());
int srcAddrBytesWritten = out.writeCharSequence(msg.sourceAddress(), CharsetUtil.US_ASCII);
out.writeZero(UNIX_ADDRESS_BYTES_LENGTH - srcAddrBytesWritten);
int dstAddrBytesWritten = out.writeCharSequence(msg.destinationAddress(), CharsetUtil.US_ASCII);
out.writeZero(UNIX_ADDRESS_BYTES_LENGTH - dstAddrBytesWritten);
encodeTlvs(msg.tlvs(), out);
break;
case AF_UNSPEC:
out.writeShort(0);
break;
default:
throw new HAProxyProtocolException("unexpected addrFamily");
}
}
private static void encodeTlv(HAProxyTLV haProxyTLV, ByteBuf out) {
if (haProxyTLV instanceof HAProxySSLTLV) {
HAProxySSLTLV ssltlv = (HAProxySSLTLV) haProxyTLV;
out.writeByte(haProxyTLV.typeByteValue());
out.writeShort(ssltlv.contentNumBytes());
out.writeByte(ssltlv.client());
out.writeInt(ssltlv.verify());
encodeTlvs(ssltlv.encapsulatedTLVs(), out);
} else {
out.writeByte(haProxyTLV.typeByteValue());
ByteBuf value = haProxyTLV.content();
int readableBytes = value.readableBytes();
out.writeShort(readableBytes);
out.writeBytes(value.readSlice(readableBytes));
}
}
private static void encodeTlvs(List haProxyTLVs, ByteBuf out) {
for (int i = 0; i < haProxyTLVs.size(); i++) {
encodeTlv(haProxyTLVs.get(i), out);
}
}
}