2

I'm currently experimenting with javafx and I'm trying to make a web browser with it. So far it's coming along pretty nicely, but it annoys me that I continuously have to log in on every single page. So I decided to use cookies and store them inside a file, so I don't have to log in each and every time. I've been trying to get this working for the past 5 hours, but I still have to log in each time. This is what I have so far:

public class Main extends Application {

public static void main(String[] args) {
    if (!Values.SRCFILE.exists()) {
        Installation.launch(Installation.class, args);
        return;
    }

    launch(args);
}

private Stage stage;
private GridPane pane;

private List<BrowserTab> tabs;

@FXML
private TabPane tabPane;

@FXML
public void initialize() {
    tabs = new ArrayList<>();

    CookieManager manager = new CookieManager();
    manager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
    CookieHandler.setDefault(manager);

    Map<String, List<String>> map = new HashMap<>();
    URI uri = null;

    try {
        for (String line : Files.readAllLines(Values.COOKIESFILE.toPath())) {
            String[] values = line.split("\\|");
            URI newUri = new URI(values[0]);

            if (uri == null)
                uri = newUri;

            if (!uri.equals(newUri)) {
                CookieHandler.getDefault().put(uri, map);
                uri = newUri;
                System.out.println(map);
                map = new HashMap<>();
            }

            String[] actualValues = values[1].split(":");

            map.put(actualValues[0], Arrays.asList(actualValues[1].split(";")));
        }

        if (uri != null)
            CookieHandler.getDefault().put(uri, map);
    } catch (IOException | URISyntaxException e) {
        e.printStackTrace();
    }

    System.out.println(map);

    stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
        @Override
        public void handle(WindowEvent event) {
            if (tabs.size() > 1) {
                Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
                alert.setTitle("Closing window");
                alert.setHeaderText("");
                alert.setContentText("Are you sure you want to close this window? Doing so will close all open tabs");
                alert.showAndWait();
            }

            //save cookies
            CookieStore store = ((CookieManager) CookieHandler.getDefault()).getCookieStore();
            try {
                Files.write(Values.COOKIESFILE.toPath(), ("").getBytes(), StandardOpenOption.TRUNCATE_EXISTING);

                for (URI uri : store.getURIs()) {
                    Map<String, List<String>> map = CookieHandler.getDefault().get(uri, new HashMap<>());

                    Files.write(Values.COOKIESFILE.toPath(), (uri + "|").getBytes(), StandardOpenOption.APPEND);

                    for (String value : map.keySet()) {
                        Files.write(Values.COOKIESFILE.toPath(), (value + ":").getBytes(), StandardOpenOption.APPEND);

                        for (String line : map.get(value))
                            Files.write(Values.COOKIESFILE.toPath(), (line + ";").getBytes(), StandardOpenOption.APPEND);

                        Files.write(Values.COOKIESFILE.toPath(), ("\n").getBytes(), StandardOpenOption.APPEND);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    });

    addTab();
}

@Override
public void start(Stage primaryStage) {
    this.stage = primaryStage;
    stage.setTitle("Browser");

    try {
        // Load person overview.
        FXMLLoader loader = new FXMLLoader();
        loader.setController(this);
        loader.setLocation(Main.class.getResource("/browser.fxml"));
        pane = loader.load();

        Scene scene = new Scene(pane);
        stage.setScene(scene);
        stage.show();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public void setURL(String url) {
    tabs.get(tabPane.getSelectionModel().getSelectedIndex()).setURL(url);
}

public void search(String text) {
    tabs.get(tabPane.getSelectionModel().getSelectedIndex()).search(text);
}

void addTab() {
    BrowserTab browserTab = new BrowserTab(this);
    browserTab.setText("Loading...");
    browserTab.setURL("https://google.com/");

    tabs.add(browserTab);

    browserTab.setOnClosed(new EventHandler<Event>() {
        @Override
        public void handle(Event event) {
            tabs.remove(browserTab);

            if (tabPane.getTabs().isEmpty())
                Platform.exit();
        }
    });
    tabPane.getTabs().add(browserTab);
}

And my BrowserTab class

public class BrowserTab extends Tab {

private Main main;

private GridPane pane;

@FXML
private WebView webView;
@FXML
private TextField urlField;
@FXML
private Button backButton;
@FXML
private Button forwardButton;
@FXML
private Button goButton;
@FXML
private Button addTabButton;

public BrowserTab(Main main) {
    this.main = main;

    try {
        FXMLLoader loader = new FXMLLoader();
        loader.setController(this);
        loader.setLocation(getClass().getResource("/tab-template.fxml"));

        setContent(loader.load());
    } catch (IOException e) {
        e.printStackTrace();
    }

    initialize();
}

@FXML
public void initialize() {
    webView.getEngine().getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
        @Override
        public void changed(ObservableValue ov, Worker.State oldState, Worker.State newState) {
            if (newState == Worker.State.SUCCEEDED) {
                String title = webView.getEngine().titleProperty().getValue();

                if (title == null || title.trim().isEmpty())
                    title = webView.getEngine().getLocation();

                setText(title);
                urlField.setText(webView.getEngine().getLocation());
            }
        }
    });

    backButton.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
            WebHistory history = webView.getEngine().getHistory();

            history.go(-1);

            int index = history.getCurrentIndex();

            if (index + 1 > history.getEntries().size() - 1)
                forwardButton.setDisable(true);
            else
                forwardButton.setDisable(false);

            if (index - 1 < 0)
                backButton.setDisable(true);
            else
                backButton.setDisable(false);
        }
    });

    forwardButton.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
            WebHistory history = webView.getEngine().getHistory();

            history.go(1);

            int index = history.getCurrentIndex();

            if (index + 1 > history.getEntries().size() - 1)
                forwardButton.setDisable(true);
            else
                forwardButton.setDisable(false);

            if (index - 1 < 0)
                backButton.setDisable(true);
            else
                backButton.setDisable(false);
        }
    });

    urlField.setOnKeyPressed(new EventHandler<KeyEvent>() {
        @Override
        public void handle(KeyEvent event) {
            if (event.getCode() == KeyCode.ENTER)
                goButton.fire();
        }
    });

    goButton.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
            String url = urlField.getText();

            if (!url.contains(".")) {
                search(url);
                return;
            }

            if (!(url.startsWith("http://") || url.startsWith("https://")))
                url = "http://" + url;

            setURL(url);
        }
    });

    webView.getEngine().getHistory().getEntries().addListener(new ListChangeListener<WebHistory.Entry>() {
        @Override
        public void onChanged(Change<? extends WebHistory.Entry> c) {
            Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    int index = webView.getEngine().getHistory().getCurrentIndex();

                    System.out.println(index);

                    if (index + 1 > c.getList().size() - 1)
                        forwardButton.setDisable(true);
                    else
                        forwardButton.setDisable(false);

                    if (index - 1 < 0)
                        backButton.setDisable(true);
                    else
                        backButton.setDisable(false);
                }
            });
        }
    });

    addTabButton.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
            addTab();
        }
    });
}

public void setURL(String url) {
    webView.getEngine().load(url);
}

public void search(String text) {
    webView.getEngine().load("https://google.com/search?q=" + text);
}

private void addTab() {
    main.addTab();
}

The file formatting looks like this:

uri1|value:string1;string2;string3;
uri2|value:string1;string2;string3;

Any help would really be appreciated.

  • See: [Setting a cookie using JavaFX's WebEngine/WebView](http://stackoverflow.com/questions/14385233/setting-a-cookie-using-javafxs-webengine-webview). – jewelsea Mar 06 '17 at 21:28
  • @jewelsea That explains how to use the CookieManager, my main problem is that once my cookies are loaded from a file and I put them into the CookieManager my WebView seems to ignore them at all. I'm sure my cookies are saved correctly when not loading from a file, cause I am still logged in when I open a new tab in my application. –  Mar 06 '17 at 21:57
  • Actually the quote in the answer is "Do not waste your time trying to use java.net.CookieManager, and java.net.CookieStore. They are likely to cause problems with many sites because they implement the wrong standard.". Anyway, I didn't look at your question or the the related question in detail, so perhaps it isn't of use to you. Good luck with your problem. – jewelsea Mar 06 '17 at 22:50

1 Answers1

2

Alright after some more digging I found the solution. The problem is that the default string inside the map (key element) is always 'Cookie:'. However, when creating the map to actually add it to the CookieHandler it should be either 'Set-Cookie' or 'Set-Cookie2'. If it isn't either one of these, it'll simply skip the value and you end up with no cookies at all. Also, I ended up using a CookieManager and some methods to turn cookies into strings and vice versa. When creating the CookieManager you have to be careful to choose the constructor with two parameters (cookiestore and cookiepolicy) and not the one with zero parameters. Choosing the one with zero paramaters will not create a cookiestore and result in an error. When using the one with two parameters, just leave the store as null and it will create one for you. This is what I ended up using:

Saving:

CookieStore store = ((CookieManager) CookieHandler.getDefault()).getCookieStore();
try {
  Files.write(Values.COOKIESFILE.toPath(), ("").getBytes(), StandardOpenOption.TRUNCATE_EXISTING);

  for (URI uri : store.getURIs()) {
    Map<String, List<String>> map = CookieHandler.getDefault().get(uri, new HashMap<>());

    Files.write(Values.COOKIESFILE.toPath(), (uri + "|Cookie:").getBytes(), StandardOpenOption.APPEND);

    for (HttpCookie cookie : store.get(uri)) {
      if (cookie.hasExpired())
        continue;

      Files.write(Values.COOKIESFILE.toPath(), (CookieUtil.toString(cookie) + "~").getBytes(), StandardOpenOption.APPEND);
    }

    Files.write(Values.COOKIESFILE.toPath(), "\n".getBytes(), StandardOpenOption.APPEND);
  }
} catch (IOException e) {
  e.printStackTrace();
}

Loading:

CookieManager manager = new CookieManager(null, CookiePolicy.ACCEPT_ALL);

try {
  for (String line : Files.readAllLines(Values.COOKIESFILE.toPath())) {
    String[] values = line.split("\\|");
    URI uri = new URI(values[0]);

    String[] actualValues = values[1].split(":");

    if (actualValues.length < 2)
      continue;

    for (String header : actualValues[1].split("~"))
      manager.getCookieStore().add(uri, CookieUtil.fromString(header));
    }
  } catch (IOException | URISyntaxException e) {
    e.printStackTrace();
  }

CookieHandler.setDefault(manager);