com.servoy.extensions.plugins.http.HttpClient.java Source code

Java tutorial

Introduction

Here is the source code for com.servoy.extensions.plugins.http.HttpClient.java

Source

/*
 This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV
    
 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU Affero General Public License as published by the Free
 Software Foundation; either version 3 of the License, or (at your option) any
 later version.
    
 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
    
 You should have received a copy of the GNU Affero General Public License along
 with this program; if not, see http://www.gnu.org/licenses or write to the Free
 Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
 */

package com.servoy.extensions.plugins.http;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.cert.X509Certificate;
import java.sql.Date;
import java.util.List;

import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSocket;

import org.apache.http.client.params.AuthPolicy;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.auth.NTLMSchemeFactory;
import org.apache.http.impl.auth.NegotiateSchemeFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

import com.servoy.j2db.documentation.ServoyDocumented;
import com.servoy.j2db.plugins.IClientPluginAccess;
import com.servoy.j2db.plugins.ISmartRuntimeWindow;
import com.servoy.j2db.scripting.IJavaScriptType;
import com.servoy.j2db.scripting.IScriptable;
import com.servoy.j2db.util.Debug;
import com.servoy.j2db.util.Utils;

@ServoyDocumented
public class HttpClient implements IScriptable, IJavaScriptType {
    DefaultHttpClient client;

    private String proxyUser = null;
    private String proxyPassword = null;
    private final IClientPluginAccess plugin;

    public HttpClient(IClientPluginAccess plugin) {
        client = new DefaultHttpClient();
        client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, Boolean.TRUE);
        client.getAuthSchemes().register(AuthPolicy.NTLM, new NTLMSchemeFactory());
        client.getAuthSchemes().register(AuthPolicy.SPNEGO, new NegotiateSchemeFactory());
        this.plugin = plugin;

        try {
            final AllowedCertTrustStrategy allowedCertTrustStrategy = new AllowedCertTrustStrategy();
            SSLSocketFactory sf = new SSLSocketFactory(allowedCertTrustStrategy) {
                @Override
                public Socket connectSocket(Socket socket, InetSocketAddress remoteAddress,
                        InetSocketAddress localAddress, HttpParams params)
                        throws IOException, UnknownHostException, ConnectTimeoutException {
                    if (socket instanceof SSLSocket) {
                        try {
                            Method s = socket.getClass().getMethod("setHost", String.class);
                            s.invoke(socket, remoteAddress.getHostName());
                        } catch (NoSuchMethodException ex) {
                        } catch (IllegalAccessException ex) {
                        } catch (InvocationTargetException ex) {
                        } catch (IllegalArgumentException ex) {
                        } catch (SecurityException ex) {
                        }
                    }
                    try {
                        return super.connectSocket(socket, remoteAddress, localAddress, params);
                    } catch (SSLPeerUnverifiedException ex) {
                        X509Certificate[] lastCertificates = allowedCertTrustStrategy.getAndClearLastCertificates();
                        if (lastCertificates != null) {
                            // allow for next time
                            if (HttpClient.this.plugin.getApplicationType() == IClientPluginAccess.CLIENT
                                    || HttpClient.this.plugin.getApplicationType() == IClientPluginAccess.RUNTIME) {
                                // show dialog
                                CertificateDialog dialog = new CertificateDialog(
                                        ((ISmartRuntimeWindow) HttpClient.this.plugin.getCurrentRuntimeWindow())
                                                .getWindow(),
                                        remoteAddress, lastCertificates);
                                if (dialog.shouldAccept()) {
                                    allowedCertTrustStrategy.add(lastCertificates);
                                    // try it again now with the new chain.
                                    return super.connectSocket(socket, remoteAddress, localAddress, params);
                                }
                            } else {
                                Debug.error("Couldn't connect to " + remoteAddress
                                        + ", please make sure that the ssl certificates of that site are added to the java keystore."
                                        + "Download the keystore in the browser and update the java cacerts file in jre/lib/security: "
                                        + "keytool -import -file downloaded.crt -keystore cacerts");
                            }
                        }
                        throw ex;
                    } finally {
                        // always just clear the last request.
                        allowedCertTrustStrategy.getAndClearLastCertificates();
                    }

                }
            };
            Scheme https = new Scheme("https", 443, sf); //$NON-NLS-1$
            client.getConnectionManager().getSchemeRegistry().register(https);
        } catch (Exception e) {
            Debug.error("Can't register a https scheme", e); //$NON-NLS-1$
        }
    }

    /**
     * Sets a timeout in milliseconds for retrieving of data (when 0 there is no timeout).
     *
     * @sample
     * client.setTimeout(1000)
     *
     * @param msTimeout 
     */
    public void js_setTimeout(int timeout) {
        HttpParams params = client.getParams();
        HttpConnectionParams.setConnectionTimeout(params, timeout);
        HttpConnectionParams.setSoTimeout(params, timeout);
    }

    /**
     * Add cookie to the this client.
     *
     * @sample
     * var cookieSet = client.setCookie('JSESSIONID', 'abc', 'localhost', '/', -1, false)
     * if (cookieSet)
     * {
     *    //do something
     * }
     *
     * @param cookieName the name of the cookie 
     * @param cookieValue the value of the cookie
     */
    public boolean js_setCookie(String cookieName, String cookieValue) {
        return js_setCookie(cookieName, cookieValue, ""); //$NON-NLS-1$
    }

    /**
     * @clonedesc js_setCookie(String, String)
     * @sampleas js_setCookie(String, String)
     *
     * @param cookieName the name of the cookie
     * @param cookieValue the value of the cookie
     * @param domain the domain
     */
    public boolean js_setCookie(String cookieName, String cookieValue, String domain) {
        return js_setCookie(cookieName, cookieValue, domain, ""); //$NON-NLS-1$
    }

    /**
     * @clonedesc js_setCookie(String, String)
     * @sampleas js_setCookie(String, String)
     *
     * @param cookieName the name of the cookie
     * @param cookieValue the value of the cookie
     * @param domain the domain
     * @param path the path
     */
    public boolean js_setCookie(String cookieName, String cookieValue, String domain, String path) {
        return js_setCookie(cookieName, cookieValue, domain, path, -1);
    }

    /**
     * @clonedesc js_setCookie(String, String)
     * @sampleas js_setCookie(String, String)
     *
     * @param cookieName the name of the cookie
     * @param cookieValue the value of the cookie
     * @param domain the domain
     * @param path the path
     * @param maxAge maximum age of cookie
     */
    public boolean js_setCookie(String cookieName, String cookieValue, String domain, String path, int maxAge) {
        return js_setCookie(cookieName, cookieValue, domain, path, maxAge, false);
    }

    /**
     * @clonedesc js_setCookie(String, String)
     * @sampleas js_setCookie(String, String)
     *
     * @param cookieName the name of the cookie
     * @param cookieValue the value of the cookie
     * @param domain the domain
     * @param path the path
     * @param maxAge maximum age of cookie
     * @param secure true if it is a secure cookie, false otherwise
     */
    public boolean js_setCookie(String cookieName, String cookieValue, String domain, String path, int maxAge,
            boolean secure) {
        //Correct to disallow empty Cookie values? how to clear a Cookie then?
        if (Utils.stringIsEmpty(cookieName) || Utils.stringIsEmpty(cookieValue)) {
            return false;
        }
        int age = maxAge;
        if (maxAge == 0) {
            age = -1;
        }

        BasicClientCookie cookie;
        cookie = new BasicClientCookie(cookieName, cookieValue);
        if (!Utils.stringIsEmpty(path)) {
            cookie.setPath(path);
            cookie.setExpiryDate(new Date(System.currentTimeMillis() + age));
            cookie.setSecure(secure);
        }
        cookie.setDomain(domain);
        client.getCookieStore().addCookie(cookie);
        return true;
    }

    /**
     * Get a cookie by name.
     *
     * @sample
     * var cookie = client.getCookie('JSESSIONID');
     * if (cookie != null)
     * {
     *    // do something
     * }
     * else
     *    client.setCookie('JSESSIONID', 'abc', 'localhost', '/', -1, false)
     *
     * @param cookieName 
     */
    public Cookie js_getCookie(String cookieName) {
        List<org.apache.http.cookie.Cookie> cookies = client.getCookieStore().getCookies();
        for (org.apache.http.cookie.Cookie element : cookies) {
            if (element.getName().equals(cookieName))
                return new com.servoy.extensions.plugins.http.Cookie(element);
        }
        return null;
    }

    /**
     * Get all cookies from this client.
     *
     * @sample
     * var cookies = client.getHttpClientCookies()
     */
    public Cookie[] js_getCookies() {
        List<org.apache.http.cookie.Cookie> cookies = client.getCookieStore().getCookies();
        Cookie[] cookieObjects = new Cookie[cookies.size()];
        for (int i = 0; i < cookies.size(); i++) {
            cookieObjects[i] = new Cookie(cookies.get(i));
        }
        return cookieObjects;
    }

    /**
     * Create a new post request ( Origin server should accept/process the submitted data.)
     * If this url is a https ssl encrypted url which certificates are not in the java certificate store.
     * (Like a self signed certificate or a none existing root certificate)
     * Then for a smart client a dialog will be given, to give the user the ability to accept this certificate for the next time.
     * For a Web or Headless client the system administrator does have to add that certificate (chain) to the java install on the server.
     * See http://wiki.servoy.com/display/tutorials/Import+a+%28Root%29+certificate+in+the+java+cacerts+file 
     *
     * @sample
     * var client = plugins.http.createNewHttpClient();
     * var poster = client.createPostRequest('https://twitter.com/statuses/update.json');
     * poster.addParameter('status',globals.textToPost);
     * poster.addParameter('source','Test Source');
     * poster.setCharset('UTF-8');
     * var httpCode = poster.executeRequest(globals.twitterUserName, globals.twitterPassword).getStatusCode(); // httpCode 200 is ok
     *
     * @param url 
     */
    public PostRequest js_createPostRequest(String url) {
        HttpProvider.setHttpClientProxy(client, url, proxyUser, proxyPassword);
        return new PostRequest(url, client, plugin);
    }

    /**
     * Creates a new get request (retrieves whatever information is stored on specified url).
     * If this url is a https ssl encrypted url which certificates are not in the java certificate store.
     * (Like a self signed certificate or a none existing root certificate)
     * Then for a smart client a dialog will be given, to give the user the ability to accept this certificate for the next time.
     * For a Web or Headless client the system administrator does have to add that certificate (chain) to the java install on the server.
     * See http://wiki.servoy.com/display/tutorials/Import+a+%28Root%29+certificate+in+the+java+cacerts+file 
     *
     * @sample
     * var client = plugins.http.createNewHttpClient();
     * var request = client.createGetRequest('http://www.servoy.com');
     * var response = request.executeRequest();
     * var httpCode = response.getStatusCode(); // httpCode 200 is ok"
     * var content = response.getResponseBody();
     *
     * @param url 
     */
    public GetRequest js_createGetRequest(String url) {
        HttpProvider.setHttpClientProxy(client, url, proxyUser, proxyPassword);
        return new GetRequest(url, client, plugin);
    }

    /**
     * Creates a new delete request (a request to delete a resource on server).
     *
     * @sample
     * var client = plugins.http.createNewHttpClient();
     * var request = client.createDeleteRequest('http://www.servoy.com/delete.me');
     * var response = request.executeRequest();
     * var httpCode = response.getStatusCode(); // httpCode 200 is ok"
     * var content = response.getResponseBody();
     * 
     * @param url 
     */
    public DeleteRequest js_createDeleteRequest(String url) {
        HttpProvider.setHttpClientProxy(client, url, proxyUser, proxyPassword);
        return new DeleteRequest(url, client, plugin);
    }

    /**
     * Creates a new put request (similar to post request, contains information to be submitted).
     *
     * @sample
     * var client = plugins.http.createNewHttpClient();
     * var request = client.createPutRequest('http://jakarta.apache.org');
     * request.setFile('UploadMe.gif');
     * var httpCode = putRequest.executeRequest().getStatusCode() // httpCode 200 is ok
     *
     * @param url 
     */
    public PutRequest js_createPutRequest(String url) {
        HttpProvider.setHttpClientProxy(client, url, proxyUser, proxyPassword);
        return new PutRequest(url, client, plugin);
    }

    /**
     * Creates a new options request (a request for information about communication options).
     *
     * @sample
     * var client = plugins.http.createNewHttpClient();
     * var request = client.createOptionsRequest('http://www.servoy.com');
     * var methods = request.getAllowedMethods(request.executeRequest());
     * 
     * @param url 
     */
    public OptionsRequest js_createOptionsRequest(String url) {
        HttpProvider.setHttpClientProxy(client, url, proxyUser, proxyPassword);
        return new OptionsRequest(url, client, plugin);
    }

    /**
     * Creates a new head request (similar to get request, must not contain body content).
     *
     * @sample
     * var client = plugins.http.createNewHttpClient();
     * var request = client.createHeadRequest('http://www.servoy.com');
     * var response = request.executeRequest();
     * var httpCode = response.getStatusCode(); // httpCode 200 is ok
     * var header = response.getResponseHeaders('last-modified');
     *
     * @param url 
     */
    public HeadRequest js_createHeadRequest(String url) {
        HttpProvider.setHttpClientProxy(client, url, proxyUser, proxyPassword);
        return new HeadRequest(url, client, plugin);
    }

    /**
     * Creates a new trace request (debug request, server will just echo back).
     *
     * @sample
     * var client = plugins.http.createNewHttpClient();
     * var response = request.executeRequest();
     * var httpCode = response.getStatusCode(); // httpCode 200 is ok"
     * var content = response.getResponseBody();
     * 
     * @param url 
     */
    public TraceRequest js_createTraceRequest(String url) {
        HttpProvider.setHttpClientProxy(client, url, proxyUser, proxyPassword);
        return new TraceRequest(url, client, plugin);
    }

    /**
     * Set proxy credentials.
     *
     * @sample
     * client.setClientProxyCredentials('my_proxy_username','my_proxy_password');
     *
     * @param userName 
     * @param password 
     */
    public void js_setClientProxyCredentials(String userName, String password) {
        if (!Utils.stringIsEmpty(userName)) {
            this.proxyUser = userName;
            this.proxyPassword = password;
        }
    }

}