001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.camel.util;
018
019/**
020 * A Camel specific URI parser that parses endpoint URIs in a quasi syntax that Camel uses.
021 *
022 * The {@link java.net.URI} is much slower and parses endpoint URIs into additional parts which
023 * Camel does not use or need.
024 */
025public final class CamelURIParser {
026 
027    private CamelURIParser() {
028    }
029
030    /**
031     * Parses the URI.
032     *
033     * If this parser cannot parse the uri then <tt>null</tt> is returned. And instead the follow code can be used:
034     * <pre>
035     *     URI u = new URI(UnsafeUriCharactersEncoder.encode(uri, true));
036     * </pre>
037     *
038     * @param uri the uri
039     *
040     * @return <tt>null</tt> if not possible to parse, or an array[3] with scheme,path,query
041     */
042    public static String[] parseUri(String uri) {
043        int schemeStart = 0;
044        int schemeEnd = 0;
045        int pathStart = 0;
046        int pathEnd = 0;
047        int queryStart = 0;
048
049        int len = uri.length();
050        for (int i = 0; i < len; i++) {
051            char ch = uri.charAt(i);
052            if (ch > 128) {
053                // must be an ascii char
054                return null;
055            }
056            // must be a safe char
057            if (!UnsafeUriCharactersEncoder.isSafeFastParser(ch)) {
058                return null;
059            }
060            if (schemeEnd == 0) {
061                if (ch == ':') {
062                    schemeEnd = i;
063                    // skip colon
064                    pathStart = i + 1;
065                }
066            } else if (pathEnd == 0) {
067                if (ch == '?') {
068                    pathEnd = i;
069                    // skip ? marker
070                    queryStart = i + 1;
071                }
072            }
073        }
074
075        if (pathStart == 0 && schemeEnd != 0) {
076            // skip colon
077            pathStart = schemeEnd + 1;
078        }
079        // invalid if there is no path anyway
080        if (pathStart >= len) {
081            return null;
082        }
083
084        String scheme = null;
085        if (schemeEnd != 0) {
086            scheme = uri.substring(schemeStart, schemeEnd);
087        }
088        if (scheme == null) {
089            return null;
090        }
091
092        String path;
093        // skip two leading slashes
094        int next = pathStart + 1;
095        if (uri.charAt(pathStart) == '/' && next < len && uri.charAt(next) == '/') {
096            pathStart = pathStart + 2;
097        }
098        if (pathEnd != 0) {
099            path = uri.substring(pathStart, pathEnd);
100        } else {
101            path = uri.substring(pathStart);
102        }
103
104        String query = null;
105        if (queryStart != 0 && queryStart < len) {
106            query = uri.substring(queryStart);
107        }
108
109        return new String[]{scheme, path, query};
110    }
111}