home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1995 November
/
PCWK1195.iso
/
inne
/
win95
/
sieciowe
/
hotja32.lzh
/
hotjava
/
classsrc
/
net
/
www
/
httpd
/
server.java
< prev
next >
Wrap
Text File
|
1995-08-11
|
12KB
|
406 lines
/*
* @(#)Server.java 1.4 95/05/12 James Gosling
*
* Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for NON-COMMERCIAL purposes and without fee is hereby
* granted provided that this copyright notice appears in all copies. Please
* refer to the file "copyright.html" for further important copyright and
* licensing information.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
* SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
* OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
* LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR
* ITS DERIVATIVES.
*/
package net.www.httpd;
import net.NetworkServer;
import net.InetAddress;
import net.www.html.MessageHeader;
import net.www.html.URL;
import java.io.*;
import java.util.Hashtable;
import java.util.Cache;
/**
* This is the base class for http servers. To define a new type
* of server define a new subclass of Server with a getRequest
* method that services one request. Start the server by executing:
* <pre>
* new MyServerClass().startServer(port);
* </pre>
*/
public class Server extends NetworkServer {
/** The mime header from the request. */
MessageHeader mh;
static int totalConnections;
static URL defaultContext;
ServerParameters params;
Cache fileCache = new Cache(1000);
/** True iff the client expects a mime header (ie. HTTP/1.n) */
boolean expectsMime;
Server (String argv[]) {
params = new ServerParameters(getClass().getName(), argv);
if (params.verbose)
params.print();
}
/** Satisfy one get request. It is invoked with the clientInput and
clientOutput streams initialized. This method handles one client
connection. When it is done, it can simply exit. */
protected void getRequest(URL u, String param) {
try {
String fn = u.file;
if (fn.endsWith("/"))
fn = fn + params.welcome;
InputStream is = null;
int size = 0;
is = new FileInputStream(fn);
size = is.available();
String ct = params.mimeType(fn);
CachedFile cf = null;
MessageHeader mh = new MessageHeader();
mh.add("Content-type", ct);
mh.add("Server", params.serverName);
mh.add("Content-length", String.valueOf(size));
if (size <= params.maxRamCacheEntryBuffer) {
try {
cf = new CachedFile(is, size, mh);
fileCache.put(u, cf);
if (params.verbose)
System.out.print(u.toExternalForm() + ": Into RAM cache\n");
} catch(Exception e) {
if (params.verbose)
e.printStackTrace();
}
} else if (params.verbose)
System.out.print(u.toExternalForm() + ": from disk (too big for RAM cache: " + size + ")\n");
if (expectsMime) {
clientOutput.print("HTTP/1.0 200 Document follows\n");
mh.print(clientOutput);
}
if (cf != null)
cf.sendto(clientOutput);
else {
int nb;
byte buf[] = new byte[2048];
while ((nb = is.read(buf)) >= 0)
clientOutput.write(buf, 0, nb);
}
if (is != null)
is.close();
} catch(Exception e) {
if (params.verbose)
e.printStackTrace();
error("Can't read " + u.file);
}
}
private static File TrashFile; // File to rename to instead of
// removing files
private void remove(File f) {
if (TrashFile == null)
TrashFile = new File(params.CacheRoot + "/trash");
try {
f.renameTo(TrashFile);
} catch(Exception e) {
System.out.print("Couldn't remove " + f + "\n");
}
}
/** Satisfy one get request where this host is acting as a proxy.
It is invoked with the clientInput and
clientOutput streams initialized. This method handles one client
connection. When it is done, it can simply exit. The default
server just echoes it's input. */
protected void getProxyRequest(URL u, String param) {
InputStream is = null;
OutputStream os = null;
MessageHeader mh = null;
boolean tryCache = params.Caching && u.canCache();
String ff = u.toExternalForm();
File CacheFile = new File(params.CacheRoot, u.toExternalForm()
.replace('/', File.separatorChar) + "+");
CachedFile cf = null;
if (tryCache) {
try {
is = new BufferedInputStream(new FileInputStream(CacheFile));
if (params.verbose)
System.out.print(u.toExternalForm() + ": Found in proxy cache\n");
tryCache = false;
mh = new MessageHeader(is);
u.content_type = mh.findValue("content-type");
/* we have it: try to put it in the RAM cache */
int size = is.available();
mh.set("Content-size", String.valueOf(size));
if (size <= params.maxRamCacheEntryBuffer) {
try {
/*
* slurp it into the RAM cache, then shoot it out
* right away
*/
cf = new CachedFile(is, size, mh);
fileCache.put(u, cf);
if (params.verbose)
System.out.print(u.toExternalForm() + ": Proxy cached file into RAM cache\n");
if (expectsMime) {
clientOutput.print("HTTP/1.0 200 Document follows\n");
mh.print(clientOutput);
}
cf.sendto(clientOutput);
is.close();
return;
} catch(Exception e) {
if (params.verbose)
e.printStackTrace();
}
} else if (params.verbose)
System.out.print(u.toExternalForm() + ": Too big for RAM cache (" + size +
"<" + params.maxRamCacheEntryBuffer + ")\n");
} catch(Exception e) {
if (is != null) {
e.printStackTrace();
is.close();
}
is = null;
}
}
if (is == null)
if (params.CacheNoConnect) {
if (params.verbose)
System.out.print("Proxy cache missed with remote access disabled " + u.toExternalForm() + "\n");
if (expectsMime)
clientOutput.print("HTTP/1.0 404 not found (remote access disabled)\n" +
"Server: " + params.serverName +
"\nContent-type: text/html" +
"\n\n");
clientOutput.print("<html><body><h1>File not found in cache, remote access disabled.</h1>\n"
+ u.toExternalForm() + "\n");
return;
} else {
try {
is = u.openStream();
if (params.verbose)
System.out.print(u.toExternalForm() + ": Proxy get.\n");
} catch(FileNotFoundException e) {
if (params.verbose)
System.out.print(u.toExternalForm() + ": Proxy get failed.\n");
if (expectsMime)
clientOutput.print("HTTP/1.0 404 not found\n" +
"Server: " + params.serverName +
"\nContent-type: text/html" +
"\n\n");
clientOutput.print("<html><body><h1>File not found</h1>\n"
+ u.toExternalForm() + "\n");
return;
}
}
if (tryCache) {
try {
try {
os = new BufferedOutputStream(new FileOutputStream(CacheFile));
} catch(Exception e) {
new File(CacheFile.getParent()).mkdirs();
os = new BufferedOutputStream(new FileOutputStream(CacheFile));
}
} catch(Exception e) {
}
}
if (os != null)
if (mh != null)
mh.print(new PrintStream(os));
else
new PrintStream(os).print("Content-type: " + u.content_type + "\n\n");
if (expectsMime) {
clientOutput.print("HTTP/1.0 200 Document follows\n");
if (mh != null)
mh.print(clientOutput);
else
clientOutput.print("Server: " + params.serverName +
"\nContent-type: " + u.content_type +
"\n\n");
}
byte buf[] = new byte[2048];
int nb;
int nWritten = 0;
while ((nb = is.read(buf)) >= 0) {
if (os != null) {
try {
os.write(buf, 0, nb);
nWritten += nb;
} catch(Exception e) {
if (params.verbose)
System.out.print("Cache write to " + CacheFile + " failed (" + e + ")\n");
remove(CacheFile);
os.close();
os = null;
}
}
clientOutput.write(buf, 0, nb);
}
if (os != null)
os.close();
if (is != null)
is.close();
}
/** Start generating an html reply to a get request. This is a
convenience method to simplify getRequest */
public void startHtml(String title)
{
if (expectsMime)
clientOutput.print("HTTP/1.0 200 Document follows\n" +
"Server: Java/" + params.serverName + "\n" +
"Content-type: text/html\n\n");
clientOutput.print("<html><head><title>" + title +
"</title></head>\n<body><h1>" +
title + "</h1>\n");
}
/** Generate an html reply to a get request that contains a
dump of the statistics for the current server. getRequest
handlers can call it in response to special file names. */
protected void generateStatistics()
{
startHtml("Server statistics");
clientOutput.print(totalConnections + " total connections.<p>\n");
}
/** Generate an html reply to a get request that contains the
output after executing a system command. getRequest
handlers can call it in response to special file names. */
public void generateProcessOutput(String title, String command)
{
startHtml(title);
try {
InputStream in = new BufferedInputStream(System.execin(command));
clientOutput.print("<pre>\n");
int c;
while ((c = in.read()) >= 0)
switch (c) {
case '<':
clientOutput.print("<");
break;
case '&':
clientOutput.print("&");
break;
default:
clientOutput.write(c);
break;
}
in.close();
clientOutput.print("</pre>\n");
} catch(Exception e) {
clientOutput.print("Failed to execute " + command + "\n");
}
}
public void error(String msg)
{
if (expectsMime)
clientOutput.print("HTTP/1.0 403 Error - " + msg + "\n" +
"Content-type: text/html\n\n");
clientOutput.print("<html><head>Error</head><body>" +
"<H1>Error when fetching document:</h1>\n" +
msg + "\n");
if (mh != null) {
clientOutput.print("<p><hr><pre>\n");
mh.print(clientOutput);
clientOutput.print("</pre>\n");
}
}
final public void serviceRequest()
{
totalConnections++;
if (defaultContext == null)
defaultContext = new URL("http", InetAddress.localHostName, "/");
try {
mh = new MessageHeader(clientInput);
String cmd = mh.findValue(null);
if (cmd == null) {
error("Missing command " + mh);
return;
}
int fsp = cmd.indexOf(' ');
if (fsp < 0) {
error("Syntax error in command: " + cmd);
return;
}
String k = cmd.substring(0, fsp);
int nsp = cmd.indexOf(' ', fsp + 1);
String p1, p2;
if (nsp > 0) {
p1 = cmd.substring(fsp + 1, nsp);
p2 = cmd.substring(nsp + 1);
} else {
p1 = cmd.substring(fsp + 1);
p2 = null;
}
expectsMime = p2 != null;
if (k.equalsIgnoreCase("get")) {
URL u = new URL(defaultContext, p1);
CachedFile cf = (CachedFile) fileCache.get(u);
if (cf != null) {
/* Found in RAM cache */
if (params.verbose)
System.out.print(u.toExternalForm() + ": get from RAM cache\n");
if (expectsMime) {
clientOutput.print("HTTP/1.0 200 Document follows\n");
cf.headerto(clientOutput);
}
cf.sendto(clientOutput);
} else if (u.protocol.equals(defaultContext.protocol) &&
u.host.equals(defaultContext.host)) {
/* Local request */
String fn = u.file;
Object r = params.applyRules(fn);
if (fn == null || fn == params.failObject)
error("Access denied (by rule)");
else if (r instanceof String) {
u.file = (String) r;
getRequest(u, p2);
} else if (r instanceof ServerPlugin) {
((ServerPlugin) r).getRequest(this, u);
} else {
error("Can't cope with " + r + " yet\n");
}
} else
getProxyRequest(u, p2);
} else {
error("Unknown command: " + k + " (" + cmd + ")");
return;
}
} catch(IOException e) {
// totally ignore IOException. Theyre usually client
// crashes.
error("IOException: " + e);
} catch(Exception e) {
e.printStackTrace();
error("Exception: " + e);
}
}
public static void main(String argv[])
{
Server s = new Server (argv);
try {
s.startServer(s.params.port);
} catch(Exception e) {
e.printStackTrace();
}
}
}