1 package com.omarpolo.gemini;
3 import javax.net.ssl.*;
6 import java.security.KeyManagementException;
7 import java.security.NoSuchAlgorithmException;
8 import java.security.SecureRandom;
9 import java.security.cert.X509Certificate;
10 import java.util.Collections;
11 import java.util.NoSuchElementException;
12 import java.util.Scanner;
14 public class Request implements AutoCloseable {
16 private final BufferedReader in;
17 private final PrintWriter out;
18 private final SSLSocket sock;
20 private final int code;
21 private final String meta;
23 public static class DummyManager extends X509ExtendedTrustManager {
26 public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket) {
30 public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket) {
34 public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine) {
38 public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine) {
42 public void checkClientTrusted(X509Certificate[] chain, String authType) {
46 public void checkServerTrusted(X509Certificate[] chain, String authType) {
50 public X509Certificate[] getAcceptedIssuers() {
55 public static class MalformedResponse extends Exception {}
57 public Request(String uri) throws IOException, MalformedResponse, URISyntaxException {
61 public Request(URL url) throws IOException, MalformedResponse {
62 this(url.getHost(), url.getPort(), url.toString());
65 public Request(URI uri) throws IOException, MalformedResponse {
66 this(uri.getHost(), uri.getPort(), uri.toString());
69 public Request(String host, int port, URL req) throws IOException, MalformedResponse {
70 this(host, port, req.toString());
73 public Request(String host, int port, URI req) throws IOException, MalformedResponse {
74 this(host, port, req.toString());
77 public Request(String host, int port, String req) throws IOException, MalformedResponse {
82 sock = connect(host, port);
84 var outStream = sock.getOutputStream();
85 out = new PrintWriter(
86 new BufferedWriter(new OutputStreamWriter(outStream)));
92 var inStream = sock.getInputStream();
93 in = new BufferedReader(new InputStreamReader(inStream));
95 var reply = in.readLine();
97 if (reply.length() > 1027) {
98 throw new MalformedResponse();
101 var s = new Scanner(new StringReader(reply));
106 } catch (NoSuchElementException e) {
107 throw new MalformedResponse();
111 private SSLSocket connect(String host, int port) throws IOException {
113 var params = new SSLParameters();
114 params.setServerNames(Collections.singletonList(new SNIHostName(host)));
116 var ctx = SSLContext.getInstance("TLS");
117 ctx.init(null, new DummyManager[]{new DummyManager()}, new SecureRandom());
118 var factory = (SSLSocketFactory) ctx.getSocketFactory();
120 var socket = (SSLSocket) factory.createSocket(host, port);
121 socket.setSSLParameters(params);
122 socket.startHandshake();
124 } catch (NoSuchAlgorithmException | KeyManagementException e) {
125 throw new RuntimeException("Unexpected failure", e);
129 public int getCode() {
133 public String getMeta() {
137 public BufferedReader body() {
141 public void close() throws IOException {