1616package io .fusionauth .http .util ;
1717
1818import java .io .ByteArrayInputStream ;
19+ import java .io .ByteArrayOutputStream ;
1920import java .net .URLEncoder ;
2021import java .nio .charset .Charset ;
2122import java .nio .charset .StandardCharsets ;
2627import java .util .Map ;
2728
2829import com .inversoft .json .ToString ;
30+ import io .fusionauth .http .BaseTest ;
2931import io .fusionauth .http .HTTPMethod ;
3032import io .fusionauth .http .io .PushbackInputStream ;
3133import io .fusionauth .http .server .HTTPRequest ;
4244 * @author Brian Pontarelli
4345 */
4446@ Test
45- public class HTTPToolsTest {
47+ public class HTTPToolsTest extends BaseTest {
4648 @ Test
4749 public void getMaxRequestBodySize () {
4850 var configuration = Map .of (
@@ -183,16 +185,18 @@ public void parseHeaderValue() {
183185 assertEquals (HTTPTools .parseHeaderValue ("value; f= f" ), new HeaderValue ("value" , Map .of ("f" , " f" )));
184186 }
185187
186- @ Test
187- public void parsePreamble () throws Exception {
188+ @ Test ( dataProvider = "contentEncoding" )
189+ public void parsePreamble (String contentEncoding ) throws Exception {
188190 // Ensure that we can correctly read the preamble when the InputStream contains the next request.
191+ // - Optionally compress the body to ensure we can push back bytes on the preamble read w/out hosing it up.
189192
190- //noinspection ExtractMethodRecommender
191- String request = """
193+ ByteArrayOutputStream out = new ByteArrayOutputStream ();
194+ String header = """
192195 GET / HTTP/1.1\r
193196 Host: localhost:42\r
194197 Connection: close\r
195- Content-Length: 113\r
198+ Content-Encoding: {contentEncoding}\r
199+ Content-Length: {contentLength}\r
196200 Header1: Value1\r
197201 Header2: Value2\r
198202 Header3: Value3\r
@@ -204,17 +208,31 @@ public void parsePreamble() throws Exception {
204208 Header9: Value9\r
205209 Header10: Value10\r
206210 \r
207- These pretzels are making me thirsty. These pretzels are making me thirsty. These pretzels are making me thirsty.GET / HTTP/1.1\r
208- """ ;
211+ """ .replace ("{contentEncoding}" , contentEncoding );
212+
213+ // Now add the body, optionally compressed
214+ String body = "These pretzels are making me thirsty. These pretzels are making me thirsty. These pretzels are making me thirsty." ;
215+ byte [] bodyBytes = body .getBytes (StandardCharsets .UTF_8 );
216+ int uncompressedBodyLength = bodyBytes .length ;
217+ bodyBytes = compressUsingContentEncoding (bodyBytes , contentEncoding );
218+
219+ header = header .replace ("{contentLength}" , bodyBytes .length + "" );
220+ out .write (header .getBytes (StandardCharsets .UTF_8 ));
221+ out .write (bodyBytes );
222+
223+ // Now add part of the next request
224+ String nextRequest = "GET / HTTP/1.1\n \r " ;
225+ byte [] nextRequestBytes = nextRequest .getBytes (StandardCharsets .UTF_8 );
226+ out .write (nextRequestBytes );
209227
210228 // Fixed length body with the start of the next request in the buffer
211- byte [] bytes = request . getBytes ( StandardCharsets . UTF_8 );
212- int bytesAvailable = bytes .length ;
229+ byte [] payload = out . toByteArray ( );
230+ int bytesAvailable = payload .length ;
213231
214232 // Ensure the request buffer size will contain the entire request.
215233 HTTPServerConfiguration configuration = new HTTPServerConfiguration ().withRequestBufferSize (bytesAvailable + 100 );
216234
217- ByteArrayInputStream is = new ByteArrayInputStream (bytes );
235+ ByteArrayInputStream is = new ByteArrayInputStream (payload );
218236 PushbackInputStream pushbackInputStream = new PushbackInputStream (is , null );
219237
220238 HTTPRequest httpRequest = new HTTPRequest ();
@@ -229,37 +247,38 @@ public void parsePreamble() throws Exception {
229247 assertEquals (httpRequest .getMethod (), HTTPMethod .GET );
230248 assertEquals (httpRequest .getHost (), "localhost" );
231249 assertEquals (httpRequest .getPort (), 42 );
232- assertEquals (httpRequest .getContentLength (), 113 );
233- assertEquals (httpRequest .getHeaders ().size (), 13 );
234- assertEquals (httpRequest .getHeader ("Content-Length" ), "113" );
250+ assertEquals (httpRequest .getContentLength (), bodyBytes .length );
251+ assertEquals (httpRequest .getHeaders ().size (), contentEncoding .isEmpty () ? 13 : 14 );
252+ assertEquals (httpRequest .getHeader ("Content-Encoding" ), contentEncoding .isEmpty () ? null : contentEncoding );
253+ assertEquals (httpRequest .getHeader ("Content-Length" ), bodyBytes .length + "" );
235254 assertEquals (httpRequest .getHeader ("Connection" ), "close" );
236255 assertEquals (httpRequest .getHeader ("Host" ), "localhost:42" );
237256 for (int i = 1 ; i <= 10 ; i ++) {
238257 assertEquals (httpRequest .getHeader ("Header" + i ), "Value" + i );
239258 }
240259
241- // Expect 129 bytes left over which is 113 for the body + 16 from the next request
242- assertEquals (pushbackInputStream .getAvailableBufferedBytesRemaining (), 113 + 16 );
260+ // Expect that the body bytes and the next request have been pushed into the pushback buffer
261+ assertEquals (pushbackInputStream .getAvailableBufferedBytesRemaining (), bodyBytes . length + nextRequestBytes . length );
243262
244263 // Read the remaining bytes for this request, we should still have some left over.
245264 HTTPInputStream httpInputStream = new HTTPInputStream (configuration , httpRequest , pushbackInputStream , -1 );
246265 byte [] buffer = new byte [1024 ];
247266 int read = httpInputStream .read (buffer );
248- assertEquals (read , 113 );
267+ assertEquals (read , uncompressedBodyLength );
249268
250269 // Another read should return -1 because we are at the end of this request.
251270 int nextRead = httpInputStream .read (buffer );
252271 assertEquals (nextRead , -1 );
253272
254273 // The next read from the pushback which will be used by the next request should return the remaining bytes.
255- assertEquals (pushbackInputStream .getAvailableBufferedBytesRemaining (), 16 );
274+ assertEquals (pushbackInputStream .getAvailableBufferedBytesRemaining (), nextRequestBytes . length );
256275 int nextRequestRead = pushbackInputStream .read (buffer );
257- assertEquals (nextRequestRead , 16 );
276+ // Expect that we are able to read the bytes for the next request header
277+ assertEquals (nextRequestRead , nextRequestBytes .length );
258278 }
259279
260280 private void assertEncodedData (String actualValue , String expectedValue , Charset charset ) {
261281 assertEncodedData (actualValue , expectedValue , charset , charset );
262-
263282 }
264283
265284 private void assertEncodedData (String actualValue , String expectedValue , Charset encodingCharset , Charset decodingCharset ) {
0 commit comments