Michael Chungkun Chen
SeasNet ID
= mchen
Course CS
118
Project 1
[WebServer.java]
The source code following is of part A and B
combined, using the fixed width font Verdana.
The modifications that I made from the original code given to us by the
packet is marked in bold face font.
<<BEGIN SOURCE WebServer.java>>
import
java.io.* ;
import
java.net.* ;
import
java.util.* ;
public
final class WebServer
{
public static void main(String argv[])
throws Exception
{
ServerSocket mysock = null;
Socket clientSocket = null;
// Set the port number.
int port = 65534;
// Establish the listen socket.
try {
mysock =
new ServerSocket(port);
} catch (IOException e) {
System.out.println("Could
not listen on port: " + port);
System.exit(-1);
}
// Process HTTP service requests in an
infinite loop.
while (true) {
//
Listen for a TCP connection request.
try
{
clientSocket
= mysock.accept();
System.out.println("Connection
made on port: " + port);
}
catch (IOException e) {
System.out.println("Accept
failed: ");
System.exit(-1);
}
//
Construct an object to process the HTTP request message.
HttpRequest
request = new HttpRequest( clientSocket );
//
Create a new thread to process the request.
Thread
thread = new Thread(request);
//
Start the thread.
thread.start();
}
}
}
final
class HttpRequest implements Runnable
{
final static String CRLF =
"\r\n";
Socket socket;
// Constructor
public HttpRequest(Socket socket) throws
Exception
{
this.socket
= socket;
}
// Implement the run() method of the
Runnable interface.
public void run()
{
try
{
processRequest();
}
catch (Exception e) {
System.out.println(e);
}
}
private void processRequest() throws
Exception
{
//
Get a reference to the socket's input and output streams.
InputStream
is = socket.getInputStream();
DataOutputStream
os = new DataOutputStream(socket.getOutputStream());
//
Set up input stream filters.
BufferedReader
br = new BufferedReader( new InputStreamReader(is));
//
Get the request line of the HTTP request message.
String
requestLine = br.readLine();
System.out.println();
System.out.println(requestLine);
//
Get and display the header lines.
String
headerLine = null;
while
((headerLine = br.readLine()).length() != 0) {
System.out.println(headerLine);
}
//Beginning
of part B
//
Extract the filename from the request line.
StringTokenizer
tokens = new StringTokenizer(requestLine);
tokens.nextToken(); // skip over the method, which should be
"GET"
String
fileName = tokens.nextToken();
//
Prepend a "." so that file request is within the current directory.
fileName
= "." + fileName;
//
Open the requested file.
FileInputStream
fis = null;
boolean
fileExists = true;
try
{
fis
= new FileInputStream(fileName);
}
catch (FileNotFoundException e) {
fileExists
= false;
}
//
Construct the response message.
String
statusLine = null;
String
contentTypeLine = null;
String
entityBody = null;
if
(fileExists) {
statusLine
= "HTTP/1.0 200 OK" + CRLF;
contentTypeLine
= "Content-type: " + contentType( fileName ) + CRLF;
}
else {
statusLine
= "HTTP/1.0 404 Not Found" + CRLF;
contentTypeLine
= "Content-type: text/html" + CRLF;
entityBody
= "<HTML>" + CRLF +
"<HEAD><TITLE>Not
Found</TITLE></HEAD>" + CRLF +
"<BODY>Not
Found< Home
| About Me | Text Depository | Future
Enhancements | Guest Book | Links
All Rights Reserved.
}
//
Send the status line.
os.writeBytes(statusLine);
//
Send the content type line.
os.writeBytes(contentTypeLine);
//
Send a blank line to indicate the end of the header lines.
os.writeBytes(CRLF);
//
Send the entity body.
if
(fileExists) {
sendBytes(fis,
os);
fis.close();
}
else {
os.writeBytes(entityBody);
}
//
Close streams and socket.
os.close();
br.close();
socket.close();
System.out.println("Connection
closed.");
}
private static void
sendBytes(FileInputStream fis, OutputStream os) throws Exception
{
//
Construct a 1K buffer to hold bytes on their way to the socket.
byte[]
buffer = new byte[1024];
int
bytes = 0;
//
Copy requested file into the socket's output stream.
while((bytes
= fis.read(buffer)) != -1 ) {
os.write(buffer,
0, bytes);
}
}
private static String contentType(String
fileName)
{
if(fileName.endsWith(".htm")
|| fileName.endsWith(".html")) {
return
"text/html";
}
if(fileName.endsWith(".jpg")
|| fileName.endsWith(".jpeg")) {
return
"image/jpeg";
}
if(fileName.endsWith(".gif"))
{
return
"image/gif";
}
//Following lines include the five extra mime
extensions.
if(fileName.endsWith(".txt")
|| fileName.endsWith(".text")) {
return
"text/plain";
}
if(fileName.endsWith(".au"))
{
return
"audio/basic";
}
if(fileName.endsWith(".mpg")
|| fileName.endsWith(".mpeg")) {
return
"video/mpeg";
}
if(fileName.endsWith(".avi"))
{
return
"video/avi";
}
if(fileName.endsWith(".ps"))
{
return
"application/PostScript";
}
return
"application/octet-stream";
}
}
<<END SOURCE
WebServer.java>>
The following excerpt is copied from the java class
WebServer after a request was made by Microsoft’s Internet Explorer version 5.5
on a SeasNet machine, the request line is http://olvera:65534/
in this case the server applet was run from the olvera machine and the applet
uses the port specified as 65534.
Connection
made on port: 65534
[This line was generated
by the applet which I added to inform the server console that a connection was
made on the specified port]
GET
/ HTTP/1.0
[The
specification of RFC 1945 states that there are 4 primary commands, GET, HEAD,
POST, and extension-method. In this
situation we used the GET command. The
following fowardslash signifies that the file that we wish to get, the
WebServer will interpret this to mean the directory the WebServer applet was
run from. The next part HTTP signifies
the protocol being used, and the number following the / is the version(1.0) of
the HTTP protocol that is implemented by the client.]
Accept:
application/vnd.ms-excel, application/msword, application/vnd.ms-powerpoint,
image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-comet, */*
[The
accept request-header field is used to indicate a list of media ranges which
are acceptable as a response to the request, a * indicates all, so a */*
indicates all types and subtypes are accepted, while a type/* indicates all
subtypes of type type is accepted]
Accept-Language:
en-us
[This field is similar to accept except that it
indicates which set of natural languages are preferred in the response to the
client. In our case it is English-us]
User-Agent:
Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0)
[This field contains information about the user agent
and version number originating the request.
This is for statistical purposes, the tracing of protocol violations,
the automated recognition of user agents for the sake of tailoring responses to
avoid particular user agent limitations.
The items in parenthesis provide more details about the user agent.]
Host:
olvera:65534
[This field simply states the host name and the port
number the format of this field should be as follows Hostname[:portnumber]
where the port number is optional]
Connection:
Keep-Alive
[This field does not appear in RFC 1945. The client is trying to request a persistent
connection with the server in which the connection remains open after the
message is sent.]
Connection
closed.
[This line was also
generated by the applet, also added by me, in order to inform the server
console the connection was closed.]