/** * 全局设定文件 * * @author xiaoleilu */ public class ServerSetting { private static Logger log = Log.get(); // -------------------------------------------------------- Default value start /** 默认的字符集编码 */ public static final String DEFAULT_CHARSET = "utf-8"; public static final String WILD_CARD = "/*"; // -------------------------------------------------------- Default value end /** 字符编码 */ private static String charset = DEFAULT_CHARSET; /** 端口 */ private static int port = 8090; /** 根目录 */ private static File root; /** Filter映射表 */ private static Map<String, Filter> filterMap; /** Action映射表 */ private static Map<String, Action> actionMap; static { filterMap = new ConcurrentHashMap<String, Filter>(); actionMap = new ConcurrentHashMap<String, Action>(); final DefaultIndexAction defaultIndexAction = new DefaultIndexAction(); actionMap.put(StrUtil.SLASH, defaultIndexAction); } /** @return 获取编码 */ public static String getCharset() { return charset; } /** @return 字符集 */ public static Charset charset() { return Charset.forName(getCharset()); } /** * 设置编码 * * @param charset 编码 */ public static void setCharset(String charset) { ServerSetting.charset = charset; } /** @return 监听端口 */ public static int getPort() { return port; } /** * 设置监听端口 * * @param port 端口 */ public static void setPort(int port) { ServerSetting.port = port; } // ----------------------------------------------------------------------------------------------- // Root start /** @return 根目录 */ public static File getRoot() { return root; } /** @return 根目录 */ public static boolean isRootAvailable() { if (root != null && root.isDirectory() && root.isHidden() == false && root.canRead()) { return true; } return false; } /** @return 根目录 */ public static String getRootPath() { return FileUtil.getAbsolutePath(root); } /** * 根目录 * * @param root 根目录绝对路径 */ public static void setRoot(String root) { ServerSetting.root = FileUtil.mkdir(root); log.debug("Set root to [{}]", ServerSetting.root.getAbsolutePath()); } /** * 根目录 * * @param root 根目录绝对路径 */ public static void setRoot(File root) { if (root.exists() == false) { root.mkdirs(); } else if (root.isDirectory() == false) { throw new ServerSettingException(StrUtil.format("{} is not a directory!", root.getPath())); } ServerSetting.root = root; } // ----------------------------------------------------------------------------------------------- // Root end // ----------------------------------------------------------------------------------------------- // Filter start /** @return 获取FilterMap */ public static Map<String, Filter> getFilterMap() { return filterMap; } /** * 获得路径对应的Filter * * @param path 路径,为空时将获得 根目录对应的Action * @return Filter */ public static Filter getFilter(String path) { if (StrUtil.isBlank(path)) { path = StrUtil.SLASH; } return getFilterMap().get(path.trim()); } /** * 设置FilterMap * * @param filterMap FilterMap */ public static void setFilterMap(Map<String, Filter> filterMap) { ServerSetting.filterMap = filterMap; } /** * 设置Filter类,已有的Filter类将被覆盖 * * @param path 拦截路径(必须以"/"开头) * @param filter Action类 */ public static void setFilter(String path, Filter filter) { if (StrUtil.isBlank(path)) { path = StrUtil.SLASH; } if (null == filter) { log.warn("Added blank action, pass it."); return; } // 所有路径必须以 "/" 开头,如果没有则补全之 if (false == path.startsWith(StrUtil.SLASH)) { path = StrUtil.SLASH + path; } ServerSetting.filterMap.put(path, filter); } /** * 设置Filter类,已有的Filter类将被覆盖 * * @param path 拦截路径(必须以"/"开头) * @param filterClass Filter类 */ public static void setFilter(String path, Class<? extends Filter> filterClass) { setFilter(path, (Filter) Singleton.get(filterClass)); } /** * 设置通配Filter类,已有的Filter类将被覆盖 * * @param filter Action类 */ public static void setWildCardFilter(Filter filter) { setFilter(WILD_CARD, filter); } /** * 设置通配Filter类,已有的Filter类将被覆盖 * * @param filterClass Filter类 */ public static void setWildCardFilter(Class<? extends Filter> filterClass) { setWildCardFilter((Filter) Singleton.get(filterClass)); } /** @return 获得通配路径对应的Filter */ public static Filter getWildCardFilter() { return getFilter(WILD_CARD); } // ----------------------------------------------------------------------------------------------- // Filter end // ----------------------------------------------------------------------------------------------- // Action start /** @return 获取ActionMap */ public static Map<String, Action> getActionMap() { return actionMap; } /** * 获得路径对应的Action * * @param path 路径,为空时将获得 根目录对应的Action * @return Action */ public static Action getAction(String path) { if (StrUtil.isBlank(path)) { path = StrUtil.SLASH; } return getActionMap().get(path.trim()); } /** * 设置ActionMap * * @param actionMap ActionMap */ public static void setActionMap(Map<String, Action> actionMap) { ServerSetting.actionMap = actionMap; } /** * 设置Action类,已有的Action类将被覆盖 * * @param path 拦截路径(必须以"/"开头) * @param action Action类 */ public static void setAction(String path, Action action) { if (StrUtil.isBlank(path)) { path = StrUtil.SLASH; } if (null == action) { log.warn("Added blank action, pass it."); return; } // 所有路径必须以 "/" 开头,如果没有则补全之 if (false == path.startsWith(StrUtil.SLASH)) { path = StrUtil.SLASH + path; } ServerSetting.actionMap.put(path, action); } /** * 增加Action类,已有的Action类将被覆盖<br> * 所有Action都是以单例模式存在的! * * @param path 拦截路径(必须以"/"开头) * @param actionClass Action类 */ public static void setAction(String path, Class<? extends Action> actionClass) { setAction(path, (Action) Singleton.get(actionClass)); } /** * 增加Action类,已有的Action类将被覆盖<br> * 自动读取Route的注解来获得Path路径 * * @param action 带注解的Action对象 */ public static void setAction(Action action) { final Route route = action.getClass().getAnnotation(Route.class); if (route != null) { final String path = route.value(); if (StrUtil.isNotBlank(path)) { setAction(path, action); return; } } throw new ServerSettingException( "Can not find Route annotation,please add annotation to Action class!"); } /** * 增加Action类,已有的Action类将被覆盖<br> * 所有Action都是以单例模式存在的! * * @param actionClass 带注解的Action类 */ public static void setAction(Class<? extends Action> actionClass) { setAction((Action) Singleton.get(actionClass)); } // ----------------------------------------------------------------------------------------------- // Action start }
/** * 认证器 * * @author Looly */ public class Auth implements Cloneable { private static final Logger log = Log.get(); // --------------------------------------------------------------- Static method start /** * 创建认证器 * * @return 认证器 */ public static Auth build() { return new Auth(); } /** * 创建认证器 * * @param bucket Bucket * @param key 文件key * @param contentMd5 内容MD5 * @param date 日期 * @param config 配置文件 * @param request Http请求对象 */ public static Auth build( String bucket, String key, String contentMd5, String date, Config config, HttpRequest request) { return new Auth(bucket, key, contentMd5, date, config, request); } /** * 用于签名的字符串 * * @param bucket Bucket * @param key 文件key * @param contentMd5 内容的md5值 * @param date 日期 * @param request 请求对象 * @return 用于签名的字符串 */ public static String strToSign( String bucket, String key, String contentMd5, String date, HttpRequest request) { String contentType = request.contentType(); if (StrUtil.isBlank(contentType)) { contentType = "text/plain"; request.contentType(contentType); log.warn("Content-Type header is empty, use default Content-Type: {}", contentType); } return StrUtil.builder() .append(request.method()) .append("\n") .append(StrUtil.nullToEmpty(contentMd5)) .append("\n") .append(contentType) .append("\n") .append(StrUtil.nullToEmpty(date)) .append("\n") .append(canonicalizedUcloudHeaders(request)) // canonicalizedUcloudHeaders尾部带一个换行符 .append(canonicalizedResource(bucket, key)) .toString(); } /** * 签名 * * @param privateKey 私钥 * @param strToSign 被签名的字符串 * @return 签名 */ public static String sign(String privateKey, String strToSign) { return SignatureUtil.macSign(privateKey, strToSign); } /** * 认证字符串 * * @param publicKey 公钥 * @param signature 签名 * @return 认证字符串 */ public static String authorization(String publicKey, String signature) { return StrUtil.builder() .append("UCloud ") .append(publicKey) .append(":") .append(signature) .toString(); } /** * 用于签名的标准Ucloud头信息字符串,尾部带换行符 * * @param request Http请求 * @return 用于签名的Ucloud头信息字符串 */ public static String canonicalizedUcloudHeaders(HttpRequest request) { Param param = Param.create(); Map<String, String[]> headers = request.headers(); String[] value; for (Entry<String, String[]> headerEntry : headers.entrySet()) { String name = headerEntry.getKey().toLowerCase(); if (name.startsWith("x-ucloud-")) { value = headerEntry.getValue(); if (value != null && value.length > 0) { param.set(name, value[0]); } } } StringBuilder builder = StrUtil.builder(); for (Entry<String, Object> entry : param.entrySet()) { builder.append(entry.getKey()).append(":").append(entry.getValue()).append("\n"); } return builder.toString(); } /** * 用于签名的标准资源字符串 * * @param bucket Bucket * @param key 文件的key(在Ufile中的文件名) * @return 标准资源字符串 */ public static String canonicalizedResource(String bucket, String key) { return StrUtil.builder().append("/").append(bucket).append("/").append(key).toString(); } // --------------------------------------------------------------- Static method end // --------------------------------------------------------------- Field start /** Bucket */ private String bucket; /** 文件在Bucket中的唯一名 */ private String key; /** 文件的MD5 */ private String contentMd5 = StrUtil.EMPTY; /** 日期 */ private String date = StrUtil.EMPTY; /** 配置文件 */ private Config config; /** Http请求对象 */ private HttpRequest request; // --------------------------------------------------------------- Field end /** 构造 */ public Auth() {} /** * 构造 * * @param bucket Bucket * @param key 文件key * @param contentMd5 内容MD5 * @param date 日期 * @param config 配置文件 * @param request Http请求对象 */ public Auth( String bucket, String key, String contentMd5, String date, Config config, HttpRequest request) { super(); this.bucket = bucket; this.key = key; this.contentMd5 = contentMd5; this.date = date; this.config = config; this.request = request; } // --------------------------------------------------------------- Getters and Setters start /** * 获得Bucket * * @return Bucket */ public String getBucket() { return bucket; } /** * 设置Bucket * * @param bucket Bucket */ public void setBucket(String bucket) { this.bucket = bucket; } /** @return 文件key */ public String getKey() { return key; } /** * 设置文件key * * @param key 文件key */ public void setKey(String key) { this.key = key; } /** @return 文件内容MD5 */ public String getContentMd5() { return contentMd5; } /** * 设置文件内容MD5 * * @param contentMd5 文件内容MD5 */ public void setContentMd5(String contentMd5) { this.contentMd5 = contentMd5; } /** @return 日期 */ public String getDate() { return date; } /** * 设置日期 * * @param date 日期 */ public void setDate(String date) { this.date = date; } /** @return 配置文件 */ public Config getConfig() { return config; } /** * 设置配置文件 * * @param config 配置文件 */ public void setConfig(Config config) { this.config = config; } /** @return Http请求对象 */ public HttpRequest getRequest() { return request; } /** * 设置Http请求对象 * * @param request Http请求对象 */ public void setRequest(HttpRequest request) { this.request = request; } // --------------------------------------------------------------- Getters and Setters end /** 生成认证字符串 */ @Override public String toString() { final String strToSign = Auth.strToSign(bucket, key, contentMd5, date, request); final String signature = Auth.sign(config.getPrivateKey(), strToSign); final String authorization = Auth.authorization(config.getPublicKey(), signature); return authorization; } /** 克隆对象 */ public Auth clone() { try { return (Auth) super.clone(); } catch (CloneNotSupportedException e) { throw new RuntimeException(e.getMessage(), e); } } }