/* * Copyright (c) 2002-2012 Alibaba Group Holding Limited. * All rights reserved. * * 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 com.alibaba.citrus.service.requestcontext.rewrite.impl; import static com.alibaba.citrus.service.requestcontext.rewrite.impl.RewriteUtil.*; import static com.alibaba.citrus.util.ArrayUtil.*; import static com.alibaba.citrus.util.Assert.*; import static com.alibaba.citrus.util.BasicConstant.*; import static com.alibaba.citrus.util.StringUtil.*; import java.util.regex.MatchResult; import javax.servlet.http.HttpServletResponse; import com.alibaba.citrus.service.requestcontext.parser.ParameterParser; import com.alibaba.citrus.util.ArrayUtil; import com.alibaba.citrus.util.ObjectUtil; import com.alibaba.citrus.util.StringEscapeUtil; import com.alibaba.citrus.util.StringUtil; import com.alibaba.citrus.util.ToStringBuilder; import com.alibaba.citrus.util.ToStringBuilder.MapBuilder; import com.alibaba.citrus.util.regex.MatchResultSubstitution; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; public class RewriteSubstitution implements InitializingBean { private static final Logger log = LoggerFactory.getLogger(RewriteSubstitution.class); private String uri; private SubstitutionFlags flags; private Parameter[] parameters; public void setUri(String uri) { this.uri = StringUtil.trimToNull(uri); } public SubstitutionFlags getFlags() { return flags; } public void setFlags(String[] flags) { this.flags = new SubstitutionFlags(flags); } public void setParameters(Parameter[] params) { this.parameters = params; } public void afterPropertiesSet() throws Exception { // flags if (flags == null) { flags = new SubstitutionFlags(); } // params if (parameters == null) { parameters = new Parameter[0]; } } public String substitute(String path, MatchResultSubstitution resultSubs) { if (uri == null) { if (log.isTraceEnabled()) { log.trace("No substitution applied to path: \"{}\"", StringEscapeUtil.escapeJava(path)); } return path; } String subsPath = resultSubs.substitute(uri); if (!isFullURL(subsPath)) { MatchResult ruleMatchResult = resultSubs.getMatch(); subsPath = path.substring(0, ruleMatchResult.start()) // before match + subsPath // match + path.substring(ruleMatchResult.end()); // after match } if (log.isDebugEnabled()) { log.debug("Rewriting \"{}\" to \"{}\"", StringEscapeUtil.escapeJava(path), StringEscapeUtil.escapeJava(subsPath)); } return subsPath; } public boolean substituteParameters(ParameterParser params, MatchResultSubstitution resultSubs) { boolean parameterSubstituted = false; if (!params.isEmpty()) { if (!flags.hasQSA()) { params.clear(); parameterSubstituted = true; log.debug("All parameters have been cleared. To prevent from clearing the parameters, " + "just specify \"QSA\" or \"qsappend\"(query string append) flag to the substitution"); } } for (Parameter param : parameters) { String key = param.getKey(resultSubs); String[] values = param.getValues(resultSubs); if (!StringUtil.isEmpty(key)) { if (ArrayUtil.isEmptyArray(values) || values.length == 1 && StringUtil.isEmpty(values[0])) { params.remove(key); if (log.isDebugEnabled()) { log.debug("Removed parameter: \"{}\"", StringEscapeUtil.escapeJava(key)); } } else { params.setStrings(key, values); if (log.isDebugEnabled()) { log.debug("Set parameter: \"{}\"=\"{}\"", StringEscapeUtil.escapeJava(key), ObjectUtil.toString(values)); } } parameterSubstituted = true; } } return parameterSubstituted; } @Override public String toString() { MapBuilder mb = new MapBuilder(); if (uri != null) { mb.append("uri", uri); } if (!isEmptyArray(parameters)) { mb.append("params", parameters); } if (!flags.isEmpty()) { mb.append("flags", flags); } return new ToStringBuilder().append("Substitution").append(mb).toString(); } /** 代表substitution的标志位。 */ public static class SubstitutionFlags extends Flags { public SubstitutionFlags() { super(); } public SubstitutionFlags(String... flags) { super(flags); } /** 标志位:保留所有GET、POST、UPLOAD所得的参数。 */ public boolean hasQSA() { return hasFlags("QSA", "qsappend"); } /** 标志位:如果一个规则被匹配,则继续处理其后继规则;如果该规则不被匹配,则其后继规则将被跳过。 */ public boolean hasC() { return hasFlags("C", "chain"); } /** 标志位:如果一个规则被匹配,并指明该参数,则立即结束。 */ public boolean hasL() { return hasFlags("L", "last"); } /** * 标志位:重定向,并取得redirect code。如果未指定重定向,则返回<code>0</code>。 * <p> * 默认为<code>302 moved temporarily</code>。如指定<code>R=301</code>则表示 * <code>301 moved permanently</code>。 * </p> */ public int getRedirectCode() { String value = getFlagValue("R", "redirect"); int defaultStatusCode = HttpServletResponse.SC_MOVED_TEMPORARILY; if (value == null) { return 0; } else if (value.length() == 0) { return defaultStatusCode; } else { try { return Integer.parseInt(value); } catch (NumberFormatException e) { return defaultStatusCode; } } } } public static class Parameter implements InitializingBean { private String key; private String[] values; public void setKey(String key) { this.key = trimToNull(key); } public void setValue(String value) { this.values = new String[] { value }; } public void setValues(String[] values) { this.values = values; } public void afterPropertiesSet() throws Exception { assertNotNull(key, "missing key attribute for parameter"); if (values == null) { values = EMPTY_STRING_ARRAY; } } public String getKey(MatchResultSubstitution resultSubs) { return resultSubs.substitute(key); } public String[] getValues(MatchResultSubstitution resultSubs) { String[] subsValues = new String[values.length]; for (int i = 0; i < values.length; i++) { subsValues[i] = resultSubs.substitute(values[i]); } return subsValues; } @Override public String toString() { ToStringBuilder buf = new ToStringBuilder().append(key).append(" = "); if (values.length == 1) { buf.append(values[0]); } else { buf.appendArray(values); } return buf.toString(); } } }