001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.lib.collab.util;
043:
044: import java.net.*;
045: import java.io.*;
046: import java.util.*;
047:
048: /**
049: * the worlds simplist and most ineffecient web server
050: *
051: *
052: *
053: * @author Rahul Shah
054: *
055: */
056: public class Http extends Thread {
057:
058: /**
059: * active client socket
060: */
061: Socket s;
062:
063: /**
064: * default file
065: */
066: final static String index = "index.html";
067:
068: /**
069: * root directory to serv from or file if only one file is to be served
070: */
071: private File rootFile;
072:
073: private static Hashtable _servers = new Hashtable();
074:
075: /**
076: * create a client connection
077: * @param file The root directory to serv from or file if only one file is to be served
078: * @param s
079: */
080: public Http(File file, Socket s) {
081: this .s = s;
082: rootFile = file;
083: }
084:
085: /**
086: * start the http server as application
087: *
088: * @param args
089: */
090: public static void main(String[] args) {
091:
092: String port = "9980";
093: String root = ".";
094:
095: for (int x = 0; x < args.length; x++) {
096: if (args[x].equals("-port")) {
097: port = args[x++];
098: }
099: if (args[x].equals("-root")) {
100: root = args[x++];
101: }
102: }
103: HostPort hp = new HostPort(port, 9980);
104: try {
105: startServ(root, hp);
106: } catch (IOException ioe) {
107: ioe.printStackTrace();
108: }
109: }
110:
111: /**
112: * start the http server
113: *
114: * @param filepath - root directory to serv from or the file path if only one file is to be served
115: * @param port - port to listne on
116: * @param i - address to bind server to
117: * @throws IOException if Unable to start the server
118: */
119: public static void startServ(String filepath, HostPort hp)
120: throws IOException {
121: HTTPAcceptor acceptor = (HTTPAcceptor) _servers.get(hp);
122: if (acceptor != null) {
123: //System.out.println("HTTP port alreary enabled");
124: return;
125: }
126: File file = new File(filepath);
127: if (!file.exists()) {
128: //System.out.println("Invalid HTTP doc root: " + file.getAbsolutePath() + " does not exists");
129: return;
130: }
131: acceptor = new HTTPAcceptor(file, hp);
132: acceptor.startServ();
133: Thread t = new Thread(acceptor);
134: _servers.put(hp, acceptor);
135: t.setDaemon(true);
136: t.start();
137: }
138:
139: static class HTTPAcceptor implements Runnable {
140: private HostPort _hp;
141: private boolean running;
142: private ServerSocket serv;
143: private File file;
144:
145: HTTPAcceptor(File f, HostPort hp) {
146: _hp = hp;
147: file = f;
148: }
149:
150: public void startServ() throws IOException {
151: int port = _hp.getPort();
152: InetAddress i = _hp.getHost();
153: serv = new ServerSocket(port, 10, i);
154: running = true;
155: if (port == 0) {
156: _hp.setPort(serv.getLocalPort());
157: }
158: //System.out.println("HTTP port accepting connections: " + serv.getLocalPort() +
159: // " : " + file.getAbsolutePath());
160: }
161:
162: public void run() {
163: try {
164: while (running) {
165: Http n = new Http(file, serv.accept());
166: n.setDaemon(true);
167: n.start();
168: }
169: } catch (IOException e) {
170: //if (running == true) System.out.println("HTTP listener error: " + e);
171: }
172: stopServ();
173: }
174:
175: boolean isRunning() {
176: return running;
177: }
178:
179: /**
180: * stop the http server
181: */
182: void stopServ() {
183: if (running == false)
184: return;
185: running = false;
186: if (serv != null) {
187: try {
188: serv.close();
189: } catch (Exception e) {
190: }
191: }
192: serv = null;
193: //System.out.println("Stopping HTTP listener on port " + _hp.getPort());
194: }
195: }
196:
197: /**
198: * stop the http server
199: */
200: public static void stopServ(HostPort hp) {
201: HTTPAcceptor acceptor = (HTTPAcceptor) _servers.get(hp);
202: if (acceptor != null) {
203: acceptor.stopServ();
204: }
205: }
206:
207: /**
208: * server content to a client
209: */
210: public void run() {
211: String version = "";
212:
213: try {
214: PrintStream os = new PrintStream(new BufferedOutputStream(s
215: .getOutputStream()));
216: BufferedReader is = new BufferedReader(
217: new InputStreamReader(s.getInputStream()));
218: String line = is.readLine();
219: if (line == null)
220: return;
221: StringTokenizer st = new StringTokenizer(line);
222: String method = st.nextToken();
223: String fileName = st.nextToken();
224: if (st.hasMoreTokens()) {
225: version = st.nextToken();
226: }
227: //read header but ignore
228: while ((line = is.readLine()) != null) {
229: if (line.trim().equals(""))
230: break;
231: }
232:
233: //System.out.println("HTTP request = " + method + " " + fileName);
234:
235: //we only do gets
236: if (method.equals("GET") || method.equals("HEAD")) {
237: File file;
238: FileInputStream fs = null;
239: boolean headOnly = false;
240: if (method.equals("HEAD")) {
241: headOnly = true;
242: }
243: try {
244: if (fileName.endsWith("/"))
245: fileName += index;
246: fileName = fileName.substring(1, fileName.length());
247: if (rootFile.isFile()) {
248: if (rootFile.getName().equals(fileName)) {
249: file = rootFile;
250: fs = new FileInputStream(file);
251: } else {
252: //send an unauthorized message
253: file = null;
254: }
255: } else if (rootFile.isDirectory()) {
256: file = new File(rootFile, fileName);
257: if (file.isDirectory())
258: file = new File(file, index);
259: fs = new FileInputStream(file);
260: } else {
261: file = null;
262: }
263: } catch (IOException e) {
264: //could not open file
265: file = null;
266: //not a get so output error
267: if (version.startsWith("HTTP/")) { //send headers
268: String header = "HTTP/1.0 404 File Not Found\r\n";
269: header += standardHeaders();
270: header += "Content-type: text/html\r\n\r\n";
271: os.print(header);
272: }
273: os
274: .println("<HTML><HEAD><TITLE>File Not Found</TITLE><HEAD>");
275: os
276: .println("<BODY><H1>HTTP Error 404: File Not Found</H1></BODY></HTML>");
277: os.close();
278: //System.out.println( "Requested HTTP File: >" + fileName + "< not found");
279: }
280: if (file != null) {
281: if (version.startsWith("HTTP/")) { //send headers
282: String header = "HTTP/1.0 200 OK\r\n";
283: header += standardHeaders();
284: header += "Content-length: " + file.length()
285: + "\r\n";
286: header += "Content-type: "
287: + contentType(fileName) + "\r\n\r\n";
288: os.print(header);
289: }
290: if (!headOnly) {
291: byte[] data = new byte[1024];
292: int r;
293: while ((r = fs.read(data)) > 0) {
294: os.write(data, 0, r);
295: }
296: }
297: os.flush();
298: os.close();
299: fs.close();
300: s.close();
301: //System.out.println("HTTP File: >" + fileName + "< size: " + file.length() + " bytes - Content-type: " + contentType(fileName));
302: }
303: } else {
304: //not a get/head so output error
305: if (version.startsWith("HTTP/")) { //send headers
306: String header = "HTTP/1.0 501 Not Implemented\r\n";
307: header += standardHeaders();
308: header += "Content-type: text/html\r\n\r\n";
309: os.print(header);
310: }
311: os
312: .println("<HTML><HEAD><TITLE>Not Implemented</TITLE><HEAD>");
313: os
314: .println("<BODY><H1>HTTP Error 501: Not Implemented</H1></BODY></HTML>");
315: os.close();
316: //System.out.println( "HTTP only supports GET or HEAD" );
317: }
318: } catch (IOException e) {
319: //file io or socket error so nothing to do
320: }
321: try {
322: s.close();
323: } catch (IOException e) {
324: //must have already been closed or error
325: }
326: }
327:
328: /**
329: * send boring standard http headers
330: */
331: private String standardHeaders() {
332: //Date now = LazyDate.getDate();
333: Date now = new Date();
334: return "Date: " + now + "\r\nServer: iim http 1.0\r\n";
335: }
336:
337: /**
338: * get the content type for request
339: *
340: * @param filename
341: */
342: private String contentType(String filename) {
343: String[] a = { ".html", "text/html", ".htm", "text/html",
344: ".txt", "text/plain", ".jar",
345: "application/octet-stream", ".class",
346: "application/octet-stream", ".gif", "image/gif",
347: ".jpg", "image/jpeg", ".jpeg", "image/jpeg", ".jnlp",
348: "application/x-java-jnlp-file", ".nlc",
349: "application/x-x509-ca-cert" };
350: for (int x = 0; x < a.length - 1; x += 2) {
351: if (filename.endsWith(a[x]))
352: return a[x + 1];
353: }
354: return "application/octet-stream";
355: }
356: }
|