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.commons.vfs2.provider.url; 018 019import org.apache.commons.vfs2.FileName; 020import org.apache.commons.vfs2.FileSystemException; 021import org.apache.commons.vfs2.provider.AbstractFileNameParser; 022import org.apache.commons.vfs2.provider.URLFileName; 023import org.apache.commons.vfs2.provider.URLFileNameParser; 024import org.apache.commons.vfs2.provider.VfsComponentContext; 025import org.apache.commons.vfs2.provider.local.GenericFileNameParser; 026 027/** 028 * Implementation for any java.net.url based filesystem. 029 * <p> 030 * Composite of URLFilenameParser and GenericFilenameParser 031 */ 032public class UrlFileNameParser extends AbstractFileNameParser { 033 private final URLFileNameParser url = new URLFileNameParser(80); 034 private final GenericFileNameParser generic = new GenericFileNameParser(); 035 036 public UrlFileNameParser() { 037 super(); 038 } 039 040 @Override 041 public boolean encodeCharacter(final char ch) { 042 return super.encodeCharacter(ch) || ch == '?'; 043 } 044 045 /** 046 * Parse a URI. 047 * 048 * @param context The component context. 049 * @param base The base FileName. 050 * @param uri The target file name. 051 * @return The FileName. 052 * @throws FileSystemException if an error occurs 053 */ 054 @Override 055 public FileName parseUri(final VfsComponentContext context, final FileName base, final String uri) 056 throws FileSystemException { 057 if (isUrlBased(base, uri)) { 058 return url.parseUri(context, base, uri); 059 } 060 061 return generic.parseUri(context, base, uri); 062 } 063 064 /** 065 * Guess if the given file name is an URL with host or not. 066 * <p> 067 * VFS treats such URLs differently. 068 * <p> 069 * A file name is URL-based if the base is a {@code URLFileName} or there are only 2 slashes after the scheme. e.g: 070 * {@code http://host/path}, {@code file:/path/to/file}, {@code file:///path/to/file}. 071 * 072 * @param base The filename is relative to this base. 073 * @param filename The filename. 074 * @return true if filename contains two slashes or base was URLFileName. 075 */ 076 protected boolean isUrlBased(final FileName base, final String filename) { 077 if (base instanceof URLFileName) { 078 return true; 079 } 080 081 return countSlashes(filename) == 2; 082 } 083 084 /** 085 * This method counts the slashes after the scheme. 086 * 087 * @param filename The file name. 088 * @return number of slashes 089 */ 090 protected int countSlashes(final String filename) { 091 int state = 0; 092 int nuofSlash = 0; 093 for (int pos = 0; pos < filename.length(); pos++) { 094 final char c = filename.charAt(pos); 095 if (state == 0) { 096 if (c >= 'a' && c <= 'z') { 097 continue; 098 } 099 if (c == ':') { 100 state++; 101 continue; 102 } 103 } else if (state == 1) { 104 if (c == '/') { 105 nuofSlash++; 106 } else { 107 return nuofSlash; 108 } 109 } 110 } 111 return nuofSlash; 112 } 113}