View Javadoc

    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one
    3    *  or more contributor license agreements.  See the NOTICE file
    4    *  distributed with this work for additional information
    5    *  regarding copyright ownership.  The ASF licenses this file
    6    *  to you under the Apache License, Version 2.0 (the
    7    *  "License"); you may not use this file except in compliance
    8    *  with the License.  You may obtain a copy of the License at
    9    *
    10   *    http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   *  Unless required by applicable law or agreed to in writing,
    13   *  software distributed under the License is distributed on an
    14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    15   *  KIND, either express or implied.  See the License for the
    16   *  specific language governing permissions and limitations
    17   *  under the License.
    18   *
    19   */
    20  package org.apache.mina.filter.codec.textline;
    21
    22  import static org.junit.Assert.assertEquals;
    23  import static org.junit.Assert.assertTrue;
    24  import static org.junit.Assert.fail;
    25
    26  import java.nio.charset.Charset;
    27  import java.nio.charset.CharsetEncoder;
    28
    29  import org.apache.mina.core.buffer.IoBuffer;
    30  import org.apache.mina.filter.codec.ProtocolCodecSession;
    31  import org.apache.mina.filter.codec.ProtocolDecoderOutput;
    32  import org.apache.mina.filter.codec.RecoverableProtocolDecoderException;
    33  import org.junit.Test;
    34
    35  /**
    36   * Tests {@link TextLineDecoder}.
    37   *
    38   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
    39   */
    40  public class TextLineDecoderTest {
    41      @Test
    42      public void testNormalDecode() throws Exception {
    43          TextLineDecoder decoder = new TextLineDecoder(Charset.forName("UTF-8"), LineDelimiter.WINDOWS);
    44
    45          CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder();
    46          ProtocolCodecSession session = new ProtocolCodecSession();
    47          ProtocolDecoderOutput out = session.getDecoderOutput();
    48          IoBuffer in = IoBuffer.allocate(16);
    49
    50          // Test one decode and one output
    51          in.putString("ABC\r\n", encoder);
    52          in.flip();
    53          decoder.decode(session, in, out);
    54          assertEquals(1, session.getDecoderOutputQueue().size());
    55          assertEquals("ABC", session.getDecoderOutputQueue().poll());
    56
    57          // Test two decode and one output
    58          in.clear();
    59          in.putString("DEF", encoder);
    60          in.flip();
    61          decoder.decode(session, in, out);
    62          assertEquals(0, session.getDecoderOutputQueue().size());
    63          in.clear();
    64          in.putString("GHI\r\n", encoder);
    65          in.flip();
    66          decoder.decode(session, in, out);
    67          assertEquals(1, session.getDecoderOutputQueue().size());
    68          assertEquals("DEFGHI", session.getDecoderOutputQueue().poll());
    69
    70          // Test one decode and two output
    71          in.clear();
    72          in.putString("JKL\r\nMNO\r\n", encoder);
    73          in.flip();
    74          decoder.decode(session, in, out);
    75          assertEquals(2, session.getDecoderOutputQueue().size());
    76          assertEquals("JKL", session.getDecoderOutputQueue().poll());
    77          assertEquals("MNO", session.getDecoderOutputQueue().poll());
    78
    79          // Test aborted delimiter (DIRMINA-506)
    80          in.clear();
    81          in.putString("ABC\r\r\n", encoder);
    82          in.flip();
    83          decoder.decode(session, in, out);
    84          assertEquals(1, session.getDecoderOutputQueue().size());
    85          assertEquals("ABC\r", session.getDecoderOutputQueue().poll());
    86
    87          // Test splitted long delimiter
    88          decoder = new TextLineDecoder(Charset.forName("UTF-8"), new LineDelimiter("\n\n\n"));
    89          in.clear();
    90          in.putString("PQR\n", encoder);
    91          in.flip();
    92          decoder.decode(session, in, out);
    93          assertEquals(0, session.getDecoderOutputQueue().size());
    94          in.clear();
    95          in.putString("\n", encoder);
    96          in.flip();
    97          decoder.decode(session, in, out);
    98          assertEquals(0, session.getDecoderOutputQueue().size());
    99          in.clear();
    100         in.putString("\n", encoder);
    101         in.flip();
    102         decoder.decode(session, in, out);
    103         assertEquals(1, session.getDecoderOutputQueue().size());
    104         assertEquals("PQR", session.getDecoderOutputQueue().poll());
    105
    106         // Test splitted long delimiter which produces two output
    107         decoder = new TextLineDecoder(Charset.forName("UTF-8"), new LineDelimiter("\n\n\n"));
    108         in.clear();
    109         in.putString("PQR\n", encoder);
    110         in.flip();
    111         decoder.decode(session, in, out);
    112         assertEquals(0, session.getDecoderOutputQueue().size());
    113         in.clear();
    114         in.putString("\n", encoder);
    115         in.flip();
    116         decoder.decode(session, in, out);
    117         assertEquals(0, session.getDecoderOutputQueue().size());
    118         in.clear();
    119         in.putString("\nSTU\n\n\n", encoder);
    120         in.flip();
    121         decoder.decode(session, in, out);
    122         assertEquals(2, session.getDecoderOutputQueue().size());
    123         assertEquals("PQR", session.getDecoderOutputQueue().poll());
    124         assertEquals("STU", session.getDecoderOutputQueue().poll());
    125
    126         // Test splitted long delimiter mixed with partial non-delimiter.
    127         decoder = new TextLineDecoder(Charset.forName("UTF-8"), new LineDelimiter("\n\n\n"));
    128         in.clear();
    129         in.putString("PQR\n", encoder);
    130         in.flip();
    131         decoder.decode(session, in, out);
    132         assertEquals(0, session.getDecoderOutputQueue().size());
    133         in.clear();
    134         in.putString("X\n", encoder);
    135         in.flip();
    136         decoder.decode(session, in, out);
    137         assertEquals(0, session.getDecoderOutputQueue().size());
    138         in.clear();
    139         in.putString("\n\nSTU\n\n\n", encoder);
    140         in.flip();
    141         decoder.decode(session, in, out);
    142         assertEquals(2, session.getDecoderOutputQueue().size());
    143         assertEquals("PQR\nX", session.getDecoderOutputQueue().poll());
    144         assertEquals("STU", session.getDecoderOutputQueue().poll());
    145     }
    146
    147     public void testAutoDecode() throws Exception {
    148         TextLineDecoder decoder = new TextLineDecoder(Charset.forName("UTF-8"), LineDelimiter.AUTO);
    149
    150         CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder();
    151         ProtocolCodecSession session = new ProtocolCodecSession();
    152         ProtocolDecoderOutput out = session.getDecoderOutput();
    153         IoBuffer in = IoBuffer.allocate(16);
    154
    155         // Test one decode and one output
    156         in.putString("ABC\r\n", encoder);
    157         in.flip();
    158         decoder.decode(session, in, out);
    159         assertEquals(1, session.getDecoderOutputQueue().size());
    160         assertEquals("ABC", session.getDecoderOutputQueue().poll());
    161
    162         // Test two decode and one output
    163         in.clear();
    164         in.putString("DEF", encoder);
    165         in.flip();
    166         decoder.decode(session, in, out);
    167         assertEquals(0, session.getDecoderOutputQueue().size());
    168         in.clear();
    169         in.putString("GHI\r\n", encoder);
    170         in.flip();
    171         decoder.decode(session, in, out);
    172         assertEquals(1, session.getDecoderOutputQueue().size());
    173         assertEquals("DEFGHI", session.getDecoderOutputQueue().poll());
    174
    175         // Test one decode and two output
    176         in.clear();
    177         in.putString("JKL\r\nMNO\r\n", encoder);
    178         in.flip();
    179         decoder.decode(session, in, out);
    180         assertEquals(2, session.getDecoderOutputQueue().size());
    181         assertEquals("JKL", session.getDecoderOutputQueue().poll());
    182         assertEquals("MNO", session.getDecoderOutputQueue().poll());
    183
    184         // Test multiple '\n's
    185         in.clear();
    186         in.putString("\n\n\n", encoder);
    187         in.flip();
    188         decoder.decode(session, in, out);
    189         assertEquals(3, session.getDecoderOutputQueue().size());
    190         assertEquals("", session.getDecoderOutputQueue().poll());
    191         assertEquals("", session.getDecoderOutputQueue().poll());
    192         assertEquals("", session.getDecoderOutputQueue().poll());
    193
    194         // Test splitted long delimiter (\r\r\n)
    195         in.clear();
    196         in.putString("PQR\r", encoder);
    197         in.flip();
    198         decoder.decode(session, in, out);
    199         assertEquals(0, session.getDecoderOutputQueue().size());
    200         in.clear();
    201         in.putString("\r", encoder);
    202         in.flip();
    203         decoder.decode(session, in, out);
    204         assertEquals(0, session.getDecoderOutputQueue().size());
    205         in.clear();
    206         in.putString("\n", encoder);
    207         in.flip();
    208         decoder.decode(session, in, out);
    209         assertEquals(1, session.getDecoderOutputQueue().size());
    210         assertEquals("PQR", session.getDecoderOutputQueue().poll());
    211
    212         // Test splitted long delimiter (\r\r\n) which produces two output
    213         in.clear();
    214         in.putString("PQR\r", encoder);
    215         in.flip();
    216         decoder.decode(session, in, out);
    217         assertEquals(0, session.getDecoderOutputQueue().size());
    218         in.clear();
    219         in.putString("\r", encoder);
    220         in.flip();
    221         decoder.decode(session, in, out);
    222         assertEquals(0, session.getDecoderOutputQueue().size());
    223         in.clear();
    224         in.putString("\nSTU\r\r\n", encoder);
    225         in.flip();
    226         decoder.decode(session, in, out);
    227         assertEquals(2, session.getDecoderOutputQueue().size());
    228         assertEquals("PQR", session.getDecoderOutputQueue().poll());
    229         assertEquals("STU", session.getDecoderOutputQueue().poll());
    230
    231         // Test splitted long delimiter mixed with partial non-delimiter.
    232         in.clear();
    233         in.putString("PQR\r", encoder);
    234         in.flip();
    235         decoder.decode(session, in, out);
    236         assertEquals(0, session.getDecoderOutputQueue().size());
    237         in.clear();
    238         in.putString("X\r", encoder);
    239         in.flip();
    240         decoder.decode(session, in, out);
    241         assertEquals(0, session.getDecoderOutputQueue().size());
    242         in.clear();
    243         in.putString("\r\nSTU\r\r\n", encoder);
    244         in.flip();
    245         decoder.decode(session, in, out);
    246         assertEquals(2, session.getDecoderOutputQueue().size());
    247         assertEquals("PQR\rX", session.getDecoderOutputQueue().poll());
    248         assertEquals("STU", session.getDecoderOutputQueue().poll());
    249
    250         in.clear();
    251         String s = new String(new byte[] { 0, 77, 105, 110, 97 });
    252         in.putString(s, encoder);
    253         in.flip();
    254         decoder.decode(session, in, out);
    255         assertEquals(1, session.getDecoderOutputQueue().size());
    256         assertEquals(s, session.getDecoderOutputQueue().poll());
    257     }
    258
    259     public void testOverflow() throws Exception {
    260         TextLineDecoder decoder = new TextLineDecoder(Charset.forName("UTF-8"), LineDelimiter.AUTO);
    261         decoder.setMaxLineLength(3);
    262
    263         CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder();
    264         ProtocolCodecSession session = new ProtocolCodecSession();
    265         ProtocolDecoderOutput out = session.getDecoderOutput();
    266         IoBuffer in = IoBuffer.allocate(16);
    267
    268         // Make sure the overflow exception is not thrown until
    269         // the delimiter is encountered.
    270         in.putString("A", encoder).flip().mark();
    271         decoder.decode(session, in.reset().mark(), out);
    272         assertEquals(0, session.getDecoderOutputQueue().size());
    273         decoder.decode(session, in.reset().mark(), out);
    274         assertEquals(0, session.getDecoderOutputQueue().size());
    275         decoder.decode(session, in.reset().mark(), out);
    276         assertEquals(0, session.getDecoderOutputQueue().size());
    277         decoder.decode(session, in.reset().mark(), out);
    278         assertEquals(0, session.getDecoderOutputQueue().size());
    279
    280         in.clear().putString("A\r\nB\r\n", encoder).flip();
    281
    282         try {
    283             decoder.decode(session, in, out);
    284             fail();
    285         } catch (RecoverableProtocolDecoderException e) {
    286             // signifies a successful test execution
    287             assertTrue(true);
    288         }
    289
    290         decoder.decode(session, in, out);
    291         assertEquals(1, session.getDecoderOutputQueue().size());
    292         assertEquals("B", session.getDecoderOutputQueue().poll());
    293
    294         // Make sure OOM is not thrown.
    295         System.gc();
    296         long oldFreeMemory = Runtime.getRuntime().freeMemory();
    297         in = IoBuffer.allocate(1048576 * 16).sweep((byte) ' ').mark();
    298
    299         for (int i = 0; i < 10; i++) {
    300             decoder.decode(session, in.reset().mark(), out);
    301             assertEquals(0, session.getDecoderOutputQueue().size());
    302
    303             // Memory consumption should be minimal.
    304             assertTrue(Runtime.getRuntime().freeMemory() - oldFreeMemory < 1048576);
    305         }
    306
    307         in.clear().putString("C\r\nD\r\n", encoder).flip();
    308         try {
    309             decoder.decode(session, in, out);
    310             fail();
    311         } catch (RecoverableProtocolDecoderException e) {
    312             // signifies a successful test execution
    313             assertTrue(true);
    314         }
    315
    316         decoder.decode(session, in, out);
    317         assertEquals(1, session.getDecoderOutputQueue().size());
    318         assertEquals("D", session.getDecoderOutputQueue().poll());
    319
    320         // Memory consumption should be minimal.
    321         assertTrue(Runtime.getRuntime().freeMemory() - oldFreeMemory < 1048576);
    322     }
    323
    324     public void testSMTPDataBounds() throws Exception {
    325         TextLineDecoder decoder = new TextLineDecoder(Charset.forName("ISO-8859-1"), new LineDelimiter("\r\n.\r\n"));
    326
    327         CharsetEncoder encoder = Charset.forName("ISO-8859-1").newEncoder();
    328         ProtocolCodecSession session = new ProtocolCodecSession();
    329         IoBuffer in = IoBuffer.allocate(16).setAutoExpand(true);
    330
    331         in.putString("\r\n", encoder).flip().mark();
    332         decoder.decode(session, in.reset().mark(), session.getDecoderOutput());
    333         assertEquals(0, session.getDecoderOutputQueue().size());
    334         in.putString("Body\r\n.\r\n", encoder).flip().mark();
    335         decoder.decode(session, in.reset().mark(), session.getDecoderOutput());
    336         assertEquals(1, session.getDecoderOutputQueue().size());
    337         assertEquals("\r\n\r\nBody", session.getDecoderOutputQueue().poll());
    338     }
    339 }