精华内容
下载资源
问答
  • The valid characters are defined in RFC 7230 and RFC 3986查了一下,是因为高版本tomcat中的新特性:严格按照 RFC 3986规范进行访问解析,而 RFC 3986规范定义了URL中只允许包含英文字母(...

    在用axios从前台向后台发请求时,后台报错

    Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986

    查了一下,是因为高版本tomcat中的新特性:严格按照 RFC 3986规范进行访问解析,而 RFC 3986规范定义了URL中只允许

    包含英文字母(a-z,A-Z)

    数字(0-9)

    -_.~4个特殊字符

    以及所有保留字符(RFC3986中指定了以下字符为保留字符:! * ’ ( ) ; : @ & = + $ , / ? # [ ])。

    而本例在传参时,在参数中传了一段JSON,传入的参数中有”{“,且有中文字符,均不在RFC3986中的保留字段中,所以会报这个错。

    解决方法:

    1、配置tomcat的catalina.properties

    添加或者修改:

    tomcat.util.http.parser.HttpParser.requestTargetAllow=|{}

    这种方法只适合对应的英文,如果含中文则就不行。如果有?和&这些符合那么

    tomcat.util.http.parser.HttpParser.requestTargetAllow=|{}?&

    2、更换Tomcat版本,但是不建议,既然有这个规范就养成习惯去遵守。

    3、对相应参数编码后传输到后台再进行解码

    JS端,使用encodeURI()方法:

    param: encodeURI(something)

    Java端,使用URLDecoder.decode()方法解码:

    String temp = req.getParameter("param");

    temp= URLDecoder.decode(temp, "utf-8");

    如果你需要在服务器端加密,可用URLDecoder.encode(),与URLDecoder.decode()作用相反不再赘述。需要注意的是这两个java方法有两个参数,第二个参数是加密方法。不指定加密方式的写法已被废弃。

    2b90becf6e290b91b37c81fb17ef10ab.png

    展开全文
  • 基本的互联网通信协议都有在RFC文件内详细说明。...RFC7230:https://tools.ietf.org/html/rfc7230RFC3986:https://tools.ietf.org/html/rfc3986Tomcat解析的Java类:org.apache.tomcat.util.http.p...

    基本的互联网通信协议都有在RFC文件内详细说明。RFC文件还额外加入许多的论题在标准内,因此几乎所有的互联网标准都有收录在RFC文件之中。

    RFC7230:https://tools.ietf.org/html/rfc7230

    RFC3986:https://tools.ietf.org/html/rfc3986

    Tomcat解析的Java类: org.apache.tomcat.util.http.parser.HttpParser

    被修改内容/方法为:public boolean isNotRequestTargetRelaxed(int c){

    try{

    return this.IS_NOT_REQUEST_TARGET[c];

    }catch (ArrayIndexOutOfBoundsException ex) {}

    return true;

    }

    public boolean isQueryRelaxed(int c){

    try{

    return this.IS_QUERY_RELAXED[c];

    }catch (ArrayIndexOutOfBoundsException ex) {}

    return false;

    }

    修改为://不加以拘束

    public boolean isNotRequestTargetRelaxed(int c){

    return false;

    }

    public boolean isQueryRelaxed(int c)

    {

    return true;

    }

    Apache Tomcat 7.0.93,修改后的:HttpParser.java/*

    * Licensed to the Apache Software Foundation (ASF) under one or more

    * contributor license agreements.  See the NOTICE file distributed with

    * this work for additional information regarding copyright ownership.

    * The ASF licenses this file to You 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 org.apache.tomcat.util.http.parser;

    import java.io.IOException;

    import java.io.Reader;

    import java.io.StringReader;

    import java.util.HashMap;

    import java.util.LinkedHashMap;

    import java.util.Locale;

    import java.util.Map;

    import org.apache.juli.logging.Log;

    import org.apache.juli.logging.LogFactory;

    import org.apache.tomcat.util.res.StringManager;

    /**

    * HTTP header value parser implementation. Parsing HTTP headers as per RFC2616

    * is not always as simple as it first appears. For headers that only use tokens

    * the simple approach will normally be sufficient. However, for the other

    * headers, while simple code meets 99.9% of cases, there are often some edge

    * cases that make things far more complicated.

    *

    * The purpose of this parser is to let the parser worry about the edge cases.

    * It provides tolerant (where safe to do so) parsing of HTTP header values

    * assuming that wrapped header lines have already been unwrapped. (The Tomcat

    * header processing code does the unwrapping.)

    *

    * Provides parsing of the following HTTP header values as per RFC 2616: -

    * Authorization for DIGEST authentication - MediaType (used for Content-Type

    * header)

    *

    * Support for additional headers will be provided as required.

    */

    public class HttpParser {

    @SuppressWarnings("unused") // Unused due to buggy client implementations

    private static final Integer FIELD_TYPE_TOKEN = Integer.valueOf(0);

    private static final Integer FIELD_TYPE_QUOTED_STRING = Integer.valueOf(1);

    private static final Integer FIELD_TYPE_TOKEN_OR_QUOTED_STRING = Integer.valueOf(2);

    private static final Integer FIELD_TYPE_LHEX = Integer.valueOf(3);

    private static final Integer FIELD_TYPE_QUOTED_TOKEN = Integer.valueOf(4);

    private static final Map fieldTypes = new HashMap();

    private static final StringManager sm = StringManager.getManager(HttpParser.class);

    private static final Log log = LogFactory.getLog(HttpParser.class);

    private static final int ARRAY_SIZE = 128;

    private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE];

    private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE];

    private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE];

    private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE];

    private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE];

    private static final boolean[] IS_ALPHA = new boolean[ARRAY_SIZE];

    private static final boolean[] IS_NUMERIC = new boolean[ARRAY_SIZE];

    private static final boolean[] REQUEST_TARGET_ALLOW = new boolean[ARRAY_SIZE];

    private static final boolean[] IS_UNRESERVED = new boolean[ARRAY_SIZE];

    private static final boolean[] IS_SUBDELIM = new boolean[ARRAY_SIZE];

    private static final boolean[] IS_USERINFO = new boolean[ARRAY_SIZE];

    private static final boolean[] IS_RELAXABLE = new boolean[ARRAY_SIZE];

    private static final HttpParser DEFAULT;

    static {

    // Digest field types.

    // Note: These are more relaxed than RFC2617. This adheres to the

    // recommendation of RFC2616 that servers are tolerant of buggy

    // clients when they can be so without ambiguity.

    fieldTypes.put("username", FIELD_TYPE_QUOTED_STRING);

    fieldTypes.put("realm", FIELD_TYPE_QUOTED_STRING);

    fieldTypes.put("nonce", FIELD_TYPE_QUOTED_STRING);

    fieldTypes.put("digest-uri", FIELD_TYPE_QUOTED_STRING);

    // RFC2617 says response is 32LHEX. 32LHEX will also be accepted

    fieldTypes.put("response", FIELD_TYPE_LHEX);

    // RFC2617 says algorithm is token. token will also be accepted

    fieldTypes.put("algorithm", FIELD_TYPE_QUOTED_TOKEN);

    fieldTypes.put("cnonce", FIELD_TYPE_QUOTED_STRING);

    fieldTypes.put("opaque", FIELD_TYPE_QUOTED_STRING);

    // RFC2617 says qop is token. token will also be accepted

    fieldTypes.put("qop", FIELD_TYPE_QUOTED_TOKEN);

    // RFC2617 says nc is 8LHEX. 8LHEX will also be accepted

    fieldTypes.put("nc", FIELD_TYPE_LHEX);

    for (int i = 0; i 

    // Control> 0-31, 127

    if (i 

    IS_CONTROL[i] = true;

    }

    // Separator

    if (i == '(' || i == ')' || i == '' || i == '@' || i == ',' || i == ';' || i == ':'

    || i == '\\' || i == '\"' || i == '/' || i == '[' || i == ']' || i == '?' || i == '=' || i == '{'

    || i == '}' || i == ' ' || i == '\t') {

    IS_SEPARATOR[i] = true;

    }

    // Token: Anything 0-127 that is not a control and not a separator

    if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i 

    IS_TOKEN[i] = true;

    }

    // Hex: 0-9, a-f, A-F

    if ((i >= '0' && i <= '9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) {

    IS_HEX[i] = true;

    }

    // Not valid for HTTP protocol

    // "HTTP/" DIGIT "." DIGIT

    if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) {

    IS_HTTP_PROTOCOL[i] = true;

    }

    if (i >= '0' && i <= '9') {

    IS_NUMERIC[i] = true;

    }

    if (i >= 'a' && i <= 'z' || i >= 'A' && i <= 'Z') {

    IS_ALPHA[i] = true;

    }

    if (IS_ALPHA[i] || IS_NUMERIC[i] || i == '-' || i == '.' || i == '_' || i == '~') {

    IS_UNRESERVED[i] = true;

    }

    if (i == '!' || i == '$' || i == '&' || i == '\'' || i == '(' || i == ')' || i == '*' || i == '+'

    || i == ',' || i == ';' || i == '=') {

    IS_SUBDELIM[i] = true;

    }

    // userinfo = *( unreserved / pct-encoded / sub-delims / ":" )

    if (IS_UNRESERVED[i] || i == '%' || IS_SUBDELIM[i] || i == ':') {

    IS_USERINFO[i] = true;

    }

    // The characters that are normally not permitted for which the

    // restrictions may be relaxed when used in the path and/or query

    // string

    if (i == '\"' || i == '' || i == '[' || i == '\\' || i == ']' || i == '^' || i == '`'

    || i == '{' || i == '|' || i == '}') {

    IS_RELAXABLE[i] = true;

    }

    }

    String prop = System.getProperty("tomcat.util.http.parser.HttpParser.requestTargetAllow");

    if (prop != null) {

    for (int i = 0; i 

    char c = prop.charAt(i);

    if (c == '{' || c == '}' || c == '|') {

    REQUEST_TARGET_ALLOW[c] = true;

    } else {

    log.warn(sm.getString("http.invalidRequestTargetCharacter", Character.valueOf(c)));

    }

    }

    }

    DEFAULT = new HttpParser(null, null);

    }

    private final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE];

    private final boolean[] IS_ABSOLUTEPATH_RELAXED = new boolean[ARRAY_SIZE];

    private final boolean[] IS_QUERY_RELAXED = new boolean[ARRAY_SIZE];

    public HttpParser(String relaxedPathChars, String relaxedQueryChars) {

    for (int i = 0; i 

    // Not valid for request target.

    // Combination of multiple rules from RFC7230 and RFC 3986. Must be

    // ASCII, no controls plus a few additional characters excluded

    if (IS_CONTROL[i] || i > 127 || i == ' ' || i == '\"' || i == '#' || i == '' || i == '\\'

    || i == '^' || i == '`' || i == '{' || i == '|' || i == '}') {

    if (!REQUEST_TARGET_ALLOW[i]) {

    IS_NOT_REQUEST_TARGET[i] = true;

    }

    }

    /*

    * absolute-path = 1*( "/" segment ) segment = *pchar pchar = unreserved /

    * pct-encoded / sub-delims / ":" / "@"

    *

    * Note pchar allows everything userinfo allows plus "@"

    */

    if (IS_USERINFO[i] || i == '@' || i == '/' || REQUEST_TARGET_ALLOW[i]) {

    IS_ABSOLUTEPATH_RELAXED[i] = true;

    }

    /*

    * query = *( pchar / "/" / "?" )

    *

    * Note query allows everything absolute-path allows plus "?"

    */

    if (IS_ABSOLUTEPATH_RELAXED[i] || i == '?' || REQUEST_TARGET_ALLOW[i]) {

    IS_QUERY_RELAXED[i] = true;

    }

    }

    relax(IS_ABSOLUTEPATH_RELAXED, relaxedPathChars);

    relax(IS_QUERY_RELAXED, relaxedQueryChars);

    }

    /**

    * Parses an HTTP Authorization header for DIGEST authentication as per RFC 2617

    * section 3.2.2.

    *

    * @param input The header value to parse

    *

    * @return A map of directives and values as {@link String}s or

    *         null if a parsing error occurs. Although the values

    *         returned are {@link String}s they will have been validated to ensure

    *         that they conform to RFC 2617.

    *

    * @throws IllegalArgumentException If the header does not conform to RFC 2617

    * @throws IOException              If an error occurs while reading the input

    */

    public static Map parseAuthorizationDigest(StringReader input)

    throws IllegalArgumentException, IOException {

    Map result = new HashMap();

    if (skipConstant(input, "Digest") != SkipResult.FOUND) {

    return null;

    }

    // All field names are valid tokens

    String field = readToken(input);

    if (field == null) {

    return null;

    }

    while (!field.equals("")) {

    if (skipConstant(input, "=") != SkipResult.FOUND) {

    return null;

    }

    String value = null;

    Integer type = fieldTypes.get(field.toLowerCase(Locale.ENGLISH));

    if (type == null) {

    // auth-param = token "=" ( token | quoted-string )

    type = FIELD_TYPE_TOKEN_OR_QUOTED_STRING;

    }

    switch (type.intValue()) {

    case 0:

    // FIELD_TYPE_TOKEN

    value = readToken(input);

    break;

    case 1:

    // FIELD_TYPE_QUOTED_STRING

    value = readQuotedString(input, false);

    break;

    case 2:

    // FIELD_TYPE_TOKEN_OR_QUOTED_STRING

    value = readTokenOrQuotedString(input, false);

    break;

    case 3:

    // FIELD_TYPE_LHEX

    value = readLhex(input);

    break;

    case 4:

    // FIELD_TYPE_QUOTED_TOKEN

    value = readQuotedToken(input);

    break;

    default:

    // Error

    throw new IllegalArgumentException("TODO i18n: Unsupported type");

    }

    if (value == null) {

    return null;

    }

    result.put(field, value);

    if (skipConstant(input, ",") == SkipResult.NOT_FOUND) {

    return null;

    }

    field = readToken(input);

    if (field == null) {

    return null;

    }

    }

    return result;

    }

    public static MediaType parseMediaType(StringReader input) throws IOException {

    // Type (required)

    String type = readToken(input);

    if (type == null || type.length() == 0) {

    return null;

    }

    if (skipConstant(input, "/") == SkipResult.NOT_FOUND) {

    return null;

    }

    // Subtype (required)

    String subtype = readToken(input);

    if (subtype == null || subtype.length() == 0) {

    return null;

    }

    LinkedHashMap parameters = new LinkedHashMap();

    SkipResult lookForSemiColon = skipConstant(input, ";");

    if (lookForSemiColon == SkipResult.NOT_FOUND) {

    return null;

    }

    while (lookForSemiColon == SkipResult.FOUND) {

    String attribute = readToken(input);

    String value = "";

    if (skipConstant(input, "=") == SkipResult.FOUND) {

    value = readTokenOrQuotedString(input, true);

    }

    if (attribute != null) {

    parameters.put(attribute.toLowerCase(Locale.ENGLISH), value);

    }

    lookForSemiColon = skipConstant(input, ";");

    if (lookForSemiColon == SkipResult.NOT_FOUND) {

    return null;

    }

    }

    return new MediaType(type, subtype, parameters);

    }

    public boolean isNotRequestTargetRelaxed(int c) {

    // Fast for valid request target characters, slower for some incorrect

    // ones

    //try {

    //return IS_NOT_REQUEST_TARGET[c];

    //} catch (ArrayIndexOutOfBoundsException ex) {

    //return true;

    //}

    return false;

    }

    public boolean isAbsolutePathRelaxed(int c) {

    // Fast for valid user info characters, slower for some incorrect

    // ones

    try {

    return IS_ABSOLUTEPATH_RELAXED[c];

    } catch (ArrayIndexOutOfBoundsException ex) {

    return false;

    }

    }

    public boolean isQueryRelaxed(int c) {

    // Fast for valid user info characters, slower for some incorrect

    // ones

    //try {

    //return IS_QUERY_RELAXED[c];

    //} catch (ArrayIndexOutOfBoundsException ex) {

    //return false;

    //}

    return true;

    }

    public static String unquote(String input) {

    if (input == null || input.length() 

    return input;

    }

    int start;

    int end;

    // Skip surrounding quotes if there are any

    if (input.charAt(0) == '"') {

    start = 1;

    end = input.length() - 1;

    } else {

    start = 0;

    end = input.length();

    }

    StringBuilder result = new StringBuilder();

    for (int i = start; i 

    char c = input.charAt(i);

    if (input.charAt(i) == '\\') {

    i++;

    result.append(input.charAt(i));

    } else {

    result.append(c);

    }

    }

    return result.toString();

    }

    public static boolean isToken(int c) {

    // Fast for correct values, slower for incorrect ones

    try {

    return IS_TOKEN[c];

    } catch (ArrayIndexOutOfBoundsException ex) {

    return false;

    }

    }

    public static boolean isHex(int c) {

    // Fast for correct values, slower for some incorrect ones

    try {

    return IS_HEX[c];

    } catch (ArrayIndexOutOfBoundsException ex) {

    return false;

    }

    }

    public static boolean isNotRequestTarget(int c) {

    return DEFAULT.isNotRequestTargetRelaxed(c);

    }

    public static boolean isHttpProtocol(int c) {

    // Fast for valid HTTP protocol characters, slower for some incorrect

    // ones

    try {

    return IS_HTTP_PROTOCOL[c];

    } catch (ArrayIndexOutOfBoundsException ex) {

    return false;

    }

    }

    public static boolean isAlpha(int c) {

    // Fast for valid alpha characters, slower for some incorrect

    // ones

    try {

    return IS_ALPHA[c];

    } catch (ArrayIndexOutOfBoundsException ex) {

    return false;

    }

    }

    public static boolean isNumeric(int c) {

    // Fast for valid numeric characters, slower for some incorrect

    // ones

    try {

    return IS_NUMERIC[c];

    } catch (ArrayIndexOutOfBoundsException ex) {

    return false;

    }

    }

    public static boolean isUserInfo(int c) {

    // Fast for valid user info characters, slower for some incorrect

    // ones

    try {

    return IS_USERINFO[c];

    } catch (ArrayIndexOutOfBoundsException ex) {

    return false;

    }

    }

    private static boolean isRelaxable(int c) {

    // Fast for valid user info characters, slower for some incorrect

    // ones

    try {

    return IS_RELAXABLE[c];

    } catch (ArrayIndexOutOfBoundsException ex) {

    return false;

    }

    }

    public static boolean isAbsolutePath(int c) {

    return DEFAULT.isAbsolutePathRelaxed(c);

    }

    public static boolean isQuery(int c) {

    return DEFAULT.isQueryRelaxed(c);

    }

    // Skip any LWS and position to read the next character. The next character

    // is returned as being able to 'peek()' it allows a small optimisation in

    // some cases.

    private static int skipLws(Reader input) throws IOException {

    input.mark(1);

    int c = input.read();

    while (c == 32 || c == 9 || c == 10 || c == 13) {

    input.mark(1);

    c = input.read();

    }

    input.reset();

    return c;

    }

    static SkipResult skipConstant(Reader input, String constant) throws IOException {

    int len = constant.length();

    skipLws(input);

    input.mark(len);

    int c = input.read();

    for (int i = 0; i 

    if (i == 0 && c == -1) {

    return SkipResult.EOF;

    }

    if (c != constant.charAt(i)) {

    input.reset();

    return SkipResult.NOT_FOUND;

    }

    if (i != (len - 1)) {

    c = input.read();

    }

    }

    return SkipResult.FOUND;

    }

    /**

    * @return the token if one was found, the empty string if no data was available

    *         to read or null if data other than a token was found

    */

    static String readToken(Reader input) throws IOException {

    StringBuilder result = new StringBuilder();

    skipLws(input);

    input.mark(1);

    int c = input.read();

    while (c != -1 && isToken(c)) {

    result.append((char) c);

    input.mark(1);

    c = input.read();

    }

    // Use mark(1)/reset() rather than skip(-1) since skip() is a NOP

    // once the end of the String has been reached.

    input.reset();

    if (c != -1 && result.length() == 0) {

    return null;

    } else {

    return result.toString();

    }

    }

    /**

    * @return the quoted string if one was found, null if data other than a quoted

    *         string was found or null if the end of data was reached before the

    *         quoted string was terminated

    */

    private static String readQuotedString(Reader input, boolean returnQuoted) throws IOException {

    skipLws(input);

    int c = input.read();

    if (c != '"') {

    return null;

    }

    StringBuilder result = new StringBuilder();

    if (returnQuoted) {

    result.append('\"');

    }

    c = input.read();

    while (c != '"') {

    if (c == -1) {

    return null;

    } else if (c == '\\') {

    c = input.read();

    if (returnQuoted) {

    result.append('\\');

    }

    result.append((char) c);

    } else {

    result.append((char) c);

    }

    c = input.read();

    }

    if (returnQuoted) {

    result.append('\"');

    }

    return result.toString();

    }

    private static String readTokenOrQuotedString(Reader input, boolean returnQuoted) throws IOException {

    // Peek at next character to enable correct method to be called

    int c = skipLws(input);

    if (c == '"') {

    return readQuotedString(input, returnQuoted);

    } else {

    return readToken(input);

    }

    }

    /**

    * Token can be read unambiguously with or without surrounding quotes so this

    * parsing method for token permits optional surrounding double quotes. This is

    * not defined in any RFC. It is a special case to handle data from buggy

    * clients (known buggy clients for DIGEST auth include Microsoft IE 8 & 9,

    * Apple Safari for OSX and iOS) that add quotes to values that should be

    * tokens.

    *

    * @return the token if one was found, null if data other than a token or quoted

    *         token was found or null if the end of data was reached before a

    *         quoted token was terminated

    */

    private static String readQuotedToken(Reader input) throws IOException {

    StringBuilder result = new StringBuilder();

    boolean quoted = false;

    skipLws(input);

    input.mark(1);

    int c = input.read();

    if (c == '"') {

    quoted = true;

    } else if (c == -1 || !isToken(c)) {

    return null;

    } else {

    result.append((char) c);

    }

    input.mark(1);

    c = input.read();

    while (c != -1 && isToken(c)) {

    result.append((char) c);

    input.mark(1);

    c = input.read();

    }

    if (quoted) {

    if (c != '"') {

    return null;

    }

    } else {

    // Use mark(1)/reset() rather than skip(-1) since skip() is a NOP

    // once the end of the String has been reached.

    input.reset();

    }

    if (c != -1 && result.length() == 0) {

    return null;

    } else {

    return result.toString();

    }

    }

    /**

    * LHEX can be read unambiguously with or without surrounding quotes so this

    * parsing method for LHEX permits optional surrounding double quotes. Some

    * buggy clients (libwww-perl for DIGEST auth) are known to send quoted LHEX

    * when the specification requires just LHEX.

    *

    * LHEX are, literally, lower-case hexadecimal digits. This implementation

    * allows for upper-case digits as well, converting the returned value to

    * lower-case.

    *

    * @return the sequence of LHEX (minus any surrounding quotes) if any was found,

    *         or null if data other LHEX was found

    */

    private static String readLhex(Reader input) throws IOException {

    StringBuilder result = new StringBuilder();

    boolean quoted = false;

    skipLws(input);

    input.mark(1);

    int c = input.read();

    if (c == '"') {

    quoted = true;

    } else if (c == -1 || !isHex(c)) {

    return null;

    } else {

    if ('A' <= c && c <= 'F') {

    c -= ('A' - 'a');

    }

    result.append((char) c);

    }

    input.mark(1);

    c = input.read();

    while (c != -1 && isHex(c)) {

    if ('A' <= c && c <= 'F') {

    c -= ('A' - 'a');

    }

    result.append((char) c);

    input.mark(1);

    c = input.read();

    }

    if (quoted) {

    if (c != '"') {

    return null;

    }

    } else {

    // Use mark(1)/reset() rather than skip(-1) since skip() is a NOP

    // once the end of the String has been reached.

    input.reset();

    }

    if (c != -1 && result.length() == 0) {

    return null;

    } else {

    return result.toString();

    }

    }

    static enum SkipResult {

    FOUND, NOT_FOUND, EOF

    }

    /**

    * @return If inIPv6 is false, the position of ':' that separates the host from

    *         the port or -1 if it is not present. If inIPv6 is true, the number of

    *         characters read

    */

    static int readHostIPv4(Reader reader, boolean inIPv6) throws IOException {

    int octet = -1;

    int octetCount = 1;

    int c;

    int pos = 0;

    // readAheadLimit doesn't matter as all the readers passed to this

    // method buffer the entire content.

    reader.mark(1);

    do {

    c = reader.read();

    if (c == '.') {

    if (octet > -1 && octet 

    // Valid

    octetCount++;

    octet = -1;

    } else if (inIPv6 || octet == -1) {

    throw new IllegalArgumentException(sm.getString("http.invalidOctet", Integer.toString(octet)));

    } else {

    // Might not be an IPv4 address. Could be a host / FQDN with

    // a fully numeric component.

    reader.reset();

    return readHostDomainName(reader);

    }

    } else if (isNumeric(c)) {

    if (octet == -1) {

    octet = c - '0';

    } else if (octet == 0) {

    // Leading zero in non-zero octet. Not valid (ambiguous).

    if (inIPv6) {

    throw new IllegalArgumentException(sm.getString("http.invalidLeadingZero"));

    } else {

    // Could be a host/FQDN

    reader.reset();

    return readHostDomainName(reader);

    }

    } else {

    octet = octet * 10 + c - '0';

    }

    } else if (c == ':') {

    break;

    } else if (c == -1) {

    if (inIPv6) {

    throw new IllegalArgumentException(sm.getString("http.noClosingBracket"));

    } else {

    pos = -1;

    break;

    }

    } else if (c == ']') {

    if (inIPv6) {

    pos++;

    break;

    } else {

    throw new IllegalArgumentException(sm.getString("http.closingBracket"));

    }

    } else if (!inIPv6 && (isAlpha(c) || c == '-')) {

    // Go back to the start and parse as a host / FQDN

    reader.reset();

    return readHostDomainName(reader);

    } else {

    throw new IllegalArgumentException(

    sm.getString("http.illegalCharacterIpv4", Character.toString((char) c)));

    }

    pos++;

    } while (true);

    if (octetCount != 4 || octet  255) {

    // Might not be an IPv4 address. Could be a host name or a FQDN with

    // fully numeric components. Go back to the start and parse as a

    // host / FQDN.

    reader.reset();

    return readHostDomainName(reader);

    }

    return pos;

    }

    /**

    * @return The position of ':' that separates the host from the port or -1 if it

    *         is not present

    */

    static int readHostIPv6(Reader reader) throws IOException {

    // Must start with '['

    int c = reader.read();

    if (c != '[') {

    throw new IllegalArgumentException(sm.getString("http.noOpeningBracket"));

    }

    int h16Count = 0;

    int h16Size = 0;

    int pos = 1;

    boolean parsedDoubleColon = false;

    int precedingColonsCount = 0;

    do {

    c = reader.read();

    if (h16Count == 0 && precedingColonsCount == 1 && c != ':') {

    // Can't start with a single :

    throw new IllegalArgumentException(sm.getString("http.singleColonStart"));

    }

    if (HttpParser.isHex(c)) {

    if (h16Size == 0) {

    // Start of a new h16 block

    precedingColonsCount = 0;

    h16Count++;

    }

    h16Size++;

    if (h16Size > 4) {

    throw new IllegalArgumentException(sm.getString("http.invalidHextet"));

    }

    } else if (c == ':') {

    if (precedingColonsCount >= 2) {

    // ::: is not allowed

    throw new IllegalArgumentException(sm.getString("http.tooManyColons"));

    } else {

    if (precedingColonsCount == 1) {

    // End of ::

    if (parsedDoubleColon) {

    // Only allowed one :: sequence

    throw new IllegalArgumentException(sm.getString("http.tooManyDoubleColons"));

    }

    parsedDoubleColon = true;

    // :: represents at least one h16 block

    h16Count++;

    }

    precedingColonsCount++;

    // mark if the next symbol is hex before the actual read

    reader.mark(4);

    }

    h16Size = 0;

    } else if (c == ']') {

    if (precedingColonsCount == 1) {

    // Can't end on a single ':'

    throw new IllegalArgumentException(sm.getString("http.singleColonEnd"));

    }

    pos++;

    break;

    } else if (c == '.') {

    if (h16Count == 7 || h16Count 

    reader.reset();

    pos -= h16Size;

    pos += readHostIPv4(reader, true);

    h16Count++;

    break;

    } else {

    throw new IllegalArgumentException(sm.getString("http.invalidIpv4Location"));

    }

    } else {

    throw new IllegalArgumentException(

    sm.getString("http.illegalCharacterIpv6", Character.toString((char) c)));

    }

    pos++;

    } while (true);

    if (h16Count > 8) {

    throw new IllegalArgumentException(sm.getString("http.tooManyHextets", Integer.toString(h16Count)));

    } else if (h16Count != 8 && !parsedDoubleColon) {

    throw new IllegalArgumentException(sm.getString("http.tooFewHextets", Integer.toString(h16Count)));

    }

    c = reader.read();

    if (c == ':') {

    return pos;

    } else {

    if (c == -1) {

    return -1;

    }

    throw new IllegalArgumentException(sm.getString("http.illegalAfterIpv6", Character.toString((char) c)));

    }

    }

    /**

    * @return The position of ':' that separates the host from the port or -1 if it

    *         is not present

    */

    static int readHostDomainName(Reader reader) throws IOException {

    DomainParseState state = DomainParseState.NEW;

    int pos = 0;

    while (state.mayContinue()) {

    state = state.next(reader.read());

    pos++;

    }

    if (DomainParseState.COLON == state) {

    // State identifies the state of the previous character

    return pos - 1;

    } else {

    return -1;

    }

    }

    /**

    * Skips all characters until EOF or the specified target is found. Normally

    * used to skip invalid input until the next separator.

    */

    static SkipResult skipUntil(Reader input, int c, char target) throws IOException {

    while (c != -1 && c != target) {

    c = input.read();

    }

    if (c == -1) {

    return SkipResult.EOF;

    } else {

    return SkipResult.FOUND;

    }

    }

    private void relax(boolean[] flags, String relaxedChars) {

    if (relaxedChars != null && relaxedChars.length() > 0) {

    char[] chars = relaxedChars.toCharArray();

    for (char c : chars) {

    if (isRelaxable(c)) {

    flags[c] = true;

    IS_NOT_REQUEST_TARGET[c] = false;

    }

    }

    }

    }

    private enum DomainParseState {

    NEW(true, false, false, false, " at the start of"), ALPHA(true, true, true, true, " after a letter in"),

    NUMERIC(true, true, true, true, " after a number in"), PERIOD(true, false, false, true, " after a period in"),

    HYPHEN(true, true, false, false, " after a hypen in"), COLON(false, false, false, false, " after a colon in"),

    END(false, false, false, false, " at the end of");

    private final boolean mayContinue;

    private final boolean allowsHyphen;

    private final boolean allowsPeriod;

    private final boolean allowsEnd;

    private final String errorLocation;

    private DomainParseState(boolean mayContinue, boolean allowsHyphen, boolean allowsPeriod, boolean allowsEnd,

    String errorLocation) {

    this.mayContinue = mayContinue;

    this.allowsHyphen = allowsHyphen;

    this.allowsPeriod = allowsPeriod;

    this.allowsEnd = allowsEnd;

    this.errorLocation = errorLocation;

    }

    public boolean mayContinue() {

    return mayContinue;

    }

    public DomainParseState next(int c) {

    if (HttpParser.isAlpha(c)) {

    return ALPHA;

    } else if (HttpParser.isNumeric(c)) {

    return NUMERIC;

    } else if (c == '.') {

    if (allowsPeriod) {

    return PERIOD;

    } else {

    throw new IllegalArgumentException(

    sm.getString("http.invalidCharacterDomain", Character.toString((char) c), errorLocation));

    }

    } else if (c == ':') {

    if (allowsEnd) {

    return COLON;

    } else {

    throw new IllegalArgumentException(

    sm.getString("http.invalidCharacterDomain", Character.toString((char) c), errorLocation));

    }

    } else if (c == -1) {

    if (allowsEnd) {

    return END;

    } else {

    throw new IllegalArgumentException(sm.getString("http.invalidSegmentEndState", this.name()));

    }

    } else if (c == '-') {

    if (allowsHyphen) {

    return HYPHEN;

    } else {

    throw new IllegalArgumentException(

    sm.getString("http.invalidCharacterDomain", Character.toString((char) c), errorLocation));

    }

    } else {

    throw new IllegalArgumentException(

    sm.getString("http.illegalCharacterDomain", Character.toString((char) c)));

    }

    }

    }

    }

    改动相关的jar,如下:

    1、tomcat-juli.jar,相关的。

    2、tomcat-util.jar,相关的。

    3、tomcat-coyote.jar,被修改的。

    展开全文
  • mpeg dash 的element BaseURL语法规则遵循RFC 3986,需要做简单了解:I.1URI各个部分的名称foo://example.com:8042/over/there?name=ferret#nose\_/\______________/\_________/\_________/\__/||...

    mpeg dash 的element BaseURL语法规则遵循RFC 3986,需要做简单了解:

    I.1 URI各个部分的名称

    foo://example.com:8042/over/there?name=ferret#nose

    \_/   \______________/\_________/ \_________/ \__/

    |                   |                          |                     |             |

    scheme     authority                    path              query   fragment

    |   _________________________|__

    / \ /                                           \

    urn:example:animal:ferret:nose

    scheme:协议的名称,以字母开头,后接任意个字母/数字/+/-/.的组合。

    scheme      = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )

    authority:以双斜线”//”开始但不包括”//”, 以紧接着的第一个’/’或者?或者#(#在这里

    叫着number sign)结束但不包括该符号,或者一直到URL结束为止。

    authority   = [ userinfo "@" ] host [ ":" port ]

    []内的部分是可选部分。

    path: 在authority之后,以/开头,以紧接着的第一个?或者#结束或者直到URL结束为止。

    query:以?开头,以紧接着的第一个#结束,或者直到URL结束为止,query常常以

    “key=value”的形式来携带一些认证信息。

    fragment: 以#开头,直到URL结束为止。Fragment常用于标记一个参考主要资源的次要

    资源。

    I.2 URI的参考规则

    URI-reference:URI-reference可能是URI或者relative-reference,当URI-reference的前缀不

    匹配scheme的语法时,表明URI-reference是一个relative-reference。

    Relative-reference所参考的URI叫target URI。

    在mpeg dash中,暂时只需要知道BaseURL可能需要参考上级的BaseURL来组合成一个完整的http链接即可,如下:

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns="urn:mpeg:DASH:schema:MPD:2011"

    xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd"

    type="static"

    mediaPresentationDuration="PT3256S"

    minBufferTime="PT1.2S"

    profiles="urn:mpeg:dash:profile:isoff-on-demand:2011">

    http://cdn1.example.com/

    http://cdn2.example.com/

    subsegmentStartsWithSAP="1">

    7657412348.mp4

    3463646346.mp4

    访问两个MP4文件的HTTP URL需要组合MPD中的BaseURL和Representation中的BaseURL:

    或者

    展开全文
  • Is it correct to assume that everything that is not unreserved, can/should be percent-...RFC 3986说:“Under normal circumstances, the only time when octets within a URI are percent-encoded is durin...

    Is it correct to assume that everything that is not unreserved, can/should be percent-encoded?

    RFC 3986说:

    “Under normal circumstances, the only time when octets within a URI are percent-encoded is during the process of producing the URI from its component parts. This is when an implementation determines which of the reserved characters are to be used as subcomponent delimiters and which can be safely used as data. “

    这意味着您决定根据上下文需要编码哪个分隔符(即< delimiter>)字符.不需要编码的那些不应该被编码.

    例如,如果出现在路径组件中,则不应该对/ a进行百分号编码,但是当它出现在查询或片段中时,您应该对它进行百分比编码.

    所以,其实一个;字符(它是< reserved>的成员)不应该被自动百分比编码,实际上,java URL和URI类不会这样做;请参阅URI(…) javadoc,具体是第7步),了解< path>组件被处理.

    这一点得到加强:

    “The purpose of reserved characters is to provide a set of delimiting characters that are distinguishable from other data within a URI. URIs that differ in the replacement of a reserved character with its corresponding percent-encoded octet are not equivalent. Percent- encoding a reserved character, or decoding a percent-encoded octet that corresponds to a reserved character, will change how the URI is interpreted by most applications. Thus, characters in the reserved set are protected from normalization and are therefore safe to be used by scheme-specific and producer-specific algorithms for delimiting data subcomponents within a URI.”

    所以这说明一个包含百分比编码的URL;与包含raw的URL不同.最后一句话意味着它们不应该被自动编码或解码百分之百.

    这让我们有这个问题 – 你为什么要被编码百分比

    Let’s say you have a CMS where people can create arbitrary pages having arbitrary paths. Later on, I need to generate href links to all pages in, for example, site map component. Therefore I need an algorithm to know which characters to escape. Semicolon has to be treated literally in this case and should be escaped.

    对不起,但不符合分号应该被转义.

    就URL / URI规范而言,没有什么特别的意义.它可能对特定的Web服务器/网站有特殊的含义,但一般来说(即没有网站的具体知识),您无法知道这一点.

    >如果在一个特定的URI中有特殊的含义,那么如果你的百分之百逃脱它,那么你会破坏这个含义.例如,如果网站使用;以允许将会话令牌附加到路径,然后百分比编码将阻止它识别会话令牌…

    >如果只是一些客户端提供的数据字符,那么如果你对它进行了编码,你可能会改变URI的含义.这是否重要取决于服务器的功能?即是否解码,作为应用逻辑的一部分.

    这意味着知道“正确的事情”需要深入了解URI对最终用户和/或站点的意义.这将需要高级思维阅读技术来实施.我的建议是通过在将URI路径传递给您的软件之前适当地转义URI路径的任何分隔符来获取CMS来解决它.该算法必然是针对CMS和内容传送平台的.它/他们将响应由URL识别的文档的请求,并且需要知道如何解释它们.

    (支持任意使用任意路径的人有点疯狂,必须有一些限制,例如Windows甚至不允许在文件名组件中使用文件分隔符,所以你必须在某处有一些边界.只是一个决定他们应该在哪里的问题.)

    展开全文
  • RFC 3986 support

    2020-12-26 06:38:26
    <p>Is is possible to support RFC 3986 http://tools.ietf.org/html/rfc3986#section-4.2 ?</p> <p>My problem is that my website supports both http and https. This is because I don't want to bother ...
  • 兼容 RFC 3986 的 URL lib。.zip,Java的现代URL工具集。符合RFC 3986
  • 问题出现:tomcat由7.0.65升级到...有效字符在RFC 7230和RFC 3986中定义原因分析:日志显示请求地址中包含不合法字符,出现400错误tomcat高版本严格按照RFC 3986规范解析地址。该规范只允许包含 a-zA-Z 0-9 - _ . ~...
  • RFC 7230 and RFC 3986

    2019-05-13 10:04:00
    java.lang.IllegalArgumentException: Invalid character found in the request ... The valid characters are defined in RFC 7230 and RFC 3986 at org.apache.coyote.http11.Http11InputBuffer.parseRequestL...
  • 最近在ssm实践项目中遇到了The valid characters are defined in RFC 7230 and RFC 3986这个问题,折腾了两天实践终于搞定了,记录一下心得。 1、首先贴出报错日志: 09-Apr-2019 14:55:11.427 信息 ...
  • 项目从原先的jdk1.6+tomcat6 升级为jdk1.8+tomcat9... RFC 3986规范定义了Url中只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~4种特殊字符以及所有保留字符(RFC3986中指定了以下字符为保留字符:! * ’ ( ) ; : @...
  • - In Section 3.3, the reference is to RFC3986 (URI) <em>and</em> RFC3987 (IRI) are both listed. Which sounds about right; this means a file name of the form <code>/téléphone</code> is all right, ...
  • tomcat 请求出现RFC 7230 and RFC3986的错误 问题出现:  tomcat由7.0.65升级到7.0.104后出现该问题  java.lang.IllegalArgumentException:在请求目标中找到无效字符。有效字符在RFC 7230和RFC 3986中定义原因...
  • 原标题:The valid characters are defined in RFC 7230 and RFC 3986皕杰报表demoserver中的演示项目report部署到tomcat8最新版本后,web端访问报表报错:java.lang.IllegalArgumentException: Invalid character ...
  • <div><p>This PR adds the <code>rfc3986</code> module into <code>urllib3.packages</code> and replaces our current URL parser with the one from <code>rfc3986</code>. This brings our URL parser in-line ...
  • 异常原因:url参数里面有特殊字符 Message Invalid character found in ... The valid characters are defined in RFC 7230 and RFC 3986 Description The server cannot or will not process the request du...
  • The valid characters are defined in RFC 7230 and RFC 3986 控制台报错: java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 ...
  • 出现这个问题 ,是因为Tomcat的版本过高 ,对request的url进行了RFC 3986文档...2.RFC3986中指定了以下字符为保留字符:! * ’ ( ) ; : @ & = + $ , / ? # [ ] 出现这个问题的原因就是url出现了其他的字符 ,比如
  • 这个问题是高版本tomcat中的新特性:就是严格按照 RFC 3986规范进行访问解析,而 RFC 3986规范定义了Url中只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~4个特殊字符以及所有保留字符(RFC3986中指定了以下字符为...
  • 是什么造成了Tomcat会报这个错误,主要在Get请求地址传参时,在url中传了一段带有特殊字符的参数,参数中有"{"不在RFC3986中的保留字段中,所以会报这个错。 例: 主要的问题是高版本tomcat中的新特性:就是...
  • <div><p>without trying to get into naming fights: if RFC 3986 gets referenced (which is currently the case, and i think that's a good choice), then it would be good to use the terminology of this ...
  • 就是严格按照 RFC 3986规范进行访问解析,而 RFC 3986规范定义了Url中只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~4个特殊字符以及所有保留字符(RFC3986中指定了以下字符为保留字符:! * ’ ( ) ; : @ &amp...
  • Tomcat中出现"RFC 7230 and RFC 3986"错误的解决方法
  • 使用Tomcat 7.0.82和Tomcat 8.0.48搭建的服务器发布网站,网站中存在url地址中传参,并且参数是包含中文,于是出现了以下错误... The valid characters are defined in RFC 7230 and RFC 3986在网上查找解决办法,得...
  • url传的值有问题得按照RFC7230andRFC3986规范 解决方式: 添加配置 import org.apache.catalina.connector.Connector; import org.springframework.boot.context.embedded.ConfigurableEm...
  • 场景描述 请求地址(URL)中参数包含符号, 导致后台产生The valid characters are defined in RFC 7230 and RFC 3986异常。 ... RFC3986中指定了以下字符为保留字符:! * ’ ( ) ; : @ &...
  • (PHP 4, PHP 5, PHP 7)rawurlencode – 按照 RFC 3986 对 URL 进行编码说明rawurlencode( string $str) : string根据 » RFC 3986 编码指定的字符。参数str要编码的 URL。返回值返回字符串,此字符串中除了-_.之外的...
  • RFC 3986规范定义了Url中只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~4种特殊字符以及所有保留字符(RFC3986中指定了以下字符为保留字符:! * ’ ( ) ; : @ & = + $ , / ? # [ ])。而我们的系统在通过地址...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,296
精华内容 518
关键字:

rfc3986