1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.vfs.provider.http;
18
19 import org.apache.commons.httpclient.Header;
20 import org.apache.commons.httpclient.HttpClient;
21 import org.apache.commons.httpclient.HttpMethod;
22 import org.apache.commons.httpclient.URIException;
23 import org.apache.commons.httpclient.methods.GetMethod;
24 import org.apache.commons.httpclient.methods.HeadMethod;
25 import org.apache.commons.httpclient.util.DateParser;
26 import org.apache.commons.httpclient.util.URIUtil;
27 import org.apache.commons.vfs.FileContentInfoFactory;
28 import org.apache.commons.vfs.FileName;
29 import org.apache.commons.vfs.FileSystemException;
30 import org.apache.commons.vfs.FileType;
31 import org.apache.commons.vfs.RandomAccessContent;
32 import org.apache.commons.vfs.provider.AbstractFileObject;
33 import org.apache.commons.vfs.provider.URLFileName;
34 import org.apache.commons.vfs.util.MonitorInputStream;
35 import org.apache.commons.vfs.util.RandomAccessMode;
36
37 import java.io.IOException;
38 import java.io.InputStream;
39 import java.net.HttpURLConnection;
40
41 /***
42 * A file object backed by commons httpclient.
43 *
44 * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a>
45 * @version $Revision: 480428 $ $Date: 2006-11-29 07:15:24 +0100 (Mi, 29 Nov 2006) $
46 * @todo status codes
47 */
48 public class HttpFileObject
49 extends AbstractFileObject
50 {
51 private final HttpFileSystem fileSystem;
52 private final String urlCharset;
53 private HeadMethod method;
54
55 protected HttpFileObject(final FileName name,
56 final HttpFileSystem fileSystem)
57 {
58 super(name, fileSystem);
59 this.fileSystem = fileSystem;
60 urlCharset = HttpFileSystemConfigBuilder.getInstance().getUrlCharset(getFileSystem().getFileSystemOptions());
61 }
62
63 /***
64 * Detaches this file object from its file resource.
65 */
66 protected void doDetach()
67 throws Exception
68 {
69 method = null;
70 }
71
72 /***
73 * Determines the type of this file. Must not return null. The return
74 * value of this method is cached, so the implementation can be expensive.
75 */
76 protected FileType doGetType()
77 throws Exception
78 {
79
80 method = new HeadMethod();
81 setupMethod(method);
82 final HttpClient client = fileSystem.getClient();
83 final int status = client.executeMethod(method);
84 method.releaseConnection();
85 if (status == HttpURLConnection.HTTP_OK)
86 {
87 return FileType.FILE;
88 }
89 else if (status == HttpURLConnection.HTTP_NOT_FOUND
90 || status == HttpURLConnection.HTTP_GONE)
91 {
92 return FileType.IMAGINARY;
93 }
94 else
95 {
96 throw new FileSystemException("vfs.provider.http/head.error", getName());
97 }
98 }
99
100 /***
101 * Lists the children of this file.
102 */
103 protected String[] doListChildren()
104 throws Exception
105 {
106 throw new Exception("Not implemented.");
107 }
108
109 /***
110 * Returns the size of the file content (in bytes).
111 */
112 protected long doGetContentSize()
113 throws Exception
114 {
115 final Header header = method.getResponseHeader("content-length");
116 if (header == null)
117 {
118
119 return 0;
120 }
121 return Integer.parseInt(header.getValue());
122 }
123
124 /***
125 * Returns the last modified time of this file.
126 * <p/>
127 * This implementation throws an exception.
128 */
129 protected long doGetLastModifiedTime()
130 throws Exception
131 {
132 final Header header = method.getResponseHeader("last-modified");
133 if (header == null)
134 {
135 throw new FileSystemException("vfs.provider.http/last-modified.error", getName());
136 }
137 return DateParser.parseDate(header.getValue()).getTime();
138 }
139
140 /***
141 * Creates an input stream to read the file content from. Is only called
142 * if {@link #doGetType} returns {@link FileType#FILE}.
143 * <p/>
144 * <p>It is guaranteed that there are no open output streams for this file
145 * when this method is called.
146 * <p/>
147 * <p>The returned stream does not have to be buffered.
148 */
149 protected InputStream doGetInputStream()
150 throws Exception
151 {
152 final GetMethod getMethod = new GetMethod();
153 setupMethod(getMethod);
154 final int status = fileSystem.getClient().executeMethod(getMethod);
155 if (status != HttpURLConnection.HTTP_OK)
156 {
157 throw new FileSystemException("vfs.provider.http/get.error", getName());
158 }
159
160 return new HttpInputStream(getMethod);
161 }
162
163 protected RandomAccessContent doGetRandomAccessContent(final RandomAccessMode mode) throws Exception
164 {
165 return new HttpRandomAccesContent(this, mode);
166 }
167
168 /***
169 * Prepares a Method object.
170 */
171 void setupMethod(final HttpMethod method) throws FileSystemException, URIException
172 {
173 String pathEncoded = ((URLFileName) getName()).getPathQueryEncoded(urlCharset);
174 method.setPath(pathEncoded);
175 method.setFollowRedirects(true);
176 method.setRequestHeader("User-Agent", "Jakarta-Commons-VFS");
177 }
178
179 protected String encodePath(final String decodedPath) throws URIException
180 {
181 String pathEncoded = URIUtil.encodePath(decodedPath);
182 return pathEncoded;
183 }
184
185 /***
186 * An InputStream that cleans up the HTTP connection on close.
187 */
188 static class HttpInputStream
189 extends MonitorInputStream
190 {
191 private final GetMethod method;
192
193 public HttpInputStream(final GetMethod method)
194 throws IOException
195 {
196 super(method.getResponseBodyAsStream());
197 this.method = method;
198 }
199
200 /***
201 * Called after the stream has been closed.
202 */
203 protected void onClose()
204 throws IOException
205 {
206 method.releaseConnection();
207 }
208 }
209
210
211 protected FileContentInfoFactory getFileContentInfoFactory()
212 {
213 return new HttpFileContentInfoFactory();
214 }
215
216 HeadMethod getHeadMethod()
217 {
218 return method;
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240 }