=htp #20915 fix too small timing issue in DirectivesSpec (#20916)

* =htp #20915 fix too small timing issue in DirectivesSpec

* applying scalariform reformatting that keeps popping up
This commit is contained in:
Konrad Malawski 2016-07-08 10:33:32 +02:00 committed by GitHub
parent b4cd30cf94
commit 54ecf32d2b
7 changed files with 119 additions and 113 deletions

View file

@ -14,6 +14,9 @@ import akka.stream.javadsl.Source;
import akka.util.ByteString; import akka.util.ByteString;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import scala.concurrent.duration.Duration;
import scala.concurrent.duration.FiniteDuration;
import java.io.File; import java.io.File;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.file.Files; import java.nio.file.Files;
@ -21,114 +24,117 @@ import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.CompletionStage; import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction; import java.util.function.BiFunction;
public class FileUploadDirectivesExamplesTest extends JUnitRouteTest { public class FileUploadDirectivesExamplesTest extends JUnitRouteTest {
@Test @Test
public void testUploadedFile() { public void testUploadedFile() {
//#uploadedFile //#uploadedFile
// function (FileInfo, File) => Route to process the file metadata and file itself // function (FileInfo, File) => Route to process the file metadata and file itself
BiFunction<FileInfo, File, Route> infoFileRoute = BiFunction<FileInfo, File, Route> infoFileRoute =
(info, file) -> { (info, file) -> {
// do something with the file and file metadata ... // do something with the file and file metadata ...
file.delete(); file.delete();
return complete(StatusCodes.OK); return complete(StatusCodes.OK);
}; };
final Route route = uploadedFile("csv", infoFileRoute); final Route route = uploadedFile("csv", infoFileRoute);
Map<String, String> filenameMapping = new HashMap<>(); Map<String, String> filenameMapping = new HashMap<>();
filenameMapping.put("filename", "data.csv"); filenameMapping.put("filename", "data.csv");
akka.http.javadsl.model.Multipart.FormData multipartForm = akka.http.javadsl.model.Multipart.FormData multipartForm =
Multiparts.createStrictFormDataFromParts(Multiparts.createFormDataBodyPartStrict("csv", Multiparts.createStrictFormDataFromParts(Multiparts.createFormDataBodyPartStrict("csv",
HttpEntities.create(ContentTypes.TEXT_PLAIN_UTF8, HttpEntities.create(ContentTypes.TEXT_PLAIN_UTF8,
"1,5,7\n11,13,17"), filenameMapping)); "1,5,7\n11,13,17"), filenameMapping));
// test: // test:
testRoute(route).run(HttpRequest.POST("/").withEntity( testRoute(route).run(HttpRequest.POST("/")
multipartForm.toEntity(HttpCharsets.UTF_8, BodyPartRenderer .withEntity(
.randomBoundaryWithDefaults()))) multipartForm.toEntity(HttpCharsets.UTF_8,
.assertStatusCode(StatusCodes.OK); BodyPartRenderer
//# .randomBoundaryWithDefaults())))
.assertStatusCode(StatusCodes.OK);
//#
}
@Test
public void testFileUpload() {
//#fileUpload
final Route route = extractRequestContext(ctx -> {
// function (FileInfo, Source<ByteString,Object>) => Route to process the file contents
BiFunction<FileInfo, Source<ByteString, Object>, Route> processUploadedFile =
(metadata, byteSource) -> {
CompletionStage<Integer> sumF = byteSource.via(Framing.delimiter(
ByteString.fromString("\n"), 1024))
.mapConcat(bs -> Arrays.asList(bs.utf8String().split(",")))
.map(s -> Integer.parseInt(s))
.runFold(0, (acc, n) -> acc + n, ctx.getMaterializer());
return onSuccess(() -> sumF, sum -> complete("Sum: " + sum));
};
return fileUpload("csv", processUploadedFile);
});
Map<String, String> filenameMapping = new HashMap<>();
filenameMapping.put("filename", "primes.csv");
akka.http.javadsl.model.Multipart.FormData multipartForm =
Multiparts.createStrictFormDataFromParts(
Multiparts.createFormDataBodyPartStrict("csv",
HttpEntities.create(ContentTypes.TEXT_PLAIN_UTF8,
"2,3,5\n7,11,13,17,23\n29,31,37\n"), filenameMapping));
// test:
testRoute(route).run(HttpRequest.POST("/").withEntity(
multipartForm.toEntity(HttpCharsets.UTF_8, BodyPartRenderer.randomBoundaryWithDefaults())))
.assertStatusCode(StatusCodes.OK).assertEntityAs(Unmarshaller.entityToString(), "Sum: 178");
//#
}
@Ignore("compileOnly")
@Test
public void testFileProcessing() {
//#fileProcessing
final Route route = extractRequestContext(ctx -> {
// function (FileInfo, Source<ByteString,Object>) => Route to process the file contents
BiFunction<FileInfo, Source<ByteString, Object>, Route> processUploadedFile =
(metadata, byteSource) -> {
CompletionStage<Integer> sumF = byteSource.via(Framing.delimiter(
ByteString.fromString("\n"), 1024))
.mapConcat(bs -> Arrays.asList(bs.utf8String().split(",")))
.map(s -> Integer.parseInt(s))
.runFold(0, (acc, n) -> acc + n, ctx.getMaterializer());
return onSuccess(() -> sumF, sum -> complete("Sum: " + sum));
};
return fileUpload("csv", processUploadedFile);
});
Map<String, String> filenameMapping = new HashMap<>();
filenameMapping.put("filename", "primes.csv");
String prefix = "primes";
String suffix = ".csv";
File tempFile = null;
try {
tempFile = File.createTempFile(prefix, suffix);
tempFile.deleteOnExit();
Files.write(tempFile.toPath(), Arrays.asList("2,3,5", "7,11,13,17,23", "29,31,37"), Charset.forName("UTF-8"));
} catch (Exception e) {
// ignore
} }
@Test
public void testFileUpload() {
//#fileUpload
final Route route = extractRequestContext(ctx -> {
// function (FileInfo, Source<ByteString,Object>) => Route to process the file contents
BiFunction<FileInfo, Source<ByteString, Object>, Route> processUploadedFile =
(metadata, byteSource) -> {
CompletionStage<Integer> sumF = byteSource.via(Framing.delimiter(
ByteString.fromString("\n"), 1024))
.mapConcat(bs -> Arrays.asList(bs.utf8String().split(",")))
.map(s -> Integer.parseInt(s))
.runFold(0, (acc, n) -> acc + n, ctx.getMaterializer());
return onSuccess(() -> sumF, sum -> complete("Sum: " + sum));
};
return fileUpload("csv", processUploadedFile);
});
Map<String, String> filenameMapping = new HashMap<>(); akka.http.javadsl.model.Multipart.FormData multipartForm =
filenameMapping.put("filename", "primes.csv"); Multiparts.createFormDataFromPath("csv", ContentTypes.TEXT_PLAIN_UTF8, tempFile.toPath());
akka.http.javadsl.model.Multipart.FormData multipartForm = // test:
Multiparts.createStrictFormDataFromParts( testRoute(route).run(HttpRequest.POST("/").withEntity(
Multiparts.createFormDataBodyPartStrict("csv", multipartForm.toEntity(HttpCharsets.UTF_8, BodyPartRenderer.randomBoundaryWithDefaults())))
HttpEntities.create(ContentTypes.TEXT_PLAIN_UTF8, .assertStatusCode(StatusCodes.OK).assertEntityAs(Unmarshaller.entityToString(), "Sum: 178");
"2,3,5\n7,11,13,17,23\n29,31,37\n"), filenameMapping)); //#
}
// test:
testRoute(route).run(HttpRequest.POST("/").withEntity(
multipartForm.toEntity(HttpCharsets.UTF_8, BodyPartRenderer.randomBoundaryWithDefaults())))
.assertStatusCode(StatusCodes.OK).assertEntityAs(Unmarshaller.entityToString(), "Sum: 178");
//#
}
@Ignore("compileOnly")
@Test
public void testFileProcessing() {
//#fileProcessing
final Route route = extractRequestContext(ctx -> {
// function (FileInfo, Source<ByteString,Object>) => Route to process the file contents
BiFunction<FileInfo, Source<ByteString, Object>, Route> processUploadedFile =
(metadata, byteSource) -> {
CompletionStage<Integer> sumF = byteSource.via(Framing.delimiter(
ByteString.fromString("\n"), 1024))
.mapConcat(bs -> Arrays.asList(bs.utf8String().split(",")))
.map(s -> Integer.parseInt(s))
.runFold(0, (acc, n) -> acc + n, ctx.getMaterializer());
return onSuccess(() -> sumF, sum -> complete("Sum: " + sum));
};
return fileUpload("csv", processUploadedFile);
});
Map<String, String> filenameMapping = new HashMap<>();
filenameMapping.put("filename", "primes.csv");
String prefix = "primes";
String suffix = ".csv";
File tempFile = null;
try {
tempFile = File.createTempFile(prefix, suffix);
tempFile.deleteOnExit();
Files.write(tempFile.toPath(), Arrays.asList("2,3,5", "7,11,13,17,23", "29,31,37"), Charset.forName("UTF-8"));
} catch (Exception e) {
// ignore
}
akka.http.javadsl.model.Multipart.FormData multipartForm =
Multiparts.createFormDataFromPath("csv", ContentTypes.TEXT_PLAIN_UTF8, tempFile.toPath());
// test:
testRoute(route).run(HttpRequest.POST("/").withEntity(
multipartForm.toEntity(HttpCharsets.UTF_8, BodyPartRenderer.randomBoundaryWithDefaults())))
.assertStatusCode(StatusCodes.OK).assertEntityAs(Unmarshaller.entityToString(), "Sum: 178");
//#
}
} }

View file

@ -53,7 +53,7 @@ class ActorWithArgs(arg: String) extends Actor {
//#actor-with-value-class-argument //#actor-with-value-class-argument
class Argument(val value: String) extends AnyVal class Argument(val value: String) extends AnyVal
class ValueClassActor(arg: Argument) extends Actor { class ValueClassActor(arg: Argument) extends Actor {
def receive = {case _ => () } def receive = { case _ => () }
} }
object ValueClassActor { object ValueClassActor {

View file

@ -416,8 +416,8 @@ private[http] object HttpServerBluePrint {
if (isEarlyResponse && response.status.isSuccess) if (isEarlyResponse && response.status.isSuccess)
log.warning( log.warning(
"Sending an 2xx 'early' response before end of request was received... " + "Sending an 2xx 'early' response before end of request was received... " +
"Note that the connection will be closed after this response. Also, many clients will not read early responses! " + "Note that the connection will be closed after this response. Also, many clients will not read early responses! " +
"Consider only issuing this response after the request data has been completely read!") "Consider only issuing this response after the request data has been completely read!")
val close = requestStart.closeRequested || val close = requestStart.closeRequested ||
(requestStart.expect100Continue && oneHundredContinueResponsePending) || (requestStart.expect100Continue && oneHundredContinueResponsePending) ||
(isClosed(requestParsingIn) && openRequests.isEmpty) || (isClosed(requestParsingIn) && openRequests.isEmpty) ||

View file

@ -34,7 +34,7 @@ abstract class RouteTest extends AllDirectives {
implicit def materializer: Materializer implicit def materializer: Materializer
implicit def executionContext: ExecutionContextExecutor = system.dispatcher implicit def executionContext: ExecutionContextExecutor = system.dispatcher
protected def awaitDuration: FiniteDuration = 500.millis protected def awaitDuration: FiniteDuration = 3.seconds
protected def defaultHostInfo: DefaultHostInfo = DefaultHostInfo(Host.create("example.com"), false) protected def defaultHostInfo: DefaultHostInfo = DefaultHostInfo(Host.create("example.com"), false)

View file

@ -40,7 +40,7 @@ class MethodDirectivesSpec extends RoutingSpec {
Head() ~> headRoute ~> check { Head() ~> headRoute ~> check {
status shouldEqual StatusCodes.OK status shouldEqual StatusCodes.OK
val lengthF = response._3.dataBytes.runFold(0)((c, _) => c+1) val lengthF = response._3.dataBytes.runFold(0)((c, _) c + 1)
val length = Await.result(lengthF, Duration(100, "millis")) val length = Await.result(lengthF, Duration(100, "millis"))
length shouldEqual 0 length shouldEqual 0
} }

View file

@ -265,13 +265,13 @@ object Credentials {
abstract case class Provided(identifier: String) extends Credentials { abstract case class Provided(identifier: String) extends Credentials {
/** /**
* First applies the passed in `hasher` function to the received secret part of the Credentials * First applies the passed in `hasher` function to the received secret part of the Credentials
* and then safely compares the passed in `secret` with the hashed received secret. * and then safely compares the passed in `secret` with the hashed received secret.
* This method can be used if the secret is not stored in plain text. * This method can be used if the secret is not stored in plain text.
* Use of this method instead of manual String equality testing is recommended in order to guard against timing attacks. * Use of this method instead of manual String equality testing is recommended in order to guard against timing attacks.
* *
* See also [[EnhancedString#secure_==]], for more information. * See also [[EnhancedString#secure_==]], for more information.
*/ */
def verify(secret: String, hasher: String String): Boolean def verify(secret: String, hasher: String String): Boolean
/** /**
@ -280,7 +280,7 @@ object Credentials {
* *
* See also [[EnhancedString#secure_==]], for more information. * See also [[EnhancedString#secure_==]], for more information.
*/ */
def verify(secret: String): Boolean = verify(secret, x => x) def verify(secret: String): Boolean = verify(secret, x x)
} }
def apply(cred: Option[HttpCredentials]): Credentials = { def apply(cred: Option[HttpCredentials]): Credentials = {