1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.haproxy;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.channel.ChannelHandler.Sharable;
20 import io.netty.channel.ChannelHandlerContext;
21 import io.netty.handler.codec.MessageToByteEncoder;
22 import io.netty.util.CharsetUtil;
23 import io.netty.util.NetUtil;
24
25 import java.util.List;
26
27 import static io.netty.handler.codec.haproxy.HAProxyConstants.*;
28
29
30
31
32
33
34 @Sharable
35 public final class HAProxyMessageEncoder extends MessageToByteEncoder<HAProxyMessage> {
36
37 private static final int V2_VERSION_BITMASK = 0x02 << 4;
38
39
40 static final int UNIX_ADDRESS_BYTES_LENGTH = 108;
41 static final int TOTAL_UNIX_ADDRESS_BYTES_LENGTH = UNIX_ADDRESS_BYTES_LENGTH * 2;
42
43 public static final HAProxyMessageEncoder INSTANCE = new HAProxyMessageEncoder();
44
45 private HAProxyMessageEncoder() {
46 super(HAProxyMessage.class);
47 }
48
49 @Override
50 protected void encode(ChannelHandlerContext ctx, HAProxyMessage msg, ByteBuf out) throws Exception {
51 switch (msg.protocolVersion()) {
52 case V1:
53 encodeV1(msg, out);
54 break;
55 case V2:
56 encodeV2(msg, out);
57 break;
58 default:
59 throw new HAProxyProtocolException("Unsupported version: " + msg.protocolVersion());
60 }
61 }
62
63 private static void encodeV1(HAProxyMessage msg, ByteBuf out) {
64 out.writeBytes(TEXT_PREFIX);
65 out.writeByte((byte) ' ');
66 out.writeCharSequence(msg.proxiedProtocol().name(), CharsetUtil.US_ASCII);
67 out.writeByte((byte) ' ');
68 out.writeCharSequence(msg.sourceAddress(), CharsetUtil.US_ASCII);
69 out.writeByte((byte) ' ');
70 out.writeCharSequence(msg.destinationAddress(), CharsetUtil.US_ASCII);
71 out.writeByte((byte) ' ');
72 out.writeCharSequence(String.valueOf(msg.sourcePort()), CharsetUtil.US_ASCII);
73 out.writeByte((byte) ' ');
74 out.writeCharSequence(String.valueOf(msg.destinationPort()), CharsetUtil.US_ASCII);
75 out.writeByte((byte) '\r');
76 out.writeByte((byte) '\n');
77 }
78
79 private static void encodeV2(HAProxyMessage msg, ByteBuf out) {
80 out.writeBytes(BINARY_PREFIX);
81 out.writeByte(V2_VERSION_BITMASK | msg.command().byteValue());
82 out.writeByte(msg.proxiedProtocol().byteValue());
83
84 switch (msg.proxiedProtocol().addressFamily()) {
85 case AF_IPv4:
86 case AF_IPv6:
87 byte[] srcAddrBytes = NetUtil.createByteArrayFromIpAddressString(msg.sourceAddress());
88 byte[] dstAddrBytes = NetUtil.createByteArrayFromIpAddressString(msg.destinationAddress());
89
90 out.writeShort(srcAddrBytes.length + dstAddrBytes.length + 4 + msg.tlvNumBytes());
91 out.writeBytes(srcAddrBytes);
92 out.writeBytes(dstAddrBytes);
93 out.writeShort(msg.sourcePort());
94 out.writeShort(msg.destinationPort());
95 encodeTlvs(msg.tlvs(), out);
96 break;
97 case AF_UNIX:
98 out.writeShort(TOTAL_UNIX_ADDRESS_BYTES_LENGTH + msg.tlvNumBytes());
99 int srcAddrBytesWritten = out.writeCharSequence(msg.sourceAddress(), CharsetUtil.US_ASCII);
100 out.writeZero(UNIX_ADDRESS_BYTES_LENGTH - srcAddrBytesWritten);
101 int dstAddrBytesWritten = out.writeCharSequence(msg.destinationAddress(), CharsetUtil.US_ASCII);
102 out.writeZero(UNIX_ADDRESS_BYTES_LENGTH - dstAddrBytesWritten);
103 encodeTlvs(msg.tlvs(), out);
104 break;
105 case AF_UNSPEC:
106 out.writeShort(0);
107 break;
108 default:
109 throw new HAProxyProtocolException("unexpected addrFamily");
110 }
111 }
112
113 private static void encodeTlv(HAProxyTLV haProxyTLV, ByteBuf out) {
114 if (haProxyTLV instanceof HAProxySSLTLV) {
115 HAProxySSLTLV ssltlv = (HAProxySSLTLV) haProxyTLV;
116 out.writeByte(haProxyTLV.typeByteValue());
117 out.writeShort(ssltlv.contentNumBytes());
118 out.writeByte(ssltlv.client());
119 out.writeInt(ssltlv.verify());
120 encodeTlvs(ssltlv.encapsulatedTLVs(), out);
121 } else {
122 out.writeByte(haProxyTLV.typeByteValue());
123 ByteBuf value = haProxyTLV.content();
124 int readableBytes = value.readableBytes();
125 out.writeShort(readableBytes);
126 out.writeBytes(value.readSlice(readableBytes));
127 }
128 }
129
130 private static void encodeTlvs(List<HAProxyTLV> haProxyTLVs, ByteBuf out) {
131 for (int i = 0; i < haProxyTLVs.size(); i++) {
132 encodeTlv(haProxyTLVs.get(i), out);
133 }
134 }
135 }