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.http4;
018
019import java.io.IOException;
020import java.io.InputStream;
021import java.net.URI;
022
023import org.apache.commons.vfs2.FileContentInfoFactory;
024import org.apache.commons.vfs2.FileNotFoundException;
025import org.apache.commons.vfs2.FileSystemException;
026import org.apache.commons.vfs2.FileSystemOptions;
027import org.apache.commons.vfs2.FileType;
028import org.apache.commons.vfs2.RandomAccessContent;
029import org.apache.commons.vfs2.provider.AbstractFileName;
030import org.apache.commons.vfs2.provider.AbstractFileObject;
031import org.apache.commons.vfs2.provider.GenericURLFileName;
032import org.apache.commons.vfs2.util.RandomAccessMode;
033import org.apache.http.Header;
034import org.apache.http.HttpResponse;
035import org.apache.http.HttpStatus;
036import org.apache.http.client.HttpClient;
037import org.apache.http.client.methods.HttpGet;
038import org.apache.http.client.methods.HttpHead;
039import org.apache.http.client.methods.HttpUriRequest;
040import org.apache.http.client.protocol.HttpClientContext;
041import org.apache.http.client.utils.DateUtils;
042import org.apache.http.client.utils.URIUtils;
043import org.apache.http.protocol.HTTP;
044
045/**
046 * A file object backed by Apache HttpComponents HttpClient.
047 *
048 * @param <FS> An {@link Http4FileSystem} subclass
049 * @since 2.3
050 * @deprecated Use {@link org.apache.commons.vfs2.provider.http5}.
051 */
052@Deprecated
053public class Http4FileObject<FS extends Http4FileSystem> extends AbstractFileObject<FS> {
054
055    /**
056     * URL charset string.
057     */
058    private final String urlCharset;
059
060    /**
061     * Internal URI mapped to this {@code FileObject}.
062     * For example, the internal URI of {@code http4://example.com/a.txt} is {@code http://example.com/a.txt}.
063     */
064    private final URI internalURI;
065
066    /**
067     * The last executed HEAD {@code HttpResponse} object.
068     */
069    private HttpResponse lastHeadResponse;
070
071    /**
072     * Constructs {@code Http4FileObject}.
073     *
074     * @param name file name
075     * @param fileSystem file system
076     * @throws FileSystemException if any error occurs
077     */
078    protected Http4FileObject(final AbstractFileName name, final FS fileSystem)
079            throws FileSystemException {
080        this(name, fileSystem, Http4FileSystemConfigBuilder.getInstance());
081    }
082
083    /**
084     * Constructs {@code Http4FileObject}.
085     *
086     * @param name file name
087     * @param fileSystem file system
088     * @param builder {@code Http4FileSystemConfigBuilder} object
089     * @throws FileSystemException if any error occurs
090     */
091    protected Http4FileObject(final AbstractFileName name, final FS fileSystem,
092            final Http4FileSystemConfigBuilder builder) throws FileSystemException {
093        super(name, fileSystem);
094        final FileSystemOptions fileSystemOptions = fileSystem.getFileSystemOptions();
095        urlCharset = builder.getUrlCharset(fileSystemOptions);
096        final String pathEncoded = ((GenericURLFileName) name).getPathQueryEncoded(getUrlCharset());
097        internalURI = URIUtils.resolve(fileSystem.getInternalBaseURI(), pathEncoded);
098    }
099
100    @Override
101    protected void doDetach() throws Exception {
102        lastHeadResponse = null;
103    }
104
105    @Override
106    protected long doGetContentSize() throws Exception {
107        if (lastHeadResponse == null) {
108            return 0L;
109        }
110
111        final Header header = lastHeadResponse.getFirstHeader(HTTP.CONTENT_LEN);
112
113        if (header == null) {
114            // Assume 0 content-length
115            return 0;
116        }
117
118        return Long.parseLong(header.getValue());
119    }
120
121    @Override
122    protected InputStream doGetInputStream(final int bufferSize) throws Exception {
123        final HttpGet getRequest = new HttpGet(getInternalURI());
124        final HttpResponse httpResponse = executeHttpUriRequest(getRequest);
125        final int status = httpResponse.getStatusLine().getStatusCode();
126
127        if (status == HttpStatus.SC_NOT_FOUND) {
128            throw new FileNotFoundException(getName());
129        }
130
131        if (status != HttpStatus.SC_OK) {
132            throw new FileSystemException("vfs.provider.http/get.error", getName(), Integer.valueOf(status));
133        }
134
135        return new MonitoredHttpResponseContentInputStream(httpResponse, bufferSize);
136    }
137
138    @Override
139    protected long doGetLastModifiedTime() throws Exception {
140        FileSystemException.requireNonNull(lastHeadResponse, "vfs.provider.http/last-modified.error", getName());
141
142        final Header header = lastHeadResponse.getFirstHeader("Last-Modified");
143
144        FileSystemException.requireNonNull(header, "vfs.provider.http/last-modified.error", getName());
145
146        return DateUtils.parseDate(header.getValue()).getTime();
147    }
148
149    @Override
150    protected RandomAccessContent doGetRandomAccessContent(final RandomAccessMode mode) throws Exception {
151        return new Http4RandomAccessContent<>(this, mode);
152    }
153
154    @Override
155    protected FileType doGetType() throws Exception {
156        lastHeadResponse = executeHttpUriRequest(new HttpHead(getInternalURI()));
157        final int status = lastHeadResponse.getStatusLine().getStatusCode();
158
159        if (status == HttpStatus.SC_OK
160                || status == HttpStatus.SC_METHOD_NOT_ALLOWED /* method is not allowed, but resource exist */) {
161            return FileType.FILE;
162        }
163        if (status == HttpStatus.SC_NOT_FOUND || status == HttpStatus.SC_GONE) {
164            return FileType.IMAGINARY;
165        }
166        throw new FileSystemException("vfs.provider.http/head.error", getName(), Integer.valueOf(status));
167    }
168
169    @Override
170    protected boolean doIsWriteable() throws Exception {
171        return false;
172    }
173
174    @Override
175    protected String[] doListChildren() throws Exception {
176        throw new UnsupportedOperationException("Not implemented.");
177    }
178
179    /**
180     * Execute the request using the given {@code httpRequest} and return a {@code HttpResponse} from the execution.
181     *
182     * @param httpRequest {@code HttpUriRequest} object
183     * @return {@code HttpResponse} from the execution
184     * @throws IOException if IO error occurs
185     * @since 2.5.0
186     */
187    protected HttpResponse executeHttpUriRequest(final HttpUriRequest httpRequest) throws IOException {
188        final HttpClient httpClient = getAbstractFileSystem().getHttpClient();
189        final HttpClientContext httpClientContext = getAbstractFileSystem().getHttpClientContext();
190        return httpClient.execute(httpRequest, httpClientContext);
191    }
192
193    @Override
194    protected FileContentInfoFactory getFileContentInfoFactory() {
195        return new Http4FileContentInfoFactory();
196    }
197
198    /**
199     * Gets the internal {@code URI} object mapped to this file object.
200     *
201     * @return the internal {@code URI} object mapped to this file object
202     */
203    protected URI getInternalURI() {
204        return internalURI;
205    }
206
207    /**
208     * Gets the last executed HEAD {@code HttpResponse} object.
209     *
210     * @return the last executed HEAD {@code HttpResponse} object
211     * @throws IOException if IO error occurs
212     */
213    HttpResponse getLastHeadResponse() throws IOException {
214        if (lastHeadResponse != null) {
215            return lastHeadResponse;
216        }
217
218        return executeHttpUriRequest(new HttpHead(getInternalURI()));
219    }
220
221    /**
222     * Gets URL charset string.
223     * @return URL charset string
224     */
225    protected String getUrlCharset() {
226        return urlCharset;
227    }
228
229}