20
20
import java .nio .charset .Charset ;
21
21
import java .util .Collections ;
22
22
import java .util .HashMap ;
23
- import java .util .List ;
24
23
import java .util .Map ;
25
24
26
25
import org .springframework .lang .Nullable ;
27
- import org .springframework .util .Assert ;
28
26
import org .springframework .util .MultiValueMap ;
29
27
import org .springframework .util .ObjectUtils ;
30
28
import org .springframework .util .StringUtils ;
@@ -51,43 +49,33 @@ public class DefaultUriBuilderFactory implements UriBuilderFactory {
51
49
public enum EncodingMode {
52
50
53
51
/**
54
- * The default way of encoding that {@link UriComponents} supports:
55
- * <ol>
56
- * <li>Expand URI variables.
57
- * <li>Encode individual URI components as described in
58
- * {@link UriComponents#encode(Charset)}.
59
- * </ol>
60
- * <p>This mode <strong>does not</strong> encode all characters with
61
- * reserved meaning but only the ones that are illegal within a given
62
- * URI component as defined in RFC 396. This matches the way the
63
- * multi-argument {@link URI} constructor does encoding.
52
+ * Apply strict encoding to URI variables at the time of expanding,
53
+ * quoting both illegal characters and characters with reserved meaning
54
+ * via {@link UriUtils#encode(String, Charset)}.
64
55
*/
65
- URI_COMPONENT ,
56
+ VALUES_ONLY ,
66
57
67
58
/**
68
- * Comprehensive encoding of URI variable values prior to expanding:
69
- * <ol>
70
- * <li>Apply {@link UriUtils#encode(String, Charset)} to each URI variable value.
71
- * <li>Expand URI variable values.
72
- * </ol>
73
- * <p>This mode encodes all characters with reserved meaning, therefore
74
- * ensuring that expanded URI variable do not have any impact on the
75
- * structure or meaning of the URI.
59
+ * Expand URI variables first, then encode the resulting URI component
60
+ * values, quoting <em>only</em> illegal characters within a given URI
61
+ * component type, but not all characters with reserved meaning.
76
62
*/
77
- VALUES_ONLY ,
63
+ URI_COMPONENT ,
78
64
79
65
/**
80
66
* No encoding should be applied.
81
67
*/
82
- NONE }
68
+ NONE
69
+ }
83
70
84
71
72
+ @ Nullable
85
73
private final UriComponentsBuilder baseUri ;
86
74
87
- private final Map <String , Object > defaultUriVariables = new HashMap <>();
88
-
89
75
private EncodingMode encodingMode = EncodingMode .URI_COMPONENT ;
90
76
77
+ private final Map <String , Object > defaultUriVariables = new HashMap <>();
78
+
91
79
private boolean parsePath = true ;
92
80
93
81
@@ -96,7 +84,7 @@ public enum EncodingMode {
96
84
* <p>The target address must be specified on each UriBuilder.
97
85
*/
98
86
public DefaultUriBuilderFactory () {
99
- this ( UriComponentsBuilder . newInstance ()) ;
87
+ this . baseUri = null ;
100
88
}
101
89
102
90
/**
@@ -109,19 +97,35 @@ public DefaultUriBuilderFactory() {
109
97
* @param baseUriTemplate the URI template to use a base URL
110
98
*/
111
99
public DefaultUriBuilderFactory (String baseUriTemplate ) {
112
- this ( UriComponentsBuilder .fromUriString (baseUriTemplate ) );
100
+ this . baseUri = UriComponentsBuilder .fromUriString (baseUriTemplate );
113
101
}
114
102
115
103
/**
116
104
* Variant of {@link #DefaultUriBuilderFactory(String)} with a
117
105
* {@code UriComponentsBuilder}.
118
106
*/
119
107
public DefaultUriBuilderFactory (UriComponentsBuilder baseUri ) {
120
- Assert .notNull (baseUri , "'baseUri' is required" );
121
108
this .baseUri = baseUri ;
122
109
}
123
110
124
111
112
+ /**
113
+ * Specify the {@link EncodingMode EncodingMode} to use when building URIs.
114
+ * <p>By default set to
115
+ * {@link EncodingMode#URI_COMPONENT EncodingMode.URI_COMPONENT}.
116
+ * @param encodingMode the encoding mode to use
117
+ */
118
+ public void setEncodingMode (EncodingMode encodingMode ) {
119
+ this .encodingMode = encodingMode ;
120
+ }
121
+
122
+ /**
123
+ * Return the configured encoding mode.
124
+ */
125
+ public EncodingMode getEncodingMode () {
126
+ return this .encodingMode ;
127
+ }
128
+
125
129
/**
126
130
* Provide default URI variable values to use when expanding URI templates
127
131
* with a Map of variables.
@@ -142,30 +146,10 @@ public void setDefaultUriVariables(@Nullable Map<String, ?> defaultUriVariables)
142
146
}
143
147
144
148
/**
145
- * Specify the {@link EncodingMode EncodingMode} to use when building URIs.
146
- * <p>By default set to
147
- * {@link EncodingMode#URI_COMPONENT EncodingMode.URI_COMPONENT}.
148
- * @param encodingMode the encoding mode to use
149
- */
150
- public void setEncodingMode (EncodingMode encodingMode ) {
151
- this .encodingMode = encodingMode ;
152
- }
153
-
154
- /**
155
- * Return the configured encoding mode.
156
- */
157
- public EncodingMode getEncodingMode () {
158
- return this .encodingMode ;
159
- }
160
-
161
- /**
162
- * Whether to parse the path into path segments for the URI string passed
163
- * into {@link #uriString(String)} or one of the expand methods.
164
- * <p>Setting this property to {@code true} ensures that URI variables
165
- * expanded into the path are subject to path segment encoding rules and
166
- * "/" characters are percent-encoded. If set to {@code false} the path is
167
- * kept as a full path and expanded URI variables will have "/" characters
168
- * preserved.
149
+ * Whether to parse the input path into path segments if the encoding mode
150
+ * is set to {@link EncodingMode#URI_COMPONENT EncodingMode.URI_COMPONENT},
151
+ * which ensures that URI variables in the path are encoded according to
152
+ * path segment rules and for example a '/' is encoded.
169
153
* <p>By default this is set to {@code true}.
170
154
* @param parsePath whether to parse the path into path segments
171
155
*/
@@ -174,7 +158,8 @@ public void setParsePath(boolean parsePath) {
174
158
}
175
159
176
160
/**
177
- * Whether the handler is configured to parse the path into path segments.
161
+ * Whether to parse the path into path segments if the encoding mode is set
162
+ * to {@link EncodingMode#URI_COMPONENT EncodingMode.URI_COMPONENT}.
178
163
*/
179
164
public boolean shouldParsePath () {
180
165
return this .parsePath ;
@@ -210,30 +195,47 @@ private class DefaultUriBuilder implements UriBuilder {
210
195
211
196
private final UriComponentsBuilder uriComponentsBuilder ;
212
197
198
+
213
199
public DefaultUriBuilder (String uriTemplate ) {
214
200
this .uriComponentsBuilder = initUriComponentsBuilder (uriTemplate );
215
201
}
216
202
217
203
private UriComponentsBuilder initUriComponentsBuilder (String uriTemplate ) {
218
- UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder .fromUriString (uriTemplate );
219
- UriComponents uriComponents = uriComponentsBuilder .build ();
220
- UriComponentsBuilder result = (uriComponents .getHost () == null ?
221
- baseUri .cloneBuilder ().uriComponents (uriComponents ) : uriComponentsBuilder );
222
204
223
- if (shouldParsePath ()) {
205
+ if (StringUtils .isEmpty (uriTemplate )) {
206
+ return baseUri != null ? baseUri .cloneBuilder () : UriComponentsBuilder .newInstance ();
207
+ }
208
+
209
+ UriComponentsBuilder result ;
210
+ if (baseUri != null ) {
211
+ UriComponentsBuilder uricBuilder = UriComponentsBuilder .fromUriString (uriTemplate );
212
+ UriComponents uric = uricBuilder .build ();
213
+ result = uric .getHost () == null ? baseUri .cloneBuilder ().uriComponents (uric ) : uricBuilder ;
214
+ }
215
+ else {
216
+ result = UriComponentsBuilder .fromUriString (uriTemplate );
217
+ }
218
+
219
+ parsePathIfNecessary (result );
220
+
221
+ return result ;
222
+ }
223
+
224
+ private void parsePathIfNecessary (UriComponentsBuilder result ) {
225
+ if (shouldParsePath () && encodingMode .equals (EncodingMode .URI_COMPONENT )) {
224
226
UriComponents uric = result .build ();
225
227
String path = uric .getPath ();
226
- List <String > pathSegments = uric .getPathSegments ();
227
228
result .replacePath (null );
228
- result .pathSegment (StringUtils .toStringArray (pathSegments ));
229
+ for (String segment : uric .getPathSegments ()) {
230
+ result .pathSegment (segment );
231
+ }
229
232
if (path != null && path .endsWith ("/" )) {
230
233
result .path ("/" );
231
234
}
232
235
}
233
-
234
- return result ;
235
236
}
236
237
238
+
237
239
@ Override
238
240
public DefaultUriBuilder scheme (@ Nullable String scheme ) {
239
241
this .uriComponentsBuilder .scheme (scheme );
@@ -335,11 +337,8 @@ public URI build(Map<String, ?> uriVars) {
335
337
if (encodingMode .equals (EncodingMode .VALUES_ONLY )) {
336
338
uriVars = UriUtils .encodeUriVariables (uriVars );
337
339
}
338
- UriComponents uriComponents = this .uriComponentsBuilder .build ().expand (uriVars );
339
- if (encodingMode .equals (EncodingMode .URI_COMPONENT )) {
340
- uriComponents = uriComponents .encode ();
341
- }
342
- return URI .create (uriComponents .toString ());
340
+ UriComponents uric = this .uriComponentsBuilder .build ().expand (uriVars );
341
+ return createUri (uric );
343
342
}
344
343
345
344
@ Override
@@ -350,11 +349,15 @@ public URI build(Object... uriVars) {
350
349
if (encodingMode .equals (EncodingMode .VALUES_ONLY )) {
351
350
uriVars = UriUtils .encodeUriVariables (uriVars );
352
351
}
353
- UriComponents uriComponents = this .uriComponentsBuilder .build ().expand (uriVars );
352
+ UriComponents uric = this .uriComponentsBuilder .build ().expand (uriVars );
353
+ return createUri (uric );
354
+ }
355
+
356
+ private URI createUri (UriComponents uric ) {
354
357
if (encodingMode .equals (EncodingMode .URI_COMPONENT )) {
355
- uriComponents = uriComponents .encode ();
358
+ uric = uric .encode ();
356
359
}
357
- return URI .create (uriComponents .toString ());
360
+ return URI .create (uric .toString ());
358
361
}
359
362
}
360
363
0 commit comments