Skip to content
This repository was archived by the owner on Jun 11, 2024. It is now read-only.

Commit 9e9b6c5

Browse files
committed
Mitmproxy process provisioning refactoring
1 parent 92a92c6 commit 9e9b6c5

File tree

2 files changed

+97
-37
lines changed

2 files changed

+97
-37
lines changed

browserup-proxy-core/src/main/java/com/browserup/bup/mitmproxy/MitmProxyProcessManager.java

Lines changed: 92 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import java.io.IOException;
1515
import java.io.PipedInputStream;
1616
import java.io.PipedOutputStream;
17+
import java.net.BindException;
1718
import java.net.InetSocketAddress;
1819
import java.util.ArrayList;
1920
import java.util.Arrays;
@@ -73,7 +74,7 @@ public void start(int port, List<AbstractAddon> addons) {
7374
try {
7475
this.proxyPort = port;
7576

76-
startProxy(port, addons);
77+
startProxyWithRetries(port, addons, 3);
7778

7879
this.isRunning = true;
7980

@@ -119,10 +120,11 @@ public boolean isRunning() {
119120
public void stop() {
120121
this.isRunning = false;
121122

122-
Process process = startedProcess.getProcess();
123-
process.destroyForcibly();
124-
125-
Awaitility.await().atMost(10, TimeUnit.SECONDS).until(() -> !process.isAlive());
123+
if (startedProcess != null) {
124+
Process process = startedProcess.getProcess();
125+
process.destroyForcibly();
126+
Awaitility.await().atMost(10, TimeUnit.SECONDS).until(() -> !process.isAlive());
127+
}
126128
}
127129

128130
public void setTrustAll(boolean trustAll) {
@@ -146,6 +148,26 @@ private List<AbstractAddon> defaultAddons() {
146148
return Arrays.asList(addonsArray);
147149
}
148150

151+
private void startProxyWithRetries(int port, List<AbstractAddon> addons, int retryCount) {
152+
for (int attempt = 1; attempt <= retryCount; attempt++) {
153+
try {
154+
startProxy(port, addons);
155+
break;
156+
} catch (Exception ex) {
157+
// For binding exception not going to retry (let driver to try another port)
158+
if (ex.getCause() != null && ex.getCause() instanceof BindException) {
159+
throw ex;
160+
}
161+
if (attempt < retryCount) {
162+
LOGGER.error("Failed to start proxy, attempt: {}, retries count: {}, going to retry...", attempt, retryCount, ex);
163+
} else {
164+
LOGGER.error("Failed to start proxy, no retries left, throwing exception", ex);
165+
throw ex;
166+
}
167+
}
168+
}
169+
}
170+
149171
private void startProxy(int port, List<AbstractAddon> addons) {
150172
List<String> command = new ArrayList<String>() {{
151173
add("mitmdump");
@@ -156,25 +178,59 @@ private void startProxy(int port, List<AbstractAddon> addons) {
156178
command.add("--ssl-insecure");
157179
}
158180

159-
InetSocketAddress upstreamProxyAddress = proxyManager.getUpstreamProxyAddress();
160-
if (upstreamProxyAddress != null) {
161-
String schema = "http";
162-
if (proxyManager.isUseHttpsUpstreamProxy()) {
163-
schema = "https";
164-
}
165-
command.add("--mode");
166-
command.add("upstream:" + schema + "://" + upstreamProxyAddress.getHostName() + ":" + upstreamProxyAddress.getPort());
167-
}
181+
updateCommandWithUpstreamProxy(command);
182+
updateCommandWithLogLevel(command);
183+
updateCommandWithAddOns(addons, command);
168184

169-
command.add("--set");
170-
command.add("termlog_verbosity=" + getMitmProxyLoggingLevel());
185+
LOGGER.info("Starting proxy using command: " + String.join(" ", command));
171186

172-
addons.forEach(addon -> command.addAll(Arrays.asList(addon.getCommandParams())));
187+
ProcessExecutor processExecutor = createProcessExecutor(command);
188+
try {
189+
startedProcess = processExecutor.start();
190+
} catch (Exception ex) {
191+
throw new RuntimeException("Couldn't start mitmproxy process", ex);
192+
}
193+
try {
194+
Awaitility.await()
195+
.atMost(5, TimeUnit.SECONDS)
196+
.until(this.proxyManager::callHealthCheck);
197+
} catch (ConditionTimeoutException ex) {
198+
handleHealthCheckFailure();
199+
}
200+
}
173201

174-
LOGGER.info("Starting proxy using command: " + String.join(" ", command));
202+
private void handleHealthCheckFailure() {
203+
LOGGER.error("MitmProxy might not started properly, healthcheck failed for port: " + this.proxyPort);
204+
if (startedProcess == null) return;
205+
206+
if (startedProcess.getProcess().isAlive()) {
207+
LOGGER.error("MitmProxy's healthcheck failed but process is alive, killing mitmproxy process...");
208+
startedProcess.getProcess().destroyForcibly();
209+
try {
210+
Awaitility.await()
211+
.atMost(5, TimeUnit.SECONDS)
212+
.until(() -> !startedProcess.getProcess().isAlive());
213+
LOGGER.info("MitmProxy process was killed successfully.");
214+
} catch (ConditionTimeoutException ex2) {
215+
LOGGER.error("Didn't manage to kill MitmProxy in time, throwing error");
216+
throw new RuntimeException("Couldn't kill mitmproxy in time", ex2);
217+
}
218+
}
219+
if (!startedProcess.getProcess().isAlive() && startedProcess.getProcess().exitValue() > 0) {
220+
Throwable cause = null;
221+
if (proxyLog.toString().contains("Address already in use")) {
222+
cause = new BindException();
223+
}
224+
throw new RuntimeException(
225+
"Couldn't start mitmproxy process on port: " + this.proxyPort +
226+
", exit with code: " + startedProcess.getProcess().exitValue(), cause);
227+
}
228+
}
175229

230+
private ProcessExecutor createProcessExecutor(List<String> command) {
176231
String logPrefix = "MitmProxy[" + this.proxyPort + "]: ";
177-
ProcessExecutor processExecutor = new ProcessExecutor(command)
232+
233+
return new ProcessExecutor(command)
178234
.readOutput(true)
179235
.destroyOnExit()
180236
.redirectOutput(Slf4jStream.ofCaller().asInfo())
@@ -185,26 +241,26 @@ protected void processLine(String line) {
185241
proxyLog.append(line).append("\n");
186242
}
187243
});
244+
}
188245

189-
try {
190-
startedProcess = processExecutor.start();
191-
} catch (Exception ex) {
192-
throw new RuntimeException("Couldn't start mitmproxy process", ex);
193-
}
246+
private void updateCommandWithAddOns(List<AbstractAddon> addons, List<String> command) {
247+
addons.forEach(addon -> command.addAll(Arrays.asList(addon.getCommandParams())));
248+
}
194249

195-
try {
196-
Awaitility.await()
197-
.atMost(5, TimeUnit.SECONDS)
198-
.until(this.proxyManager::callHealthCheck);
199-
} catch (ConditionTimeoutException ex) {
200-
LOGGER.error("MitmProxy might not started properly, healthcheck failed for port: " + this.proxyPort);
201-
if (startedProcess != null && startedProcess.getProcess().exitValue() > 0) {
202-
Throwable cause = null;
203-
if (proxyLog.toString().contains("Address already in use")) {
204-
cause = new java.net.BindException();
205-
}
206-
throw new RuntimeException("Couldn't start mitmproxy process on port: " + this.proxyPort + ", exit with code: " + startedProcess.getProcess().exitValue(), cause);
250+
private void updateCommandWithLogLevel(List<String> command) {
251+
command.add("--set");
252+
command.add("termlog_verbosity=" + getMitmProxyLoggingLevel());
253+
}
254+
255+
private void updateCommandWithUpstreamProxy(List<String> command) {
256+
InetSocketAddress upstreamProxyAddress = proxyManager.getUpstreamProxyAddress();
257+
if (upstreamProxyAddress != null) {
258+
String schema = "http";
259+
if (proxyManager.isUseHttpsUpstreamProxy()) {
260+
schema = "https";
207261
}
262+
command.add("--mode");
263+
command.add("upstream:" + schema + "://" + upstreamProxyAddress.getHostName() + ":" + upstreamProxyAddress.getPort());
208264
}
209265
}
210266

browserup-proxy-core/src/main/java/com/browserup/bup/mitmproxy/management/HarCaptureManager.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
77
import com.fasterxml.jackson.databind.ObjectMapper;
88
import org.apache.commons.lang3.tuple.Pair;
9+
import org.slf4j.Logger;
10+
import org.slf4j.LoggerFactory;
911

1012
import java.io.File;
1113
import java.io.IOException;
@@ -16,6 +18,8 @@
1618
import static org.apache.commons.lang3.tuple.Pair.of;
1719

1820
public class HarCaptureManager {
21+
private static final Logger LOGGER = LoggerFactory.getLogger(HarCaptureManager.class);
22+
1923
private final AddonsManagerClient addonsManagerClient;
2024
private final MitmProxyProcessManager mitmProxyManager;
2125
private Har lastHar = new Har();
@@ -41,7 +45,7 @@ public Har getHar(Boolean cleanHar) {
4145
add(of("cleanHar", valueOf(cleanHar)));
4246
}},
4347
HarResponse.class);
44-
System.out.println("PARSING HAR: " + response.path);
48+
LOGGER.info("Parsing HAR from file: " + response.path);
4549
return parseHar(response.path);
4650
}
4751

0 commit comments

Comments
 (0)