/* * Copyright 2017 ZhangJiupeng * * 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 cc.agentx.ui; import java.io.*; import java.lang.reflect.Method; import java.util.*; import java.util.regex.Matcher; /** * <b>Notice:</b> this project is not for a web server, * you can see that the page configuration is embedded into * <code>cc.agentx.http.Initializer</code>. <br/>However, * <code>cc.agentx.http</code> is designed separately, * it can be extracted into a single project. * <br/> * Thus, this web server project might be developed in the future, * hold on and keep attention :) */ public class PageHandler { private String baseDir; private Map<String, String> resMap; private Map<String, String> mimeTable; private Set<String> ignoredSuffix; public PageHandler(String baseDir) { this.baseDir = baseDir.replaceAll("\\\\", "/"); this.mimeTable = Initializer.getMIMETable(); resMap = new HashMap<>(); ignoredSuffix = new HashSet<>(); Initializer.parsePageIndex(resMap); Initializer.parseIgnoredSuffix(ignoredSuffix); } public synchronized Map<String, Object> fetch(String uri) throws HttpError { return fetch(uri, null); } public synchronized Map<String, Object> fetch(String uri, Map<String, String> parameters) throws HttpError { String resourcePath = ""; boolean needDynamicParse = parameters != null; if (ignoredSuffix.contains(uri.substring(uri.lastIndexOf('.') + 1).toLowerCase())) { needDynamicParse = false; resourcePath = uri; } if (resourcePath.equals("")) { resourcePath = resMap.get(uri); if (resourcePath != null) { needDynamicParse = resourcePath.contains("@"); } else { throw HttpError.HTTP_404; } } if (needDynamicParse) { try { String[] paths = resourcePath.split("@"); String pagePath = paths[0]; String targetMethodName = paths[1].substring(paths[1].lastIndexOf('.') + 1); String targetClassName = paths[1].substring(0, paths[1].lastIndexOf('.')); Class targetClass = Class.forName(targetClassName); Method targetMethod; String[] resp; if (parameters == null) { // noinspection unchecked targetMethod = targetClass.getDeclaredMethod(targetMethodName, String.class); resp = (String[]) targetMethod.invoke(targetClass.newInstance(), uri); } else { // noinspection unchecked targetMethod = targetClass.getDeclaredMethod(targetMethodName, String.class, Map.class); resp = (String[]) targetMethod.invoke(targetClass.newInstance(), uri, parameters); } if (resp == null) { throw HttpError.HTTP_404; } else { switch (resp[0]) { case "page": { File file = new File(baseDir, pagePath); if (!file.exists()) { throw HttpError.HTTP_404; } BufferedReader reader = new BufferedReader(new FileReader(file)); StringBuilder buffer = new StringBuilder(); while (reader.ready()) { buffer.append(reader.readLine()).append("\n"); } reader.close(); String respStr = buffer.toString(); for (int i = 1; i < resp.length; i++) { respStr = respStr.replaceAll(Matcher.quoteReplacement("$" + (i - 1)), resp[i]); } byte[] respBytes = respStr.getBytes("UTF-8"); return new HashMap<String, Object>() {{ put("type", "file"); put("inputStream", new ByteArrayInputStream(respBytes)); put("length", respBytes.length); put("lastModified", new Date()); put("mimeType", "text/html"); }}; } case "text": { byte[] respBytes = resp[1].getBytes("UTF-8"); return new HashMap<String, Object>() {{ put("type", "file"); put("inputStream", new ByteArrayInputStream(respBytes)); put("length", respBytes.length); put("lastModified", new Date()); put("mimeType", "text/plain"); }}; } case "html": { byte[] respBytes = resp[1].getBytes("UTF-8"); return new HashMap<String, Object>() {{ put("inputStream", new ByteArrayInputStream(respBytes)); put("length", respBytes.length); put("lastModified", new Date()); put("mimeType", "text/html"); put("type", "file"); }}; } case "redirect": return new HashMap<String, Object>() {{ put("type", "redirect"); put("url", resp[1]); }}; case "error": throw new HttpError(Integer.parseInt(resp[1]), resp[2]); default: throw new Exception(Arrays.toString(resp)); } } } catch (NoSuchMethodException nm) { nm.printStackTrace(); throw HttpError.HTTP_404; } catch (Exception e) { e.printStackTrace(); throw HttpError.HTTP_500; } } else { try { InputStream inputStream = null; long fileLen = 0; Date lastModified = null; File file = new File(baseDir, resourcePath).getCanonicalFile(); if (!file.getPath().replaceAll("\\\\", "/").startsWith(baseDir)) { throw HttpError.HTTP_400; } if (file.isDirectory()) { file = new File(file, "index.html"); } if (file.isFile()) { inputStream = new FileInputStream(file); fileLen = file.length(); lastModified = new Date(file.lastModified()); } if (inputStream == null) { throw HttpError.HTTP_404; } String fileSuffix = file.getName().substring(file.getName().lastIndexOf('.') + 1).toLowerCase(); final InputStream finalInputStream = inputStream; final long finalFileLen = fileLen; final Date finalLastModified = lastModified; return new HashMap<String, Object>() {{ put("type", "file"); put("inputStream", finalInputStream); put("length", finalFileLen); put("lastModified", finalLastModified); put("mimeType", mimeTable.get(fileSuffix)); }}; } catch (IOException e) { e.printStackTrace(); throw HttpError.HTTP_500; } } } }