001package org.dcm4che3.net.proxy;
002
003import java.io.ByteArrayOutputStream;
004import java.io.IOException;
005import java.io.InputStream;
006import java.io.OutputStream;
007import java.net.Socket;
008
009import org.dcm4che3.util.Base64;
010
011/**
012 * Define basic proxy authentication processing. This code come from old
013 * Connection.doProxyHandshake() method (before refactoring).
014 *
015 * @author Amaury Pernette
016 * 
017 */
018public class BasicProxyManager implements ProxyManager {
019
020    public static final String PROVIDER_NAME = "org.dcm4che.basic";
021    public static final String VERSION = "1.0";
022
023    @Override
024    public String getProviderName() {
025        return PROVIDER_NAME;
026    }
027
028    @Override
029    public String getVersion() {
030        return VERSION;
031    }
032
033    @Override
034    public void doProxyHandshake(Socket s, String hostname, int port, String userauth, int connectTimeout)
035            throws IOException {
036
037        StringBuilder request = new StringBuilder(128);
038        request.append("CONNECT ").append(hostname).append(':').append(port).append(" HTTP/1.1\r\nHost: ")
039                .append(hostname).append(':').append(port);
040        if (userauth != null) {
041            byte[] b = userauth.getBytes("UTF-8");
042            char[] base64 = new char[(b.length + 2) / 3 * 4];
043            Base64.encode(b, 0, b.length, base64, 0);
044            request.append("\r\nProxy-Authorization: basic ").append(base64);
045        }
046        request.append("\r\n\r\n");
047        OutputStream out = s.getOutputStream();
048        out.write(request.toString().getBytes("US-ASCII"));
049        out.flush();
050
051        s.setSoTimeout(connectTimeout);
052        @SuppressWarnings("resource")
053        String response = new HTTPResponse(s).toString();
054        s.setSoTimeout(0);
055        if (!response.startsWith("HTTP/1.1 2"))
056            throw new IOException("Unable to tunnel through " + s + ". Proxy returns \"" + response + '\"');
057
058    }
059
060    private static class HTTPResponse extends ByteArrayOutputStream {
061
062        private final String rsp;
063
064        public HTTPResponse(Socket s) throws IOException {
065            super(64);
066            InputStream in = s.getInputStream();
067            boolean eol = false;
068            int b;
069            while ((b = in.read()) != -1) {
070                write(b);
071                if (b == '\n') {
072                    if (eol) {
073                        rsp = new String(super.buf, 0, super.count, "US-ASCII");
074                        return;
075                    }
076                    eol = true;
077                } else if (b != '\r') {
078                    eol = false;
079                }
080            }
081            throw new IOException("Unexpected EOF from " + s);
082        }
083
084        @Override
085        public String toString() {
086            return rsp;
087        }
088    }
089}