diff --git a/.gitignore b/.gitignore
index 3b9e72b..43936ae 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,5 @@
.gradle
-.idea/*
+.idea
out
build
__pycache__
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
deleted file mode 100644
index 15a15b2..0000000
--- a/.idea/encodings.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
deleted file mode 100644
index 3163861..0000000
--- a/.idea/gradle.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index bc8d0a3..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 94a25f7..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/README.md b/README.md
index 9b94467..b9b1b3d 100644
--- a/README.md
+++ b/README.md
@@ -26,8 +26,8 @@ For transparently rewriting HTTP/HTTPS responses. The mitmproxy plugin lets ever
## Pre-requisites
-* [`mitmproxy` V4](https://mitmproxy.org/) must be installed and runnable from the terminal. The install method cannot be a prebuilt binary or homebrew, since those packages are missing the Python websockets module. Install via `pip` or from source.
-* Python 3.6, since we use the new async/await syntax in the mitmproxy plugin
+* [`mitmproxy` V9](https://mitmproxy.org/) must be installed and runnable from the terminal. The install method cannot be a prebuilt binary or homebrew, since those packages are missing the Python websockets module. Install via `pip` or from source.
+* Python 3.6 and above, since we use the new async/await syntax in the mitmproxy plugin
* `pip3 install websockets`
Maven:
@@ -35,13 +35,13 @@ Maven:
io.appium
mitmproxy-java
- 1.6.2
+ 2.0.2
```
Gradle:
```
-testCompile group: 'io.appium', name: 'mitmproxy-java', version: '1.6.1'
+testCompile group: 'io.appium', name: 'mitmproxy-java', version: '2.0.2'
```
## Usage
@@ -49,22 +49,34 @@ testCompile group: 'io.appium', name: 'mitmproxy-java', version: '1.6.1'
```java
List messages = new ArrayList();
+//optional, default port is 8080
+int mitmproxyPort = 8090;
+
+//optional, you can pass null if no extra params
+List extraMitmproxyParams = Arrays.asList("param1", "value1", "param2", "value2");
+
// remember to set local OS proxy settings in the Network Preferences
proxy = new MitmproxyJava("/usr/local/bin/mitmdump", (InterceptedMessage m) -> {
- System.out.println("intercepted request for " + m.requestURL.toString());
+ System.out.println("intercepted request for " + m.getRequest().getUrl());
messages.add(m);
return m;
-});
+}, mitmproxyPort, extraMitmproxyParams);
proxy.start();
// do stuff
proxy.stop();
+```
+If the above code doesn't work, and you are getting
+`Error=2, No such file or directory` please re-check your mitmdump path in new MitmproxyJava initialization.
+You can get mitmdump path using below command:
+```shell
+whereis mitmdump
```
-See AppriumPro article for more guidelines: https://appiumpro.com/editions/65
+See AppiumPro article for more guidelines: https://appiumpro.com/editions/65
Example can be found here: https://github.com/cloudgrey-io/appiumpro/blob/master/java/src/test/java/Edition065_Capture_Network_Requests.java
## Your Java code is bad and you should feel bad
@@ -75,3 +87,7 @@ I'm no Java expert! You may see some bad patterns, like my terrible disregard fo
See [node-mitmproxy](https://github.com/jvilk/mitmproxy-node/blob/master/README.md#your-python-plugin-is-bad-and-you-should-feel-bad). Pull requests welcome!
+## Develop
+
+Upload to Central Repository with command `./gradlew uploadArchives`
+Set username and password in `build.gradle` file
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 605a4a0..6b779fb 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,14 +5,13 @@ plugins {
}
group = 'io.appium'
-version = '1.6.2'
+version = '2.0.2'
archivesBaseName = 'mitmproxy-java'
sourceCompatibility = 1.8
repositories {
mavenCentral()
- jcenter()
}
dependencies {
@@ -24,7 +23,14 @@ dependencies {
implementation group: 'org.zeroturnaround', name: 'zt-process-killer', version: '1.9'
implementation group: 'org.slf4j', name: 'slf4j-simple', version: '1.7.26'
testCompile group: 'junit', name: 'junit', version: '4.12'
+ testCompile group: 'org.mockito', name: 'mockito-all', version: '1.10.19'
testCompile group: 'com.mashape.unirest', name: 'unirest-java', version: '1.4.9'
+ testCompile group: 'org.assertj', name: 'assertj-core', version: '3.12.2'
+
+ compileOnly 'org.projectlombok:lombok:1.18.8'
+ annotationProcessor 'org.projectlombok:lombok:1.18.8'
+
+ compile group: 'org.apache.commons', name: 'commons-collections4', version: '4.0'
}
task javadocJar(type: Jar) {
@@ -39,6 +45,10 @@ artifacts {
archives javadocJar, sourcesJar
}
signing {
+ setRequired {
+ // condition for when signing is required
+ gradle.taskGraph.hasTask("uploadArchives")
+ }
sign configurations.archives
}
@@ -53,10 +63,10 @@ uploadArchives {
// Destination
repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
- authentication(userName: ossrhUsername, password: ossrhPassword)
+ authentication(userName: 'username', password: 'password')
}
snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
- authentication(userName: ossrhUsername, password: ossrhPassword)
+ authentication(userName: 'username', password: 'password')
}
// Add required metadata to POM
@@ -91,4 +101,4 @@ uploadArchives {
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/io/appium/mitmproxy/InterceptedMessage.java b/src/main/java/io/appium/mitmproxy/InterceptedMessage.java
index 47326b2..18f347f 100644
--- a/src/main/java/io/appium/mitmproxy/InterceptedMessage.java
+++ b/src/main/java/io/appium/mitmproxy/InterceptedMessage.java
@@ -1,107 +1,42 @@
package io.appium.mitmproxy;
-import java.io.IOException;
-import java.net.URL;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
+import lombok.Data;
-public class InterceptedMessage {
-
- public byte[] requestBody;
- public byte[] responseBody;
+import java.util.List;
- public String requestMethod;
- public URL requestURL;
- public List requestHeaders;
- public int responseCode;
- public List responseHeaders;
+@Data
+public class InterceptedMessage {
+ private final static ObjectMapper objectMapper = new ObjectMapper();
- public InterceptedMessage(ByteBuffer buffer) throws IOException {
- buffer = buffer.order(ByteOrder.LITTLE_ENDIAN);
+ private Request request;
- int metadataSize = buffer.getInt();
- int request_content_size = buffer.getInt();
- int response_content_size = buffer.getInt();
+ private Response response;
- byte[] metadataBytes = new byte[metadataSize];
- buffer.get(metadataBytes);
+ @Data
+ public static class Request {
- requestBody = new byte[request_content_size];
- buffer.get(requestBody);
+ private String method;
- responseBody = new byte[response_content_size];
- buffer.get(responseBody);
+ private String url;
- ObjectMapper mapper = new ObjectMapper();
- JsonNode metadata = mapper.readTree(metadataBytes);
- requestMethod = metadata.get("request").get("method").asText();
- requestURL = new URL(metadata.get("request").get("url").asText());
- JsonNode headers = metadata.get("request").get("headers");
- requestHeaders = new ArrayList<>();
- for (JsonNode headerNode : headers) {
- String[] headerArray = new String[2];
- headerArray[0] = headerNode.get(0).asText();
- headerArray[1] = headerNode.get(1).asText();
- requestHeaders.add(headerArray);
- }
+ private List headers;
- responseCode = metadata.get("response").get("status_code").asInt();
- headers = metadata.get("request").get("headers");
- responseHeaders = new ArrayList<>();
- for (JsonNode headerNode : headers) {
- String[] headerArray = new String[2];
- headerArray[0] = headerNode.get(0).asText();
- headerArray[1] = headerNode.get(1).asText();
- responseHeaders.add(headerArray);
- }
+ @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
+ private byte[] body;
}
- public ByteBuffer serializedResponseToMitmproxy() throws JsonProcessingException {
- int contentLength = responseBody.length;
-
- // create JSON for metadata. Which is the responseCode and responseHeaders.
- // while we're at it, set the Content-Length header
- ObjectMapper mapper = new ObjectMapper();
- ObjectNode metadataRoot = mapper.createObjectNode();
- metadataRoot.put("status_code", responseCode);
-
- ArrayNode headersNode = mapper.createArrayNode();
- List headerNodes = responseHeaders.stream().map((h) -> {
- ArrayNode headerPair = mapper.createArrayNode();
- headerPair.add(h[0]);
- if (h[0].equals("content-length")) {
- headerPair.add(Integer.toString(contentLength));
- } else {
- headerPair.add(h[1]);
- }
- return headerPair;
- }).collect(Collectors.toList());
- headersNode.addAll(headerNodes);
- metadataRoot.set("headers", headersNode);
-
- String metadataJson = mapper.writeValueAsString(metadataRoot);
- byte[] metadata = metadataJson.getBytes(StandardCharsets.UTF_8);
- int metadataLength = metadata.length;
+ @Data
+ public static class Response {
+ @JsonProperty("status_code")
+ private int statusCode;
- ByteBuffer buffer = ByteBuffer.allocate(8 + metadataLength + contentLength);
- buffer.order(ByteOrder.LITTLE_ENDIAN);
- buffer.putInt(metadataLength);
- buffer.putInt(contentLength);
- buffer.put(metadata);
- buffer.put(responseBody);
+ private List headers;
- return (ByteBuffer) buffer.rewind();
+ @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
+ private byte[] body;
}
}
\ No newline at end of file
diff --git a/src/main/java/io/appium/mitmproxy/MessageSerializer.java b/src/main/java/io/appium/mitmproxy/MessageSerializer.java
new file mode 100644
index 0000000..2429c65
--- /dev/null
+++ b/src/main/java/io/appium/mitmproxy/MessageSerializer.java
@@ -0,0 +1,58 @@
+package io.appium.mitmproxy;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.SneakyThrows;
+
+import java.io.IOException;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public class MessageSerializer {
+
+ private final static ObjectMapper objectMapper = new ObjectMapper();
+ private static final int START_BYTES = 8;
+
+ @SneakyThrows(IOException.class)
+ public InterceptedMessage deserializeMessage(ByteBuffer buffer) {
+ buffer.order(ByteOrder.LITTLE_ENDIAN);
+
+ int metadataSize = buffer.getInt();
+ int request_content_size = buffer.getInt();
+ int response_content_size = buffer.getInt();
+
+ byte[] metadataBytes = new byte[metadataSize];
+ buffer.get(metadataBytes);
+
+ byte[] requestBody = new byte[request_content_size];
+ buffer.get(requestBody);
+
+ byte[] responseBody = new byte[response_content_size];
+ buffer.get(responseBody);
+
+ InterceptedMessage interceptedMessage = objectMapper.readValue(metadataBytes, InterceptedMessage.class);
+ interceptedMessage.getRequest().setBody(requestBody);
+ interceptedMessage.getResponse().setBody(responseBody);
+
+ return interceptedMessage;
+ }
+
+ public ByteBuffer serializeMessage(InterceptedMessage message) throws JsonProcessingException {
+ byte[] responseBody = message.getResponse().getBody();
+
+ int contentLength = responseBody.length;
+
+ byte[] metadata = objectMapper.writeValueAsBytes(message.getResponse());
+ int metadataLength = metadata.length;
+
+ ByteBuffer buffer = ByteBuffer.allocate(START_BYTES + metadataLength + contentLength);
+ buffer.order(ByteOrder.LITTLE_ENDIAN);
+ buffer.putInt(metadataLength);
+ buffer.putInt(contentLength);
+ buffer.put(metadata);
+ buffer.put(message.getResponse().getBody());
+
+ return (ByteBuffer) buffer.rewind();
+ }
+}
diff --git a/src/main/java/io/appium/mitmproxy/MitmproxyJava.java b/src/main/java/io/appium/mitmproxy/MitmproxyJava.java
index 61a7897..2da256a 100644
--- a/src/main/java/io/appium/mitmproxy/MitmproxyJava.java
+++ b/src/main/java/io/appium/mitmproxy/MitmproxyJava.java
@@ -1,5 +1,8 @@
package io.appium.mitmproxy;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.IOUtils;
import org.zeroturnaround.exec.ProcessExecutor;
import org.zeroturnaround.exec.ProcessResult;
import org.zeroturnaround.exec.stream.slf4j.Slf4jStream;
@@ -10,103 +13,113 @@
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
-import java.net.URISyntaxException;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeoutException;
import java.util.function.Function;
+import static org.apache.commons.collections4.CollectionUtils.isNotEmpty;
+
+@Slf4j
public class MitmproxyJava {
- private String mitmproxyPath;
+ private static final String LOCALHOST_IP = "127.0.0.1";
+ private static final int WEBSOCKET_PORT = 8765;
+ private static final int TIMEOUT_FOR_SOCKET_CHECKING_MINS = 5;
+
+ private final String mitmproxyPath;
+
+ private final Function messageInterceptor;
+
+ private final int proxyPort;
+
private MitmproxyServer server;
+
+ private final List extraMitmdumpParams;
+
private Future mitmproxyProcess;
- public static final int WEBSOCKET_PORT = 8765;
- public MitmproxyJava(String mitmproxyPath, Function messageInterceptor) {
+ public MitmproxyJava(String mitmproxyPath, Function messageInterceptor, int proxyPort, List extraMitmdumpParams) {
this.mitmproxyPath = mitmproxyPath;
- server = new MitmproxyServer(new InetSocketAddress("localhost", WEBSOCKET_PORT), messageInterceptor);
- server.start();
+ this.messageInterceptor = messageInterceptor;
+ this.proxyPort = proxyPort;
+ this.extraMitmdumpParams = extraMitmdumpParams;
}
- public void start() throws IOException, TimeoutException, URISyntaxException {
- System.out.println("starting mitmproxy on port 8080");
+ public MitmproxyJava(String mitmproxyPath, Function messageInterceptor) {
+ this(mitmproxyPath, messageInterceptor, 8080, null);
+ }
+
+ public MitmproxyJava start() throws IOException, TimeoutException {
+ log.info("Starting mitmproxy on port {}", proxyPort);
+
+ server = new MitmproxyServer(new InetSocketAddress(LOCALHOST_IP, WEBSOCKET_PORT), messageInterceptor);
+ server.start();
// python script file is zipped inside our jar. extract it into a temporary file.
String pythonScriptPath = extractPythonScriptToFile();
+ final List mitmproxyStartParams = new ArrayList<>();
+ mitmproxyStartParams.add(mitmproxyPath);
+ mitmproxyStartParams.add("--anticache");
+ mitmproxyStartParams.add("-p");
+ mitmproxyStartParams.add(String.valueOf(proxyPort));
+ mitmproxyStartParams.add("-s");
+ mitmproxyStartParams.add(pythonScriptPath);
+
+ // adding params if needed for mitmproxy
+ if (isNotEmpty(this.extraMitmdumpParams)) {
+ mitmproxyStartParams.addAll(this.extraMitmdumpParams);
+ }
+
mitmproxyProcess = new ProcessExecutor()
- .command(mitmproxyPath, "--anticache", "-s", pythonScriptPath)
+ .command(mitmproxyStartParams)
.redirectOutput(Slf4jStream.ofCaller().asInfo())
.destroyOnExit()
.start()
.getFuture();
- waitForPortToBeInUse(8080);
- System.out.println("mitmproxy started on port 8080");
-
+ waitForPortToBeInUse(proxyPort);
+ log.info("Mitmproxy started on port {}", proxyPort);
+ return this;
}
- private String extractPythonScriptToFile() throws URISyntaxException, IOException {
+ private String extractPythonScriptToFile() throws IOException {
File outfile = File.createTempFile("mitmproxy-python-plugin", ".py");
- InputStream instream = getClass().getClassLoader().getResourceAsStream("scripts/proxy.py");
- FileOutputStream outstream = new FileOutputStream(outfile);
-
- byte[] buffer = new byte[1024];
+ try (
+ InputStream inputStream = getClass().getClassLoader().getResourceAsStream("scripts/proxy.py");
+ FileOutputStream outputStream = new FileOutputStream(outfile)) {
- int length;
- /*copying the contents from input stream to
- * output stream using read and write methods
- */
- while ((length = instream.read(buffer)) > 0){
- outstream.write(buffer, 0, length);
+ IOUtils.copy(inputStream, outputStream);
}
- //Closing the input/output file streams
- instream.close();
- outstream.close();
-
return outfile.getCanonicalPath();
}
- public void stop() throws IOException, InterruptedException {
+ public void stop() throws InterruptedException {
if (mitmproxyProcess != null) {
mitmproxyProcess.cancel(true);
}
server.stop(1000);
- Thread.sleep(200); // this pains me. but it seems that it takes a moment for the server to actually relinquish the port it uses.
+ waitForPortToBeFree(proxyPort);
}
- private void waitForPortToBeInUse(int port) throws TimeoutException {
- boolean inUse = false;
- Socket s = null;
- int tries = 0;
- int maxTries = 60 * 1000 / 100;
+ @SneakyThrows
+ private void waitForPortToBeFree(int port) {
+ final LocalDateTime timeoutTime = LocalDateTime.now().plusMinutes(TIMEOUT_FOR_SOCKET_CHECKING_MINS);
- while (!inUse) {
- try
- {
- s = new Socket("localhost", port);
- }
- catch (IOException e)
- {
- inUse = false;
+ while (true) {
+ if(timeoutTime.isBefore(LocalDateTime.now())){
+ throw new TimeoutException("Timed out waiting for mitmproxy to stop");
}
- finally
- {
- if(s != null) {
- inUse = true;
- try {
- s.close();
- } catch (Exception e) {
- }
- break;
- }
- }
- tries++;
- if (tries == maxTries) {
- throw new TimeoutException("Timed out waiting for mitmproxy to start");
+ try (Socket s = new Socket(LOCALHOST_IP, port)) {
+ } catch (IOException ioe) {
+ return;
}
+
try {
Thread.sleep(100);
} catch (InterruptedException e) {
@@ -114,5 +127,26 @@ private void waitForPortToBeInUse(int port) throws TimeoutException {
}
}
}
-}
+ @SneakyThrows
+ private void waitForPortToBeInUse(int port) {
+ final LocalDateTime timeoutTime = LocalDateTime.now().plusMinutes(TIMEOUT_FOR_SOCKET_CHECKING_MINS);
+
+ while (true) {
+
+ if(timeoutTime.isBefore(LocalDateTime.now())){
+ throw new TimeoutException("Timed out waiting for mitmproxy to start");
+ }
+
+ try (Socket s = new Socket(LOCALHOST_IP, port)) {
+ return;
+ } catch (IOException ioe) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/io/appium/mitmproxy/MitmproxyServer.java b/src/main/java/io/appium/mitmproxy/MitmproxyServer.java
index 309af12..c88e433 100644
--- a/src/main/java/io/appium/mitmproxy/MitmproxyServer.java
+++ b/src/main/java/io/appium/mitmproxy/MitmproxyServer.java
@@ -4,71 +4,70 @@
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
-import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.function.Function;
public class MitmproxyServer extends WebSocketServer {
- private Function interceptor;
+ private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketServer.class);
- public MitmproxyServer(InetSocketAddress address, Function interceptor) {
+ private final Function interceptor;
+
+ private final MessageSerializer messageSerializer;
+
+ MitmproxyServer(InetSocketAddress address, Function interceptor) {
super(address);
this.interceptor = interceptor;
+ this.messageSerializer = new MessageSerializer();
}
@Override
public void onOpen(WebSocket conn, ClientHandshake handshake) {
- System.out.println("new connection to websocket server" + conn.getRemoteSocketAddress());
+ LOGGER.debug("new connection to websocket server" + conn.getRemoteSocketAddress());
}
@Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
- System.out.println("closed " + conn.getRemoteSocketAddress() + " with exit code " + code + " additional info: " + reason);
+ LOGGER.debug("closed " + conn.getRemoteSocketAddress() + " with exit code " + code + " additional info: " + reason);
}
@Override
public void onMessage(WebSocket conn, String message) {
- System.out.println("received message from " + conn.getRemoteSocketAddress() + ": " + message);
+ LOGGER.debug("received message from " + conn.getRemoteSocketAddress() + " : " + message);
}
@Override
- public void onMessage( WebSocket conn, ByteBuffer message ) {
- InterceptedMessage intercepted = null;
- InterceptedMessage modifiedMessage = null;
-
- try {
- intercepted = new InterceptedMessage(message);
- } catch (IOException e) {
- System.out.println("Could not parse message");
- e.printStackTrace();
- }
+ public void onMessage(WebSocket conn, ByteBuffer rawInputMessage) {
+ InterceptedMessage incomingMessage = this.messageSerializer.deserializeMessage(rawInputMessage);
- modifiedMessage = interceptor.apply(intercepted);
+ InterceptedMessage modifiedMessage = interceptor.apply(incomingMessage);
// if the supplied interceptor function does not return a message, assume no changes were intended and just
// complete the request
+ InterceptedMessage messageToSendBack = modifiedMessage;
+
if (modifiedMessage == null) {
- modifiedMessage = intercepted;
+ messageToSendBack = incomingMessage;
}
try {
- conn.send(modifiedMessage.serializedResponseToMitmproxy());
+ conn.send(this.messageSerializer.serializeMessage(messageToSendBack));
} catch (JsonProcessingException e) {
- System.out.println("Could not encode response to mitmproxy");
- e.printStackTrace();
+ LOGGER.error(e.getMessage());
}
}
@Override
public void onError(WebSocket conn, Exception ex) {
- System.err.println("an error occured on connection " + conn.getRemoteSocketAddress() + ":" + ex);
+ LOGGER.error("an error occured on connection " + conn.getRemoteSocketAddress() + ":" + ex);
}
@Override
public void onStart() {
- System.out.println("websocket server started successfully");
+ LOGGER.info("websocket server started successfully");
}
}
diff --git a/src/main/resources/scripts/proxy.py b/src/main/resources/scripts/proxy.py
index f108b1f..01ab562 100644
--- a/src/main/resources/scripts/proxy.py
+++ b/src/main/resources/scripts/proxy.py
@@ -150,7 +150,7 @@ def request(self, flow):
new_metadata = message_response[0]
new_body = message_response[1]
- flow.response = http.HTTPResponse.make(
+ flow.response = http.Response.make(
new_metadata['status_code'],
new_body,
map(convert_headers_to_bytes, new_metadata['headers'])
@@ -198,7 +198,7 @@ def response(self, flow):
#print("Prepping response!")
- flow.response = http.HTTPResponse.make(
+ flow.response = http.Response.make(
new_metadata['status_code'],
new_body,
map(convert_headers_to_bytes, new_metadata['headers'])
diff --git a/src/test/java/io/appium/mitmproxy/MitmproxyJavaTest.java b/src/test/java/io/appium/mitmproxy/MitmproxyJavaTest.java
index f893cfc..85ea9c3 100644
--- a/src/test/java/io/appium/mitmproxy/MitmproxyJavaTest.java
+++ b/src/test/java/io/appium/mitmproxy/MitmproxyJavaTest.java
@@ -7,93 +7,128 @@
import org.junit.Test;
import java.io.IOException;
-import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
-import static junit.framework.TestCase.assertTrue;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
public class MitmproxyJavaTest {
+ //private static final String MITMDUMP_PATH = "C:\\Python37\\Scripts\\mitmdump.exe";
+ private static final String MITMDUMP_PATH = getMITMDumpPath();
+
+ static String getMITMDumpPath(){
+ if(System.getProperty("os.name").contains("Mac")){
+ return "/opt/homebrew/bin/mitmdump";
+ }
+ return "/usr/local/bin/mitmdump";
+ }
@Test
- public void ConstructorTest() throws URISyntaxException, IOException, InterruptedException {
- MitmproxyJava proxy = new MitmproxyJava("/usr/local/bin/mitmdump", (InterceptedMessage m) -> {
- System.out.println(m.requestURL.toString());
+ public void ConstructorTest() throws InterruptedException, IOException, TimeoutException {
+ MitmproxyJava proxy = new MitmproxyJava(MITMDUMP_PATH, (InterceptedMessage m) -> {
+ System.out.println(m.getRequest().getUrl());
return m;
});
+ proxy.start();
System.out.println("advanced in test");
proxy.stop();
}
@Test
- public void SimpleTest() throws InterruptedException, ExecutionException, TimeoutException, IOException, URISyntaxException, UnirestException {
- List messages = new ArrayList();
+ public void SimpleTest() throws InterruptedException, TimeoutException, IOException, UnirestException {
+ List messages = new ArrayList<>();
- MitmproxyJava proxy = new MitmproxyJava("/usr/local/bin/mitmdump", (InterceptedMessage m) -> {
+ MitmproxyJava proxy = new MitmproxyJava(MITMDUMP_PATH, (InterceptedMessage m) -> {
messages.add(m);
return m;
});
proxy.start();
Unirest.setProxy(new HttpHost("localhost", 8080));
- Unirest.get("http://appium.io").asString();
+ Unirest.get("http://appium.io").header("myTestHeader", "myTestValue").asString();
proxy.stop();
+ final InterceptedMessage firstMessage = messages.get(0);
- assertTrue(messages.size() > 0);
-
- InterceptedMessage appiumIORequest = messages.stream().filter((m) -> m.requestURL.getHost().equals("appium.io")).findFirst().get();
-
- assertTrue(appiumIORequest.responseCode == 200);
+ assertThat(firstMessage.getRequest().getUrl()).startsWith("http://appium.io");
+ assertThat(firstMessage.getRequest().getHeaders()).containsOnlyOnce(new String[]{"myTestHeader", "myTestValue"});
+ assertThat(firstMessage.getResponse().getStatusCode()).isEqualTo(200);
}
@Test
- public void NullInterceptorReturnTest() throws InterruptedException, ExecutionException, TimeoutException, IOException, URISyntaxException, UnirestException {
- List messages = new ArrayList();
+ public void NullInterceptorReturnTest() throws InterruptedException, TimeoutException, IOException, UnirestException {
+ List messages = new ArrayList<>();
- MitmproxyJava proxy = new MitmproxyJava("/usr/local/bin/mitmdump", (InterceptedMessage m) -> {
+ MitmproxyJava proxy = new MitmproxyJava(MITMDUMP_PATH, (InterceptedMessage m) -> {
messages.add(m);
return null;
- });
+ }, 8087, null);
proxy.start();
- Unirest.setProxy(new HttpHost("localhost", 8080));
- Unirest.get("http://appium.io").asString();
+ Unirest.setProxy(new HttpHost("localhost", 8087));
+ Unirest.get("http://appium.io").header("myTestHeader", "myTestValue").asString();
proxy.stop();
- assertTrue(messages.size() > 0);
+ assertThat(messages).isNotEmpty();
- InterceptedMessage appiumIORequest = messages.stream().filter((m) -> m.requestURL.getHost().equals("appium.io")).findFirst().get();
+ final InterceptedMessage firstMessage = messages.get(0);
- assertTrue(appiumIORequest.responseCode == 200);
+ assertThat(firstMessage.getRequest().getUrl()).startsWith("http://appium.io");
+ assertThat(firstMessage.getRequest().getHeaders()).containsOnlyOnce(new String[]{"myTestHeader", "myTestValue"});
+ assertThat(firstMessage.getResponse().getStatusCode()).isEqualTo(200);
}
@Test
- public void ResponseModificationTest() throws InterruptedException, ExecutionException, TimeoutException, IOException, URISyntaxException, UnirestException {
- List messages = new ArrayList();
+ public void ResponseModificationTest() throws InterruptedException, TimeoutException, IOException, UnirestException {
+ List messages = new ArrayList<>();
- MitmproxyJava proxy = new MitmproxyJava("/usr/local/bin/mitmdump", (InterceptedMessage m) -> {
+ MitmproxyJava proxy = new MitmproxyJava(MITMDUMP_PATH, (InterceptedMessage m) -> {
messages.add(m);
- m.responseBody = "Hi from Test".getBytes(StandardCharsets.UTF_8);
+ m.getResponse().setBody("Hi from Test".getBytes(StandardCharsets.UTF_8));
+ m.getResponse().getHeaders().add(new String[]{"myTestResponseHeader", "myTestResponseHeaderValue"});
+ m.getResponse().setStatusCode(208);
return m;
});
proxy.start();
Unirest.setProxy(new HttpHost("localhost", 8080));
- HttpResponse response = Unirest.get("http://appium.io").asString();
+ HttpResponse response = Unirest.get("http://appium.io").header("myTestHeader", "myTestValue").asString();
+ proxy.stop();
- assertTrue(response.getBody().equals("Hi from Test"));
+ assertThat(response.getBody()).isEqualTo("Hi from Test");
- proxy.stop();
+ final InterceptedMessage firstMessage = messages.get(0);
- assertTrue(messages.size() > 0);
+ assertThat(firstMessage.getRequest().getUrl()).startsWith("http://appium.io");
+ assertThat(firstMessage.getRequest().getHeaders()).containsOnlyOnce(new String[]{"myTestHeader", "myTestValue"});
+ assertThat(firstMessage.getResponse().getHeaders()).containsOnlyOnce(new String[]{"myTestResponseHeader", "myTestResponseHeaderValue"});
+ assertThat(firstMessage.getResponse().getStatusCode()).isEqualTo(208);
+ }
+
+ @Test
+ public void shouldAddParametersToMitmdumpStart() throws IOException, TimeoutException, InterruptedException {
+ List mitmdumpParams = new ArrayList<>();
+ mitmdumpParams.add("testParam");
+
+ List spiedParams = spy(mitmdumpParams);
+
+ MitmproxyJava proxy = new MitmproxyJava(MITMDUMP_PATH, (InterceptedMessage m) -> {
+ m.getResponse().setBody("Hi from Test".getBytes(StandardCharsets.UTF_8));
+ m.getResponse().getHeaders().add(new String[]{"myTestResponseHeader", "myTestResponseHeaderValue"});
+ m.getResponse().setStatusCode(208);
+ return m;
+ }, 8087, spiedParams);
+
+ proxy.start();
+ proxy.stop();
- InterceptedMessage appiumIORequest = messages.stream().filter((m) -> m.requestURL.getHost().equals("appium.io")).findFirst().get();
+ //to verify that additional params were actually included to start path
+ verify(spiedParams).toArray();
- assertTrue(appiumIORequest.responseCode == 200);
}
}
\ No newline at end of file