Skip to content

Commit

Permalink
Allow for more than 2 nested components.
Browse files Browse the repository at this point in the history
The VPOLL component can contain VEVENT with nested VALARMS to make 3 levels.

There is a limit check on the depth - it's set to 10 and the only reason for the moment is to block DOS attacks with extremely deep components.
  • Loading branch information
douglm committed Nov 1, 2020
1 parent 64b4cef commit 870696e
Showing 1 changed file with 37 additions and 22 deletions.
59 changes: 37 additions & 22 deletions src/main/java/net/fortuna/ical4j/data/DefaultContentHandler.java
Expand Up @@ -14,6 +14,7 @@
import java.net.URISyntaxException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
Expand All @@ -38,9 +39,10 @@ public class DefaultContentHandler implements ContentHandler {

private PropertyBuilder propertyBuilder;

private ComponentBuilder<CalendarComponent> componentBuilder;

private ComponentBuilder<Component> subComponentBuilder;
/**
* The current component builders.
*/
private final LinkedList<ComponentBuilder<CalendarComponent>> components = new LinkedList<>();

private Calendar calendar;

Expand All @@ -61,9 +63,21 @@ public DefaultContentHandler(Consumer<Calendar> consumer, TimeZoneRegistry tzReg
this.componentFactorySupplier = componentFactorySupplier;
}

public ComponentBuilder<CalendarComponent> getComponentBuilder() {
if (components.size() == 0) {
return null;
}
return components.peek();
}

public void endComponent() {
components.pop();
}

@Override
public void startCalendar() {
calendar = new Calendar();
components.clear();
propertiesWithTzId = new ArrayList<>();
}

Expand All @@ -76,33 +90,38 @@ public void endCalendar() throws IOException {

@Override
public void startComponent(String name) {
if (componentBuilder != null) {
subComponentBuilder = new ComponentBuilder<>();
subComponentBuilder.factories(componentFactorySupplier.get()).name(name);
} else {
componentBuilder = new ComponentBuilder<>();
componentBuilder.factories(componentFactorySupplier.get()).name(name);
if (components.size() > 10) {
throw new RuntimeException("Components nested too deep");
}

ComponentBuilder<CalendarComponent> componentBuilder =
new ComponentBuilder<>();
componentBuilder.factories(componentFactorySupplier.get()).name(name);
components.push(componentBuilder);
}

@Override
public void endComponent(String name) {
assertComponent(componentBuilder);
assertComponent(getComponentBuilder());

final ComponentBuilder<CalendarComponent> componentBuilder =
getComponentBuilder();

if (subComponentBuilder != null) {
Component subComponent = subComponentBuilder.build();
componentBuilder.subComponent(subComponent);
DefaultContentHandler.this.endComponent();

subComponentBuilder = null;
final ComponentBuilder<CalendarComponent> parent =
getComponentBuilder();

if (parent != null) {
Component subComponent = componentBuilder.build();
parent.subComponent(subComponent);
} else {
CalendarComponent component = componentBuilder.build();
calendar.getComponents().add(component);
if (component instanceof VTimeZone && tzRegistry != null) {
// register the timezone for use with iCalendar objects..
tzRegistry.register(new TimeZone((VTimeZone) component));
}

componentBuilder = null;
}
}

Expand All @@ -127,12 +146,8 @@ public void endProperty(String name) throws URISyntaxException, ParseException,
}
// replace with a constant instance if applicable..
property = Constants.forProperty(property);
if (componentBuilder != null) {
if (subComponentBuilder != null) {
subComponentBuilder.property(property);
} else {
componentBuilder.property(property);
}
if (getComponentBuilder() != null) {
getComponentBuilder().property(property);
} else if (calendar != null) {
calendar.getProperties().add(property);
}
Expand Down

0 comments on commit 870696e

Please sign in to comment.