Skip to content
This repository was archived by the owner on Mar 3, 2026. It is now read-only.

Commit cb72e73

Browse files
committed
Surprising param encoding fix jooby-project#900
1 parent fba40aa commit cb72e73

File tree

6 files changed

+46
-4
lines changed

6 files changed

+46
-4
lines changed

jooby/src/main/java/org/jooby/Router.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,13 +203,17 @@
203203
*/
204204
package org.jooby;
205205

206+
import java.net.URLDecoder;
206207
import java.nio.file.Path;
207208
import java.util.Optional;
208209
import java.util.concurrent.Executor;
209210
import java.util.function.Consumer;
210211
import java.util.function.Predicate;
211212

213+
import com.google.common.escape.Escaper;
214+
import com.google.common.net.PercentEscaper;
212215
import org.jooby.Route.Mapper;
216+
import org.jooby.funzy.Try;
213217
import org.jooby.handlers.AssetHandler;
214218

215219
import javax.annotation.Nonnull;
@@ -222,6 +226,16 @@
222226
*/
223227
public interface Router {
224228

229+
/**
230+
* Decode a path by delegating to {@link URLDecoder#decode(String, String)}. This function keeps
231+
* the <code>+</code> character.
232+
*
233+
* @param path Path to decoded.
234+
*/
235+
static String decode(String path) {
236+
return Try.apply(() -> URLDecoder.decode(path.replace("+", "%2b"), "UTF-8")).get();
237+
}
238+
225239
/**
226240
* Import content from provide application (routes, parsers/renderers, start/stop callbacks, ...
227241
* etc.).

modules/coverage-report/src/test/java/org/jooby/PathVarMustBeDecodedFeature.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ public void pathVarShouldBeDecoded() throws Exception {
1717

1818
request()
1919
.get("/plus+plus")
20-
.expect("plus plus");
20+
.expect("plus+plus");
2121
}
2222
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.jooby.issues;
2+
3+
import org.jooby.test.ServerFeature;
4+
import org.junit.Test;
5+
6+
import java.net.URLEncoder;
7+
8+
public class Issue900 extends ServerFeature {
9+
10+
{
11+
caseSensitiveRouting(false);
12+
13+
get("/900/:code", req -> req.param("code").value());
14+
}
15+
16+
@Test
17+
public void shouldNotEncodingPlusSign() throws Exception {
18+
int ch = '+';
19+
System.out.println(Integer.toHexString(ch));
20+
request().get("/900/a+b")
21+
.expect("a+b");
22+
}
23+
24+
}

modules/jooby-netty/src/main/java/org/jooby/internal/netty/NettyRequest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@
203203
*/
204204
package org.jooby.internal.netty;
205205

206+
import com.google.common.escape.Escapers;
206207
import static io.netty.channel.ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE;
207208

208209
import java.io.IOException;
@@ -217,6 +218,7 @@
217218
import java.util.stream.Collectors;
218219

219220
import org.jooby.MediaType;
221+
import org.jooby.Router;
220222
import org.jooby.Sse;
221223
import org.jooby.spi.NativePushPromise;
222224
import org.jooby.spi.NativeRequest;
@@ -290,7 +292,7 @@ public NettyRequest(final ChannelHandlerContext ctx,
290292
this.req = req;
291293
this.tmpdir = tmpdir;
292294
this.query = new QueryStringDecoder(req.uri());
293-
this.path = URLDecoder.decode(query.path(), "UTF-8");
295+
this.path = Router.decode(query.path());
294296
this.wsMaxMessageSize = wsMaxMessageSize;
295297
Channel channel = ctx.channel();
296298
channel.attr(ASYNC).set(false);

modules/jooby-servlet/src/main/java/org/jooby/servlet/ServletServletRequest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@
223223

224224
import org.jooby.Cookie;
225225
import org.jooby.MediaType;
226+
import org.jooby.Router;
226227
import org.jooby.spi.NativeRequest;
227228
import org.jooby.spi.NativeUpload;
228229

@@ -251,7 +252,7 @@ public ServletServletRequest(final HttpServletRequest req, final String tmpdir,
251252
if (pathInfo == null) {
252253
pathInfo = "/";
253254
}
254-
this.path = req.getContextPath() + URLDecoder.decode(pathInfo, "UTF-8");
255+
this.path = req.getContextPath() + Router.decode(pathInfo);
255256
}
256257

257258
public HttpServletRequest servletRequest() {

modules/jooby-undertow/src/main/java/org/jooby/internal/undertow/UndertowRequest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@
217217

218218
import org.jooby.Cookie;
219219
import org.jooby.MediaType;
220+
import org.jooby.Router;
220221
import org.jooby.Sse;
221222
import org.jooby.spi.NativePushPromise;
222223
import org.jooby.spi.NativeRequest;
@@ -260,7 +261,7 @@ public UndertowRequest(final HttpServerExchange exchange, final Config conf) thr
260261
this.exchange = exchange;
261262
this.blocking = Suppliers.memoize(() -> this.exchange.startBlocking());
262263
this.conf = conf;
263-
this.path = URLDecoder.decode(exchange.getRequestPath(), "UTF-8");
264+
this.path = Router.decode(exchange.getRequestPath());
264265
}
265266

266267
@Override

0 commit comments

Comments
 (0)