Configuration window, allowdowngrade
This commit is contained in:
@@ -1,6 +1,3 @@
|
||||
Manifest-Version: 1.0
|
||||
Main-Class: ovh.alexisdelhaie.endpoint.Main
|
||||
Class-Path: src.zip javafx-swt.jar javafx.web.jar javafx.base.jar javafx
|
||||
.fxml.jar javafx.media.jar javafx.swing.jar javafx.controls.jar javafx.
|
||||
graphics.jar
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.stage.Stage;
|
||||
import ovh.alexisdelhaie.endpoint.controllers.Controller;
|
||||
|
||||
public class Main extends Application {
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.shape.*?>
|
||||
<?import javafx.scene.text.*?>
|
||||
|
||||
|
||||
<AnchorPane prefHeight="556.0" prefWidth="410.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ovh.alexisdelhaie.endpoint.Configuration">
|
||||
<children>
|
||||
<Label layoutX="12.0" layoutY="11.0" text="SSL">
|
||||
<font>
|
||||
<Font name="System Bold" size="12.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label layoutX="13.0" layoutY="35.0" text="Allow invalid SSL certificate" />
|
||||
<CheckBox layoutX="381.0" layoutY="31.0" mnemonicParsing="false" />
|
||||
<Line endX="100.0" layoutX="271.0" layoutY="48.0" startX="-100.0" stroke="#bfbfbf" strokeLineCap="ROUND" />
|
||||
</children>
|
||||
</AnchorPane>
|
||||
@@ -0,0 +1,127 @@
|
||||
package ovh.alexisdelhaie.endpoint.configuration;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import javafx.scene.control.Alert;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ConfigurationProperties {
|
||||
|
||||
private Map<String, String> properties;
|
||||
private String osname;
|
||||
private String filepath;
|
||||
private ObjectMapper mapper;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public ConfigurationProperties() {
|
||||
osname = System.getProperty("os.name").toUpperCase();
|
||||
properties = new HashMap<>();
|
||||
mapper = new ObjectMapper();
|
||||
filepath = new StringBuilder(getAppData())
|
||||
.append("EndPoint")
|
||||
.append(getSeparator())
|
||||
.append("settings.json")
|
||||
.toString();
|
||||
createAppFolder();
|
||||
load();
|
||||
}
|
||||
|
||||
public void setProperty(String key, String value) {
|
||||
properties.put(key, value);
|
||||
save();
|
||||
}
|
||||
|
||||
public String getStringProperty(String key, String defaultS) {
|
||||
if (properties.containsKey(key)) {
|
||||
return properties.get(key);
|
||||
}
|
||||
return defaultS;
|
||||
}
|
||||
|
||||
public boolean getBooleanProperty(String key, boolean defaultB) {
|
||||
if (properties.containsKey(key)) {
|
||||
return Boolean.parseBoolean(properties.get(key));
|
||||
}
|
||||
return defaultB;
|
||||
}
|
||||
|
||||
private void save() {
|
||||
try {
|
||||
mapper.writeValue(new File(filepath), properties);
|
||||
} catch (Exception e) {
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setTitle("Cannot save settings");
|
||||
alert.setHeaderText("There was an error while saving settings file");
|
||||
alert.setContentText(e.getMessage());
|
||||
alert.showAndWait();
|
||||
}
|
||||
}
|
||||
|
||||
private void load() {
|
||||
File f = new File(filepath);
|
||||
try {
|
||||
if (f.exists()) {
|
||||
properties = mapper.readValue(f, new TypeReference<Map<String, String>>() { });
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setTitle("Cannot initialize settings");
|
||||
alert.setHeaderText("There was an error while initializing settings file");
|
||||
alert.setContentText(e.getMessage());
|
||||
alert.showAndWait();
|
||||
}
|
||||
}
|
||||
|
||||
private void createAppFolder() {
|
||||
try {
|
||||
Path path = Paths.get(new StringBuilder(getAppData())
|
||||
.append("EndPoint")
|
||||
.append(getSeparator()).toString());
|
||||
if (!Files.exists(path)) {
|
||||
Files.createDirectories(path);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setTitle("Cannot create app folder");
|
||||
alert.setHeaderText("There was an error while creating appdata folder");
|
||||
alert.setContentText(e.getMessage());
|
||||
alert.showAndWait();
|
||||
}
|
||||
}
|
||||
|
||||
private String getAppData() {
|
||||
String path = "";
|
||||
if (osname.contains("WIN")) {
|
||||
path = System.getenv("APPDATA");
|
||||
path = (path.endsWith("\\") ? path : path + "\\");
|
||||
}
|
||||
else if (osname.contains("MAC")) {
|
||||
path = System.getProperty("user.home") + "/Library/";
|
||||
}
|
||||
else if (osname.contains("NUX")) {
|
||||
path = System.getProperty("user.home");
|
||||
path = (path.endsWith("/") ? path : path + "/");
|
||||
}
|
||||
else {
|
||||
path = System.getProperty("user.dir");
|
||||
path = (path.endsWith("/") ? path : path + "/");
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
private String getSeparator() {
|
||||
if (osname.contains("WIN")) {
|
||||
return "\\";
|
||||
}
|
||||
return "/";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package ovh.alexisdelhaie.endpoint.controllers;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import ovh.alexisdelhaie.endpoint.configuration.ConfigurationProperties;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class ConfigurationController
|
||||
{
|
||||
|
||||
private ConfigurationProperties configurationProperties;
|
||||
private Stage primaryStage;
|
||||
|
||||
@FXML
|
||||
private CheckBox allowInvalidSsl;
|
||||
@FXML
|
||||
private CheckBox allowDowngrade;
|
||||
|
||||
public void setStageAndSetupListeners(Stage s) {
|
||||
primaryStage = s;
|
||||
}
|
||||
|
||||
public void setConfigurationProperties(ConfigurationProperties properties) {
|
||||
configurationProperties = properties;
|
||||
allowInvalidSsl.setSelected(properties.getBooleanProperty("allowInvalidSsl", false));
|
||||
allowDowngrade.setSelected(properties.getBooleanProperty("allowDowngrade", true));
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void onBooleanValueChanged(MouseEvent event) {
|
||||
CheckBox c = (CheckBox) event.getSource();
|
||||
configurationProperties.setProperty(c.getId(), String.valueOf(c.isSelected()));
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void showAboutDialog() {
|
||||
try {
|
||||
Stage dialog = new Stage();
|
||||
Parent xml = FXMLLoader.load(getClass().getResource("about.fxml"));
|
||||
dialog.initOwner(primaryStage);
|
||||
dialog.setScene(new Scene(xml, 677, 365));
|
||||
dialog.setMaxHeight(365);
|
||||
dialog.setMinHeight(365);
|
||||
dialog.setMaxWidth(707);
|
||||
dialog.setMinWidth(707);
|
||||
dialog.setResizable(false);
|
||||
dialog.setTitle("About EndPoint");
|
||||
dialog.getIcons().add( new Image(
|
||||
Controller.class.getResourceAsStream( "icon.png" )));
|
||||
dialog.initModality(Modality.APPLICATION_MODAL);
|
||||
dialog.showAndWait();
|
||||
} catch (IOException e) {
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setTitle("Cannot initialize About");
|
||||
alert.setHeaderText("There was an error while initializing this dialog");
|
||||
alert.setContentText(e.getMessage());
|
||||
alert.showAndWait();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package ovh.alexisdelhaie.endpoint;
|
||||
package ovh.alexisdelhaie.endpoint.controllers;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.StringProperty;
|
||||
@@ -13,18 +13,23 @@ import javafx.scene.Scene;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import org.apache.commons.validator.routines.UrlValidator;
|
||||
import ovh.alexisdelhaie.endpoint.configuration.ConfigurationProperties;
|
||||
import ovh.alexisdelhaie.endpoint.http.HttpClient;
|
||||
import ovh.alexisdelhaie.endpoint.http.Request;
|
||||
import ovh.alexisdelhaie.endpoint.http.RequestBuilder;
|
||||
import ovh.alexisdelhaie.endpoint.http.Response;
|
||||
import ovh.alexisdelhaie.endpoint.impl.EditCell;
|
||||
import ovh.alexisdelhaie.endpoint.model.Param;
|
||||
import ovh.alexisdelhaie.endpoint.url.URLGenerator;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
@@ -80,8 +85,11 @@ public class Controller implements Initializable {
|
||||
private Stage primaryStage;
|
||||
private HashMap<Integer, String> requests;
|
||||
|
||||
private ConfigurationProperties properties;
|
||||
|
||||
@Override
|
||||
public void initialize(URL location, ResourceBundle resources) {
|
||||
properties = new ConfigurationProperties();
|
||||
requests = new HashMap<>();
|
||||
String[] method = { "GET", "POST", "HEAD", "PUT", "DELETE" };
|
||||
httpMethod.setItems(FXCollections.observableArrayList(method));
|
||||
@@ -184,6 +192,13 @@ public class Controller implements Initializable {
|
||||
|
||||
@FXML
|
||||
private void start() {
|
||||
if (requestInput.getText().isBlank()) {
|
||||
Alert alert = new Alert(Alert.AlertType.WARNING);
|
||||
alert.setTitle("URL field empty");
|
||||
alert.setContentText("Enter your URL in the field at the top of the window.");
|
||||
alert.showAndWait();
|
||||
return;
|
||||
}
|
||||
runningIndicatorPane.setVisible(true);
|
||||
new Thread(() -> {
|
||||
final String method = httpMethod.getValue();
|
||||
@@ -194,7 +209,10 @@ public class Controller implements Initializable {
|
||||
Request r = new RequestBuilder(requestInput.getText())
|
||||
.setCustomHeaders(getCustomHeaders())
|
||||
.build();
|
||||
HttpClient hc = new HttpClient();
|
||||
HttpClient hc = new HttpClient(
|
||||
properties.getBooleanProperty("allowInvalidSsl", false),
|
||||
properties.getBooleanProperty("allowDowngrade", true)
|
||||
);
|
||||
switch (method) {
|
||||
case "GET" -> response = hc.get(r);
|
||||
case "POST" -> response = hc.post(r, getBody());
|
||||
@@ -213,7 +231,6 @@ public class Controller implements Initializable {
|
||||
}
|
||||
} catch (IOException | NoSuchAlgorithmException | KeyManagementException e) {
|
||||
System.err.println(e.getMessage());
|
||||
e.printStackTrace();
|
||||
textArea.ifPresent(area -> Platform.runLater(() -> {
|
||||
resetResponseTab();
|
||||
area.setStyle("-fx-text-fill: red");
|
||||
@@ -255,6 +272,8 @@ public class Controller implements Initializable {
|
||||
raw.setText(res.getRawResponse());
|
||||
TextArea request = (TextArea) responseTab.get().getContent().lookup("#request");
|
||||
request.setText(res.getRequest().getRawRequest());
|
||||
GridPane downgradedIndicator = (GridPane) responseTab.get().getContent().lookup("#downgraded_indicator");
|
||||
downgradedIndicator.setVisible(res.isDowngraded());
|
||||
TableView<Param> headers = (TableView<Param>) responseTab.get().getContent().lookup("#headers");
|
||||
headers.getItems().clear();
|
||||
for (Map.Entry<String, String> entry : res.getHeaders().entrySet()) {
|
||||
@@ -279,6 +298,10 @@ public class Controller implements Initializable {
|
||||
time.setText("... ms");
|
||||
TextArea raw = (TextArea) responseTab.get().getContent().lookup("#raw");
|
||||
raw.setText("");
|
||||
TextArea request = (TextArea) responseTab.get().getContent().lookup("#request");
|
||||
request.setText("");
|
||||
GridPane downgradedIndicator = (GridPane) responseTab.get().getContent().lookup("#downgraded_indicator");
|
||||
downgradedIndicator.setVisible(false);
|
||||
TableView<Param> headers = (TableView<Param>) responseTab.get().getContent().lookup("#headers");
|
||||
headers.getItems().clear();
|
||||
}
|
||||
@@ -384,25 +407,29 @@ public class Controller implements Initializable {
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void showAboutDialog() {
|
||||
private void showConfigurationDialog() {
|
||||
try {
|
||||
Stage dialog = new Stage();
|
||||
Parent xml = FXMLLoader.load(getClass().getResource("about.fxml"));
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("configuration.fxml"));
|
||||
Parent xml = loader.load();
|
||||
ConfigurationController controller = loader.getController();
|
||||
controller.setStageAndSetupListeners(primaryStage);
|
||||
controller.setConfigurationProperties(properties);
|
||||
dialog.initOwner(primaryStage);
|
||||
dialog.setScene(new Scene(xml, 677, 365));
|
||||
dialog.setMaxHeight(365);
|
||||
dialog.setMinHeight(365);
|
||||
dialog.setMaxWidth(707);
|
||||
dialog.setMinWidth(707);
|
||||
dialog.setScene(new Scene(xml, 412, 556));
|
||||
dialog.setMaxHeight(556);
|
||||
dialog.setMinHeight(556);
|
||||
dialog.setMaxWidth(412);
|
||||
dialog.setMinWidth(412);
|
||||
dialog.setResizable(false);
|
||||
dialog.setTitle("About EndPoint");
|
||||
dialog.setTitle("Settings");
|
||||
dialog.getIcons().add( new Image(
|
||||
Controller.class.getResourceAsStream( "icon.png" )));
|
||||
dialog.initModality(Modality.APPLICATION_MODAL);
|
||||
dialog.showAndWait();
|
||||
} catch (IOException e) {
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setTitle("Cannot initialize About");
|
||||
alert.setTitle("Cannot initialize Settings");
|
||||
alert.setHeaderText("There was an error while initializing this dialog");
|
||||
alert.setContentText(e.getMessage());
|
||||
alert.showAndWait();
|
||||
@@ -412,7 +439,22 @@ public class Controller implements Initializable {
|
||||
@FXML
|
||||
private void requestInputOnKeyPressed() {
|
||||
Tab tab = tabs.getSelectionModel().getSelectedItem();
|
||||
requests.put(tab.hashCode(), requestInput.getText());
|
||||
String url = requestInput.getText();
|
||||
requests.put(tab.hashCode(), url);
|
||||
if (url.isBlank()) {
|
||||
tab.setText("Untitled");
|
||||
} else {
|
||||
url = URLGenerator.addSchemaToUrl(url);
|
||||
UrlValidator urlValidator = new UrlValidator();
|
||||
if (urlValidator.isValid(url)) {
|
||||
try {
|
||||
URL u = new URL(url);
|
||||
tab.setText(u.getHost());
|
||||
} catch (MalformedURLException e) {
|
||||
System.err.println(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.text.*?>
|
||||
|
||||
<AnchorPane maxHeight="556.0" maxWidth="412.0" minHeight="556.0" minWidth="412.0" prefHeight="556.0" prefWidth="412.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ovh.alexisdelhaie.endpoint.controllers.ConfigurationController">
|
||||
<children>
|
||||
<Label layoutX="12.0" layoutY="11.0" text="SSL">
|
||||
<font>
|
||||
<Font name="System Bold" size="12.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label layoutX="13.0" layoutY="35.0" text="Allow invalid SSL certificate" />
|
||||
<CheckBox fx:id="allowInvalidSsl" layoutX="381.0" layoutY="31.0" mnemonicParsing="false" onMouseClicked="#onBooleanValueChanged" AnchorPane.rightAnchor="14.333333333333332" AnchorPane.topAnchor="32.0" />
|
||||
<Label layoutX="13.0" layoutY="64.0" text="Downgrade when SSL failed" />
|
||||
<CheckBox fx:id="allowDowngrade" layoutX="381.0" layoutY="60.0" mnemonicParsing="false" onMouseClicked="#onBooleanValueChanged" selected="true" AnchorPane.rightAnchor="14.333333333333332" AnchorPane.topAnchor="60.0" />
|
||||
<Button layoutX="14.0" layoutY="517.0" mnemonicParsing="false" onMouseClicked="#showAboutDialog" text="About" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0" />
|
||||
</children>
|
||||
</AnchorPane>
|
||||
BIN
src/ovh/alexisdelhaie/endpoint/controllers/icon.png
Normal file
BIN
src/ovh/alexisdelhaie/endpoint/controllers/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
@@ -54,5 +54,22 @@
|
||||
</font>
|
||||
</TextArea>
|
||||
<Label text="Sended request" GridPane.columnIndex="4" GridPane.rowIndex="4" />
|
||||
<GridPane fx:id="downgraded_indicator" visible="false" GridPane.columnIndex="4" GridPane.rowIndex="1">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="382.0" minWidth="10.0" prefWidth="30.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="644.0" minWidth="10.0" prefWidth="644.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<Label prefHeight="17.0" prefWidth="354.0" text="This request was downgraded from SSL to plain text" textFill="#cfa600" GridPane.columnIndex="1" />
|
||||
<Label alignment="CENTER" contentDisplay="CENTER" prefHeight="22.0" prefWidth="37.0" text="" textAlignment="CENTER" textFill="#cfa600">
|
||||
<font>
|
||||
<Font name="Segoe MDL2 Assets" size="20.0" />
|
||||
</font>
|
||||
</Label>
|
||||
</children>
|
||||
</GridPane>
|
||||
</children>
|
||||
</GridPane>
|
||||
@@ -20,9 +20,15 @@ public class HttpClient {
|
||||
public final static int DEFAULT_TIMEOUT = 10000;
|
||||
|
||||
private final boolean allowInvalidSsl;
|
||||
private final boolean allowDowngrade;
|
||||
private boolean downgraded;
|
||||
|
||||
public HttpClient() { this(false); }
|
||||
public HttpClient(boolean allowInvalidSsl) { this.allowInvalidSsl = allowInvalidSsl; }
|
||||
public HttpClient() { this(false, true); }
|
||||
public HttpClient(boolean allowInvalidSsl, boolean allowDowngrade) {
|
||||
this.allowInvalidSsl = allowInvalidSsl;
|
||||
this.allowDowngrade = allowDowngrade;
|
||||
this.downgraded = false;
|
||||
}
|
||||
|
||||
public Optional<Response> get(Request r) throws IOException, KeyManagementException, NoSuchAlgorithmException {
|
||||
return process("GET", r, "");
|
||||
@@ -51,10 +57,13 @@ public class HttpClient {
|
||||
}
|
||||
|
||||
private Optional<Response> process(String method, Request r, String body) throws IOException, NoSuchAlgorithmException, KeyManagementException {
|
||||
String headers = buildHeaders(method, r);
|
||||
Socket s = (r.getScheme().equals("https")) ?
|
||||
buildSSLSocket(resolve(r.getHost()).getHostAddress(), r.getPort())
|
||||
: buildSocket(resolve(r.getHost()).getHostAddress(), r.getPort());
|
||||
if (allowDowngrade && (s.getPort() != r.getPort())) {
|
||||
r.setPort(s.getPort());
|
||||
}
|
||||
String headers = buildHeaders(method, r);
|
||||
String request = (method.equals("POST") || method.equals("PUT")) ?
|
||||
new StringBuilder(headers).append(body).toString() : headers;
|
||||
if (s.isConnected()) {
|
||||
@@ -68,7 +77,7 @@ public class HttpClient {
|
||||
Instant end = Instant.now();
|
||||
long time = end.toEpochMilli() - start.toEpochMilli();
|
||||
r.setRawRequest(request);
|
||||
return Optional.of(new Response(b, time, r));
|
||||
return Optional.of(new Response(b, time, downgraded, r));
|
||||
} finally {
|
||||
s.close();
|
||||
}
|
||||
@@ -89,6 +98,7 @@ public class HttpClient {
|
||||
}
|
||||
|
||||
private Socket buildSSLSocket(String host, int port) throws IOException, KeyManagementException, NoSuchAlgorithmException {
|
||||
System.setProperty("com.sun.net.ssl.rsaPreMasterSecretFix", "true");
|
||||
SSLSocketFactory factory;
|
||||
if(!allowInvalidSsl) {
|
||||
factory = (SSLSocketFactory)SSLSocketFactory.getDefault();
|
||||
@@ -104,11 +114,23 @@ public class HttpClient {
|
||||
sc.init(null, trustAllCerts, new java.security.SecureRandom());
|
||||
factory = sc.getSocketFactory();
|
||||
}
|
||||
Socket s = factory.createSocket(host, port);
|
||||
((SSLSocket)s).setEnabledProtocols(new String[] { "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2" });
|
||||
|
||||
SSLSocket s = (SSLSocket) factory.createSocket(host, port);
|
||||
s.setEnabledProtocols(new String[] { "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2" });
|
||||
s.setKeepAlive(false);
|
||||
s.setSoTimeout(DEFAULT_TIMEOUT);
|
||||
((SSLSocket)s).startHandshake();
|
||||
if (allowDowngrade) {
|
||||
try {
|
||||
s.startHandshake();
|
||||
return s;
|
||||
} catch (Exception e) {
|
||||
System.err.println(e.getMessage());
|
||||
System.out.println("Downgrade to Non-SSL socket");
|
||||
downgraded = true;
|
||||
return buildSocket(host, (port == 443) ? 80 : port);
|
||||
}
|
||||
}
|
||||
s.startHandshake();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -68,14 +68,13 @@ public enum HttpStatus {
|
||||
|
||||
private final int code;
|
||||
private final String message;
|
||||
private static final Map<Integer, HttpStatus> map;
|
||||
|
||||
HttpStatus(int code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
private static final Map<Integer, HttpStatus> map;
|
||||
|
||||
static {
|
||||
map = new HashMap<>();
|
||||
for (HttpStatus v : HttpStatus.values()) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package ovh.alexisdelhaie.endpoint.http;
|
||||
|
||||
import ovh.alexisdelhaie.endpoint.URLGenerator;
|
||||
import ovh.alexisdelhaie.endpoint.url.URLGenerator;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
@@ -10,7 +10,7 @@ public class Request {
|
||||
private final String host;
|
||||
private final String scheme;
|
||||
private final String path;
|
||||
private final int port;
|
||||
private int port;
|
||||
private final HashMap<String, String> params;
|
||||
private final HashMap<String, String> customHeaders;
|
||||
private final String body;
|
||||
@@ -67,6 +67,8 @@ public class Request {
|
||||
rawRequest = r;
|
||||
}
|
||||
|
||||
void setPort(int p) { this.port = p; }
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
||||
@@ -20,8 +20,9 @@ public class Response {
|
||||
private String status;
|
||||
private final long time;
|
||||
private final Request request;
|
||||
private final boolean downgraded;
|
||||
|
||||
Response(byte[] res, long time, Request r) throws UnsupportedEncodingException {
|
||||
Response(byte[] res, long time, boolean downgraded, Request r) throws UnsupportedEncodingException {
|
||||
headers = new HashMap<>();
|
||||
rawResponse = new String(res, StandardCharsets.UTF_8);
|
||||
int crlf = rawResponse.indexOf(DOUBLE_CRLF);
|
||||
@@ -31,6 +32,7 @@ public class Response {
|
||||
body = rawResponse.substring(crlf + DOUBLE_CRLF.length());
|
||||
this.time = time;
|
||||
request = r;
|
||||
this.downgraded = downgraded;
|
||||
}
|
||||
|
||||
private void parseHeaders() {
|
||||
@@ -106,6 +108,10 @@ public class Response {
|
||||
|
||||
public Request getRequest() { return request; }
|
||||
|
||||
public boolean isDowngraded() {
|
||||
return downgraded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
|
||||
<AnchorPane xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ovh.alexisdelhaie.endpoint.Controller">
|
||||
<AnchorPane xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ovh.alexisdelhaie.endpoint.controllers.Controller">
|
||||
<TextField fx:id="requestInput" layoutX="109.0" layoutY="39.0" onKeyTyped="#requestInputOnKeyPressed" prefHeight="25.0" prefWidth="861.0" AnchorPane.leftAnchor="109.0" AnchorPane.rightAnchor="96.99999999999989" AnchorPane.topAnchor="39.0" />
|
||||
<Button layoutX="979.0" layoutY="39.0" mnemonicParsing="false" onMouseClicked="#start" prefHeight="25.0" prefWidth="73.0" text="Send" AnchorPane.rightAnchor="16.0" AnchorPane.topAnchor="39.0" />
|
||||
<ChoiceBox id="httpMethod" fx:id="httpMethod" layoutX="14.0" layoutY="39.0" prefHeight="25.0" prefWidth="85.0" AnchorPane.leftAnchor="14.0" AnchorPane.topAnchor="39.0" />
|
||||
@@ -11,7 +11,7 @@
|
||||
<TabPane fx:id="tabs" layoutX="-1.0" layoutY="104.0" prefHeight="540.0" prefWidth="1067.0" tabClosingPolicy="ALL_TABS" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="104.0">
|
||||
</TabPane>
|
||||
<Button layoutX="1022.0" layoutY="71.0" mnemonicParsing="false" onMouseClicked="#createNewTab" prefHeight="25.0" prefWidth="31.0" text="+" AnchorPane.rightAnchor="16.0" AnchorPane.topAnchor="71.0" />
|
||||
<Button layoutX="1000.0" layoutY="71.0" mnemonicParsing="false" onMouseClicked="#showAboutDialog" prefHeight="25.0" prefWidth="31.0" text="?" AnchorPane.rightAnchor="58.0" AnchorPane.topAnchor="71.0" />
|
||||
<Button layoutX="1020.0" layoutY="8.0" mnemonicParsing="false" onMouseClicked="#showConfigurationDialog" prefHeight="25.0" prefWidth="73.0" text="Settings" AnchorPane.rightAnchor="16.0" AnchorPane.topAnchor="8.0" />
|
||||
<Pane fx:id="runningIndicatorPane" layoutX="109.0" layoutY="74.0" prefHeight="17.0" prefWidth="200.0" visible="false">
|
||||
<children>
|
||||
<ProgressIndicator layoutX="2.0" layoutY="1.0" prefHeight="17.0" prefWidth="18.0" />
|
||||
|
||||
44
src/ovh/alexisdelhaie/endpoint/url/SpecialChar.java
Normal file
44
src/ovh/alexisdelhaie/endpoint/url/SpecialChar.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package ovh.alexisdelhaie.endpoint.url;
|
||||
|
||||
public enum SpecialChar {
|
||||
SPACE(' ', "%20"),
|
||||
HASH('#', "%23"),
|
||||
LEFT_BRACE('{', "%7B"),
|
||||
RIGHT_BRACE('}', "%7D"),
|
||||
LEFT_BRACKET('[', "%5B"),
|
||||
RIGHT_BRACKET(']', "%5D"),
|
||||
AT('@', "%40"),
|
||||
CIRCUMFLEX('^', "%5E"),
|
||||
SLASH('/', "%2F"),
|
||||
BACK_SLASH('\\', "%5C"),
|
||||
DOLLAR('$', "%24"),
|
||||
LEFT_CHEVRON('<', "%3C"),
|
||||
RIGHT_CHEVRON('>', "%3E"),
|
||||
PIPE('|', "%7C"),
|
||||
TILDE('~', "%7E"),
|
||||
BACK_QUOTE('`', "%60"),
|
||||
INTERROGATION('?', "%3F"),
|
||||
EQUAL('=', "%3D"),
|
||||
CR('\r', "%0D"),
|
||||
LF('\n', "%0A"),
|
||||
SEMICOLON(';', "%3B"),
|
||||
COLON(':', "%3A"),
|
||||
AND('&', "%26");
|
||||
|
||||
private char decodedChar;
|
||||
private String encodedChar;
|
||||
|
||||
SpecialChar(char decodedChar, String encodedChar) {
|
||||
this.decodedChar = decodedChar;
|
||||
this.encodedChar = encodedChar;
|
||||
}
|
||||
|
||||
public static String encodeString(String decodedString) {
|
||||
String encodedString = decodedString.replace("%", "%25");
|
||||
for (SpecialChar v : SpecialChar.values()) {
|
||||
encodedString = encodedString.replace(Character.toString(v.decodedChar), v.encodedChar);
|
||||
}
|
||||
return encodedString;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,29 +1,16 @@
|
||||
package ovh.alexisdelhaie.endpoint;
|
||||
package ovh.alexisdelhaie.endpoint.url;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class URLGenerator {
|
||||
|
||||
public static final String HTTP_START = "http://";
|
||||
public static final String HTTPS_START = "https://";
|
||||
public static final String[][] SPECIAL_CHARS = new String[][] {
|
||||
{ " ", "%20" }, { "<", "%3C" }, { ">", "%3E" },
|
||||
{ "#", "%23" }, { "{", "%7B" },
|
||||
{ "}", "%7D" }, { "|", "%7C" }, { "\\", "%5C" },
|
||||
{ "^", "%5E" }, { "~", "%7E" }, { "[", "%5B" },
|
||||
{ "]", "%5D" }, { "`", "%60" }, { ";", "%3B" },
|
||||
{ "/", "%2F" }, { "?", "%3F" }, { ":", "%3A" },
|
||||
{ "@", "%40" }, { "=", "%3D" }, { "&", "%26" },
|
||||
{ "$", "%24" }, { "\r", "%0D" }, { "\n", "%0A" }
|
||||
};
|
||||
|
||||
static public String processNewUrl(HashMap<String, String> p, String url) {
|
||||
public static String processNewUrl(HashMap<String, String> p, String url) {
|
||||
try {
|
||||
if (!url.startsWith(HTTP_START) && !url.startsWith(HTTPS_START)) {
|
||||
url = HTTP_START + url;
|
||||
@@ -43,12 +30,7 @@ public class URLGenerator {
|
||||
return url;
|
||||
}
|
||||
|
||||
public static Map<String, String> getSpecialCharRef() {
|
||||
return Stream.of(SPECIAL_CHARS)
|
||||
.collect(Collectors.toMap(data -> (String) data[0], data -> (String) data[1]));
|
||||
}
|
||||
|
||||
static public String generateParamsPartWithEncoding(HashMap<String, String> p) {
|
||||
public static String generateParamsPartWithEncoding(HashMap<String, String> p) {
|
||||
String result = "?";
|
||||
for (Map.Entry<String, String> entry : p.entrySet()) {
|
||||
result = new StringBuilder(result)
|
||||
@@ -65,13 +47,11 @@ public class URLGenerator {
|
||||
return result;
|
||||
}
|
||||
|
||||
static public String generateParamsPart(HashMap<String, String> p) {
|
||||
Map<String, String> specialCharRef = getSpecialCharRef();
|
||||
|
||||
public static String generateParamsPart(HashMap<String, String> p) {
|
||||
String result = "?";
|
||||
for (Map.Entry<String, String> entry : p.entrySet()) {
|
||||
String key = escapeText(entry.getKey(), specialCharRef);
|
||||
String value = escapeText(entry.getValue(), specialCharRef);
|
||||
String key = SpecialChar.encodeString(entry.getKey());
|
||||
String value = SpecialChar.encodeString(entry.getValue());
|
||||
result = new StringBuilder(result)
|
||||
.append(key)
|
||||
.append("=")
|
||||
@@ -86,14 +66,11 @@ public class URLGenerator {
|
||||
return result;
|
||||
}
|
||||
|
||||
static public String escapeText(String s, Map<String, String> scr) {
|
||||
String result = s.replace("%", "%25");
|
||||
for (Map.Entry<String, String> entry : scr.entrySet()) {
|
||||
if (result.contains(entry.getKey())) {
|
||||
result = result.replace(entry.getKey(), entry.getValue());
|
||||
public static String addSchemaToUrl(String url) {
|
||||
if (!url.toLowerCase().startsWith("http://") && !url.toLowerCase().startsWith("https://")) {
|
||||
url = "http://" + url;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return url;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user