package eu.geoknow.generator.rdf;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.List;
import javax.xml.ws.http.HTTPException;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.log4j.Logger;
import eu.geoknow.generator.exceptions.NotAuthorizedException;
import eu.geoknow.generator.exceptions.UnsupportedAuthenticationType;
public class HttpRequestManager {
private static final Logger log = Logger.getLogger(HttpRequestManager.class);
public static String executePost(String url, String urlParameters) throws Exception {
HttpURLConnection connection = sendPost(url, urlParameters);
int responseCode = connection.getResponseCode();
switch (responseCode) {
case 200:
return readResult(connection);
default:
log.error(connection.getResponseCode() + "\n\t " + connection.getResponseMessage()
+ "\n\t url:" + url + "\n\t params:" + URLDecoder.decode(urlParameters, "UTF-8"));
throw new HTTPException(responseCode);
}
}
public static String executePost(String url, String urlParameters, String username,
String password) throws IOException, UnsupportedAuthenticationType {
// TODO: May be try to do Authorized post by default first ??? to avoid
// doing two queries? are all the queries made by the generator will use
// the
// generator user?
HttpURLConnection connection = sendPost(url, urlParameters);
int responseCode = connection.getResponseCode();
String decodedUrlParameters = URLDecoder.decode(urlParameters, "UTF-8");
switch (responseCode) {
case 200:
return readResult(connection);
case 401: // unauthorized
WWWAuthenticateHeader wwwAuthenticateHeader = getWWWAuthenticationHeader(connection);
if (wwwAuthenticateHeader.isDigest()) {
// send authorized request
connection =
sendAuthorizedPost(url, urlParameters, wwwAuthenticateHeader, username, password);
responseCode = connection.getResponseCode();
switch (responseCode) {
case 200:
return readResult(connection);
case 400: // bad request
log.error(connection.getResponseCode() + "\n\t " + connection.getResponseMessage()
+ "\n\t url:" + url + "\n\t params:" + decodedUrlParameters);
throw new HTTPException(responseCode);
case 401: // Unauthorised
log.error(connection.getResponseCode() + "\n\t " + connection.getResponseMessage()
+ "\n\t url:" + url + "\n\t params:" + decodedUrlParameters);
throw new NotAuthorizedException(connection.getResponseMessage());
default:
log.error(connection.getResponseCode() + "\n\t " + connection.getResponseMessage()
+ "\n\t url:" + url + "\n\t params:" + decodedUrlParameters);
throw new HTTPException(responseCode);
}
} else
throw new UnsupportedAuthenticationType("Unsupported authentication type: "
+ wwwAuthenticateHeader.getAuthenticationScheme());
case 400: // bad request
log.error(connection.getResponseCode() + "\n\t " + connection.getResponseMessage()
+ "\n\t url:" + url + "\n\t params:" + decodedUrlParameters);
throw new HTTPException(responseCode);
default:
log.error(connection.getResponseCode() + "\n\t " + connection.getResponseMessage()
+ "\n\t url:" + url + "\n\t params:" + decodedUrlParameters);
throw new HTTPException(responseCode);
}
}
private static HttpURLConnection sendPost(String url, String urlParameters) throws IOException {
// TODO: catch TimeOut exception java.net.ConnectException: Operation
// timed out
URL targetURL = new URL(url);
HttpURLConnection connection = (HttpURLConnection) targetURL.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setInstanceFollowRedirects(false);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("charset", "utf-8");
connection.setRequestProperty("Content-Length",
"" + Integer.toString(urlParameters.getBytes().length));
connection.setUseCaches(false);
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
wr.writeBytes(urlParameters);
wr.flush();
wr.close();
return connection;
}
private static HttpURLConnection sendAuthorizedPost(String url, String urlParameters,
WWWAuthenticateHeader wwwAuthenticateHeader, String username, String password)
throws UnsupportedAuthenticationType, IOException {
try {
URL targetURL;
targetURL = new URL(url);
HttpURLConnection connection = (HttpURLConnection) targetURL.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setInstanceFollowRedirects(false);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("charset", "utf-8");
connection.setRequestProperty("Content-Length",
"" + Integer.toString(urlParameters.getBytes().length));
connection.setUseCaches(false);
connection.setRequestProperty("Authorization",
getDigestAuthorizationProperty(url, wwwAuthenticateHeader, username, password, "POST"));
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
wr.writeBytes(urlParameters);
wr.flush();
wr.close();
return connection;
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new MalformedURLException(e.getMessage());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new IOException(e);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new UnsupportedAuthenticationType(e.getMessage());
}
}
private static WWWAuthenticateHeader getWWWAuthenticationHeader(HttpURLConnection connection) {
List<String> authenticateParams = connection.getHeaderFields().get("WWW-Authenticate");
if (authenticateParams == null) {
log.debug("Autenticate params is null");
return null;
}
WWWAuthenticateHeader wwwAuthenticateHeader = new WWWAuthenticateHeader();
for (String s : authenticateParams) {
String[] fields = s.split(",");
for (String f : fields) {
String[] pair = f.trim().split("=");
String paramName = pair[0].trim();
String paramValue = pair[1].trim();
if (paramValue.startsWith("\"") && paramValue.endsWith("\""))
paramValue = paramValue.substring(1, paramValue.length() - 1);
if (paramName.startsWith("Digest")) {
wwwAuthenticateHeader.setAuthenticationScheme("digest");
paramName = paramName.substring("Digest".length()).trim();
}
wwwAuthenticateHeader.set(paramName, paramValue);
}
}
return wwwAuthenticateHeader;
}
private static String getDigestAuthorizationProperty(String endpoint,
WWWAuthenticateHeader wwwAuthenticateHeader, String username, String password,
String requestMethod) throws Exception {
if (!wwwAuthenticateHeader.isDigest())
throw new Exception("Unexpected authentication scheme "
+ wwwAuthenticateHeader.getAuthenticationScheme() + ", Digest expected");
String nc = "00000001";
String cnonce = DigestUtils.md5Hex(Long.toString(System.currentTimeMillis()));
String a1 =
DigestUtils.md5Hex(username + ":" + wwwAuthenticateHeader.getRealm() + ":" + password);
String a2 = DigestUtils.md5Hex(requestMethod + ":" + endpoint);
String hash =
DigestUtils.md5Hex(a1 + ":" + wwwAuthenticateHeader.getNonce() + ":" + nc + ":" + cnonce
+ ":" + wwwAuthenticateHeader.getQop() + ":" + a2);
return "Digest username=\"" + username + "\"" + ", realm=" + wwwAuthenticateHeader.getRealm()
+ ", nonce=" + wwwAuthenticateHeader.getNonce() + ", uri=" + endpoint + ", response="
+ hash + ", opaque=" + wwwAuthenticateHeader.getOpaque() + ", qop="
+ wwwAuthenticateHeader.getQop() + ", nc=" + nc + ", cnonce=" + cnonce;
}
private static String readResult(HttpURLConnection connection) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine).append("\n");
}
in.close();
return response.toString();
}
public static class WWWAuthenticateHeader {
private String realm;
private String domain;
private String nonce;
private String opaque;
private String stale;
private String qop;
private String algorithm;
private String authenticationScheme;
public void set(String paramName, String paramValue) {
if (paramName.equals("realm"))
realm = paramValue;
else if (paramName.equals("domain"))
domain = paramValue;
else if (paramName.equals("nonce"))
nonce = paramValue;
else if (paramName.equals("opaque"))
opaque = paramValue;
else if (paramName.equals("stale"))
stale = paramValue;
else if (paramName.equals("qop"))
qop = paramValue;
else if (paramName.equals("algorithm"))
algorithm = paramValue;
}
public String getRealm() {
return realm;
}
public String getDomain() {
return domain;
}
public String getNonce() {
return nonce;
}
public String getOpaque() {
return opaque;
}
public String getStale() {
return stale;
}
public String getQop() {
return qop;
}
public String getAlgorithm() {
return algorithm;
}
public String getAuthenticationScheme() {
return authenticationScheme;
}
public void setAuthenticationScheme(String authenticationScheme) {
this.authenticationScheme = authenticationScheme;
}
public boolean isDigest() {
return authenticationScheme != null && authenticationScheme.toLowerCase().equals("digest");
}
}
}