package customskinloader.utils; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URI; import java.net.URL; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.Charsets; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import customskinloader.CustomSkinLoader; public class HttpRequestUtil { public static class HttpRequest{ public String url; public String userAgent=null; public String payload=null; public boolean loadContent=true; public boolean checkPNG=false; public int cacheTime=600;//-1=No Cache 0=Always Cache t=Default Cache Time(second) public File cacheFile=null;//Default Cache File public HttpRequest(String url){ this.url=url; } public HttpRequest setUserAgent(String userAgent){ this.userAgent=userAgent; return this; } public HttpRequest setPayload(String payload){ this.payload=payload; return this; } public HttpRequest setLoadContent(boolean loadContent){ this.loadContent=loadContent; return this; } public HttpRequest setCheckPNG(boolean checkPNG){ this.checkPNG=checkPNG; return this; } public HttpRequest setCacheTime(int cacheTime){ this.cacheTime=cacheTime; return this; } public HttpRequest setCacheFile(File cacheFile){ this.cacheFile=cacheFile; return this; } } public static class HttpResponce{ public String content=null; public int responceCode=-1; public boolean success=false; public boolean fromCache=false; } public static class CacheInfo{ public String url; public String etag=null; public long lastModified=-1;//ms public long expire=-1;//UNIX timestamp } public static final File CACHE_DIR=new File(CustomSkinLoader.DATA_DIR,"caches"); public static HttpResponce makeHttpRequest(HttpRequest request){ try{ CustomSkinLoader.logger.debug("Try to request '"+request.url+(request.userAgent==null?"'.":"' with user agent '"+request.userAgent+"'.")); //Check Cache if(StringUtils.isNotEmpty(request.payload)) request.cacheTime=-1;//No Cache File cacheInfoFile=null; CacheInfo cacheInfo=new CacheInfo(); if(request.cacheFile==null && request.cacheTime>=0){ String hash=DigestUtils.sha1Hex(request.url); request.cacheFile=new File(CACHE_DIR,hash); cacheInfoFile=new File(CACHE_DIR,hash+".json"); } if(request.cacheTime==0 && request.cacheFile.isFile()) return loadFromCache(request,new HttpResponce()); if(cacheInfoFile!=null&&cacheInfoFile.isFile()){ String json=FileUtils.readFileToString(cacheInfoFile, "UTF-8"); if(StringUtils.isNotEmpty(json)) cacheInfo=CustomSkinLoader.GSON.fromJson(json, CacheInfo.class); if(cacheInfo==null) cacheInfo=new CacheInfo(); if(cacheInfo.expire>=TimeUtil.getCurrentUnixTimestamp()) return loadFromCache(request,new HttpResponce(),cacheInfo.expire); } //Init Connection String url=new URI(request.url).toASCIIString(); if(!url.equalsIgnoreCase(request.url)) CustomSkinLoader.logger.debug("Encoded URL: "+url); HttpURLConnection c = (HttpURLConnection) (new URL(url)).openConnection(); c.setReadTimeout(1000 * 10); c.setConnectTimeout(1000 * 10); c.setDoInput(true); c.setUseCaches(false); c.setInstanceFollowRedirects(true); //Make Connection if(cacheInfo.lastModified>=0) c.setIfModifiedSince(cacheInfo.lastModified); if(cacheInfo.etag!=null) c.setRequestProperty("If-None-Match",cacheInfo.etag); c.setRequestProperty("Accept-Encoding","gzip"); if(request.userAgent!=null) c.setRequestProperty("User-Agent",request.userAgent); if(StringUtils.isNotEmpty(request.payload)){ CustomSkinLoader.logger.info("Payload: "+request.payload); c.setDoOutput(true); OutputStream os=c.getOutputStream(); IOUtils.write(request.payload, os, "UTF-8"); IOUtils.closeQuietly(os); } c.connect(); //Check Connection HttpResponce responce=new HttpResponce(); responce.responceCode=c.getResponseCode(); int res=c.getResponseCode()/100; if(res==4||res==5){//Failed CustomSkinLoader.logger.debug("Failed to request (Response Code: "+c.getResponseCode()+")"); return responce; } responce.success=true; CustomSkinLoader.logger.debug("Successfully request (Response Code: "+c.getResponseCode()+" , Content Length: "+c.getContentLength()+")"); if(responce.responceCode==HttpURLConnection.HTTP_NOT_MODIFIED) return loadFromCache(request,responce); if (responce.responceCode == HttpURLConnection.HTTP_NO_CONTENT) request.cacheTime = 3600; //Load Content InputStream is="gzip".equals(c.getContentEncoding())?new GZIPInputStream(c.getInputStream()):c.getInputStream(); byte [] bytes = IOUtils.toByteArray(is); if(request.checkPNG&&(bytes.length<=4||bytes[1]!=(byte)'P'||bytes[2]!=(byte)'N'||bytes[3]!=(byte)'G')){ CustomSkinLoader.logger.debug("Failed to request (Not Standard PNG)"); responce.success=false; return responce; } if(request.cacheFile!=null){ FileUtils.writeByteArrayToFile(request.cacheFile, bytes); if(cacheInfoFile!=null){ cacheInfo.url=request.url; cacheInfo.etag=c.getHeaderField("ETag"); cacheInfo.lastModified=c.getLastModified(); cacheInfo.expire=getExpire(c,request.cacheTime); FileUtils.write(cacheInfoFile, CustomSkinLoader.GSON.toJson(cacheInfo), "UTF-8"); } CustomSkinLoader.logger.debug("Saved to cache (Length: "+request.cacheFile.length()+" , Path: '"+request.cacheFile.getAbsolutePath()+"' , Expire: "+cacheInfo.expire+")"); } if(!request.loadContent) return responce; responce.content=new String(bytes, "UTF-8"); CustomSkinLoader.logger.debug("Content: "+responce.content); return responce; }catch(Exception e){ CustomSkinLoader.logger.debug("Failed to request (Exception: "+e.toString()+")"); return loadFromCache(request,new HttpResponce()); } } public static File getCacheFile(String hash){ return new File(CACHE_DIR,hash); } private static HttpResponce loadFromCache(HttpRequest request,HttpResponce responce){ return loadFromCache(request,responce,0); } private static HttpResponce loadFromCache(HttpRequest request,HttpResponce responce,long expireTime){ if(request.cacheFile==null||!request.cacheFile.isFile()) return responce; CustomSkinLoader.logger.debug("Cache file found (Length: "+request.cacheFile.length()+" , Path: '"+request.cacheFile.getAbsolutePath()+"' , Expire: "+expireTime+"')"); responce.fromCache=true; responce.success=true; if(!request.loadContent) return responce; CustomSkinLoader.logger.info("Try to load from cache '"+request.cacheFile.getAbsolutePath()+"'."); try { responce.content=FileUtils.readFileToString(request.cacheFile, "UTF-8"); CustomSkinLoader.logger.debug("Successfully load from cache"); CustomSkinLoader.logger.debug("Content: "+responce.content); } catch (IOException e) { CustomSkinLoader.logger.debug("Failed to load from cache (Exception: "+e.toString()+")"); responce.success=false; } return responce; } private final static Pattern MAX_AGE_PATTERN = Pattern.compile(".*?max-age=(\\d+).*?"); private static long getExpire(HttpURLConnection connection,int cacheTime){ String cacheControl=connection.getHeaderField("Cache-Control"); if(StringUtils.isNotEmpty(cacheControl)){ Matcher m=MAX_AGE_PATTERN.matcher(cacheControl); if(m.matches()) return TimeUtil.getUnixTimestamp(Long.parseLong(m.group(m.groupCount()))); } long expires=connection.getExpiration(); if(expires>0) return expires/1000; return TimeUtil.getUnixTimestampRandomDelay(cacheTime==0 ? 86400 : cacheTime); } }