1:   /*
2:    * Copyright (c) 1998-99 The WebApp Framework.  All rights reserved.
3:    *
4:    * Redistribution and use in source and binary forms, with or without
5:    * modification, are permitted provided that the following conditions
6:    * are met:
7:    *
8:    * 1. Redistributions of source code must retain the above copyright
9:    * notice, this list of conditions and the following disclaimer.
10:    *
11:    * 2. Redistributions in binary form must reproduce the above copyright
12:    * notice, this list of conditions and the following disclaimer in the
13:    * documentation and/or other materials provided with the distribution.
14:    *
15:    * 3. The WebApp Framework may be used for evaluation, private or
16:    * educational purposes without fee.
17:    *
18:    * 4. The right to redistribute The WebApp Framework or any part of it
19:    * as part of free software is hereby granted. Redistribution as part
20:    * of a commercial product is NOT permitted in any form without prior
21:    * written permission.
22:    *
23:    * 5. Every modification must be notified to The WebApp Framework, i.e.
24:    * Peter Rossbach and Hendrik Schreiber, and redistribution of the
25:    * modified code without prior notification is NOT permitted in any form.
26:    *
27:    * 6. All advertising materials mentioning features or use of this
28:    * software must display the following acknowledgment: "This product
29:    * includes software developed by Peter Rossbach and Hendrik Schreiber
30:    * (http://www.webapp.de/)."
31:    *
32:    * 7. The names "WebApp" and "WebApp Framework" must not be used to
33:    * endorse or promote products derived from this software without prior
34:    * written permission.
35:    *
36:    * 8. Redistributions of any form whatsoever must retain the following
37:    * acknowledgment: "This product includes software developed by Peter
38:    * Rossbach and Hendrik Schreiber (http://www.webapp.de/)."
39:    *
40:    * 9. As this release also contains software by Sun Microsystems the
41:    * following conditions have to be met, too. They apply to the
42:    * files lib/servlet.jar, lib/mail.jar and lib/activation.jar
43:    * contained in this release.
44:    *
45:    * 10. Java Platform Interface.  Licensee may not modify the Java Platform
46:    * Interface (JPI, identified as classes contained within the javax
47:    * package or any subpackages of the javax package), by creating additional
48:    * classes within the JPI or otherwise causing the addition to or modification
49:    * of the classes in the JPI.  In the event that Licensee creates any 
50:    * Java-related API and distribute such API to others for applet or
51:    * application development, you must promptly publish broadly, an accurate 
52:    * specification for such API for free use by all developers of Java-based 
53:    * software.  
54:    *
55:    * 11. Restrictions.  Software is confidential copyrighted information of Sun and 
56:    * title to all copies is retained by Sun and/or its licensors.  Licensee 
57:    * shall not modify, decompile, disassemble, decrypt, extract, or otherwise 
58:    * reverse engineer Software.  Software may not be leased, assigned, or 
59:    * sublicensed, in whole or in part.  Software is not designed or intended 
60:    * for use in on-line control of aircraft, air traffic, aircraft navigation 
61:    * or aircraft communications; or in the design, construction, operation or 
62:    * maintenance of any nuclear facility.  Licensee warrants that it will not 
63:    * use or redistribute the Software for such purposes.
64:    *
65:    * 12. Disclaimer of Warranty.  Software is provided "AS IS," without a warranty 
66:    * of any kind. *  ALL EXPRESS OR IMPLIED REPRESENTATIONS AND WARRANTIES, 
67:    * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A 
68:    * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.  
69:    *
70:    * 13. Termination.  This License is effective until terminated.  Licensee may 
71:    * terminate this License at any time by destroying all copies of Software.  
72:    * This License will terminate immediately without notice from Sun if Licensee
73:    * fails to comply with any provision of this License.  Upon such termination,
74:    * Licensee must destroy all copies of Software.
75:    *
76:    * 14. Export Regulations.  Software, including technical data, is subject to U.S.
77:    * export control laws, including the U.S.  Export Administration Act and its
78:    * associated regulations, and may be subject to export or import regulations
79:    * in other countries.  Licensee agrees to comply strictly with all such 
80:    * regulations and acknowledges that it has the responsibility to obtain
81:    * licenses to export, re-export, or import Software.  Software may not be 
82:    * downloaded, or otherwise exported or re-exported (i) into, or to a national
83:    * or resident of, Cuba, Iraq, Iran, North Korea, Libya, Sudan, Syria or any 
84:    * country to which the U.S. has embargoed goods; or (ii) to anyone on the 
85:    * U.S. Treasury Department's list of Specially Designated Nations or the U.S.
86:    * Commerce Department's Table of Denial Orders.
87:    *
88:    * THIS SOFTWARE IS PROVIDED BY PETER ROSSBACH AND HENDRIK SCHREIBER
89:    * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
90:    * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
91:    * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PETER
92:    * ROSSBACH AND HENDRIK SCHREIBER BE LIABLE FOR ANY DIRECT, INDIRECT,
93:    * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
94:    * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
95:    * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
96:    * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
97:    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
98:    * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
99:    * SUCH DAMAGE.
100:    *
101:    * For more information on The WebApp Framework, Peter Rossbach or
102:    * Hendrik Schreiber, please see <http://www.webapp.de/>.
103:    *
104:    */
105:  
106:    
107:  
108:   import java.io.*;
109:   import java.net.*;
110:   import java.util.*;
111:  
112:   /**
113:    * Server, which is capable of performing 
114:    * the <code>GET</code> command. Compared to {@link SimpleHttp}
115:    * some improvements are found. For instance, the error- and
116:    * status codes are set correctly. The Content-Type is set,
117:    * if a file <code>mime.types</code> is located in the current
118:    * directory. It should conform the following format:
119:    * <xmp>
120:    *    .ra=audio/x-realaudio
121:    *    .wav=audio/x-wav
122:    *    .gif=image/gif
123:    *    .jpeg=image/jpeg
124:    *    .jpg=image/jpeg
125:    *    .png=image/png
126:    *    .tiff=image/tiff
127:    *    .html=text/html
128:    *    .htm=text/html
129:    *    .txt=text/plain
130:    * </xmp>
131:    *
132:    @author Hendrik Schreiber, Peter Rossbach
133:    @version $Id: SimpleHttpd2.java,v 1.7 2000/07/15 12:23:39 Hendrik Exp $
134:    @see OneShotHttpd
135:    @see SimpleHttpd
136:    */
137:   public class SimpleHttpd2 extends Thread 
138:   {
139:      /**
140:       * Version
141:       */
142:      public static String vcid = "$Id: SimpleHttpd2.java,v 1.7 2000/07/15 12:23:39 Hendrik Exp $";
143:  
144:      /**
145:       * Socket of a request.
146:       */
147:      protected Socket s = null;
148:  
149:      /**
150:       * Document root.
151:       */
152:      protected static File docRoot;
153:  
154:      /**
155:       * Canonical document root.
156:       */
157:      protected static String canonicalDocRoot;
158:  
159:      /**
160:       * The port the server will listen to
161:       */
162:      public final static int HTTP_PORT = 8080;
163:  
164:      /**
165:       * CRLF
166:       */
167:      public final static String CRLF = "\r\n";
168:  
169:      /**
170:       * Protocol out server understands.
171:       */
172:      public final static String PROTOCOL = "HTTP/1.0 ";
173:  
174:      /**
175:       * Status code: All OK.
176:       */
177:      public final static String SC_OK = "200 OK";
178:  
179:      /**
180:       * Status code: Bad request.
181:       */
182:      public final static String SC_BAD_REQUEST = "400 Bad Request";
183:  
184:      /**
185:       * Status code: Forbidden request.
186:       */
187:      public final static String SC_FORBIDDEN = "403 Forbidden";
188:  
189:      /**
190:       * Status code: Resource not found.
191:       */
192:      public final static String SC_NOT_FOUND = "404 Not Found";
193:  
194:      /**
195:       * Content type map.
196:       */
197:      protected static Properties typeMap = new Properties();
198:  
199:      /**
200:       * Current status code.
201:       */
202:      protected String statusCode = SC_OK;
203:  
204:      /**
205:       * Current header.
206:       */
207:      protected Hashtable myHeaders = new Hashtable();
208:  
209:      /**
210:       * Waits for an <code>GET</code> request and performs it.
211:       * Objects are searched for relatively to the current directory
212:       * (Document root = "./"). If no file is specified, only
213:       * a directory, the file <code>index.html</code> is delivered.<br>
214:       * If the request is not a <code>GET</code> request, the error
215:       * message 400, <code>Bad Request</code>, is sent to the client.
216:       */
217:      public static void main(String argv[])
218:      {
219:         try
220:         {
221:            typeMap.load(new FileInputStream("mime.types"));
222:            docRoot = new File(".");
223:            canonicalDocRoot = docRoot.getCanonicalPath();
224:            ServerSocket listen = new ServerSocket(HTTP_PORT);
225:            while(true)
226:            {
227:               SimpleHttpd2 aRequest = new SimpleHttpd2(listen.accept());
228:            }
229:         }
230:         catch(IOException e)
231:         {
232:            System.err.println("Error: " e.toString());
233:         }
234:      }
235:  
236:      /**
237:       * Sets the socket of this request and starts the thread.
238:       *
239:       @param s Socket of a request
240:       */
241:      public SimpleHttpd2(Socket s)
242:      {
243:         this.s = s;
244:         start();
245:      }
246:  
247:      /**
248:       * The actually slogger of this class. The request is parsed
249:       * and the method {@link #getDocument()} is called
250:       */
251:      public void run()
252:      {
253:         try
254:         {
255:            setHeader("Server","SimpleHttpd2");
256:            BufferedReader is = new BufferedReader(new InputStreamReader(s.getInputStream()));
257:            DataOutputStream os = new DataOutputStream(s.getOutputStream());
258:            String request = is.readLine();
259:            System.out.println("Request: " request);
260:            StringTokenizer st = new StringTokenizer(request);
261:            if((st.countTokens() == 3&& st.nextToken().equals("GET"))
262:            {
263:               String filename = docRoot.getPath() + st.nextToken();
264:               if(filename.endsWith("/") || filename.equals(""))
265:                  filename +"index.html";
266:               File file = new File(filename);
267:               if(file.getCanonicalPath().startsWith(canonicalDocRoot))
268:                  sendDocument(os,file);
269:               else
270:                  sendError(SC_FORBIDDEN,os);
271:            }
272:            else
273:            {
274:               sendError(SC_BAD_REQUEST,os);
275:            }
276:            is.close();
277:            os.close();
278:            s.close();
279:         }
280:         catch(IOException ioe)
281:         {
282:            System.err.println("Error: " ioe.toString());
283:         }
284:      }
285:  
286:      /**
287:       * Reads the file, specified in <code>request</code> and writes it to
288:       * the OutputStream.<br>
289:       * If the file could not be found, the error message 404,
290:       * <code>Not Found</code>, is returned.
291:       *
292:       @exception IOException in case writing to the <code>DataOutputStream</code>
293:       *    fails.
294:       @param os Stream, where the requested object is to be copied to.
295:       @param file file to copy.
296:       */
297:      protected void sendDocument(DataOutputStream osFile filethrows IOException
298:      {
299:         try
300:         {
301:            BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
302:            sendStatusLine(os);
303:            setHeader("Content-Length",(new Long(file.length())).toString());
304:            setHeader("Content-Type",guessType(file.getPath()));
305:            sendHeader(os);
306:            os.writeBytes(CRLF);
307:            byte[] buf = new byte[1024];
308:            int len;
309:            while((len = in.read(buf,0,1024)) !-1)
310:            {
311:               os.write(buf,0,len);
312:            }
313:            in.close();
314:         }
315:         catch(FileNotFoundException fnfe)
316:         {
317:            sendError(SC_NOT_FOUND,os);
318:         }
319:      }
320:  
321:      /**
322:       * Sets a status code.
323:       *
324:       @param statusCode status code
325:       */
326:      protected void setStatusCode(String statusCode)
327:      {
328:         this.statusCode = statusCode;
329:      }
330:  
331:      /**
332:       * Gets the status code.
333:       *
334:       @return status code
335:       */
336:      protected String getStatusCode()
337:      {
338:         return statusCode;
339:      }
340:  
341:      /**
342:       * Writes the status line to the consigned <code>DataOutputStream</code>.
343:       *
344:       @param out DataOutputStream where the line is to be written.
345:       @exception IOException in case writing fails.
346:       */
347:      protected void sendStatusLine(DataOutputStream outthrows IOException
348:      {
349:         out.writeBytes(PROTOCOL getStatusCode() + CRLF);
350:      }
351:  
352:      /**
353:       * Sets an header value.
354:       *
355:       @param key key of the header value.
356:       @param value the header value.
357:       */
358:      protected void setHeader(String keyString value)
359:      {
360:         myHeaders.put(key,value);
361:      }
362:  
363:      /**
364:       * Writes the header to the consigned <code>DataOutputStream</code>.
365:       *
366:       @param out DataOutputStream where the header is to be written.
367:       @exception IOException in case writing fails.
368:       */
369:      protected void sendHeader(DataOutputStream outthrows IOException
370:      {
371:         String line;
372:         String key;
373:         Enumeration e = myHeaders.keys();
374:         while(e.hasMoreElements())
375:         {
376:            key (String)e.nextElement();
377:            out.writeBytes(key ": " myHeaders.get(key) + CRLF);
378:         }
379:      }
380:  
381:      /**
382:       * Writes an error message to the consigned <code>DataOutputStream</code>.
383:       *
384:       @param out DataOutputStream where the error message is to be written.
385:       @param statusCode status code.
386:       @exception IOException in case writing fails.
387:       */
388:      protected void sendError(String statusCodeDataOutputStream outthrows IOException
389:      {
390:         setStatusCode(statusCode);
391:         sendStatusLine(out);
392:         out.writeBytes(CRLF "<html>" "<head><title>" getStatusCode() + "</title></head>" "<body><h1>" getStatusCode() + "</h1></body>" "</html>");
393:         System.err.println(getStatusCode());
394:      }
395:  
396:      /**
397:       * Surmise the <code>Content-Type</code> of the file by means
398:       * of the file extension.
399:       *
400:       @param filename file name
401:       @return Content-Type or "unknown/unknown" in case no
402:       *     appropriate type is found.
403:       */
404:      public String guessType(String filename)
405:      {
406:         String type = null;
407:         int i = filename.lastIndexOf(".");
408:         if(0)
409:            type = typeMap.getProperty(filename.substring(i));
410:         if(type == null)
411:            type = "unknown/unknown";
412:         return type;
413:      }
414:  
415:   }
416:  
417:   // end of class

This page was automatically generated by SharpDevelop.