Skip to content

Commit c697417

Browse files
committed
Initial version
1 parent 2ec3bff commit c697417

File tree

8 files changed

+210
-0
lines changed

8 files changed

+210
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/target
2+
/.idea

pom.xml

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
3+
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<groupId>dk.anderslangballe</groupId>
7+
<artifactId>yuge</artifactId>
8+
<version>1.0-SNAPSHOT</version>
9+
<packaging>jar</packaging>
10+
11+
<name>yuge</name>
12+
13+
<properties>
14+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
15+
<kotlin.version>1.3.72</kotlin.version>
16+
<kotlin.code.style>official</kotlin.code.style>
17+
<junit.version>4.12</junit.version>
18+
</properties>
19+
20+
<dependencies>
21+
<dependency>
22+
<groupId>org.jetbrains.kotlin</groupId>
23+
<artifactId>kotlin-stdlib</artifactId>
24+
<version>${kotlin.version}</version>
25+
</dependency>
26+
27+
<dependency>
28+
<groupId>org.jetbrains.kotlin</groupId>
29+
<artifactId>kotlin-test-junit</artifactId>
30+
<version>${kotlin.version}</version>
31+
<scope>test</scope>
32+
</dependency>
33+
</dependencies>
34+
35+
<build>
36+
<sourceDirectory>src/main/kotlin</sourceDirectory>
37+
38+
<plugins>
39+
<plugin>
40+
<groupId>org.jetbrains.kotlin</groupId>
41+
<artifactId>kotlin-maven-plugin</artifactId>
42+
<version>${kotlin.version}</version>
43+
<executions>
44+
<execution>
45+
<id>compile</id>
46+
<phase>compile</phase>
47+
<goals>
48+
<goal>compile</goal>
49+
</goals>
50+
</execution>
51+
</executions>
52+
</plugin>
53+
</plugins>
54+
</build>
55+
</project>

samples/sample.request

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
GET /test HTTP/1.1
2+
Accept-Language: en-us
3+
Accept-Encoding: gzip, deflate
4+
Connection: Keep-Alive
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package dk.anderslangballe
2+
3+
import dk.anderslangballe.attack.HttpAttack
4+
import dk.anderslangballe.utility.getSamplePath
5+
import java.io.File
6+
import kotlin.system.exitProcess
7+
8+
fun main() {
9+
val targetHost = System.getenv("TARGET_HOST")
10+
val targetPort = System.getenv("TARGET_PORT")
11+
val requestFile = System.getenv("REQUEST_FILE")
12+
13+
if (targetHost == null || targetPort == null) {
14+
println("Target host and port must be declared")
15+
16+
exitProcess(1)
17+
}
18+
19+
if (requestFile == null || !File(getSamplePath(requestFile)).exists()) {
20+
println("Request file must be declared and exist")
21+
22+
exitProcess(1)
23+
}
24+
25+
val attack = HttpAttack(
26+
targetHost, Integer.parseInt(targetPort),
27+
getSamplePath(requestFile)
28+
)
29+
attack.start()
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package dk.anderslangballe.attack
2+
3+
import java.io.File
4+
import java.util.concurrent.CountDownLatch
5+
import kotlin.concurrent.thread
6+
7+
class HttpAttack(private val targetHost: String, private val targetPort: Int, private val sampleFile: String) {
8+
private val numberOfRequests = 1000
9+
10+
private val launchLatch = CountDownLatch(numberOfRequests)
11+
private val completeLatch = CountDownLatch(numberOfRequests)
12+
13+
private fun getRequestContent(): String {
14+
val content = File(sampleFile).readText(Charsets.UTF_8)
15+
16+
// Ensure connection stays alive
17+
return content.replace("Connection: Close", "Connection: Keep-Alive")
18+
}
19+
20+
fun start() {
21+
val requestContent = getRequestContent()
22+
23+
for (i in 1..numberOfRequests) {
24+
thread {
25+
HttpRequest(targetHost, targetPort, false, launchLatch, completeLatch, requestContent).start()
26+
}
27+
}
28+
29+
launchLatch.await()
30+
31+
val startTime = System.currentTimeMillis()
32+
33+
completeLatch.await()
34+
35+
println("RPS: ${numberOfRequests / ((System.currentTimeMillis() - startTime) / 1000F)}")
36+
}
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package dk.anderslangballe.attack
2+
3+
import dk.anderslangballe.ssl.getSecureSocketFactory
4+
import java.io.OutputStream
5+
import java.net.Socket
6+
import java.util.concurrent.CountDownLatch
7+
8+
class HttpRequest(private val targetHost: String, private val targetPort: Int, private val secureConnection: Boolean,
9+
private val launchLatch: CountDownLatch, private val completeLatch: CountDownLatch,
10+
private val requestContent: String) {
11+
private val withheldBytes = 1
12+
13+
fun start() {
14+
val socket: Socket = getSocket()
15+
val outputStream = socket.getOutputStream()
16+
val requestBytes = getRequestBytes()
17+
18+
writeInitial(requestBytes, outputStream)
19+
20+
launchLatch.await()
21+
22+
writeFinal(requestBytes, outputStream)
23+
}
24+
25+
private fun getRequestBytes(): ByteArray = requestContent.toByteArray(Charsets.UTF_8)
26+
27+
private fun writeFinal(requestBytes: ByteArray, outputStream: OutputStream) {
28+
outputStream.write(requestBytes, requestBytes.size - 1, withheldBytes)
29+
outputStream.close()
30+
31+
completeLatch.countDown()
32+
}
33+
34+
private fun writeInitial(requestBytes: ByteArray, outputStream: OutputStream) {
35+
outputStream.write(requestBytes, 0, requestBytes.size - withheldBytes)
36+
outputStream.flush()
37+
38+
launchLatch.countDown()
39+
}
40+
41+
private fun getSocket(): Socket {
42+
val socket: Socket = if (secureConnection) {
43+
getSecureSocketFactory().createSocket(targetHost, targetPort)
44+
} else {
45+
Socket(targetHost, targetPort)
46+
}
47+
48+
socket.tcpNoDelay = true
49+
50+
return socket
51+
}
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package dk.anderslangballe.ssl
2+
3+
import java.security.cert.X509Certificate
4+
import javax.net.ssl.SSLContext
5+
import javax.net.ssl.SSLSocketFactory
6+
import javax.net.ssl.X509TrustManager
7+
8+
private class TrustManager : X509TrustManager {
9+
override fun getAcceptedIssuers(): Array<X509Certificate>? {
10+
return null
11+
}
12+
13+
override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {}
14+
15+
override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {}
16+
}
17+
18+
fun getSecureSocketFactory(): SSLSocketFactory {
19+
val context = SSLContext.getInstance("TLS")
20+
context.init(null, arrayOf<javax.net.ssl.TrustManager>(TrustManager()), null)
21+
22+
return context.socketFactory
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package dk.anderslangballe.utility
2+
3+
import java.nio.file.Paths
4+
5+
fun getSamplePath(sampleName: String): String {
6+
return Paths.get("samples", sampleName).toString()
7+
}

0 commit comments

Comments
 (0)