KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > nutch > protocol > file > FileResponse


1 /* Copyright (c) 2004 The Nutch Organization. All rights reserved. */
2 /* Use subject to the conditions in http://www.nutch.org/LICENSE.txt. */
3
4 package net.nutch.protocol.file;
5
6 import javax.activation.MimetypesFileTypeMap JavaDoc;
7 // 20040528, xing, disabled for now
8
//import xing.net.nutch.util.magicfile.*;
9

10 import net.nutch.protocol.Content;
11
12 import java.net.URL JavaDoc;
13
14 import java.util.TreeMap JavaDoc;
15 import java.util.Properties JavaDoc;
16
17 import java.util.logging.Level JavaDoc;
18
19 import java.io.InputStream JavaDoc;
20 import java.io.IOException JavaDoc;
21
22 /************************************
23  * FileResponse.java mimics file replies as http response.
24  * It tries its best to follow http's way for headers, response codes
25  * as well as exceptions.
26  *
27  * Comments:
28  * (1) java.net.URL and java.net.URLConnection can handle file: scheme.
29  * However they are not flexible enough, so not used in this implementation.
30  *
31  * (2) java.io.File is used for its abstractness across platforms.
32  * Warning:
33  * java.io.File API (1.4.2) does not elaborate on how special files,
34  * such as /dev/* in unix and /proc/* on linux, are treated. Tests show
35  * (a) java.io.File.isFile() return false for /dev/*
36  * (b) java.io.File.isFile() return true for /proc/*
37  * (c) java.io.File.length() return 0 for /proc/*
38  * We are probably oaky for now. Could be buggy here.
39  * How about special files on windows?
40  *
41  * (3) java.io.File API (1.4.2) does not seem to know unix hard link files.
42  * They are just treated as individual files.
43  *
44  * (4) No funcy POSIX file attributes yet. May never need?
45  *
46  * @author John Xing
47  ***********************************/

48 public class FileResponse {
49   private String JavaDoc orig;
50   private String JavaDoc base;
51   private byte[] content;
52   private int code;
53   private Properties JavaDoc headers = new Properties JavaDoc();
54
55   private final File file;
56
57   /** Returns the response code. */
58   public int getCode() { return code; }
59
60   /** Returns the value of a named header. */
61   public String JavaDoc getHeader(String JavaDoc name) {
62     return (String JavaDoc)headers.get(name);
63   }
64
65   public byte[] getContent() { return content; }
66
67   public Content toContent() {
68     return new Content(orig, base, content,
69                        getHeader("Content-Type"),
70                        headers);
71   }
72
73   public FileResponse(URL JavaDoc url, File file)
74     throws FileException, IOException JavaDoc {
75     this(url.toString(), url, file);
76   }
77
78   public FileResponse(String JavaDoc orig, URL JavaDoc url, File file)
79     throws FileException, IOException JavaDoc {
80
81     this.orig = orig;
82     this.base = url.toString();
83     this.file = file;
84
85     if (!"file".equals(url.getProtocol()))
86       throw new FileException("Not a file url:" + url);
87
88     if (File.LOG.isLoggable(Level.FINE))
89       File.LOG.fine("fetching " + url);
90
91     if (url.getPath() != url.getFile())
92       File.LOG.warning("url.getPath() != url.getFile(): " + url);
93
94     String JavaDoc path = "".equals(url.getPath()) ? "/" : url.getPath();
95
96     try {
97
98       this.content = null;
99
100       // url.toURI() is only in j2se 1.5.0
101
//java.io.File f = new java.io.File(url.toURI());
102
java.io.File JavaDoc f = new java.io.File JavaDoc(path);
103
104       if (!f.exists()) {
105         this.code = 404; // http Not Found
106
return;
107       }
108
109       if (!f.canRead()) {
110         this.code = 401; // http Unauthorized
111
return;
112       }
113
114       // symbolic link or relative path on unix
115
// fix me: what's the consequence on windows platform
116
// where case is insensitive
117
if (!f.equals(f.getCanonicalFile())) {
118         // set headers
119
TreeMap JavaDoc hdrs = new TreeMap JavaDoc(String.CASE_INSENSITIVE_ORDER);
120         //hdrs.put("Location", f.getCanonicalFile().toURI());
121
hdrs.put("Location", f.getCanonicalFile().toURL().toString());
122         this.headers.putAll(hdrs);
123
124         this.code = 300; // http redirect
125
return;
126       }
127
128       if (f.isDirectory()) {
129         getDirAsHttpResponse(f);
130       } else if (f.isFile()) {
131         getFileAsHttpResponse(f);
132       } else {
133         this.code = 500; // http Internal Server Error
134
return;
135       }
136
137     } catch (IOException JavaDoc e) {
138       throw e;
139     }
140
141   }
142
143   // get file as http response
144
private void getFileAsHttpResponse(java.io.File JavaDoc f)
145     throws FileException, IOException JavaDoc {
146
147     // ignore file of size larger than
148
// Integer.MAX_VALUE = 2^31-1 = 2147483647
149
long size = f.length();
150     if (size > Integer.MAX_VALUE) {
151       throw new FileException("file is too large, size: "+size);
152       // or we can do this?
153
// this.code = 400; // http Bad request
154
// return;
155
}
156
157     // capture content
158
int len = (int) size;
159     
160     if (this.file.maxContentLength > 0 && len > this.file.maxContentLength)
161       len = this.file.maxContentLength;
162
163     this.content = new byte[len];
164
165     java.io.InputStream JavaDoc is = new java.io.FileInputStream JavaDoc(f);
166     int offset = 0; int n = 0;
167     while (offset < len
168       && (n = is.read(this.content, offset, len-offset)) >= 0) {
169       offset += n;
170     }
171     if (offset < len) // keep whatever already have, but issue a warning
172
File.LOG.warning("not enough bytes read from file: "+f.getPath());
173     is.close();
174
175     // set headers
176
TreeMap JavaDoc hdrs = new TreeMap JavaDoc(String.CASE_INSENSITIVE_ORDER);
177
178     hdrs.put("Content-Length", new Long JavaDoc(size).toString());
179
180     hdrs.put("Last-Modified",
181       this.file.httpDateFormat.toString(f.lastModified()));
182
183     String JavaDoc contentType = null;
184 // 20040528, xing, disabled for now
185
// if (contentType == null && this.file.MAGIC != null)
186
// contentType = this.file.MAGIC.getMimeType(this.content);
187
if (contentType == null && this.file.TYPE_MAP != null)
188       contentType = this.file.TYPE_MAP.getContentType(f.getName());
189     if (contentType != null)
190       hdrs.put("Content-Type", contentType);
191
192     this.headers.putAll(hdrs);
193
194     // response code
195
this.code = 200; // http OK
196
}
197
198   // get dir list as http response
199
private void getDirAsHttpResponse(java.io.File JavaDoc f)
200     throws IOException JavaDoc {
201
202     String JavaDoc path = f.toString();
203     this.content = list2html(f.listFiles(), path, "/".equals(path) ? false : true);
204
205     // set headers
206
TreeMap JavaDoc hdrs = new TreeMap JavaDoc(String.CASE_INSENSITIVE_ORDER);
207
208     hdrs.put("Content-Length",
209       new Integer JavaDoc(this.content.length).toString());
210
211     hdrs.put("Content-Type", "text/html");
212
213     hdrs.put("Last-Modified",
214       this.file.httpDateFormat.toString(f.lastModified()));
215
216     this.headers.putAll(hdrs);
217
218     // response code
219
this.code = 200; // http OK
220
}
221
222   // generate html page from dir list
223
private byte[] list2html(java.io.File JavaDoc[] list,
224     String JavaDoc path, boolean includeDotDot) {
225
226     StringBuffer JavaDoc x = new StringBuffer JavaDoc("<html><head>");
227     x.append("<title>Index of "+path+"</title></head>\n");
228     x.append("<body><h1>Index of "+path+"</h1><pre>\n");
229
230     if (includeDotDot) {
231       x.append("<a HREF='../'>../</a>\t-\t-\t-\n");
232     }
233
234     // fix me: we might want to sort list here! but not now.
235

236     java.io.File JavaDoc f;
237     for (int i=0; i<list.length; i++) {
238       f = list[i];
239       String JavaDoc name = f.getName();
240       String JavaDoc time = this.file.httpDateFormat.toString(f.lastModified());
241       if (f.isDirectory()) {
242         // java 1.4.2 api says dir itself and parent dir are not listed
243
// so the following is not needed.
244
//if (name.equals(".") || name.equals(".."))
245
// continue;
246
x.append("<a HREF='"+name+"/"+"'>"+name+"/</a>\t");
247         x.append(time+"\t-\n");
248       } else if (f.isFile()) {
249         x.append("<a HREF='"+name+ "'>"+name+"</a>\t");
250         x.append(time+"\t"+f.length()+"\n");
251       } else {
252         // ignore any other
253
}
254     }
255
256     x.append("</pre></body></html>\n");
257
258     return new String JavaDoc(x).getBytes();
259   }
260
261 }
262
Popular Tags