aboutsummaryrefslogtreecommitdiff
path: root/src/test/java/org/yaml/snakeyaml/issues/issue377/ReferencesTest.java
blob: cb17cb8ab1df765edb6cde9863d9082edc6c1926 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/**
 * Copyright (c) 2008, SnakeYAML
 *
 * Licensed 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
 *
 * http://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.yaml.snakeyaml.issues.issue377;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.util.HashMap;
import org.junit.Test;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;

public class ReferencesTest {

  /**
   * Create data which is difficult to parse.
   *
   * @param size - size of the map, defines the complexity
   * @return YAML to parse
   */
  private String createDump(int size) {
    HashMap root = new HashMap();
    HashMap s1, s2, t1, t2;
    s1 = root;
    s2 = new HashMap();
    /*
     * the time to parse grows very quickly SIZE -> time to parse in seconds 25 -> 1 26 -> 2 27 -> 3
     * 28 -> 8 29 -> 13 30 -> 28 31 -> 52 32 -> 113 33 -> 245 34 -> 500
     */
    for (int i = 0; i < size; i++) {

      t1 = new HashMap();
      t2 = new HashMap();
      t1.put("foo", "1");
      t2.put("bar", "2");

      s1.put("a", t1);
      s1.put("b", t2);
      s2.put("a", t1);
      s2.put("b", t2);

      s1 = t1;
      s2 = t2;
    }

    // this is VERY BAD code
    // the map has itself as a key (no idea why it may be used except of a DoS attack)
    HashMap f = new HashMap();
    f.put(f, "a");
    f.put("g", root);

    Yaml yaml = new Yaml(new SafeConstructor());
    String output = yaml.dump(f);
    return output;
  }

  @Test
  public void referencesWithRecursiveKeysNotAllowedByDefault() {
    String output = createDump(30);
    // System.out.println(output);
    long time1 = System.currentTimeMillis();
    // Load
    LoaderOptions settings = new LoaderOptions();
    settings.setMaxAliasesForCollections(150);
    Yaml yaml = new Yaml(settings);
    try {
      yaml.load(output);
      fail();
    } catch (Exception e) {
      assertEquals("Recursive key for mapping is detected but it is not configured to be allowed.",
          e.getMessage());
    }
    long time2 = System.currentTimeMillis();
    float duration = (time2 - time1) / 1000;
    assertTrue("It should fail quickly. Time was " + duration + " seconds.", duration < 1.0);
  }

  @Test
  public void parseManyAliasesForCollections() {
    String output = createDump(25);
    // Load
    // long time1 = System.currentTimeMillis();
    LoaderOptions settings = new LoaderOptions();
    settings.setMaxAliasesForCollections(50);
    settings.setAllowRecursiveKeys(true);
    Yaml yaml = new Yaml(settings);
    yaml.load(output);
    // Disabling this as it runs slower than 0.9 on my machine
    // long time2 = System.currentTimeMillis();
    // double duration = (time2 - time1) / 1000.0;
    // assertTrue("It should take time. Time was " + duration + " seconds.", duration > 0.9);
    // assertTrue("Time was " + duration + " seconds.", duration < 5.0);
  }

  @Test
  public void referencesWithRestrictedNesting() {
    // without alias restriction this size should occupy tons of CPU, memory and time to parse
    int depth = 35;
    String bigYAML = createDump(depth);
    // Load
    long time1 = System.currentTimeMillis();
    LoaderOptions settings = new LoaderOptions();
    settings.setMaxAliasesForCollections(1000);
    settings.setAllowRecursiveKeys(true);
    settings.setNestingDepthLimit(depth);
    Yaml yaml = new Yaml(settings);
    try {
      yaml.load(bigYAML);
      fail();
    } catch (Exception e) {
      assertEquals("Nesting Depth exceeded max 35", e.getMessage());
    }
    long time2 = System.currentTimeMillis();
    float duration = (time2 - time1) / 1000;
    assertTrue("It should fail quickly. Time was " + duration + " seconds.", duration < 1.0);
  }

}