8f67da670a9231369cc8914dfb490b02428d88a5
[controller.git] / opendaylight / netconf / netconf-netty-util / src / main / java / org / opendaylight / controller / netconf / nettyutil / handler / NetconfEXICodec.java
1 package org.opendaylight.controller.netconf.nettyutil.handler;
2
3 import com.google.common.base.Preconditions;
4 import org.openexi.proc.HeaderOptionsOutputType;
5 import org.openexi.proc.common.EXIOptions;
6 import org.openexi.proc.common.EXIOptionsException;
7 import org.openexi.proc.common.GrammarOptions;
8 import org.openexi.proc.grammars.GrammarCache;
9 import org.openexi.sax.EXIReader;
10 import org.openexi.sax.Transmogrifier;
11 import org.openexi.sax.TransmogrifierException;
12 import org.xml.sax.EntityResolver;
13 import org.xml.sax.InputSource;
14
15 public final class NetconfEXICodec {
16     /**
17      * NETCONF is XML environment, so the use of EXI cookie is not really needed. Adding it
18      * decreases efficiency of encoding by adding human-readable 4 bytes "EXI$" to the head
19      * of the stream. This is really useful, so let's output it now.
20      */
21     private static final boolean OUTPUT_EXI_COOKIE = true;
22     /**
23      * OpenEXI does not allow us to directly prevent resolution of external entities. In order
24      * to prevent XXE attacks, we reuse a single no-op entity resolver.
25      */
26     private static final EntityResolver ENTITY_RESOLVER = new EntityResolver() {
27         @Override
28         public InputSource resolveEntity(final String publicId, final String systemId) {
29             return new InputSource();
30         }
31     };
32
33     /**
34      * Grammar cache acts as a template and is duplicated by the Transmogrifier and the Reader
35      * before use. It is safe to reuse a single instance.
36      */
37     private final GrammarCache exiGrammarCache;
38     private final EXIOptions exiOptions;
39
40     public NetconfEXICodec(final EXIOptions exiOptions) {
41         this.exiOptions = Preconditions.checkNotNull(exiOptions);
42         this.exiGrammarCache = createGrammarCache(exiOptions);
43     }
44
45     private static GrammarCache createGrammarCache(final EXIOptions exiOptions) {
46         short go = GrammarOptions.DEFAULT_OPTIONS;
47         if (exiOptions.getPreserveComments()) {
48             go = GrammarOptions.addCM(go);
49         }
50         if (exiOptions.getPreserveDTD()) {
51             go = GrammarOptions.addDTD(go);
52         }
53         if (exiOptions.getPreserveNS()) {
54             go = GrammarOptions.addNS(go);
55         }
56         if (exiOptions.getPreservePIs()) {
57             go = GrammarOptions.addPI(go);
58         }
59
60         return new GrammarCache(go);
61     }
62
63     EXIReader getReader() throws EXIOptionsException {
64         final EXIReader r = new EXIReader();
65         r.setPreserveLexicalValues(exiOptions.getPreserveLexicalValues());
66         r.setGrammarCache(exiGrammarCache);
67         r.setEntityResolver(ENTITY_RESOLVER);
68         return r;
69     }
70
71     Transmogrifier getTransmogrifier() throws EXIOptionsException, TransmogrifierException {
72         final Transmogrifier transmogrifier = new Transmogrifier();
73         transmogrifier.setAlignmentType(exiOptions.getAlignmentType());
74         transmogrifier.setBlockSize(exiOptions.getBlockSize());
75         transmogrifier.setGrammarCache(exiGrammarCache);
76         transmogrifier.setOutputCookie(OUTPUT_EXI_COOKIE);
77         transmogrifier.setOutputOptions(HeaderOptionsOutputType.all);
78         transmogrifier.setResolveExternalGeneralEntities(false);
79         return transmogrifier;
80     }
81 }