You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2018/11/02 01:53:30 UTC

svn commit: r1845527 [1/2] - in /commons/proper/vfs/trunk: ./ commons-vfs2-examples/ commons-vfs2-examples/src/main/java/org/apache/commons/vfs2/example/ commons-vfs2-sandbox/ commons-vfs2/ commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/ c...

Author: ggregory
Date: Fri Nov  2 01:53:29 2018
New Revision: 1845527

URL: http://svn.apache.org/viewvc?rev=1845527&view=rev
Log:
[VFS-360] Migrate to HttpComponent HttpClient. This patch from Woonsan Ko (woonsan on GitHub) adds a new provider "http4" using Apache HttpComponents HttpClient 4. PR https://github.com/apache/commons-vfs/pull/38. Closes #38.

Added:
    commons/proper/vfs/trunk/commons-vfs2-examples/README.md
    commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/GenericURLFileName.java
    commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/GenericURLFileNameParser.java
    commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/
    commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileContentInfoFactory.java
    commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileNameParser.java
    commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileObject.java
    commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileProvider.java
    commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileSystem.java
    commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileSystemConfigBuilder.java
    commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4RandomAccessContent.java
    commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/MonitoredHttpResponseContentInputStream.java
    commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/package.html
    commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4s/
    commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4s/Http4sFileNameParser.java
    commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4s/Http4sFileProvider.java
    commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4s/package.html
    commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/util/URIBitSets.java
    commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/util/URIUtils.java
    commons/proper/vfs/trunk/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/http4/
    commons/proper/vfs/trunk/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/http4/test/
    commons/proper/vfs/trunk/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/http4/test/Http4FilesCacheTestCase.java
    commons/proper/vfs/trunk/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/http4/test/Http4GetContentInfoTest.java
    commons/proper/vfs/trunk/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/http4/test/Http4ProviderTestCase.java
    commons/proper/vfs/trunk/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/http4s/
    commons/proper/vfs/trunk/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/http4s/test/
    commons/proper/vfs/trunk/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/http4s/test/Http4sGetContentInfoTest.java
Modified:
    commons/proper/vfs/trunk/commons-vfs2-examples/pom.xml
    commons/proper/vfs/trunk/commons-vfs2-examples/src/main/java/org/apache/commons/vfs2/example/Shell.java
    commons/proper/vfs/trunk/commons-vfs2-sandbox/pom.xml
    commons/proper/vfs/trunk/commons-vfs2/pom.xml
    commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/URLFileName.java
    commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/URLFileNameParser.java
    commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/url/UrlFileProvider.java
    commons/proper/vfs/trunk/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/DefaultFileContentTest.java
    commons/proper/vfs/trunk/pom.xml

Added: commons/proper/vfs/trunk/commons-vfs2-examples/README.md
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/commons-vfs2-examples/README.md?rev=1845527&view=auto
==============================================================================
--- commons/proper/vfs/trunk/commons-vfs2-examples/README.md (added)
+++ commons/proper/vfs/trunk/commons-vfs2-examples/README.md Fri Nov  2 01:53:29 2018
@@ -0,0 +1,35 @@
+<!---
+ 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.
+-->
+
+# Test Provider(s) with the Shell
+
+## Build modules in the parent folder
+
+    mvn clean install
+
+## Test `http` and `https` providers
+
+    mvn -Pshell -Dhttp
+
+## Test `http4` and `http4s` providers
+
+    mvn -Pshell -Dhttp4
+
+## Test `http`, `https`, `http4` and `http4s` providers together
+
+    mvn -Pshell -Dhttp -Dhttp4
+

Modified: commons/proper/vfs/trunk/commons-vfs2-examples/pom.xml
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/commons-vfs2-examples/pom.xml?rev=1845527&r1=1845526&r2=1845527&view=diff
==============================================================================
--- commons/proper/vfs/trunk/commons-vfs2-examples/pom.xml (original)
+++ commons/proper/vfs/trunk/commons-vfs2-examples/pom.xml Fri Nov  2 01:53:29 2018
@@ -51,11 +51,6 @@
       <optional>true</optional>
     </dependency>
     <dependency>
-      <groupId>commons-httpclient</groupId>
-      <artifactId>commons-httpclient</artifactId>
-      <optional>true</optional>
-    </dependency>
-    <dependency>
       <groupId>com.jcraft</groupId>
       <artifactId>jsch</artifactId>
       <optional>true</optional>
@@ -79,4 +74,67 @@
     </resources>
   </build>
 
+  <profiles>
+
+    <profile>
+      <id>shell</id>
+      <build>
+        <defaultGoal>validate</defaultGoal>
+        <plugins>
+          <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>exec-maven-plugin</artifactId>
+            <version>1.6.0</version>
+            <executions>
+              <execution>
+                <phase>validate</phase>
+                <goals>
+                  <goal>java</goal>
+                </goals>
+              </execution>
+            </executions>
+            <configuration>
+              <mainClass>org.apache.commons.vfs2.example.Shell</mainClass>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+
+    <profile>
+      <id>with-http</id>
+      <activation>
+        <activeByDefault>true</activeByDefault>
+        <property>
+          <name>http</name>
+        </property>
+      </activation>
+      <dependencies>
+        <dependency>
+          <groupId>commons-httpclient</groupId>
+          <artifactId>commons-httpclient</artifactId>
+          <scope>runtime</scope>
+        </dependency>
+      </dependencies>
+    </profile>
+
+    <profile>
+      <id>with-http4</id>
+      <activation>
+        <activeByDefault>true</activeByDefault>
+        <property>
+          <name>http4</name>
+        </property>
+      </activation>
+      <dependencies>
+        <dependency>
+          <groupId>org.apache.httpcomponents</groupId>
+          <artifactId>httpclient</artifactId>
+          <scope>runtime</scope>
+        </dependency>
+      </dependencies>
+    </profile>
+
+  </profiles>
+
 </project>

Modified: commons/proper/vfs/trunk/commons-vfs2-examples/src/main/java/org/apache/commons/vfs2/example/Shell.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/commons-vfs2-examples/src/main/java/org/apache/commons/vfs2/example/Shell.java?rev=1845527&r1=1845526&r2=1845527&view=diff
==============================================================================
--- commons/proper/vfs/trunk/commons-vfs2-examples/src/main/java/org/apache/commons/vfs2/example/Shell.java (original)
+++ commons/proper/vfs/trunk/commons-vfs2-examples/src/main/java/org/apache/commons/vfs2/example/Shell.java Fri Nov  2 01:53:29 2018
@@ -38,7 +38,9 @@ import org.apache.commons.vfs2.FileType;
 import org.apache.commons.vfs2.FileUtil;
 import org.apache.commons.vfs2.Selectors;
 import org.apache.commons.vfs2.VFS;
+import org.apache.commons.vfs2.impl.DefaultFileSystemManager;
 import org.apache.commons.vfs2.operations.FileOperationProvider;
+import org.apache.commons.vfs2.provider.FileProvider;
 
 /**
  * A simple command-line shell for performing file operations.
@@ -46,12 +48,30 @@ import org.apache.commons.vfs2.operation
  * See <a href="https://wiki.apache.org/commons/VfsExampleShell">Commons VFS Shell Examples</a> in Apache Commons Wiki.
  */
 public final class Shell {
+
     private final FileSystemManager mgr;
     private FileObject cwd;
     private final BufferedReader reader;
 
     private Shell() throws IOException {
         mgr = VFS.getManager();
+
+        // TODO: VFS-360 - Remove this manual registration of http4 once http4 becomes part of standard providers.
+        boolean httpClient4Available = false;
+        try {
+            Class.forName("org.apache.http.client.HttpClient");
+            httpClient4Available = true;
+            final DefaultFileSystemManager manager = (DefaultFileSystemManager) VFS.getManager();
+            if (!manager.hasProvider("http4")) {
+                manager.addProvider("http4", (FileProvider) Class.forName("org.apache.commons.vfs2.provider.http4.Http4FileProvider").newInstance());
+                manager.addProvider("http4s", (FileProvider) Class.forName("org.apache.commons.vfs2.provider.http4s.Http4sFileProvider").newInstance());
+            }
+        } catch (Exception e) {
+            if (httpClient4Available) {
+                e.printStackTrace();
+            }
+        }
+
         cwd = mgr.toFileObject(new File(System.getProperty("user.dir")));
         reader = new BufferedReader(new InputStreamReader(System.in, Charset.defaultCharset()));
     }

Modified: commons/proper/vfs/trunk/commons-vfs2-sandbox/pom.xml
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/commons-vfs2-sandbox/pom.xml?rev=1845527&r1=1845526&r2=1845527&view=diff
==============================================================================
--- commons/proper/vfs/trunk/commons-vfs2-sandbox/pom.xml (original)
+++ commons/proper/vfs/trunk/commons-vfs2-sandbox/pom.xml Fri Nov  2 01:53:29 2018
@@ -55,6 +55,11 @@
       <optional>true</optional>
     </dependency>
     <dependency>
+      <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpclient</artifactId>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
       <groupId>javax.mail</groupId>
       <artifactId>mail</artifactId>
       <optional>true</optional>

Modified: commons/proper/vfs/trunk/commons-vfs2/pom.xml
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/commons-vfs2/pom.xml?rev=1845527&r1=1845526&r2=1845527&view=diff
==============================================================================
--- commons/proper/vfs/trunk/commons-vfs2/pom.xml (original)
+++ commons/proper/vfs/trunk/commons-vfs2/pom.xml Fri Nov  2 01:53:29 2018
@@ -75,6 +75,11 @@
       <optional>true</optional>
     </dependency>
     <dependency>
+      <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpclient</artifactId>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
       <groupId>org.apache.jackrabbit</groupId>
       <artifactId>jackrabbit-webdav</artifactId>
       <optional>true</optional>

Added: commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/GenericURLFileName.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/GenericURLFileName.java?rev=1845527&view=auto
==============================================================================
--- commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/GenericURLFileName.java (added)
+++ commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/GenericURLFileName.java Fri Nov  2 01:53:29 2018
@@ -0,0 +1,139 @@
+/*
+ * 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.commons.vfs2.provider;
+
+import java.net.URISyntaxException;
+
+import org.apache.commons.vfs2.FileName;
+import org.apache.commons.vfs2.FileSystemException;
+import org.apache.commons.vfs2.FileType;
+import org.apache.commons.vfs2.util.URIUtils;
+
+/**
+ * Generic file name that represents a URL.
+ */
+public class GenericURLFileName extends GenericFileName {
+
+    private static final int BUFFER_SIZE = 250;
+
+    private final String queryString;
+
+    public GenericURLFileName(final String scheme, final String hostName, final int port, final int defaultPort,
+            final String userName, final String password, final String path, final FileType type,
+            final String queryString) {
+        super(scheme, hostName, port, defaultPort, userName, password, path, type);
+        this.queryString = queryString;
+    }
+
+    /**
+     * Get the query string.
+     *
+     * @return the query string part of the filename
+     */
+    public String getQueryString() {
+        return queryString;
+    }
+
+    /**
+     * Get the path and query string e.g. /path/servlet?param1=true.
+     *
+     * @return the path and its query string
+     */
+    public String getPathQuery() {
+        final StringBuilder sb = new StringBuilder(BUFFER_SIZE);
+        sb.append(getPath());
+        sb.append("?");
+        sb.append(getQueryString());
+
+        return sb.toString();
+    }
+
+    /**
+     * Get the path encoded suitable for url like filesystem e.g. (http, webdav).
+     *
+     * @param charset the charset used for the path encoding
+     * @return The encoded path.
+     * @throws URISyntaxException If an error occurs encoding the URI.
+     * @throws FileSystemException If some other error occurs.
+     */
+    public String getPathQueryEncoded(final String charset) throws URISyntaxException, FileSystemException {
+        if (getQueryString() == null) {
+            if (charset != null) {
+                return URIUtils.encodePath(getPathDecoded(), charset);
+            } else {
+                return URIUtils.encodePath(getPathDecoded());
+            }
+        }
+
+        final StringBuilder sb = new StringBuilder(BUFFER_SIZE);
+        if (charset != null) {
+            sb.append(URIUtils.encodePath(getPathDecoded(), charset));
+        } else {
+            sb.append(URIUtils.encodePath(getPathDecoded()));
+        }
+        sb.append("?");
+        sb.append(getQueryString());
+        return sb.toString();
+    }
+
+    /**
+     * Create a FileName.
+     *
+     * @param absPath The absolute path.
+     * @param type The FileType.
+     * @return The FileName
+     */
+    @Override
+    public FileName createName(final String absPath, final FileType type) {
+        return new GenericURLFileName(getScheme(), getHostName(), getPort(), getDefaultPort(), getUserName(), getPassword(),
+                absPath, type, getQueryString());
+    }
+
+    /**
+     * Append query string to the uri.
+     *
+     * @return the uri
+     */
+    @Override
+    protected String createURI() {
+        if (getQueryString() != null) {
+            final StringBuilder sb = new StringBuilder(BUFFER_SIZE);
+            sb.append(super.createURI());
+            sb.append("?");
+            sb.append(getQueryString());
+
+            return sb.toString();
+        }
+
+        return super.createURI();
+    }
+
+    /**
+     * Encode a URI.
+     *
+     * @param charset The character set.
+     * @return The encoded URI
+     * @throws FileSystemException if some other exception occurs.
+     * @throws URISyntaxException if an exception occurs encoding the URI.
+     */
+    public String getURIEncoded(final String charset) throws FileSystemException, URISyntaxException {
+        final StringBuilder sb = new StringBuilder(BUFFER_SIZE);
+        appendRootUri(sb, true);
+        sb.append(getPathQueryEncoded(charset));
+        return sb.toString();
+    }
+}

Added: commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/GenericURLFileNameParser.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/GenericURLFileNameParser.java?rev=1845527&view=auto
==============================================================================
--- commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/GenericURLFileNameParser.java (added)
+++ commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/GenericURLFileNameParser.java Fri Nov  2 01:53:29 2018
@@ -0,0 +1,60 @@
+/*
+ * 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.commons.vfs2.provider;
+
+import org.apache.commons.vfs2.FileName;
+import org.apache.commons.vfs2.FileSystemException;
+import org.apache.commons.vfs2.FileType;
+
+/**
+ * Generic implementation for any url based filesystem, without depending a specific library.
+ * <p>
+ * Parses the url into user/password/host/port/path/queryString.
+ */
+public class GenericURLFileNameParser extends HostFileNameParser {
+
+    public GenericURLFileNameParser(final int defaultPort) {
+        super(defaultPort);
+    }
+
+    @Override
+    public boolean encodeCharacter(final char ch) {
+        return super.encodeCharacter(ch) || ch == '?';
+    }
+
+    @Override
+    public FileName parseUri(final VfsComponentContext context, final FileName base, final String filename)
+            throws FileSystemException {
+        // FTP URI are generic URI (as per RFC 2396)
+        final StringBuilder name = new StringBuilder();
+
+        // Extract the scheme and authority parts
+        final Authority auth = extractToPath(filename, name);
+
+        // Extract the queryString
+        final String queryString = UriParser.extractQueryString(name);
+
+        // Decode and normalise the file name
+        UriParser.canonicalizePath(name, 0, name.length(), this);
+        UriParser.fixSeparators(name);
+        final FileType fileType = UriParser.normalisePath(name);
+        final String path = name.toString();
+
+        return new GenericURLFileName(auth.getScheme(), auth.getHostName(), auth.getPort(), getDefaultPort(),
+                auth.getUserName(), auth.getPassword(), path, fileType, queryString);
+    }
+}

Modified: commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/URLFileName.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/URLFileName.java?rev=1845527&r1=1845526&r2=1845527&view=diff
==============================================================================
--- commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/URLFileName.java (original)
+++ commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/URLFileName.java Fri Nov  2 01:53:29 2018
@@ -24,7 +24,9 @@ import org.apache.commons.vfs2.FileType;
 
 /**
  * A file name that represents URL.
+ * @deprecated Use {@link GenericURLFileName} as it doesn't depend on Http Client v3 API directly.
  */
+@Deprecated
 public class URLFileName extends GenericFileName {
     private static final int BUFFER_SIZE = 250;
 

Modified: commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/URLFileNameParser.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/URLFileNameParser.java?rev=1845527&r1=1845526&r2=1845527&view=diff
==============================================================================
--- commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/URLFileNameParser.java (original)
+++ commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/URLFileNameParser.java Fri Nov  2 01:53:29 2018
@@ -24,7 +24,9 @@ import org.apache.commons.vfs2.FileType;
  * Implementation for any url based filesystem.
  * <p>
  * Parses the url into user/password/host/port/path/queryString.
+ * @deprecated Use {@link GenericURLFileNameParser} as it doesn't depend on Http Client v3 API directly.
  */
+@Deprecated
 public class URLFileNameParser extends HostFileNameParser {
     public URLFileNameParser(final int defaultPort) {
         super(defaultPort);

Added: commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileContentInfoFactory.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileContentInfoFactory.java?rev=1845527&view=auto
==============================================================================
--- commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileContentInfoFactory.java (added)
+++ commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileContentInfoFactory.java Fri Nov  2 01:53:29 2018
@@ -0,0 +1,63 @@
+/*
+ * 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.commons.vfs2.provider.http4;
+
+import java.io.IOException;
+
+import org.apache.commons.vfs2.FileContent;
+import org.apache.commons.vfs2.FileContentInfo;
+import org.apache.commons.vfs2.FileContentInfoFactory;
+import org.apache.commons.vfs2.FileSystemException;
+import org.apache.commons.vfs2.impl.DefaultFileContentInfo;
+import org.apache.commons.vfs2.util.FileObjectUtils;
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.entity.ContentType;
+import org.apache.http.protocol.HTTP;
+
+/**
+ * Creates <code>FileContentInfoFactory</code> instances for http4 provider.
+ */
+public class Http4FileContentInfoFactory implements FileContentInfoFactory {
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public FileContentInfo create(final FileContent fileContent) throws FileSystemException {
+        String contentMimeType = null;
+        String contentCharset = null;
+
+        try (final Http4FileObject<Http4FileSystem> http4File = (Http4FileObject<Http4FileSystem>) FileObjectUtils
+                .getAbstractFileObject(fileContent.getFile())) {
+            final HttpResponse lastHeadResponse = http4File.getLastHeadResponse();
+
+            final Header header = lastHeadResponse.getFirstHeader(HTTP.CONTENT_TYPE);
+
+            if (header != null) {
+                final ContentType contentType = ContentType.parse(header.getValue());
+                contentMimeType = contentType.getMimeType();
+
+                if (contentType.getCharset() != null) {
+                    contentCharset = contentType.getCharset().name();
+                }
+            }
+
+            return new DefaultFileContentInfo(contentMimeType, contentCharset);
+        } catch (final IOException e) {
+            throw new FileSystemException(e);
+        }
+    }
+}

Added: commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileNameParser.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileNameParser.java?rev=1845527&view=auto
==============================================================================
--- commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileNameParser.java (added)
+++ commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileNameParser.java Fri Nov  2 01:53:29 2018
@@ -0,0 +1,38 @@
+/*
+ * 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.commons.vfs2.provider.http4;
+
+import org.apache.commons.vfs2.provider.FileNameParser;
+import org.apache.commons.vfs2.provider.GenericURLFileNameParser;
+
+/**
+ * <code>FileNameParser</code> implementation for http4 provider, setting default port to 80.
+ */
+public class Http4FileNameParser extends GenericURLFileNameParser {
+
+    private static final int DEFAULT_PORT = 80;
+
+    private static final Http4FileNameParser INSTANCE = new Http4FileNameParser();
+
+    public Http4FileNameParser() {
+        super(DEFAULT_PORT);
+    }
+
+    public static FileNameParser getInstance() {
+        return INSTANCE;
+    }
+}

Added: commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileObject.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileObject.java?rev=1845527&view=auto
==============================================================================
--- commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileObject.java (added)
+++ commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileObject.java Fri Nov  2 01:53:29 2018
@@ -0,0 +1,229 @@
+/*
+ * 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.commons.vfs2.provider.http4;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.apache.commons.vfs2.FileContentInfoFactory;
+import org.apache.commons.vfs2.FileNotFoundException;
+import org.apache.commons.vfs2.FileSystemException;
+import org.apache.commons.vfs2.FileSystemOptions;
+import org.apache.commons.vfs2.FileType;
+import org.apache.commons.vfs2.RandomAccessContent;
+import org.apache.commons.vfs2.provider.AbstractFileName;
+import org.apache.commons.vfs2.provider.AbstractFileObject;
+import org.apache.commons.vfs2.provider.GenericURLFileName;
+import org.apache.commons.vfs2.util.RandomAccessMode;
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpHead;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.client.utils.DateUtils;
+import org.apache.http.client.utils.URIUtils;
+import org.apache.http.protocol.HTTP;
+
+/**
+ * A file object backed by Apache HttpComponents HttpClient.
+ *
+ * @param <FS> An {@link Http4FileSystem} subclass
+ */
+public class Http4FileObject<FS extends Http4FileSystem> extends AbstractFileObject<FS> {
+
+    /**
+     * URL charset string.
+     */
+    private final String urlCharset;
+
+    /**
+     * Internal URI mapped to this <code>FileObject</code>.
+     * For example, the internal URI of <code>http4://example.com/a.txt</code> is <code>http://example.com/a.txt</code>.
+     */
+    private final URI internalURI;
+
+    /**
+     * The last executed HEAD <code>HttpResponse</code> object.
+     */
+    private HttpResponse lastHeadResponse;
+
+    /**
+     * Construct <code>Http4FileObject</code>.
+     * @param name file name
+     * @param fileSystem file system
+     * @throws FileSystemException if any error occurs
+     * @throws URISyntaxException if given file name cannot be converted to a URI due to URI syntax error
+     */
+    protected Http4FileObject(final AbstractFileName name, final FS fileSystem)
+            throws FileSystemException, URISyntaxException {
+        this(name, fileSystem, Http4FileSystemConfigBuilder.getInstance());
+    }
+
+    /**
+     * Construct <code>Http4FileObject</code>.
+     * @param name file name
+     * @param fileSystem file system
+     * @param builder <code>Http4FileSystemConfigBuilder</code> object
+     * @throws FileSystemException if any error occurs
+     * @throws URISyntaxException if given file name cannot be converted to a URI due to URI syntax error
+     */
+    protected Http4FileObject(final AbstractFileName name, final FS fileSystem,
+            final Http4FileSystemConfigBuilder builder) throws FileSystemException, URISyntaxException {
+        super(name, fileSystem);
+        final FileSystemOptions fileSystemOptions = fileSystem.getFileSystemOptions();
+        urlCharset = builder.getUrlCharset(fileSystemOptions);
+        final String pathEncoded = ((GenericURLFileName) name).getPathQueryEncoded(getUrlCharset());
+        internalURI = URIUtils.resolve(fileSystem.getInternalBaseURI(), pathEncoded);
+    }
+
+    @Override
+    protected FileType doGetType() throws Exception {
+        lastHeadResponse = executeHttpUriRequest(new HttpHead(getInternalURI()));
+        final int status = lastHeadResponse.getStatusLine().getStatusCode();
+
+        if (status == HttpStatus.SC_OK
+                || status == HttpStatus.SC_METHOD_NOT_ALLOWED /* method is not allowed, but resource exist */) {
+            return FileType.FILE;
+        } else if (status == HttpStatus.SC_NOT_FOUND || status == HttpStatus.SC_GONE) {
+            return FileType.IMAGINARY;
+        } else {
+            throw new FileSystemException("vfs.provider.http/head.error", getName(), Integer.valueOf(status));
+        }
+    }
+
+    @Override
+    protected long doGetContentSize() throws Exception {
+        if (lastHeadResponse == null) {
+            return 0L;
+        }
+
+        final Header header = lastHeadResponse.getFirstHeader(HTTP.CONTENT_LEN);
+
+        if (header == null) {
+            // Assume 0 content-length
+            return 0;
+        }
+
+        return Long.parseLong(header.getValue());
+    }
+
+    @Override
+    protected long doGetLastModifiedTime() throws Exception {
+        if (lastHeadResponse == null) {
+            throw new FileSystemException("vfs.provider.http/last-modified.error", getName());
+        }
+
+        final Header header = lastHeadResponse.getFirstHeader("Last-Modified");
+
+        if (header == null) {
+            throw new FileSystemException("vfs.provider.http/last-modified.error", getName());
+        }
+
+        return DateUtils.parseDate(header.getValue()).getTime();
+    }
+
+
+    @Override
+    protected InputStream doGetInputStream() throws Exception {
+        final HttpGet getRequest = new HttpGet(getInternalURI());
+        final HttpResponse httpResponse = executeHttpUriRequest(getRequest);
+        final int status = httpResponse.getStatusLine().getStatusCode();
+
+        if (status == HttpStatus.SC_NOT_FOUND) {
+            throw new FileNotFoundException(getName());
+        }
+
+        if (status != HttpStatus.SC_OK) {
+            throw new FileSystemException("vfs.provider.http/get.error", getName(), Integer.valueOf(status));
+        }
+
+        return new MonitoredHttpResponseContentInputStream(httpResponse);
+    }
+
+    @Override
+    protected RandomAccessContent doGetRandomAccessContent(final RandomAccessMode mode) throws Exception {
+        return new Http4RandomAccessContent<>(this, mode);
+    }
+
+    @Override
+    protected String[] doListChildren() throws Exception {
+        throw new UnsupportedOperationException("Not implemented.");
+    }
+
+    @Override
+    protected boolean doIsWriteable() throws Exception {
+        return false;
+    }
+
+    @Override
+    protected FileContentInfoFactory getFileContentInfoFactory() {
+        return new Http4FileContentInfoFactory();
+    }
+
+    @Override
+    protected void doDetach() throws Exception {
+        lastHeadResponse = null;
+    }
+
+    /**
+     * Return URL charset string.
+     * @return URL charset string
+     */
+    protected String getUrlCharset() {
+        return urlCharset;
+    }
+
+    /**
+     * Return the internal <code>URI</code> object mapped to this file object.
+     * @return the internal <code>URI</code> object mapped to this file object
+     * @throws FileSystemException if any error occurs
+     */
+    protected URI getInternalURI() throws FileSystemException {
+        return internalURI;
+    }
+
+    /**
+     * Return the last executed HEAD <code>HttpResponse</code> object.
+     * @return the last executed HEAD <code>HttpResponse</code> object
+     * @throws IOException if IO error occurs
+     */
+    HttpResponse getLastHeadResponse() throws IOException {
+        if (lastHeadResponse != null) {
+            return lastHeadResponse;
+        }
+
+        return executeHttpUriRequest(new HttpHead(getInternalURI()));
+    }
+
+    /**
+     * Execute the request using the given {@code httpRequest} and return a <code>HttpResponse</code> from the execution.
+     * @param httpRequest <code>HttpUriRequest</code> object
+     * @return <code>HttpResponse</code> from the execution
+     * @throws IOException if IO error occurs
+     */
+    HttpResponse executeHttpUriRequest(final HttpUriRequest httpRequest) throws IOException {
+        final HttpClient httpClient = getAbstractFileSystem().getHttpClient();
+        final HttpClientContext httpClientContext = getAbstractFileSystem().getHttpClientContext();
+        return httpClient.execute(httpRequest, httpClientContext);
+    }
+
+}

Added: commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileProvider.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileProvider.java?rev=1845527&view=auto
==============================================================================
--- commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileProvider.java (added)
+++ commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileProvider.java Fri Nov  2 01:53:29 2018
@@ -0,0 +1,363 @@
+/*
+ * 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.commons.vfs2.provider.http4;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.ProxySelector;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLContext;
+
+import org.apache.commons.vfs2.Capability;
+import org.apache.commons.vfs2.FileName;
+import org.apache.commons.vfs2.FileSystem;
+import org.apache.commons.vfs2.FileSystemConfigBuilder;
+import org.apache.commons.vfs2.FileSystemException;
+import org.apache.commons.vfs2.FileSystemOptions;
+import org.apache.commons.vfs2.UserAuthenticationData;
+import org.apache.commons.vfs2.UserAuthenticator;
+import org.apache.commons.vfs2.provider.AbstractOriginatingFileProvider;
+import org.apache.commons.vfs2.provider.GenericFileName;
+import org.apache.commons.vfs2.util.UserAuthenticatorUtils;
+import org.apache.http.ConnectionReuseStrategy;
+import org.apache.http.Header;
+import org.apache.http.HttpHost;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.AuthCache;
+import org.apache.http.client.CookieStore;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.config.SocketConfig;
+import org.apache.http.conn.HttpClientConnectionManager;
+import org.apache.http.conn.routing.HttpRoutePlanner;
+import org.apache.http.conn.ssl.DefaultHostnameVerifier;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.conn.ssl.TrustAllStrategy;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.impl.DefaultConnectionReuseStrategy;
+import org.apache.http.impl.NoConnectionReuseStrategy;
+import org.apache.http.impl.auth.BasicScheme;
+import org.apache.http.impl.client.BasicAuthCache;
+import org.apache.http.impl.client.BasicCookieStore;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.impl.conn.SystemDefaultRoutePlanner;
+import org.apache.http.message.BasicHeader;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.ssl.SSLContextBuilder;
+
+/**
+ * <code>FileProvider</code> implementation using HttpComponents HttpClient library.
+ */
+public class Http4FileProvider extends AbstractOriginatingFileProvider {
+
+    /** Authenticator information. */
+    static final UserAuthenticationData.Type[] AUTHENTICATOR_TYPES =
+            new UserAuthenticationData.Type[] {
+                    UserAuthenticationData.USERNAME,
+                    UserAuthenticationData.PASSWORD
+                    };
+
+    /** FileProvider capabilities */
+    static final Collection<Capability> capabilities =
+            Collections.unmodifiableCollection(
+                    Arrays.asList(
+                            Capability.GET_TYPE,
+                            Capability.READ_CONTENT,
+                            Capability.URI,
+                            Capability.GET_LAST_MODIFIED,
+                            Capability.ATTRIBUTES,
+                            Capability.RANDOM_ACCESS_READ,
+                            Capability.DIRECTORY_READ_CONTENT
+                            )
+                    );
+
+    /**
+     * Constructs a new provider.
+     */
+    public Http4FileProvider() {
+        super();
+        setFileNameParser(Http4FileNameParser.getInstance());
+    }
+
+    @Override
+    public FileSystemConfigBuilder getConfigBuilder() {
+        return Http4FileSystemConfigBuilder.getInstance();
+    }
+
+    @Override
+    public Collection<Capability> getCapabilities() {
+        return capabilities;
+    }
+
+    @Override
+    protected FileSystem doCreateFileSystem(FileName name, FileSystemOptions fileSystemOptions)
+            throws FileSystemException {
+        final GenericFileName rootName = (GenericFileName) name;
+
+        UserAuthenticationData authData = null;
+        HttpClient httpClient = null;
+        HttpClientContext httpClientContext = null;
+
+        try {
+            final Http4FileSystemConfigBuilder builder = Http4FileSystemConfigBuilder.getInstance();
+            authData = UserAuthenticatorUtils.authenticate(fileSystemOptions, AUTHENTICATOR_TYPES);
+            httpClientContext = createHttpClientContext(builder, rootName, fileSystemOptions, authData);
+            httpClient = createHttpClient(builder, rootName, fileSystemOptions);
+        } finally {
+            UserAuthenticatorUtils.cleanup(authData);
+        }
+
+        return new Http4FileSystem(rootName, fileSystemOptions, httpClient, httpClientContext);
+    }
+
+    /**
+     * Create an {@link HttpClient} object for an http4 file system.
+     * @param builder Configuration options builder for http4 provider
+     * @param rootName The root path
+     * @param fileSystemOptions The file system options
+     * @return an {@link HttpClient} object
+     * @throws FileSystemException if an error occurs.
+     */
+    protected HttpClient createHttpClient(final Http4FileSystemConfigBuilder builder, final GenericFileName rootName,
+            final FileSystemOptions fileSystemOptions) throws FileSystemException {
+        return createHttpClientBuilder(builder, rootName, fileSystemOptions).build();
+    }
+
+    /**
+     * Create an {@link HttpClientBuilder} object. Invoked by {@link #createHttpClient(Http4FileSystemConfigBuilder, GenericFileName, FileSystemOptions)}.
+     * @param builder Configuration options builder for HTTP4 provider
+     * @param rootName The root path
+     * @param fileSystemOptions The FileSystem options
+     * @return an {@link HttpClientBuilder} object
+     * @throws FileSystemException if an error occurs
+     */
+    protected HttpClientBuilder createHttpClientBuilder(final Http4FileSystemConfigBuilder builder, final GenericFileName rootName,
+            final FileSystemOptions fileSystemOptions) throws FileSystemException {
+        final List<Header> defaultHeaders = new ArrayList<>();
+        defaultHeaders.add(new BasicHeader(HTTP.USER_AGENT, builder.getUserAgent(fileSystemOptions)));
+
+        final ConnectionReuseStrategy connectionReuseStrategy = builder.isKeepAlive(fileSystemOptions)
+                ? DefaultConnectionReuseStrategy.INSTANCE
+                : NoConnectionReuseStrategy.INSTANCE;
+
+        final HttpClientBuilder httpClientBuilder =
+                HttpClients.custom()
+                .setRoutePlanner(createHttpRoutePlanner(builder, fileSystemOptions))
+                .setConnectionManager(createConnectionManager(builder, fileSystemOptions))
+                .setSSLContext(createSSLContext(builder, fileSystemOptions))
+                .setSSLHostnameVerifier(createHostnameVerifier(builder, fileSystemOptions))
+                .setConnectionReuseStrategy(connectionReuseStrategy)
+                .setDefaultRequestConfig(createDefaultRequestConfig(builder, fileSystemOptions))
+                .setDefaultHeaders(defaultHeaders)
+                .setDefaultCookieStore(createDefaultCookieStore(builder, fileSystemOptions));
+
+        if (!builder.getFollowRedirect(fileSystemOptions)) {
+            httpClientBuilder.disableRedirectHandling();
+        }
+
+        return httpClientBuilder;
+    }
+
+    /**
+     * Create {@link SSLContext} for HttpClient. Invoked by {@link #createHttpClientBuilder(Http4FileSystemConfigBuilder, GenericFileName, FileSystemOptions)}.
+     * @param builder Configuration options builder for HTTP4 provider
+     * @param fileSystemOptions The FileSystem options
+     * @return a {@link SSLContext} for HttpClient
+     * @throws FileSystemException if an error occurs
+     */
+    protected SSLContext createSSLContext(final Http4FileSystemConfigBuilder builder,
+            final FileSystemOptions fileSystemOptions) throws FileSystemException {
+        try {
+            final SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
+
+            File keystoreFileObject = null;
+            final String keystoreFile = builder.getKeyStoreFile(fileSystemOptions);
+
+            if (keystoreFile != null && !keystoreFile.isEmpty()) {
+                keystoreFileObject = new File(keystoreFile);
+            }
+
+            if (keystoreFileObject != null && keystoreFileObject.exists()) {
+                final String keystorePass = builder.getKeyStorePass(fileSystemOptions);
+                final char[] keystorePassChars = (keystorePass != null) ? keystorePass.toCharArray() : null;
+                sslContextBuilder.loadTrustMaterial(keystoreFileObject, keystorePassChars, TrustAllStrategy.INSTANCE);
+            } else {
+                sslContextBuilder.loadTrustMaterial(TrustAllStrategy.INSTANCE);
+            }
+
+            return sslContextBuilder.build();
+        } catch (KeyStoreException e) {
+            throw new FileSystemException("Keystore error. " + e.getMessage(), e);
+        } catch (KeyManagementException e) {
+            throw new FileSystemException("Cannot retrieve keys. " + e.getMessage(), e);
+        } catch (NoSuchAlgorithmException e) {
+            throw new FileSystemException("Algorithm error. " + e.getMessage(), e);
+        } catch (CertificateException e) {
+            throw new FileSystemException("Certificate error. " + e.getMessage(), e);
+        } catch (IOException e) {
+            throw new FileSystemException("Cannot open key file. " + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * Create an {@link HttpClientContext} object for an http4 file system.
+     * @param builder Configuration options builder for http4 provider
+     * @param rootName The root path
+     * @param fileSystemOptions The FileSystem options
+     * @param authData The <code>UserAuthentiationData</code> object
+     * @return an {@link HttpClientContext} object
+     * @throws FileSystemException if an error occurs
+     */
+    protected HttpClientContext createHttpClientContext(final Http4FileSystemConfigBuilder builder,
+            final GenericFileName rootName, final FileSystemOptions fileSystemOptions,
+            final UserAuthenticationData authData) throws FileSystemException {
+
+        final HttpClientContext clientContext = HttpClientContext.create();
+        final CredentialsProvider credsProvider = new BasicCredentialsProvider();
+        clientContext.setCredentialsProvider(credsProvider);
+
+        final String username = UserAuthenticatorUtils.toString(UserAuthenticatorUtils.getData(authData,
+                UserAuthenticationData.USERNAME, UserAuthenticatorUtils.toChar(rootName.getUserName())));
+        final String password = UserAuthenticatorUtils.toString(UserAuthenticatorUtils.getData(authData,
+                UserAuthenticationData.PASSWORD, UserAuthenticatorUtils.toChar(rootName.getPassword())));
+
+        if (username != null && !username.isEmpty()) {
+            credsProvider.setCredentials(new AuthScope(rootName.getHostName(), AuthScope.ANY_PORT),
+                    new UsernamePasswordCredentials(username, password));
+        }
+
+        final HttpHost proxyHost = getProxyHttpHost(builder, fileSystemOptions);
+
+        if (proxyHost != null) {
+            final UserAuthenticator proxyAuth = builder.getProxyAuthenticator(fileSystemOptions);
+
+            if (proxyAuth != null) {
+                final UserAuthenticationData proxyAuthData = UserAuthenticatorUtils.authenticate(proxyAuth,
+                        new UserAuthenticationData.Type[] { UserAuthenticationData.USERNAME,
+                                UserAuthenticationData.PASSWORD });
+
+                if (proxyAuthData != null) {
+                    final UsernamePasswordCredentials proxyCreds = new UsernamePasswordCredentials(
+                            UserAuthenticatorUtils.toString(
+                                    UserAuthenticatorUtils.getData(authData, UserAuthenticationData.USERNAME, null)),
+                            UserAuthenticatorUtils.toString(
+                                    UserAuthenticatorUtils.getData(authData, UserAuthenticationData.PASSWORD, null)));
+
+                    credsProvider.setCredentials(new AuthScope(proxyHost.getHostName(), AuthScope.ANY_PORT),
+                            proxyCreds);
+                }
+
+                if (builder.isPreemptiveAuth(fileSystemOptions)) {
+                    final AuthCache authCache = new BasicAuthCache();
+                    final BasicScheme basicAuth = new BasicScheme();
+                    authCache.put(proxyHost, basicAuth);
+                    clientContext.setAuthCache(authCache);
+                }
+            }
+        }
+
+        return clientContext;
+    }
+
+    private HttpClientConnectionManager createConnectionManager(final Http4FileSystemConfigBuilder builder,
+            final FileSystemOptions fileSystemOptions) throws FileSystemException {
+        final PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
+        connManager.setMaxTotal(builder.getMaxTotalConnections(fileSystemOptions));
+        connManager.setDefaultMaxPerRoute(builder.getMaxConnectionsPerHost(fileSystemOptions));
+
+        final SocketConfig socketConfig =
+                SocketConfig
+                .custom()
+                .setSoTimeout(builder.getSoTimeout(fileSystemOptions))
+                .build();
+
+        connManager.setDefaultSocketConfig(socketConfig);
+
+        return connManager;
+    }
+
+    private RequestConfig createDefaultRequestConfig(final Http4FileSystemConfigBuilder builder,
+            final FileSystemOptions fileSystemOptions) {
+        return RequestConfig.custom()
+                .setConnectTimeout(builder.getConnectionTimeout(fileSystemOptions))
+                .build();
+    }
+
+    private HttpRoutePlanner createHttpRoutePlanner(final Http4FileSystemConfigBuilder builder,
+            final FileSystemOptions fileSystemOptions) {
+        final HttpHost proxyHost = getProxyHttpHost(builder, fileSystemOptions);
+
+        if (proxyHost != null) {
+            return new DefaultProxyRoutePlanner(proxyHost);
+        }
+
+        return new SystemDefaultRoutePlanner(ProxySelector.getDefault());
+    }
+
+    private HttpHost getProxyHttpHost(final Http4FileSystemConfigBuilder builder,
+            final FileSystemOptions fileSystemOptions) {
+        final String proxyHost = builder.getProxyHost(fileSystemOptions);
+        final int proxyPort = builder.getProxyPort(fileSystemOptions);
+
+        if (proxyHost != null && proxyHost.length() > 0 && proxyPort > 0) {
+            return new HttpHost(proxyHost, proxyPort);
+        }
+
+        return null;
+    }
+
+    private CookieStore createDefaultCookieStore(final Http4FileSystemConfigBuilder builder,
+            final FileSystemOptions fileSystemOptions) {
+        final CookieStore cookieStore = new BasicCookieStore();
+        final Cookie[] cookies = builder.getCookies(fileSystemOptions);
+
+        if (cookies != null) {
+            for (Cookie cookie : cookies) {
+                cookieStore.addCookie(cookie);
+            }
+        }
+
+        return cookieStore;
+    }
+
+    private HostnameVerifier createHostnameVerifier(final Http4FileSystemConfigBuilder builder,
+            final FileSystemOptions fileSystemOptions) throws FileSystemException {
+        if (!builder.isHostnameVerificationEnabled(fileSystemOptions)) {
+            return NoopHostnameVerifier.INSTANCE;
+        }
+
+        return new DefaultHostnameVerifier();
+    }
+
+}

Added: commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileSystem.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileSystem.java?rev=1845527&view=auto
==============================================================================
--- commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileSystem.java (added)
+++ commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileSystem.java Fri Nov  2 01:53:29 2018
@@ -0,0 +1,123 @@
+/*
+ * 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.commons.vfs2.provider.http4;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.Collection;
+
+import org.apache.commons.vfs2.Capability;
+import org.apache.commons.vfs2.FileName;
+import org.apache.commons.vfs2.FileObject;
+import org.apache.commons.vfs2.FileSystemOptions;
+import org.apache.commons.vfs2.provider.AbstractFileName;
+import org.apache.commons.vfs2.provider.AbstractFileSystem;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.impl.client.CloseableHttpClient;
+
+/**
+ * http4 file system.
+ */
+public class Http4FileSystem extends AbstractFileSystem {
+
+    /**
+     * Internal base URI of this file system.
+     */
+    private final URI internalBaseURI;
+
+    /**
+     * Internal <code>HttpClient</code> instance of this file system.
+     */
+    private final HttpClient httpClient;
+
+    /**
+     * Internal <code>HttpClientContext</code> instance of this file system.
+     */
+    private final HttpClientContext httpClientContext;
+
+    /**
+     * Construct <code>Http4FileSystem</code>.
+     * @param rootName root base name
+     * @param fileSystemOptions file system options
+     * @param httpClient {@link HttpClient} instance
+     * @param httpClientContext {@link HttpClientContext} instance
+     */
+    protected Http4FileSystem(FileName rootName, FileSystemOptions fileSystemOptions, HttpClient httpClient,
+            HttpClientContext httpClientContext) {
+        super(rootName, null, fileSystemOptions);
+
+        final String rootURI = getRootURI();
+        final int offset = rootURI.indexOf(':');
+        final char lastCharOfScheme = (offset > 0) ? rootURI.charAt(offset - 1) : 0;
+
+        // if scheme is 'http*s' or 'HTTP*S', then the internal base URI should be 'https'. 'http' otherwise.
+        if (lastCharOfScheme == 's' || lastCharOfScheme == 'S') {
+            this.internalBaseURI = URI.create("https" + rootURI.substring(offset));
+        } else {
+            this.internalBaseURI = URI.create("http" + rootURI.substring(offset));
+        }
+
+        this.httpClient = httpClient;
+        this.httpClientContext = httpClientContext;
+    }
+
+    @Override
+    protected FileObject createFile(AbstractFileName name) throws Exception {
+        return new Http4FileObject<>(name, this);
+    }
+
+    @Override
+    protected void addCapabilities(Collection<Capability> caps) {
+        caps.addAll(Http4FileProvider.capabilities);
+    }
+
+    @Override
+    protected void doCloseCommunicationLink() {
+        if (httpClient instanceof CloseableHttpClient) {
+            try {
+                ((CloseableHttpClient) httpClient).close();
+            } catch (IOException e) {
+                throw new RuntimeException("Error closing HttpClient", e);
+            }
+        }
+    }
+
+    /**
+     * Return the internal {@link HttpClient} instance.
+     * @return the internal {@link HttpClient} instance
+     */
+    protected HttpClient getHttpClient() {
+        return httpClient;
+    }
+
+    /**
+     * Return the internal {@link HttpClientContext} instance.
+     * @return the internal {@link HttpClientContext} instance
+     */
+    protected HttpClientContext getHttpClientContext() {
+        return httpClientContext;
+    }
+
+    /**
+     * Return the internal base <code>URI</code> instance.
+     * @return the internal base <code>URI</code> instance
+     */
+    protected URI getInternalBaseURI() {
+        return internalBaseURI;
+    }
+}

Added: commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileSystemConfigBuilder.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileSystemConfigBuilder.java?rev=1845527&view=auto
==============================================================================
--- commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileSystemConfigBuilder.java (added)
+++ commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4FileSystemConfigBuilder.java Fri Nov  2 01:53:29 2018
@@ -0,0 +1,515 @@
+/*
+ * 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.commons.vfs2.provider.http4;
+
+import org.apache.commons.vfs2.FileSystem;
+import org.apache.commons.vfs2.FileSystemConfigBuilder;
+import org.apache.commons.vfs2.FileSystemOptions;
+import org.apache.commons.vfs2.UserAuthenticator;
+import org.apache.http.cookie.Cookie;
+
+/**
+ * Configuration options builder utility for http4 provider.
+ */
+public class Http4FileSystemConfigBuilder extends FileSystemConfigBuilder {
+
+    private static final Http4FileSystemConfigBuilder BUILDER = new Http4FileSystemConfigBuilder();
+
+    /** 
+     * Defines the maximum number of connections allowed overall. This value only applies
+     * to the number of connections from a particular instance of HTTP connection manager.
+     * <p>
+     * This parameter expects a value of type {@link Integer}.
+     * </p>
+     */
+    private static final String MAX_TOTAL_CONNECTIONS = "http.connection-manager.max-total";
+
+    /** 
+     * Defines the maximum number of connections allowed per host configuration. 
+     * These values only apply to the number of connections from a particular instance 
+     * of HTTP connection manager.
+     */
+    private static final String MAX_HOST_CONNECTIONS = "http.connection-manager.max-per-host";
+
+    /** 
+     * Defines the connection timeout of an HTTP request.
+     * <p>
+     * This parameter expects a value of type {@link Integer}.
+     * </p>
+     */
+    private static final String CONNECTION_TIMEOUT = "http.connection.timeout";
+
+    /** 
+     * Defines the socket timeout of an HTTP request.
+     * <p>
+     * This parameter expects a value of type {@link Integer}.
+     * </p>
+     */
+    private static final String SO_TIMEOUT = "http.socket.timeout";
+
+    /** 
+     * Defines whether Keep-Alive option is used or not.
+     * <p>
+     * This parameter expects a value of type {@link Boolean}.
+     * </p>
+     */
+    private static final String KEEP_ALIVE = "http.keepAlive";
+
+    /** 
+     * Defines the keystore file path for SSL connections.
+     * <p>
+     * This parameter expects a value of type {@link String}.
+     * </p>
+     */
+    private static final String KEYSTORE_FILE = "http.keystoreFile";
+
+    /** 
+     * Defines the keystore pass phrase for SSL connections.
+     * <p>
+     * This parameter expects a value of type {@link String}.
+     * </p>
+     */
+    private static final String KEYSTORE_PASS = "http.keystorePass";
+
+    /** 
+     * Defines whether the host name should be verified or not in SSL connections.
+     * <p>
+     * This parameter expects a value of type {@link Boolean}.
+     * </p>
+     */
+    private static final String HOSTNAME_VERIFICATION_ENABLED = "http.hostname-verification.enabled";
+
+    /** 
+     * Defines whether the HttpClient should follow redirections from the responses.
+     * <p>
+     * This parameter expects a value of type {@link Boolean}.
+     * </p>
+     */
+    private static final String KEY_FOLLOW_REDIRECT = "followRedirect";
+
+    /** 
+     * Defines the User-Agent request header string of the underlying HttpClient.
+     * <p>
+     * This parameter expects a value of type {@link String}.
+     * </p>
+     */
+    private static final String KEY_USER_AGENT = "userAgent";
+
+    /** 
+     * Defines whether the preemptive authentication should be enabled or not.
+     * <p>
+     * This parameter expects a value of type {@link Boolean}.
+     * </p>
+     */
+    private static final String KEY_PREEMPTIVE_AUTHENTICATION = "preemptiveAuth";
+
+    /**
+     * The default value for {@link #MAX_TOTAL_CONNECTIONS} configuration.
+     */
+    private static final int DEFAULT_MAX_CONNECTIONS = 50;
+
+    /**
+     * The default value for {@link #MAX_HOST_CONNECTIONS} configuration.
+     */
+    private static final int DEFAULT_MAX_HOST_CONNECTIONS = 5;
+
+    /**
+     * The default value for {@link #CONNECTION_TIMEOUT} configuration.
+     */
+    private static final int DEFAULT_CONNECTION_TIMEOUT = 0;
+
+    /**
+     * The default value for {@link #SO_TIMEOUT} configuration.
+     */
+    private static final int DEFAULT_SO_TIMEOUT = 0;
+
+    /**
+     * The default value for {@link #KEEP_ALIVE} configuration.
+     */
+    private static final boolean DEFAULT_KEEP_ALIVE = true;
+
+    /**
+     * The default value for {@link #KEY_FOLLOW_REDIRECT} configuration.
+     */
+    private static final boolean DEFAULT_FOLLOW_REDIRECT = true;
+
+    /**
+     * The default value for {@link #KEY_USER_AGENT} configuration.
+     */
+    private static final String DEFAULT_USER_AGENT = "Jakarta-Commons-VFS";
+
+    /**
+     * The default value for {@link #HOSTNAME_VERIFICATION_ENABLED} configuration.
+     */
+    private static final boolean DEFAULT_HOSTNAME_VERIFICATION_ENABLED = true;
+
+    /**
+     * Construct an <code>Http4FileSystemConfigBuilder</code>.
+     *
+     * @param prefix String for properties of this file system.
+     */
+    protected Http4FileSystemConfigBuilder(final String prefix) {
+        super(prefix);
+    }
+
+    private Http4FileSystemConfigBuilder() {
+        super("http.");
+    }
+
+    /**
+     * Gets the singleton builder.
+     *
+     * @return the singleton builder.
+     */
+    public static Http4FileSystemConfigBuilder getInstance() {
+        return BUILDER;
+    }
+
+    /**
+     * Sets the charset used for url encoding.<br>
+     *
+     * @param opts The FileSystem options.
+     * @param chaset the chaset
+     */
+    public void setUrlCharset(final FileSystemOptions opts, final String chaset) {
+        setParam(opts, "urlCharset", chaset);
+    }
+
+    /**
+     * Sets the charset used for url encoding.<br>
+     *
+     * @param opts The FileSystem options.
+     * @return the chaset
+     */
+    public String getUrlCharset(final FileSystemOptions opts) {
+        return getString(opts, "urlCharset");
+    }
+
+    /**
+     * Sets the proxy to use for http connection.<br>
+     * You have to set the ProxyPort too if you would like to have the proxy really used.
+     *
+     * @param opts The FileSystem options.
+     * @param proxyHost the host
+     * @see #setProxyPort
+     */
+    public void setProxyHost(final FileSystemOptions opts, final String proxyHost) {
+        setParam(opts, "proxyHost", proxyHost);
+    }
+
+    /**
+     * Sets the proxy-port to use for http connection. You have to set the ProxyHost too if you would like to have the
+     * proxy really used.
+     *
+     * @param opts The FileSystem options.
+     * @param proxyPort the port
+     * @see #setProxyHost
+     */
+    public void setProxyPort(final FileSystemOptions opts, final int proxyPort) {
+        setParam(opts, "proxyPort", Integer.valueOf(proxyPort));
+    }
+
+    /**
+     * Gets the proxy to use for http connection. You have to set the ProxyPort too if you would like to have the proxy
+     * really used.
+     *
+     * @param opts The FileSystem options.
+     * @return proxyHost
+     * @see #setProxyPort
+     */
+    public String getProxyHost(final FileSystemOptions opts) {
+        return getString(opts, "proxyHost");
+    }
+
+    /**
+     * Gets the proxy-port to use for http the connection. You have to set the ProxyHost too if you would like to have
+     * the proxy really used.
+     *
+     * @param opts The FileSystem options.
+     * @return proxyPort: the port number or 0 if it is not set
+     * @see #setProxyHost
+     */
+    public int getProxyPort(final FileSystemOptions opts) {
+        return getInteger(opts, "proxyPort", 0);
+    }
+
+    /**
+     * Sets the proxy authenticator where the system should get the credentials from.
+     *
+     * @param opts The FileSystem options.
+     * @param authenticator The UserAuthenticator.
+     */
+    public void setProxyAuthenticator(final FileSystemOptions opts, final UserAuthenticator authenticator) {
+        setParam(opts, "proxyAuthenticator", authenticator);
+    }
+
+    /**
+     * Gets the proxy authenticator where the system should get the credentials from.
+     *
+     * @param opts The FileSystem options.
+     * @return The UserAuthenticator.
+     */
+    public UserAuthenticator getProxyAuthenticator(final FileSystemOptions opts) {
+        return (UserAuthenticator) getParam(opts, "proxyAuthenticator");
+    }
+
+    /**
+     * The cookies to add to the request.
+     *
+     * @param opts The FileSystem options.
+     * @param cookies An array of Cookies.
+     */
+    public void setCookies(final FileSystemOptions opts, final Cookie[] cookies) {
+        setParam(opts, "cookies", cookies);
+    }
+
+    /**
+     * Sets whether to follow redirects for the connection.
+     *
+     * @param opts The FileSystem options.
+     * @param redirect {@code true} to follow redirects, {@code false} not to.
+     * @see #setFollowRedirect
+     */
+    public void setFollowRedirect(final FileSystemOptions opts, final boolean redirect) {
+        setParam(opts, KEY_FOLLOW_REDIRECT, redirect);
+    }
+
+    /**
+     * Gets the cookies to add to the request.
+     *
+     * @param opts The FileSystem options.
+     * @return the Cookie array.
+     */
+    public Cookie[] getCookies(final FileSystemOptions opts) {
+        return (Cookie[]) getParam(opts, "cookies");
+    }
+
+    /**
+     * Gets whether to follow redirects for the connection.
+     *
+     * @param opts The FileSystem options.
+     * @return {@code true} to follow redirects, {@code false} not to.
+     * @see #setFollowRedirect
+     */
+    public boolean getFollowRedirect(final FileSystemOptions opts) {
+        return getBoolean(opts, KEY_FOLLOW_REDIRECT, DEFAULT_FOLLOW_REDIRECT);
+    }
+
+    /**
+     * Sets the maximum number of connections allowed.
+     *
+     * @param opts The FileSystem options.
+     * @param maxTotalConnections The maximum number of connections.
+     */
+    public void setMaxTotalConnections(final FileSystemOptions opts, final int maxTotalConnections) {
+        setParam(opts, MAX_TOTAL_CONNECTIONS, Integer.valueOf(maxTotalConnections));
+    }
+
+    /**
+     * Gets the maximum number of connections allowed.
+     *
+     * @param opts The FileSystemOptions.
+     * @return The maximum number of connections allowed.
+     */
+    public int getMaxTotalConnections(final FileSystemOptions opts) {
+        return getInteger(opts, MAX_TOTAL_CONNECTIONS, DEFAULT_MAX_CONNECTIONS);
+    }
+
+    /**
+     * Sets the maximum number of connections allowed to any host.
+     *
+     * @param opts The FileSystem options.
+     * @param maxHostConnections The maximum number of connections to a host.
+     */
+    public void setMaxConnectionsPerHost(final FileSystemOptions opts, final int maxHostConnections) {
+        setParam(opts, MAX_HOST_CONNECTIONS, Integer.valueOf(maxHostConnections));
+    }
+
+    /**
+     * Gets the maximum number of connections allowed per host.
+     *
+     * @param opts The FileSystemOptions.
+     * @return The maximum number of connections allowed per host.
+     */
+    public int getMaxConnectionsPerHost(final FileSystemOptions opts) {
+        return getInteger(opts, MAX_HOST_CONNECTIONS, DEFAULT_MAX_HOST_CONNECTIONS);
+    }
+
+    /**
+     * Determines if the FileSystemOptions indicate that preemptive authentication is requested.
+     *
+     * @param opts The FileSystemOptions.
+     * @return true if preemptiveAuth is requested.
+     */
+    public boolean isPreemptiveAuth(final FileSystemOptions opts) {
+        return getBoolean(opts, KEY_PREEMPTIVE_AUTHENTICATION, Boolean.FALSE).booleanValue();
+    }
+
+    /**
+     * Sets the given value for preemptive HTTP authentication (using BASIC) on the given FileSystemOptions object.
+     * Defaults to false if not set. It may be appropriate to set to true in cases when the resulting chattiness of the
+     * conversation outweighs any architectural desire to use a stronger authentication scheme than basic/preemptive.
+     *
+     * @param opts The FileSystemOptions.
+     * @param preemptiveAuth the desired setting; true=enabled and false=disabled.
+     */
+    public void setPreemptiveAuth(final FileSystemOptions opts, final boolean preemptiveAuth) {
+        setParam(opts, KEY_PREEMPTIVE_AUTHENTICATION, Boolean.valueOf(preemptiveAuth));
+    }
+
+    /**
+     * The connection timeout.
+     *
+     * @param opts The FileSystem options.
+     * @param connectionTimeout The connection timeout.
+     */
+    public void setConnectionTimeout(final FileSystemOptions opts, final int connectionTimeout) {
+        setParam(opts, CONNECTION_TIMEOUT, Integer.valueOf(connectionTimeout));
+    }
+
+    /**
+     * Gets the connection timeout.
+     *
+     * @param opts The FileSystem options.
+     * @return The connection timeout.
+     */
+    public int getConnectionTimeout(final FileSystemOptions opts) {
+        return getInteger(opts, CONNECTION_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT);
+    }
+
+    /**
+     * The socket timeout.
+     *
+     * @param opts The FileSystem options.
+     * @param soTimeout socket timeout.
+     */
+    public void setSoTimeout(final FileSystemOptions opts, final int soTimeout) {
+        setParam(opts, SO_TIMEOUT, Integer.valueOf(soTimeout));
+    }
+
+    /**
+     * Gets the socket timeout.
+     *
+     * @param opts The FileSystemOptions.
+     * @return The socket timeout.
+     */
+    public int getSoTimeout(final FileSystemOptions opts) {
+        return getInteger(opts, SO_TIMEOUT, DEFAULT_SO_TIMEOUT);
+    }
+
+    /**
+     * Sets if the FileSystemOptions indicate that HTTP Keep-Alive is respected.
+     *
+     * @param opts The FileSystemOptions.
+     * @param keepAlive whether the FileSystemOptions indicate that HTTP Keep-Alive is respected or not.
+     */
+    public void setKeepAlive(final FileSystemOptions opts, boolean keepAlive) {
+        setParam(opts, KEEP_ALIVE, Boolean.valueOf(keepAlive));
+    }
+
+    /**
+     * Determines if the FileSystemOptions indicate that HTTP Keep-Alive is respected.
+     *
+     * @param opts The FileSystemOptions.
+     * @return true if if the FileSystemOptions indicate that HTTP Keep-Alive is respected.
+     */
+    public boolean isKeepAlive(final FileSystemOptions opts) {
+        return getBoolean(opts, KEEP_ALIVE, DEFAULT_KEEP_ALIVE);
+    }
+
+    /**
+     * Sets the user agent to attach to the outgoing http methods
+     *
+     * @param opts the file system options to modify
+     * @param userAgent User Agent String
+     */
+    public void setUserAgent(final FileSystemOptions opts, final String userAgent) {
+        setParam(opts, "userAgent", userAgent);
+    }
+
+    /**
+     * Gets the user agent string
+     *
+     * @param opts the file system options to modify
+     * @return User provided User-Agent string, otherwise default of: Commons-VFS
+     */
+    public String getUserAgent(final FileSystemOptions opts) {
+        final String userAgent = (String) getParam(opts, KEY_USER_AGENT);
+        return userAgent != null ? userAgent : DEFAULT_USER_AGENT;
+    }
+
+    /**
+     * Set keystore file path for SSL connections.
+     * @param opts the file system options to modify
+     * @param keyStoreFile keystore file path
+     */
+    public void setKeyStoreFile(final FileSystemOptions opts, String keyStoreFile) {
+        setParam(opts, KEYSTORE_FILE, keyStoreFile);
+    }
+
+    /**
+     * Return keystore file path to be used in SSL connections.
+     * @param opts the file system options to modify
+     * @return keystore file path to be used in SSL connections
+     */
+    public String getKeyStoreFile(final FileSystemOptions opts) {
+        return (String) getParam(opts, KEYSTORE_FILE);
+    }
+
+    /**
+     * Set keystore pass phrase for SSL connecdtions.
+     * @param opts the file system options to modify
+     * @param keyStorePass keystore pass phrase for SSL connecdtions
+     */
+    public void setKeyStorePass(final FileSystemOptions opts, String keyStorePass) {
+        setParam(opts, KEYSTORE_PASS, keyStorePass);
+    }
+
+    /**
+     * Return keystore pass phrase for SSL connections.
+     * @param opts the file system options to modify
+     * @return keystore pass phrase for SSL connections
+     */
+    String getKeyStorePass(final FileSystemOptions opts) {
+        return (String) getParam(opts, KEYSTORE_PASS);
+    }
+
+    /**
+     * Sets if the hostname should be verified in SSL context.
+     *
+     * @param opts The FileSystemOptions.
+     * @param hostnameVerificationEnabled whether hostname should be verified
+     */
+    public void setHostnameVerificationEnabled(final FileSystemOptions opts, boolean hostnameVerificationEnabled) {
+        setParam(opts, HOSTNAME_VERIFICATION_ENABLED, Boolean.valueOf(hostnameVerificationEnabled));
+    }
+
+    /**
+     * Determines if the hostname should be verified in SSL context.
+     *
+     * @param opts The FileSystemOptions.
+     * @return true if if the FileSystemOptions indicate that HTTP Keep-Alive is respected.
+     */
+    public boolean isHostnameVerificationEnabled(final FileSystemOptions opts) {
+        return getBoolean(opts, HOSTNAME_VERIFICATION_ENABLED, DEFAULT_HOSTNAME_VERIFICATION_ENABLED);
+    }
+
+    @Override
+    protected Class<? extends FileSystem> getConfigClass() {
+        return Http4FileSystem.class;
+    }
+}

Added: commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4RandomAccessContent.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4RandomAccessContent.java?rev=1845527&view=auto
==============================================================================
--- commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4RandomAccessContent.java (added)
+++ commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/Http4RandomAccessContent.java Fri Nov  2 01:53:29 2018
@@ -0,0 +1,143 @@
+/*
+ * 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.commons.vfs2.provider.http4;
+
+import java.io.DataInputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+
+import org.apache.commons.vfs2.FileSystemException;
+import org.apache.commons.vfs2.provider.AbstractRandomAccessStreamContent;
+import org.apache.commons.vfs2.util.MonitorInputStream;
+import org.apache.commons.vfs2.util.RandomAccessMode;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+
+/**
+ * RandomAccess content using <code>Http4FileObject</code>.
+ */
+class Http4RandomAccessContent<FS extends Http4FileSystem> extends AbstractRandomAccessStreamContent {
+
+    protected long filePointer = 0;
+
+    private final Http4FileObject<FS> fileObject;
+
+    private DataInputStream dis = null;
+    private MonitorInputStream mis = null;
+
+    Http4RandomAccessContent(final Http4FileObject<FS> fileObject, final RandomAccessMode mode) {
+        super(mode);
+        this.fileObject = fileObject;
+    }
+
+    @Override
+    public long getFilePointer() throws IOException {
+        return filePointer;
+    }
+
+    @Override
+    public void seek(final long pos) throws IOException {
+        if (pos == filePointer) {
+            // no change
+            return;
+        }
+
+        if (pos < 0) {
+            throw new FileSystemException("vfs.provider/random-access-invalid-position.error", Long.valueOf(pos));
+        }
+
+        if (dis != null) {
+            close();
+        }
+
+        filePointer = pos;
+    }
+
+    @Override
+    protected DataInputStream getDataInputStream() throws IOException {
+        if (dis != null) {
+            return dis;
+        }
+
+        final HttpGet httpGet = new HttpGet(fileObject.getInternalURI());
+        httpGet.setHeader("Range", "bytes=" + filePointer + "-");
+        final HttpResponse httpResponse = fileObject.executeHttpUriRequest(httpGet);
+        final int status = httpResponse.getStatusLine().getStatusCode();
+
+        if (status != HttpURLConnection.HTTP_PARTIAL && status != HttpURLConnection.HTTP_OK) {
+            throw new FileSystemException("vfs.provider.http/get-range.error", fileObject.getName(),
+                    Long.valueOf(filePointer), Integer.valueOf(status));
+        }
+
+        mis = new MonitoredHttpResponseContentInputStream(httpResponse);
+
+        // If the range request was ignored
+        if (status == HttpURLConnection.HTTP_OK) {
+            final long skipped = mis.skip(filePointer);
+            if (skipped != filePointer) {
+                throw new FileSystemException("vfs.provider.http/get-range.error", fileObject.getName(),
+                        Long.valueOf(filePointer), Integer.valueOf(status));
+            }
+        }
+
+        dis = new DataInputStream(new FilterInputStream(mis) {
+            @Override
+            public int read() throws IOException {
+                final int ret = super.read();
+                if (ret > -1) {
+                    filePointer++;
+                }
+                return ret;
+            }
+
+            @Override
+            public int read(final byte[] b) throws IOException {
+                final int ret = super.read(b);
+                if (ret > -1) {
+                    filePointer += ret;
+                }
+                return ret;
+            }
+
+            @Override
+            public int read(final byte[] b, final int off, final int len) throws IOException {
+                final int ret = super.read(b, off, len);
+                if (ret > -1) {
+                    filePointer += ret;
+                }
+                return ret;
+            }
+        });
+
+        return dis;
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (dis != null) {
+            dis.close();
+            dis = null;
+            mis = null;
+        }
+    }
+
+    @Override
+    public long length() throws IOException {
+        return fileObject.getContent().getSize();
+    }
+}

Added: commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/MonitoredHttpResponseContentInputStream.java
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/MonitoredHttpResponseContentInputStream.java?rev=1845527&view=auto
==============================================================================
--- commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/MonitoredHttpResponseContentInputStream.java (added)
+++ commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/MonitoredHttpResponseContentInputStream.java Fri Nov  2 01:53:29 2018
@@ -0,0 +1,44 @@
+/*
+ * 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.commons.vfs2.provider.http4;
+
+import java.io.IOException;
+
+import org.apache.commons.vfs2.util.MonitorInputStream;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.CloseableHttpResponse;
+
+/**
+ * An InputStream that cleans up the <code>org.apache.http.client.methods.CloseableHttpResponse</code> on close.
+ */
+class MonitoredHttpResponseContentInputStream extends MonitorInputStream {
+
+    private final HttpResponse httpResponse;
+
+    public MonitoredHttpResponseContentInputStream(final HttpResponse httpResponse) throws IOException {
+        super(httpResponse.getEntity().getContent());
+        this.httpResponse = httpResponse;
+    }
+
+    @Override
+    protected void onClose() throws IOException {
+        if (httpResponse instanceof CloseableHttpResponse) {
+            ((CloseableHttpResponse) httpResponse).close();
+        }
+    }
+
+}

Added: commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/package.html
URL: http://svn.apache.org/viewvc/commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/package.html?rev=1845527&view=auto
==============================================================================
--- commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/package.html (added)
+++ commons/proper/vfs/trunk/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/http4/package.html Fri Nov  2 01:53:29 2018
@@ -0,0 +1,19 @@
+<!--
+    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.
+-->
+<body>
+<p>The HTTP4 File Provider</p>
+</body>