2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.controller.netconf.util.handler;
11 import io.netty.buffer.ByteBuf;
12 import io.netty.channel.ChannelHandlerContext;
13 import io.netty.handler.codec.ByteToMessageDecoder;
15 import java.util.List;
17 import org.slf4j.Logger;
18 import org.slf4j.LoggerFactory;
20 public class NetconfChunkAggregator extends ByteToMessageDecoder {
21 private final static Logger logger = LoggerFactory.getLogger(NetconfChunkAggregator.class);
22 public static final int DEFAULT_MAXIMUM_CHUNK_SIZE = 16 * 1024 * 1024;
24 private static enum State {
27 HEADER_LENGTH_FIRST, // [1-9]
28 HEADER_LENGTH_OTHER, // [0-9]*\n
36 private final int maxChunkSize = DEFAULT_MAXIMUM_CHUNK_SIZE;
37 private State state = State.HEADER_ONE;
38 private long chunkSize;
39 private ByteBuf chunk;
42 protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
43 while (in.isReadable()) {
47 final byte b = in.readByte();
49 logger.debug("Got byte {} while waiting for {}", b, (byte)'\n');
50 throw new IllegalStateException("Malformed chunk header encountered (byte 0)");
53 state = State.HEADER_TWO;
58 final byte b = in.readByte();
60 logger.debug("Got byte {} while waiting for {}", b, (byte)'#');
61 throw new IllegalStateException("Malformed chunk header encountered (byte 1)");
64 state = State.HEADER_LENGTH_FIRST;
67 case HEADER_LENGTH_FIRST:
69 final byte b = in.readByte();
70 if (b < '1' || b > '9') {
71 logger.debug("Got byte {} while waiting for {}-{}", b, (byte)'1', (byte)'9');
72 throw new IllegalStateException("Invalid chunk size encountered (byte 0)");
76 state = State.HEADER_LENGTH_OTHER;
79 case HEADER_LENGTH_OTHER:
81 final byte b = in.readByte();
87 if (b < '0' || b > '9') {
88 logger.debug("Got byte {} while waiting for {}-{}", b, (byte)'0', (byte)'9');
89 throw new IllegalStateException("Invalid chunk size encountered");
95 if (chunkSize > maxChunkSize) {
96 logger.debug("Parsed chunk size {}, maximum allowed is {}", chunkSize, maxChunkSize);
97 throw new IllegalStateException("Maximum chunk size exceeded");
103 * FIXME: this gathers all data into one big chunk before passing
104 * it on. Make sure the pipeline can work with partial data
105 * and then change this piece to pass the data on as it
108 if (in.readableBytes() < chunkSize) {
109 logger.debug("Buffer has {} bytes, need {} to complete chunk", in.readableBytes(), chunkSize);
110 in.discardReadBytes();
114 chunk = in.readBytes((int)chunkSize);
115 state = State.FOOTER_ONE;
119 final byte b = in.readByte();
121 logger.debug("Got byte {} while waiting for {}", b, (byte)'\n');
122 throw new IllegalStateException("Malformed chunk footer encountered (byte 0)");
125 state = State.FOOTER_TWO;
130 final byte b = in.readByte();
132 logger.debug("Got byte {} while waiting for {}", b, (byte)'#');
133 throw new IllegalStateException("Malformed chunk footer encountered (byte 1)");
136 state = State.FOOTER_THREE;
141 final byte b = in.readByte();
143 logger.debug("Got byte {} while waiting for {}", b, (byte)'#');
144 throw new IllegalStateException("Malformed chunk footer encountered (byte 2)");
147 state = State.FOOTER_FOUR;
152 final byte b = in.readByte();
154 logger.debug("Got byte {} while waiting for {}", b, (byte)'\n');
155 throw new IllegalStateException("Malformed chunk footer encountered (byte 3)");
158 state = State.HEADER_ONE;
167 in.discardReadBytes();