com.wifiafterconnect.ParsedHttpInput.java Source code

Java tutorial

Introduction

Here is the source code for com.wifiafterconnect.ParsedHttpInput.java

Source

/*
 * Copyright (C) 2013 Sasha Vasko <sasha at aftercode dot net> 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.wifiafterconnect;

import java.net.HttpURLConnection;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.json.JSONException;
import org.json.JSONObject;

import android.util.Log;

import com.wifiafterconnect.handlers.CaptivePageHandler;
import com.wifiafterconnect.html.HtmlForm;
import com.wifiafterconnect.html.HtmlPage;
import com.wifiafterconnect.html.WISPAccessGatewayParam;
import com.wifiafterconnect.http.HttpConnectionWrapper;
import com.wifiafterconnect.http.HttpConnectionFactory;
import com.wifiafterconnect.util.HttpInput;
import com.wifiafterconnect.util.Preferences;
import com.wifiafterconnect.util.Worker;

public class ParsedHttpInput extends Worker {

    public class JsonInput extends HttpInput {
        private JSONObject json = null;

        public JsonInput(URL url) {
            super(url);
            // TODO Auto-generated constructor stub
        }

        @Override
        public boolean parse(String source) {
            json = null;
            if (!super.parse(source))
                return false;
            try {
                json = new JSONObject(source);
            } catch (JSONException e) {
            }
            return (json != null);
        }

        public JSONObject getJSONObject() {
            return json;
        }

        public JSONObject getJSONObject(final String name) throws JSONException {
            return json != null ? json.getJSONObject(name) : null;
        }
    }

    private CaptivePageHandler captiveHandler = null;
    private HttpInput httpInput = null;
    private Map<String, String> httpHeaders;

    public static final String HTTP_HEADER_LOCATION = "Location";

    public ParsedHttpInput(Worker other, URL url, String html, Map<String, String> headers) {
        super(other);
        // create a copy of headers hash map, so that we retain original input in case 
        // parameter gets modified later on by the caller for some reason.
        httpHeaders = new HashMap<String, String>(headers);
        parse(url, html);
    }

    private void parse(URL url, String input) {
        captiveHandler = null;
        httpInput = null;

        if (input.startsWith("{")) {
            // TODO implement parsing as JSON???
            JsonInput jsonInput = new JsonInput(url);
            if (!jsonInput.parse(input))
                error("Failed to parse JSON input");
            else {
                httpInput = jsonInput;
                captiveHandler = CaptivePageHandler.autodetect(httpInput);
            }
        } else {
            HtmlPage htmlPage = new HtmlPage(url);
            if (!htmlPage.parse(input)) {
                error("Failed to parse the HTML page");
            } else {
                httpInput = htmlPage;
                debug("HTML page parsed. OnLoad = [" + htmlPage.getOnLoad() + "]");
                if (!submitOnLoad(htmlPage)) {
                    // Probably the actual login page
                    captiveHandler = CaptivePageHandler.autodetect(httpInput);
                }
            }
        }

        if (captiveHandler != null)
            debug("Detected page handler " + captiveHandler);

        // Fallback - plain text container
        if (httpInput == null) {
            httpInput = new HttpInput(url);
            httpInput.parse(input);
        }
    }

    public HtmlPage getHtmlPage() {
        return (httpInput != null && httpInput instanceof HtmlPage) ? (HtmlPage) httpInput : null;
    }

    public JSONObject getJSONObject() {
        return (httpInput != null && httpInput instanceof JsonInput) ? ((JsonInput) httpInput).getJSONObject()
                : null;
    }

    public JSONObject getJSONObject(final String name) throws JSONException {
        return (httpInput != null && httpInput instanceof JsonInput) ? ((JsonInput) httpInput).getJSONObject(name)
                : null;
    }

    /*
     * Guaranteed not to return null
     */
    public String getHttpHeader(final String key) {
        String val = httpHeaders.get(key);
        return val == null ? "" : val;
    }

    public HtmlForm getHtmlForm() {
        HtmlPage hp = getHtmlPage();
        return hp != null ? hp.getForm() : null;
    }

    public String buildPostData(final WifiAuthParams authParams) {
        if (captiveHandler != null)
            return captiveHandler.getPostData(authParams);
        HtmlForm form = getHtmlForm();
        if (form != null)
            return form.formatPostData();

        return "";
    }

    public boolean checkParamsMissing(WifiAuthParams params) {
        Log.d(Constants.TAG, "checkParamsMissing: CaptiveHandler = " + captiveHandler);
        if (captiveHandler != null)
            return captiveHandler.checkParamsMissing(params);
        return false;
    }

    public WifiAuthParams addMissingParams(WifiAuthParams params) {
        Log.d(Constants.TAG, "addMissingParams: CaptiveHandler = " + captiveHandler);
        if (captiveHandler != null)
            return captiveHandler.addMissingParams(params);
        return null;
    }

    public ParsedHttpInput handleAutoRedirects(int maxRequests, boolean authFollowup) {

        debug("handleAutoRedirects(): this = " + this + " max Requests = " + maxRequests + " authFollowup = "
                + authFollowup);
        if (maxRequests <= 0 || (Preferences.getWISPrEnabled() && getWISPr() != null)) // per WISPr 2.0 spec 7.3.3
            return this;

        ParsedHttpInput result = null;

        String redirectLoc = getHttpHeader(HTTP_HEADER_LOCATION);
        if (BuildConfig.DEBUG)
            debug("submitOnLoad() = " + submitOnLoad() + ", hasSubmittableForm = " + hasSubmittableForm()
                    + ", redirectLoc = " + redirectLoc + ", hasMetaRefresh() = " + hasMetaRefresh());

        if (submitOnLoad() || (authFollowup && hasSubmittableForm())) {
            debug("Handling onLoad submit ...");
            result = postForm(null);
        } else if (!redirectLoc.isEmpty()) {
            debug("Handling Location redirect ...");
            result = getRefresh(redirectLoc);
        } else if (hasMetaRefresh() && (authFollowup || getHtmlForm() == null)) {
            debug("Handling meta refresh ...");
            result = getRefresh(null);
        } else {
            debug("No redirect action detected ...");
            return this;
        }

        if (result != null)
            result = result.handleAutoRedirects(maxRequests - 1, authFollowup);
        debug("handleAutoRedirects(): result = " + result);
        return result;
    }

    public ParsedHttpInput authenticateCaptivePortal(WifiAuthParams authParams) {
        return (captiveHandler != null) ? captiveHandler.authenticate(this, authParams) : null;
    }

    public CaptivePageHandler.States getCaptivePortalState() {
        return (captiveHandler != null) ? captiveHandler.getState() : CaptivePageHandler.States.Failed;
    }

    public boolean submitOnLoad(HtmlPage hp) {
        if (hp != null) {
            String onLoad = hp.getOnLoad();
            return onLoad.equalsIgnoreCase("document.forms[0].submit();")
                    || onLoad.equalsIgnoreCase("document.form.submit();") || onLoad.endsWith(".submit();"); // this one is probably enough
        }
        return false;
    }

    public boolean submitOnLoad() {
        return submitOnLoad(getHtmlPage());
    }

    public final String getHtml() {
        return (httpInput != null && httpInput instanceof HtmlPage) ? httpInput.getSource() : "";
    }

    public final String getRaw() {
        return (httpInput != null) ? httpInput.getSource() : "";
    }

    public final URL getURL() {
        return (httpInput != null) ? httpInput.getURL() : null;
    }

    public boolean hasMetaRefresh() {
        HtmlPage hp = getHtmlPage();
        return hp != null && hp.hasMetaRefresh();
    }

    public HtmlPage.MetaRefresh getMetaRefresh() {
        HtmlPage hp = getHtmlPage();
        return hp != null ? hp.getMetaRefresh() : null;
    }

    public boolean isKnownCaptivePortal() {
        return (captiveHandler != null);
    }

    /* ###################################################### 
     * The Captive Portal check code from android. Unlike them,
     * we actually need the portal page, so that we can post a response.
     * 
     * Copyright (C) 2012 The Android Open Source Project
     * Licensed under the Apache License, Version 2.0 (the "License");
     */
    public static InetAddress lookupHost(String hostname) {
        InetAddress inetAddress[];
        try {
            inetAddress = InetAddress.getAllByName(hostname);
        } catch (UnknownHostException e) {
            return null;
        }

        for (InetAddress a : inetAddress) {
            if (a instanceof Inet4Address)
                return a;
        }
        return null;
    }
    /* ======================================================
     * End of the The Captive Portal check code from android
     */

    public URL getFormPostURL() {
        return (captiveHandler != null) ? captiveHandler.getPostURL() : getURL();
    }

    public WISPAccessGatewayParam getWISPr() {
        HtmlPage hp = getHtmlPage();
        return (hp != null) ? hp.getWISPr() : null;
    }

    public String getCookies() {
        // TODO Auto-generated method stub
        return null;
    }

    public boolean hasSubmittableForm() {
        HtmlPage hp = getHtmlPage();
        return hp != null && hp.hasSubmittableForm();
    }

    public boolean hasForm() {
        HtmlPage hp = getHtmlPage();
        return (hp != null && hp.getForm() != null);
    }

    public String getURLQueryVar(String varName) {
        return httpInput.getURLQueryVar(varName);
    }

    public ParsedHttpInput postForm(WifiAuthParams authParams) {

        URL url = getFormPostURL();
        String postDataString = buildPostData(authParams);
        String cookies = getCookies();

        return post(this, url, postDataString, cookies, getURL().toString());
    }

    public URL makeRefreshURL(String urlString) {
        URL url = null;
        if (httpInput != null) {
            try {
                HtmlPage.MetaRefresh metaRefresh;
                if (urlString != null)
                    url = httpInput.makeURL(urlString);
                else if ((metaRefresh = getMetaRefresh()) != null) {
                    url = metaRefresh.getURL();
                    if (url != null && metaRefresh.getTimeout() > 0) {
                        try {
                            Thread.sleep(1000 * Math.min(metaRefresh.getTimeout(), Constants.MAX_REFRESH_TIMEOUT));
                        } catch (InterruptedException e) {
                        } // don't care
                    }
                }
            } catch (MalformedURLException ee) {
                exception(ee);
            }
        }
        return url;
    }

    public ParsedHttpInput getRefresh(String urlString) {
        URL url = makeRefreshURL(urlString);
        return url == null ? null : get(this, url, getURL().toString());
    }

    public static void showRequestProperties(Worker context, HttpURLConnection conn) {
        Map<String, List<String>> reqProps = conn.getRequestProperties();
        context.debug("RequestProperties for [" + conn.getURL() + "]");
        for (String key : reqProps.keySet()) {
            String propStr = "RequestPropery[" + key + "] = {";
            for (String val : reqProps.get(key)) {
                propStr += "[" + val + "]";
            }
            context.debug(propStr + "}");
        }
    }

    public static ParsedHttpInput post(Worker context, URL url, String postDataString, String cookies,
            String referer) {
        HttpConnectionWrapper conn = HttpConnectionFactory.INSTANCE.getConnection();
        conn.setUrl(url);
        return conn.post(context, postDataString, cookies, referer) ? valueOf(context, conn) : null;
    }

    private static ParsedHttpInput valueOf(Worker context, HttpConnectionWrapper conn) {
        ParsedHttpInput parsed = null;
        if (conn != null) {
            parsed = new ParsedHttpInput(context, conn.getUrl(), conn.getData(), conn.getHeaders());
        }
        return parsed;
    }

    public static ParsedHttpInput get(Worker context, URL url, String referer) {
        HttpConnectionWrapper conn = HttpConnectionFactory.INSTANCE.getConnection();
        conn.setUrl(url);
        return conn.get(context, referer) ? valueOf(context, conn) : null;
    }
}