/*
* Copyright (C) 2011 Red Hat, Inc. and/or its affiliates.
*
* 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 org.jboss.errai.tools.proxy;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.Security;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Logger;
/**
* @author Yutaka Yoshida, Greg Murray, Heiko Braun
* <p/>
* Minimum set of HTTPclient supporting both http and https.
* It's aslo capable of POST, but it doesn't provide doGet because
* the caller can just read the inputstream.
*/
public class HttpClient {
private static Logger logger;
private String proxyHost = null;
private int proxyPort = -1;
private boolean isHttps = false;
private boolean isProxy = false;
private HttpURLConnection urlConnection = null;
private Map headers;
private String setCookieHeader;
private XmlHttpProxy.CookieCallback callback;
/**
* @param phost PROXY host name
* @param pport PROXY port string
* @param url URL string
* @param headers Map
*/
public HttpClient(
String phost,
int pport,
String url,
Map headers,
String method,
XmlHttpProxy.CookieCallback callback)
throws MalformedURLException {
this.callback = callback;
if (phost != null && pport != -1) {
this.isProxy = true;
}
this.proxyHost = phost;
this.proxyPort = pport;
if (url.trim().startsWith("https:")) {
isHttps = true;
}
this.urlConnection = getURLConnection(url);
try {
this.urlConnection.setRequestMethod(method);
}
catch (java.net.ProtocolException pe) {
HttpClient.getLogger().severe("Unable protocol method to " + method + " : " + pe);
}
this.headers = headers;
writeHeaders(headers);
}
private void writeHeaders(Map headers) {
if (this.callback != null) {
Map<String, XmlHttpProxy.Cookie> cookies = callback.getCookies();
Iterator it = cookies.keySet().iterator();
while (it.hasNext()) {
XmlHttpProxy.Cookie c = cookies.get(it.next());
if (headers == null) headers = new HashMap();
headers.put(
"Cookie", c.name + "=" + c.value // + "; Path=" + c.path
);
}
}
// set headers
if (headers != null) {
Iterator it = headers.keySet().iterator();
if (it != null) {
while (it.hasNext()) {
String key = (String) it.next();
String value = (String) headers.get(key);
System.out.println("Set Request Header: " + key + "->" + value);
this.urlConnection.setRequestProperty(key, value);
}
}
}
}
/**
* @param phost PROXY host name
* @param pport PROXY port string
* @param url URL string
* @param headers Map
* @param userName string
* @param password string
*/
public HttpClient(String phost,
int pport,
String url,
Map headers,
String method,
String userName,
String password,
XmlHttpProxy.CookieCallback callback)
throws MalformedURLException {
this.callback = callback;
try {
if (phost != null && pport != -1) {
this.isProxy = true;
}
this.proxyHost = phost;
this.proxyPort = pport;
if (url.trim().startsWith("https:")) {
isHttps = true;
}
this.urlConnection = getURLConnection(url);
try {
this.urlConnection.setRequestMethod(method);
}
catch (java.net.ProtocolException pe) {
HttpClient.getLogger().severe("Unable protocol method to " + method + " : " + pe);
}
// set basic authentication information
String auth = userName + ":" + password;
String encoded = new sun.misc.BASE64Encoder().encode(auth.getBytes());
// set basic authorization
this.urlConnection.setRequestProperty("Authorization", "Basic " + encoded);
this.headers = headers;
writeHeaders(headers);
}
catch (Exception ex) {
HttpClient.getLogger().severe("Unable to set basic authorization for " + userName + " : " + ex);
}
}
/**
* private method to get the URLConnection
*
* @param str URL string
*/
private HttpURLConnection getURLConnection(String str)
throws MalformedURLException {
try {
if (isHttps) {
/* when communicating with the server which has unsigned or invalid
* certificate (https), SSLException or IOException is thrown.
* the following line is a hack to avoid that
*/
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
System.setProperty("java.protocol.handler.pkgs", "com.sun.net.ssl.internal.www.protocol");
if (isProxy) {
System.setProperty("https.proxyHost", proxyHost);
System.setProperty("https.proxyPort", proxyPort + "");
}
}
else {
if (isProxy) {
System.setProperty("http.proxyHost", proxyHost);
System.setProperty("http.proxyPort", proxyPort + "");
}
}
URL url = new URL(str);
HttpURLConnection uc = (HttpURLConnection) url.openConnection();
// if this header has not been set by a request set the user agent.
if (headers == null ||
(headers != null && headers.get("user-agent") == null)) {
// set user agent to mimic a common browser
String ua = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)";
uc.setRequestProperty("user-agent", ua);
}
uc.setInstanceFollowRedirects(false);
return uc;
}
catch (MalformedURLException me) {
throw new MalformedURLException(str + " is not a valid URL");
}
catch (Exception e) {
throw new RuntimeException("Unknown error creating UrlConnection: " + e);
}
}
public String getSetCookieHeader() {
return setCookieHeader;
}
/**
* returns the inputstream from URLConnection
*
* @return InputStream
*/
public InputStream getInputStream() {
try {
// logger doesnt work, because it writes to stderr,
// which causes GwtTest to interpret it as failure
System.out.println(
this.urlConnection.getRequestMethod() + " " +
this.urlConnection.getURL() + ": " +
this.urlConnection.getResponseCode()
);
try {
// HACK: manually follow redirects, for the login to work
// HTTPUrlConnection auto redirect doesn't respect the provided headers
if (this.urlConnection.getResponseCode() == 302) {
HttpClient redirectClient =
new HttpClient(proxyHost, proxyPort, urlConnection.getHeaderField("Location"),
headers, urlConnection.getRequestMethod(), callback);
redirectClient.getInputStream().close();
}
}
catch (Throwable e) {
System.out.println("Following redirect failed");
}
setCookieHeader = this.urlConnection.getHeaderField("Set-Cookie");
return (this.urlConnection.getInputStream());
}
catch (Exception e) {
System.out.println("Failed to open " + this.urlConnection.getURL());
e.printStackTrace();
return null;
}
}
/**
* return the OutputStream from URLConnection
*
* @return OutputStream
*/
public OutputStream getOutputStream() {
try {
return (this.urlConnection.getOutputStream());
}
catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* posts data to the inputstream and returns the InputStream.
*
* @param postData data to be posted. must be url-encoded already.
* @param contentType allows you to set the contentType of the request.
* @return InputStream input stream from URLConnection
*/
public InputStream doPost(String postData, String contentType) {
this.urlConnection.setDoOutput(true);
if (contentType != null) this.urlConnection.setRequestProperty("Content-type", contentType);
OutputStream os = this.getOutputStream();
PrintStream ps = new PrintStream(os);
ps.print(postData);
ps.close();
return (this.getInputStream());
}
public String getContentEncoding() {
if (this.urlConnection == null) return null;
return (this.urlConnection.getContentEncoding());
}
public int getContentLength() {
if (this.urlConnection == null) return -1;
return (this.urlConnection.getContentLength());
}
public String getContentType() {
if (this.urlConnection == null) return null;
return (this.urlConnection.getContentType());
}
public long getDate() {
if (this.urlConnection == null) return -1;
return (this.urlConnection.getDate());
}
public String getHeader(String name) {
if (this.urlConnection == null) return null;
return (this.urlConnection.getHeaderField(name));
}
public long getIfModifiedSince() {
if (this.urlConnection == null) return -1;
return (this.urlConnection.getIfModifiedSince());
}
public static Logger getLogger() {
if (logger == null) {
logger = Logger.getLogger("jmaki.xhp.Log");
}
return logger;
}
}