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 throw new IllegalStateException("Malformed chunk header encountered (byte 0)");
52 state = State.HEADER_TWO;
57 final byte b = in.readByte();
59 throw new IllegalStateException("Malformed chunk header encountered (byte 1)");
62 state = State.HEADER_LENGTH_FIRST;
65 case HEADER_LENGTH_FIRST:
67 final byte b = in.readByte();
68 if (b < '1' || b > '9') {
69 throw new IllegalStateException("Invalid chunk size encountered (byte 0)");
73 state = State.HEADER_LENGTH_OTHER;
76 case HEADER_LENGTH_OTHER:
78 final byte b = in.readByte();
84 if (b < '0' || b > '9') {
85 throw new IllegalStateException("Invalid chunk size encountered");
91 if (chunkSize > maxChunkSize) {
92 throw new IllegalStateException("Maximum chunk size exceeded");
98 * FIXME: this gathers all data into one big chunk before passing
99 * it on. Make sure the pipeline can work with partial data
100 * and then change this piece to pass the data on as it
103 if (in.readableBytes() < chunkSize) {
104 logger.debug("Buffer has {} bytes, need {} to complete chunk", in.readableBytes(), chunkSize);
105 in.discardReadBytes();
109 chunk = in.readBytes((int)chunkSize);
110 state = State.FOOTER_ONE;
114 final byte b = in.readByte();
116 logger.debug("Got byte {} while waiting for {}", b, (byte)'\n');
117 throw new IllegalStateException("Malformed chunk footer encountered (byte 0)");
120 state = State.FOOTER_TWO;
125 final byte b = in.readByte();
127 logger.debug("Got byte {} while waiting for {}", b, (byte)'#');
128 throw new IllegalStateException("Malformed chunk footer encountered (byte 1)");
131 state = State.FOOTER_THREE;
136 final byte b = in.readByte();
138 logger.debug("Got byte {} while waiting for {}", b, (byte)'#');
139 throw new IllegalStateException("Malformed chunk footer encountered (byte 2)");
142 state = State.FOOTER_FOUR;
147 final byte b = in.readByte();
149 logger.debug("Got byte {} while waiting for {}", b, (byte)'\n');
150 throw new IllegalStateException("Malformed chunk footer encountered (byte 3)");
153 state = State.HEADER_ONE;
162 in.discardReadBytes();