/**
* Most of the code in the Qalingo project is copyrighted Hoteia and licensed
* under the Apache License Version 2.0 (release version 0.8.0)
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (c) Hoteia, 2012-2014
* http://www.hoteia.com - http://twitter.com/hoteia - contact@hoteia.com
*
*/
package org.hoteia.qalingo.core.service.openid;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
/**
*
*/
public class Utils {
public static final String ATTR_MAC = "openid_mac";
public static final String ATTR_ALIAS = "openid_alias";
private static final int MAX_SIZE = 10240;
private static final String CONTENT = "Content";
private static final char[] HEX = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
static Map<String, Object> httpRequest(String url, String method, String accept, String formPostData, int timeOutInMilliseconds) {
HttpURLConnection hc = null;
InputStream input = null;
OutputStream output = null;
try {
hc = (HttpURLConnection) new URL(url).openConnection();
hc.setRequestMethod(method);
hc.setDoOutput("POST".equals(method));
hc.setUseCaches(false);
hc.setConnectTimeout(timeOutInMilliseconds);
hc.setReadTimeout(timeOutInMilliseconds);
hc.addRequestProperty("Accept", accept);
hc.addRequestProperty("Accept-Encoding", "gzip");
if (hc.getDoOutput()) {
output = hc.getOutputStream();
output.write(formPostData.getBytes("UTF-8"));
output.flush();
}
hc.connect();
int code = hc.getResponseCode();
if (code != 200){
throw new OpenIdException("Bad response code: " + code);
}
// handle content:
// try to detect encoding:
boolean gzip = "gzip".equals(hc.getContentEncoding());
input = hc.getInputStream();
ByteArrayOutputStream byteArrayOutput = new ByteArrayOutputStream();
boolean overflow = false;
int read = 0;
byte[] buffer = new byte[1024];
for(;;) {
int n = input.read(buffer);
if(n==(-1))
break;
byteArrayOutput.write(buffer, 0, n);
read += n;
if(read>MAX_SIZE) {
overflow = true;
break;
}
}
byteArrayOutput.close();
if(overflow)
throw new RuntimeException();
byte[] data = byteArrayOutput.toByteArray();
if(gzip)
data = gunzip(data);
Map<String, Object> map = new HashMap<String, Object>();
map.put("Cache-Control", hc.getHeaderField("Cache-Control"));
map.put("Content-Type", hc.getHeaderField("Content-Type"));
map.put("Content-Encoding", hc.getHeaderField("Content-Encoding"));
map.put("Expires", hc.getHeaderField("Expires"));
map.put(CONTENT, data);
return map;
}
catch(IOException e) {
throw new OpenIdException("Request failed: " + url, e);
}
finally {
if(output!=null) {
try { output.close(); } catch (IOException e) {}
}
if(input!=null) {
try { input.close(); } catch (IOException e) {}
}
if(hc!=null) {
hc.disconnect();
}
}
}
/**
* Get 'max-age' field from HTTP header.
*/
static long getMaxAge(Map<String, Object> map) {
String cache = (String) map.get("Cache-Control");
if (cache==null)
return 0L;
int pos = cache.indexOf("max-age=");
if (pos!=(-1)) {
String maxAge = cache.substring(pos + "max-age=".length());
pos = maxAge.indexOf(',');
if (pos!=(-1))
maxAge = maxAge.substring(0, pos);
try {
return Integer.parseInt(maxAge) * 1000L;
}
catch (Exception e) {}
}
return 0L;
}
/**
* Get text content from HTTP response.
*/
static String getContent(Map<String, Object> map) throws UnsupportedEncodingException {
byte[] data = (byte[]) map.get(CONTENT);
String charset = getCharset(map);
if (charset==null)
charset = "UTF-8";
return new String(data, charset);
}
/**
* Unzip data using gzip.
*/
public static byte[] gunzip(byte[] data) {
ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(10240);
GZIPInputStream input = null;
try {
input = new GZIPInputStream(new ByteArrayInputStream(data));
byte[] buffer = new byte[1024];
int n = 0;
for(;;) {
n = input.read(buffer);
if(n<=0)
break;
byteOutput.write(buffer, 0, n);
}
}
catch (IOException e) {
throw new OpenIdException(e);
}
finally {
if(input!=null) {
try {
input.close();
}
catch(IOException ioe) {}
}
}
return byteOutput.toByteArray();
}
/**
* Get substring between start token and end token.
*/
public static String mid(String s, String startToken, String endToken) {
return mid(s, startToken, endToken, 0);
}
/**
* Get substring between start token and end token, searching from specific index.
*/
public static String mid(String s, String startToken, String endToken, int fromStart) {
if (startToken==null || endToken==null)
return null;
int start = s.indexOf(startToken, fromStart);
if (start==(-1))
return null;
int end = s.indexOf(endToken, start + startToken.length());
if (end==(-1))
return null;
String sub = s.substring(start + startToken.length(), end);
return sub.trim();
}
/**
* Get 'charset' field from HTTP header.
*/
public static String getCharset(Map<String, Object> map) {
String contentType = (String) map.get("Content-Type");
String charset = null;
if(contentType!=null) {
int pos = contentType.indexOf("charset=");
if(pos!=(-1)) {
charset = contentType.substring(pos + "charset=".length());
int sp = contentType.indexOf(';');
if(sp!=(-1))
contentType = contentType.substring(0, sp).trim();
}
}
return charset;
}
/**
* Encode URL with UTF-8.
*/
public static String urlEncode(String s) throws UnsupportedEncodingException {
return URLEncoder.encode(s, "UTF-8");
}
/**
* Build query string like "a=1&b=2&c=3".
*/
public static String buildQuery(List<String> list) {
if (!list.isEmpty()) {
StringBuilder sb = new StringBuilder(1024);
try {
for (String s : list) {
int n = s.indexOf('=');
sb.append(s.substring(0, n+1))
.append(URLEncoder.encode(s.substring(n+1), "UTF-8"))
.append('&');
}
// remove last '&':
sb.deleteCharAt(sb.length()-1);
}
catch(UnsupportedEncodingException e) {
throw new OpenIdException(e);
}
return sb.toString();
}
return "";
}
/**
* Encode bytes as hex string.
*/
public static String toHexString(byte[] bytes) {
int length = bytes.length;
StringBuffer sb = new StringBuffer(length * 2);
int x = 0;
int n1 = 0, n2 = 0;
for(int i=0; i<length; i++) {
if(bytes[i]>=0)
x = bytes[i];
else
x= 256 + bytes[i];
n1 = x >> 4;
n2 = x & 0x0f;
sb = sb.append(HEX[n1]);
sb = sb.append(HEX[n2]);
}
return sb.toString();
}
}