3ed86017f1ee154056b1582c755b5e19b0222361
[idea/community.git] / python / educational-core / student / src / com / jetbrains / edu / learning / stepic / EduStepicClient.java
1 package com.jetbrains.edu.learning.stepic;
2
3 import com.google.gson.FieldNamingPolicy;
4 import com.google.gson.Gson;
5 import com.google.gson.GsonBuilder;
6 import com.intellij.openapi.diagnostic.Logger;
7 import com.intellij.util.net.HttpConfigurable;
8 import com.intellij.util.net.ssl.CertificateManager;
9 import com.jetbrains.edu.learning.StudySerializationUtils;
10 import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
11 import com.jetbrains.edu.learning.courseFormat.TaskFile;
12 import org.apache.http.HttpEntity;
13 import org.apache.http.HttpHost;
14 import org.apache.http.HttpStatus;
15 import org.apache.http.StatusLine;
16 import org.apache.http.client.methods.CloseableHttpResponse;
17 import org.apache.http.client.methods.HttpGet;
18 import org.apache.http.impl.DefaultConnectionReuseStrategy;
19 import org.apache.http.impl.client.CloseableHttpClient;
20 import org.apache.http.impl.client.HttpClientBuilder;
21 import org.apache.http.impl.client.HttpClients;
22 import org.apache.http.util.EntityUtils;
23 import org.jetbrains.annotations.NotNull;
24
25 import javax.net.ssl.SSLContext;
26 import javax.net.ssl.TrustManager;
27 import javax.net.ssl.X509TrustManager;
28 import java.io.IOException;
29 import java.net.InetSocketAddress;
30 import java.net.Proxy;
31 import java.net.URI;
32 import java.security.KeyManagementException;
33 import java.security.NoSuchAlgorithmException;
34 import java.security.SecureRandom;
35 import java.security.cert.X509Certificate;
36 import java.util.List;
37
38 public class EduStepicClient {
39   private static final Logger LOG = Logger.getInstance(EduStepicClient.class.getName());
40   private static CloseableHttpClient ourClient;
41
42   private EduStepicClient() {
43   }
44
45   @NotNull
46   public static CloseableHttpClient getHttpClient() {
47     if (ourClient == null) {
48       initializeClient();
49     }
50     return ourClient;
51   }
52
53   public static <T> T getFromStepic(String link, final Class<T> container) throws IOException {
54     return getFromStepic(link, container, getHttpClient());
55   }
56
57   static <T> T getFromStepic(String link, final Class<T> container, @NotNull final CloseableHttpClient client) throws IOException {
58     if (!link.startsWith("/")) link = "/" + link;
59     final HttpGet request = new HttpGet(EduStepicNames.STEPIC_API_URL + link);
60     if (ourClient == null) {
61       initializeClient();
62     }
63
64     final CloseableHttpResponse response = client.execute(request);
65     final StatusLine statusLine = response.getStatusLine();
66     final HttpEntity responseEntity = response.getEntity();
67     final String responseString = responseEntity != null ? EntityUtils.toString(responseEntity) : "";
68     EntityUtils.consume(responseEntity);
69     if (statusLine.getStatusCode() != HttpStatus.SC_OK) {
70       throw new IOException("Stepic returned non 200 status code " + responseString);
71     }
72     Gson gson = new GsonBuilder().registerTypeAdapter(TaskFile.class, new StudySerializationUtils.Json.StepicTaskFileAdapter()).
73       registerTypeAdapter(AnswerPlaceholder.class, new StudySerializationUtils.Json.StepicAnswerPlaceholderAdapter()).
74       setDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").
75       setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
76     return gson.fromJson(responseString, container);
77   }
78
79   private static void initializeClient() {
80     if (ourClient == null) {
81       final HttpClientBuilder builder = getBuilder();
82       ourClient = builder.build();
83     }
84   }
85
86   @NotNull
87   private static TrustManager[] trustAllCerts() {
88     // Create a trust manager that does not validate certificate for this connection
89     return new TrustManager[]{new X509TrustManager() {
90       public X509Certificate[] getAcceptedIssuers() {
91         return null;
92       }
93
94       public void checkClientTrusted(X509Certificate[] certs, String authType) {
95       }
96
97       public void checkServerTrusted(X509Certificate[] certs, String authType) {
98       }
99     }};
100   }
101
102   @NotNull
103   private static HttpClientBuilder getBuilder() {
104     final HttpClientBuilder builder = HttpClients.custom().setSslcontext(CertificateManager.getInstance().getSslContext()).
105       setMaxConnPerRoute(100000).setConnectionReuseStrategy(DefaultConnectionReuseStrategy.INSTANCE);
106
107     final HttpConfigurable proxyConfigurable = HttpConfigurable.getInstance();
108     final List<Proxy> proxies = proxyConfigurable.getOnlyBySettingsSelector().select(URI.create(EduStepicNames.STEPIC_URL));
109     final InetSocketAddress address = proxies.size() > 0 ? (InetSocketAddress)proxies.get(0).address() : null;
110     if (address != null) {
111       builder.setProxy(new HttpHost(address.getHostName(), address.getPort()));
112     }
113     final TrustManager[] trustAllCerts = trustAllCerts();
114     try {
115       SSLContext sslContext = SSLContext.getInstance("TLS");
116       sslContext.init(null, trustAllCerts, new SecureRandom());
117       builder.setSslcontext(sslContext);
118     }
119     catch (NoSuchAlgorithmException | KeyManagementException e) {
120       LOG.error(e.getMessage());
121     }
122     return builder;
123   }
124 }