OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 180 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
17 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
10
 *
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
13
 
14
 package org.openconcerto.utils;
15
 
41 ilm 16
import java.io.ByteArrayOutputStream;
17
import java.io.IOException;
18
import java.io.InputStream;
19
import java.io.OutputStream;
177 ilm 20
import java.io.UnsupportedEncodingException;
17 ilm 21
import java.net.InetAddress;
22
import java.net.NetworkInterface;
67 ilm 23
import java.net.ServerSocket;
17 ilm 24
import java.net.SocketException;
41 ilm 25
import java.net.URL;
177 ilm 26
import java.net.URLEncoder;
27
import java.nio.charset.StandardCharsets;
174 ilm 28
import java.security.KeyManagementException;
29
import java.security.NoSuchAlgorithmException;
30
import java.security.cert.X509Certificate;
17 ilm 31
import java.util.Enumeration;
177 ilm 32
import java.util.LinkedHashMap;
33
import java.util.Map;
34
import java.util.Map.Entry;
182 ilm 35
import java.util.regex.Pattern;
17 ilm 36
 
41 ilm 37
import javax.net.ssl.HostnameVerifier;
38
import javax.net.ssl.HttpsURLConnection;
174 ilm 39
import javax.net.ssl.SSLContext;
41 ilm 40
import javax.net.ssl.SSLSession;
174 ilm 41
import javax.net.ssl.TrustManager;
42
import javax.net.ssl.X509TrustManager;
41 ilm 43
 
17 ilm 44
public class NetUtils {
45
 
67 ilm 46
    public static int findFreePort(final int preferred) {
47
        return findFreePort(null, preferred);
48
    }
49
 
17 ilm 50
    /**
67 ilm 51
     * Returns a free port number on localhost.
52
     *
53
     * @param addr the bind address, <code>null</code> meaning an address of the loopback interface.
54
     * @param preferred if this port is free, then it's returned.
55
     * @return preferred if free otherwise any free port.
56
     */
57
    public static int findFreePort(final String addr, final int preferred) {
58
        if (isPortFree(addr, preferred))
59
            return preferred;
60
        else
61
            return findFreePort(addr);
62
    }
63
 
64
    /**
65
     * Returns a free port number on localhost.
66
     *
67
     * @return a free port number on localhost, or -1 if unable to find a free port
68
     */
69
    public static int findFreePort() {
70
        return findFreePort(null);
71
    }
72
 
73
    public static int findFreePort(final String addr) {
74
        return checkPort(addr, 0);
75
    }
76
 
77
    public static boolean isPortFree(final String addr, final int port) {
78
        if (port <= 0)
79
            throw new IllegalArgumentException(port + " is negative");
80
        return checkPort(addr, port) == port;
81
    }
82
 
83
    // with code from from org/eclipse/jdt/launching/SocketUtil.java
84
    private static int checkPort(final String addr, final int port) {
85
        ServerSocket socket = null;
86
        try {
87
            // ATTN InetAddress.getByName(null) means an address of the loopback interface, while
88
            // passing null means any/all local addresses. The problem is that the constructor will
89
            // succeed for a given port even if it is already bound with the other address.
90
            socket = new ServerSocket(port, 0, InetAddress.getByName(addr));
91
            return socket.getLocalPort();
92
        } catch (IOException e) {
93
        } finally {
94
            if (socket != null) {
95
                try {
96
                    socket.close();
97
                } catch (IOException e) {
98
                }
99
            }
100
        }
101
        return -1;
102
    }
103
 
104
    /**
17 ilm 105
     * Whether the passed address refers to this computer.
106
     *
107
     * @param addr an ip or dns address, eg "192.168.28.52".
108
     * @return <code>true</code> if <code>addr</code> is bound to an interface of this computer.
109
     */
110
    static public final boolean isSelfAddr(String addr) {
111
        if (addr == null)
112
            return false;
113
        if (addr.startsWith("127.") || addr.startsWith("localhost"))
114
            return true;
115
 
116
        try {
117
            final Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();
118
            while (en.hasMoreElements()) {
119
                final NetworkInterface ni = en.nextElement();
120
                final Enumeration<InetAddress> addresses = ni.getInetAddresses();
121
                while (addresses.hasMoreElements()) {
122
                    final InetAddress inetAddress = addresses.nextElement();
123
                    if (addr.startsWith(inetAddress.getHostAddress()))
124
                        return true;
125
                }
126
            }
127
            return false;
128
        } catch (SocketException e) {
129
            e.printStackTrace();
130
            return false;
131
        }
132
    }
133
 
57 ilm 134
    public static final HostnameVerifier HostnameNonVerifier = new HostnameVerifier() {
135
        @Override
41 ilm 136
        public boolean verify(String hostname, SSLSession session) {
137
            return true;
138
        }
57 ilm 139
    };
41 ilm 140
 
174 ilm 141
    public static final String getHTTPContent(String address) {
142
        return getHTTPContent(address, false);
143
    }
144
 
57 ilm 145
    public static final String getHTTPContent(String address, final boolean dontVerify) {
41 ilm 146
        String content = "";
147
        OutputStream out = null;
148
        HttpsURLConnection conn = null;
149
        InputStream in = null;
150
        try {
151
            URL url = new URL(address);
152
            out = new ByteArrayOutputStream();
153
            conn = (HttpsURLConnection) url.openConnection();
154
            // Sur la connexion
57 ilm 155
            if (dontVerify) {
156
                conn.setHostnameVerifier(HostnameNonVerifier);
41 ilm 157
                // ou globalement
158
                // HttpsURLConnection.setDefaultHostnameVerifier(new CustomizedHostnameVerifier());
159
            }
160
 
161
            in = conn.getInputStream();
162
            final byte[] buffer = new byte[1024];
163
            int numRead;
164
 
165
            while ((numRead = in.read(buffer)) != -1) {
166
                out.write(buffer, 0, numRead);
167
 
168
            }
169
            content = out.toString();
170
 
171
        } catch (Exception exception) {
172
            exception.printStackTrace();
173
        } finally {
174
            try {
175
                if (in != null) {
176
                    in.close();
177
                }
178
                if (out != null) {
179
                    out.close();
180
                }
181
            } catch (IOException ioe) {
182
            }
183
        }
184
 
185
        return content;
186
    }
174 ilm 187
 
177 ilm 188
    static public final String urlEncode(final String... kv) {
182 ilm 189
        return urlEncode(false, kv);
190
    }
191
 
192
    static public final String urlEncode(final boolean spaceAsPlus, final String... kv) {
177 ilm 193
        final int size = kv.length;
194
        if (size % 2 != 0)
195
            throw new IllegalArgumentException("Odd number of items : " + size);
196
        final LinkedHashMap<String, Object> map = new LinkedHashMap<>(size / 2, 1);
197
        for (int i = 0; i < size; i += 2) {
198
            map.put(kv[i], kv[i + 1]);
199
        }
182 ilm 200
        return urlEncode(map, spaceAsPlus);
177 ilm 201
    }
202
 
180 ilm 203
    /**
182 ilm 204
     * Encode pairs in application/x-www-form-urlencoded format. Although both the
205
     * <a href="https://url.spec.whatwg.org/#urlencoded-serializing">URL standard</a> and the
206
     * <a href="https://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1">HTML standard</a>
207
     * specifies <code>spaceAsPlus</code> some applications expect the opposite (e.g. POST with
208
     * jetty).
209
     *
210
     * @param map the values to encode.
211
     * @param spaceAsPlus <code>true</code> to use '+' for a space, <code>false</code> to use '%20'.
212
     * @return the encoded string.
213
     * @see #percentEncode(String, String, boolean)
180 ilm 214
     */
182 ilm 215
    static public final String urlEncode(final Map<String, ?> map, final boolean spaceAsPlus) {
177 ilm 216
        if (map.isEmpty())
217
            return "";
218
        final String charset = StandardCharsets.UTF_8.name();
219
        final StringBuilder sb = new StringBuilder(256);
220
        for (final Entry<String, ?> e : map.entrySet()) {
221
            final Object value = e.getValue();
222
            // Avoid null and "null" confusion.
223
            if (value != null) {
224
                try {
182 ilm 225
                    sb.append(percentEncode(e.getKey(), charset, spaceAsPlus));
177 ilm 226
                    sb.append('=');
182 ilm 227
                    sb.append(percentEncode(String.valueOf(value), charset, spaceAsPlus));
177 ilm 228
                    sb.append('&');
229
                } catch (UnsupportedEncodingException exn) {
230
                    throw new IllegalStateException("UTF-8 should be standard", exn);
231
                }
232
            }
233
        }
234
        // remove last '&'
235
        sb.setLength(sb.length() - 1);
236
        return sb.toString();
237
    }
238
 
182 ilm 239
    static private final Pattern SPACE_PATTERN = Pattern.compile("+", Pattern.LITERAL);
240
 
241
    /**
242
     * Percent encode a string.
243
     *
244
     * @param s the string to encode.
245
     * @param charset the charset to use.
246
     * @param spaceAsPlus <code>true</code> to use '+' for a space (as per
247
     *        <a href="https://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1">HTML</a> and
248
     *        <a href=
249
     *        "https://url.spec.whatwg.org/#urlencoded-serializing">application/x-www-form-urlencoded</a>
250
     *        of URL Standard), <code>false</code> to use '%20' (as per
251
     *        <a href="https://url.spec.whatwg.org/#path-state">Path part</a> of URL Standard).
252
     * @return the encoded string.
253
     * @throws UnsupportedEncodingException if charset is unknown.
254
     * @see <a href="https://url.spec.whatwg.org/#string-percent-encode-after-encoding">URL
255
     *      standard</a>
256
     */
257
    static public final String percentEncode(final String s, final String charset, final boolean spaceAsPlus) throws UnsupportedEncodingException {
258
        final String withPlus = URLEncoder.encode(s, charset);
259
        if (spaceAsPlus)
260
            return withPlus;
261
        return SPACE_PATTERN.matcher(withPlus).replaceAll("%20");
262
    }
263
 
174 ilm 264
    // Create a trust manager that does not validate certificate chains
265
    static private final TrustManager[] TRUSTALL_MANAGERS = new TrustManager[] { new X509TrustManager() {
266
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
267
            return null;
268
        }
269
 
270
        public void checkClientTrusted(X509Certificate[] certs, String authType) {
271
        }
272
 
273
        public void checkServerTrusted(X509Certificate[] certs, String authType) {
274
        }
275
    } };
276
 
277
    static public final SSLContext createTrustAllContext() throws KeyManagementException, NoSuchAlgorithmException {
278
        final SSLContext sc = SSLContext.getInstance("TLS");
279
        sc.init(null, TRUSTALL_MANAGERS, new java.security.SecureRandom());
280
        return sc;
281
    }
17 ilm 282
}