1
18
19 package io.undertow.servlet.handlers;
20
21 import io.undertow.UndertowMessages;
22 import io.undertow.util.SubstringMap;
23
24 import java.util.HashMap;
25 import java.util.Map;
26
27
33 class ServletPathMatchesData {
34
35 private final Map<String, ServletPathMatch> exactPathMatches;
36
37 private final SubstringMap<PathMatch> prefixMatches;
38
39 private final Map<String, ServletChain> nameMatches;
40
41 ServletPathMatchesData(final Map<String, ServletChain> exactPathMatches, final SubstringMap<PathMatch> prefixMatches, final Map<String, ServletChain> nameMatches) {
42 this.prefixMatches = prefixMatches;
43 this.nameMatches = nameMatches;
44 Map<String, ServletPathMatch> newExactPathMatches = new HashMap<>();
45 for (Map.Entry<String, ServletChain> entry : exactPathMatches.entrySet()) {
46 newExactPathMatches.put(entry.getKey(), new ServletPathMatch(entry.getValue(), entry.getKey(), entry.getValue().isDefaultServletMapping()));
47 }
48 this.exactPathMatches = newExactPathMatches;
49
50 }
51
52 public ServletChain getServletHandlerByName(final String name) {
53 return nameMatches.get(name);
54 }
55
56 public ServletPathMatch getServletHandlerByExactPath(final String path) {
57 return exactPathMatches.get(path);
58 }
59
60 public ServletPathMatch getServletHandlerByPath(final String path) {
61 ServletPathMatch exact = exactPathMatches.get(path);
62 if (exact != null) {
63 return exact;
64 }
65 SubstringMap.SubstringMatch<PathMatch> match = prefixMatches.get(path, path.length());
66 if (match != null) {
67 return handleMatch(path, match.getValue(), path.lastIndexOf('.'));
68 }
69 int extensionPos = -1;
70 for (int i = path.length() - 1; i >= 0; --i) {
71 final char c = path.charAt(i);
72 if (c == '/') {
73 match = prefixMatches.get(path, i);
74 if (match != null) {
75 return handleMatch(path, match.getValue(), extensionPos);
76 }
77 } else if (c == '.' && extensionPos == -1) {
78 extensionPos = i;
79 }
80 }
81
82
83 throw UndertowMessages.MESSAGES.servletPathMatchFailed();
84 }
85
86 private ServletPathMatch handleMatch(final String path, final PathMatch match, final int extensionPos) {
87 if (match.extensionMatches.isEmpty()) {
88 return new ServletPathMatch(match.defaultHandler, path, match.requireWelcomeFileMatch);
89 }
90 if (extensionPos == -1) {
91 return new ServletPathMatch(match.defaultHandler, path, match.requireWelcomeFileMatch);
92 }
93 final String ext;
94 ext = path.substring(extensionPos + 1, path.length());
95 ServletChain handler = match.extensionMatches.get(ext);
96 if (handler != null) {
97 return new ServletPathMatch(handler, path, handler.getManagedServlet().getServletInfo().isRequireWelcomeFileMapping());
98 }
99 return new ServletPathMatch(match.defaultHandler, path, match.requireWelcomeFileMatch);
100 }
101
102 public static Builder builder() {
103 return new Builder();
104 }
105
106 public static final class Builder {
107
108 private final Map<String, ServletChain> exactPathMatches = new HashMap<>();
109
110 private final SubstringMap<PathMatch> prefixMatches = new SubstringMap<PathMatch>();
111
112 private final Map<String, ServletChain> nameMatches = new HashMap<>();
113
114 public void addExactMatch(final String exactMatch, final ServletChain match) {
115 exactPathMatches.put(exactMatch, match);
116 }
117
118 public void addPrefixMatch(final String prefix, final ServletChain match, final boolean requireWelcomeFileMatch) {
119 SubstringMap.SubstringMatch<PathMatch> mt = prefixMatches.get(prefix);
120 PathMatch m;
121 if (mt == null) {
122 prefixMatches.put(prefix, m = new PathMatch(match));
123 } else {
124 m = mt.getValue();
125 }
126 m.defaultHandler = match;
127 m.requireWelcomeFileMatch = requireWelcomeFileMatch;
128 }
129
130 public void addExtensionMatch(final String prefix, final String extension, final ServletChain match) {
131 SubstringMap.SubstringMatch<PathMatch> mt = prefixMatches.get(prefix);
132 PathMatch m;
133 if (mt == null) {
134 prefixMatches.put(prefix, m = new PathMatch(null));
135 } else {
136 m = mt.getValue();
137 }
138 m.extensionMatches.put(extension, match);
139 }
140
141 public void addNameMatch(final String name, final ServletChain match) {
142 nameMatches.put(name, match);
143 }
144
145 public ServletPathMatchesData build() {
146 return new ServletPathMatchesData(exactPathMatches, prefixMatches, nameMatches);
147 }
148
149 }
150
151
152 private static class PathMatch {
153
154 private final Map<String, ServletChain> extensionMatches = new HashMap<>();
155 private volatile ServletChain defaultHandler;
156 private volatile boolean requireWelcomeFileMatch;
157
158 PathMatch(final ServletChain defaultHandler) {
159 this.defaultHandler = defaultHandler;
160 }
161 }
162
163
164 }
165