diff --git a/core/src/main/java/io/undertow/server/protocol/http/HttpRequestParser.java b/core/src/main/java/io/undertow/server/protocol/http/HttpRequestParser.java
index ab4e543ef..a37f59a0a 100644
--- a/core/src/main/java/io/undertow/server/protocol/http/HttpRequestParser.java
+++ b/core/src/main/java/io/undertow/server/protocol/http/HttpRequestParser.java
@@ -18,6 +18,7 @@
 
 package io.undertow.server.protocol.http;
 
+import java.io.ByteArrayOutputStream;
 import java.io.UnsupportedEncodingException;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
@@ -372,18 +373,20 @@ public abstract class HttpRequestParser {
     @SuppressWarnings("unused")
     final void handlePath(ByteBuffer buffer, ParseState state, HttpServerExchange exchange) throws BadRequestException {
         StringBuilder stringBuilder = state.stringBuilder;
+        ByteArrayOutputStream baos = state.baos;
         int parseState = state.parseState;
         int canonicalPathStart = state.pos;
         boolean urlDecodeRequired = state.urlDecodeRequired;
 
         while (buffer.hasRemaining()) {
-            char next = (char) (buffer.get() & 0xFF);
+            byte raw = buffer.get();
+            char next = (char) (raw & 0xFF);
             if(!allowUnescapedCharactersInUrl && !ALLOWED_TARGET_CHARACTER[next]) {
                 throw new BadRequestException(UndertowMessages.MESSAGES.invalidCharacterInRequestTarget(next));
             }
             if (next == ' ' || next == '\t') {
-                if (stringBuilder.length() != 0) {
-                    final String path = stringBuilder.toString();
+                if (baos.size() != 0) {
+                    final String path = new String(baos.toByteArray());
                     if(parseState == SECOND_SLASH) {
                         exchange.setRequestPath("/");
                         exchange.setRelativePath("/");
@@ -399,6 +402,7 @@ public abstract class HttpRequestParser {
                     exchange.setQueryString("");
                     state.state = ParseState.VERSION;
                     state.stringBuilder.setLength(0);
+                    state.baos.reset();
                     state.parseState = 0;
                     state.pos = 0;
                     state.urlDecodeRequired = false;
@@ -425,13 +429,14 @@ public abstract class HttpRequestParser {
                     parseState = SECOND_SLASH;
                 } else if (next == '/' && parseState == SECOND_SLASH) {
                     parseState = HOST_DONE;
-                    canonicalPathStart = stringBuilder.length();
+                    canonicalPathStart = baos.size();
                 } else if (parseState == FIRST_COLON || parseState == FIRST_SLASH) {
                     parseState = IN_PATH;
                 } else if (next == '/' && parseState != HOST_DONE) {
                     parseState = IN_PATH;
                 }
                 stringBuilder.append(next);
+                baos.write(raw & 0xFF);
             }
 
         }
@@ -465,7 +470,7 @@ public abstract class HttpRequestParser {
     }
 
     private void beginQueryParameters(ByteBuffer buffer, ParseState state, HttpServerExchange exchange, StringBuilder stringBuilder, int parseState, int canonicalPathStart, boolean urlDecodeRequired) throws BadRequestException {
-        final String path = stringBuilder.toString();
+        final String path = new String(state.baos.toByteArray());
         if (parseState == SECOND_SLASH) {
             exchange.setRequestPath("/");
             exchange.setRelativePath("/");
@@ -480,6 +485,7 @@ public abstract class HttpRequestParser {
         }
         state.state = ParseState.QUERY_PARAMETERS;
         state.stringBuilder.setLength(0);
+        state.baos.reset();
         state.parseState = 0;
         state.pos = 0;
         state.urlDecodeRequired = false;
@@ -505,6 +511,7 @@ public abstract class HttpRequestParser {
     @SuppressWarnings("unused")
     final void handleQueryParameters(ByteBuffer buffer, ParseState state, HttpServerExchange exchange) throws BadRequestException {
         StringBuilder stringBuilder = state.stringBuilder;
+        ByteArrayOutputStream baos = state.baos;
         int queryParamPos = state.pos;
         int mapCount = state.mapCount;
         boolean urlDecodeRequired = state.urlDecodeRequired;
@@ -518,23 +525,25 @@ public abstract class HttpRequestParser {
         //we encounter an encoded character
 
         while (buffer.hasRemaining()) {
-            char next = (char) (buffer.get() & 0xFF);
+            byte raw = buffer.get();
+            char next = (char) (raw & 0xFF);
             if(!allowUnescapedCharactersInUrl && !ALLOWED_TARGET_CHARACTER[next]) {
                 throw new BadRequestException(UndertowMessages.MESSAGES.invalidCharacterInRequestTarget(next));
             }
             if (next == ' ' || next == '\t') {
-                final String queryString = stringBuilder.toString();
+                final String queryString = new String(baos.toByteArray());
                 exchange.setQueryString(queryString);
                 if (nextQueryParam == null) {
-                    if (queryParamPos != stringBuilder.length()) {
-                        exchange.addQueryParam(decode(stringBuilder.substring(queryParamPos), urlDecodeRequired, state, true, true), "");
+                    if (queryParamPos != baos.size()) {
+                        exchange.addQueryParam(decode(new String(baos.toByteArray()).substring(queryParamPos), urlDecodeRequired, state, true, true), "");
                     }
                 } else {
-                    exchange.addQueryParam(nextQueryParam, decode(stringBuilder.substring(queryParamPos), urlDecodeRequired, state, true, true));
+                    exchange.addQueryParam(nextQueryParam, decode(new String(baos.toByteArray()).substring(queryParamPos), urlDecodeRequired, state, true, true));
                 }
                 state.state = ParseState.VERSION;
                 state.stringBuilder.setLength(0);
                 state.pos = 0;
+                state.baos.reset();
                 state.nextQueryParam = null;
                 state.urlDecodeRequired = false;
                 state.mapCount = 0;
@@ -545,29 +554,29 @@ public abstract class HttpRequestParser {
                 if (decode && (next == '+' || next == '%' || next > 127)) { //+ is only a whitespace substitute in the query part of the URL
                     urlDecodeRequired = true;
                 } else if (next == '=' && nextQueryParam == null) {
-                    nextQueryParam = decode(stringBuilder.substring(queryParamPos), urlDecodeRequired, state, true, true);
+                    nextQueryParam = decode(new String(baos.toByteArray()).substring(queryParamPos), urlDecodeRequired, state, true, true);
                     urlDecodeRequired = false;
-                    queryParamPos = stringBuilder.length() + 1;
+                    queryParamPos = baos.size() + 1;
                 } else if (next == '&' && nextQueryParam == null) {
                     if (++mapCount >= maxParameters) {
                         throw UndertowMessages.MESSAGES.tooManyQueryParameters(maxParameters);
                     }
-                    if (queryParamPos != stringBuilder.length()) {
-                        exchange.addQueryParam(decode(stringBuilder.substring(queryParamPos), urlDecodeRequired, state, true, true), "");
+                    if (queryParamPos != baos.size()) {
+                        exchange.addQueryParam(decode(new String(baos.toByteArray()).substring(queryParamPos), urlDecodeRequired, state, true, true), "");
                     }
                     urlDecodeRequired = false;
-                    queryParamPos = stringBuilder.length() + 1;
+                    queryParamPos = baos.size() + 1;
                 } else if (next == '&') {
                     if (++mapCount >= maxParameters) {
                         throw UndertowMessages.MESSAGES.tooManyQueryParameters(maxParameters);
                     }
-                    exchange.addQueryParam(nextQueryParam, decode(stringBuilder.substring(queryParamPos), urlDecodeRequired, state, true, true));
+                    exchange.addQueryParam(nextQueryParam, decode(new String(baos.toByteArray()).substring(queryParamPos), urlDecodeRequired, state, true, true));
                     urlDecodeRequired = false;
-                    queryParamPos = stringBuilder.length() + 1;
+                    queryParamPos = baos.size() + 1;
                     nextQueryParam = null;
                 }
                 stringBuilder.append(next);
-
+                baos.write(raw & 0xFF);
             }
 
         }
@@ -588,6 +597,7 @@ public abstract class HttpRequestParser {
 
     final void handlePathParameters(ByteBuffer buffer, ParseState state, HttpServerExchange exchange) throws BadRequestException {
         StringBuilder stringBuilder = state.stringBuilder;
+        ByteArrayOutputStream baos = state.baos;
         int queryParamPos = state.pos;
         int mapCount = state.mapCount;
         boolean urlDecodeRequired = state.urlDecodeRequired;
@@ -601,20 +611,22 @@ public abstract class HttpRequestParser {
         //we encounter an encoded character
 
         while (buffer.hasRemaining()) {
-            char next = (char) (buffer.get() & 0xFF);
+            byte raw = buffer.get();
+            char next = (char) (raw & 0xFF);
             if(!allowUnescapedCharactersInUrl && !ALLOWED_TARGET_CHARACTER[next]) {
                 throw new BadRequestException(UndertowMessages.MESSAGES.invalidCharacterInRequestTarget(next));
             }
             if (next == ' ' || next == '\t' || next == '?') {
                 if (nextQueryParam == null) {
-                    if (queryParamPos != stringBuilder.length()) {
-                        exchange.addPathParam(decode(stringBuilder.substring(queryParamPos), urlDecodeRequired, state, true, true), "");
+                    if (queryParamPos != baos.size()) {
+                        exchange.addPathParam(decode(new String(baos.toByteArray()).substring(queryParamPos), urlDecodeRequired, state, true, true), "");
                     }
                 } else {
-                    exchange.addPathParam(nextQueryParam, decode(stringBuilder.substring(queryParamPos), urlDecodeRequired, state, true, true));
+                    exchange.addPathParam(nextQueryParam, decode(new String(baos.toByteArray()).substring(queryParamPos), urlDecodeRequired, state, true, true));
                 }
-                exchange.setRequestURI(exchange.getRequestURI() + ';' + stringBuilder.toString(), state.parseState > HOST_DONE);
+                exchange.setRequestURI(exchange.getRequestURI() + ';' + new String(baos.toByteArray()), state.parseState > HOST_DONE);
                 state.stringBuilder.setLength(0);
+                state.baos.reset();
                 state.pos = 0;
                 state.nextQueryParam = null;
                 state.mapCount = 0;
@@ -633,28 +645,28 @@ public abstract class HttpRequestParser {
                     urlDecodeRequired = true;
                 }
                 if (next == '=' && nextQueryParam == null) {
-                    nextQueryParam = decode(stringBuilder.substring(queryParamPos), urlDecodeRequired, state, true, true);
+                    nextQueryParam = decode(new String(baos.toByteArray()).substring(queryParamPos), urlDecodeRequired, state, true, true);
                     urlDecodeRequired = false;
-                    queryParamPos = stringBuilder.length() + 1;
+                    queryParamPos = baos.size() + 1;
                 } else if (next == '&' && nextQueryParam == null) {
                     if (++mapCount >= maxParameters) {
                         throw UndertowMessages.MESSAGES.tooManyQueryParameters(maxParameters);
                     }
-                    exchange.addPathParam(decode(stringBuilder.substring(queryParamPos), urlDecodeRequired, state, true, true), "");
+                    exchange.addPathParam(decode(new String(baos.toByteArray()).substring(queryParamPos), urlDecodeRequired, state, true, true), "");
                     urlDecodeRequired = false;
-                    queryParamPos = stringBuilder.length() + 1;
+                    queryParamPos = baos.size() + 1;
                 } else if (next == '&') {
                     if (++mapCount >= maxParameters) {
                         throw UndertowMessages.MESSAGES.tooManyQueryParameters(maxParameters);
                     }
 
-                    exchange.addPathParam(nextQueryParam, decode(stringBuilder.substring(queryParamPos), urlDecodeRequired, state, true, true));
+                    exchange.addPathParam(nextQueryParam, decode(new String(baos.toByteArray()).substring(queryParamPos), urlDecodeRequired, state, true, true));
                     urlDecodeRequired = false;
-                    queryParamPos = stringBuilder.length() + 1;
+                    queryParamPos = baos.size() + 1;
                     nextQueryParam = null;
                 }
                 stringBuilder.append(next);
-
+                baos.write(raw & 0xFF);
             }
 
         }
diff --git a/core/src/main/java/io/undertow/server/protocol/http/ParseState.java b/core/src/main/java/io/undertow/server/protocol/http/ParseState.java
index 1efa9e100..90c383e89 100644
--- a/core/src/main/java/io/undertow/server/protocol/http/ParseState.java
+++ b/core/src/main/java/io/undertow/server/protocol/http/ParseState.java
@@ -18,6 +18,8 @@
 
 package io.undertow.server.protocol.http;
 
+import java.io.ByteArrayOutputStream;
+
 import io.undertow.util.HttpString;
 
 /**
@@ -80,7 +82,7 @@ class ParseState {
      * If this is in {@link io.undertow.annotationprocessor.AbstractParserGenerator#NO_STATE} then this holds the current token that has been read so far.
      */
     final StringBuilder stringBuilder = new StringBuilder();
-
+    final ByteArrayOutputStream baos = new ByteArrayOutputStream();
     /**
      * This has different meanings depending on the current state.
      *
@@ -140,5 +142,6 @@ class ParseState {
         this.nextHeader = null;
         this.nextQueryParam = null;
         this.mapCount = 0;
+        this.baos.reset();
     }
 }
