Generating Http 301 Response Message - java

I'm trying to create a little web server and have be able to generate Http response messages 200, 301, and 404.
I am able to get 200 and 404 to work, but I am having problems with 301.
When I try to access a page that has "permanently moved" my browser doesn't get redirected and I get a java.lang.NullPointerException from java.
The way I have it determine if the code should be a 301 is it checks a list of strings for the file the client is trying to access, and if the original file they're trying to access has been moved, it will be in the list, along with it's new name/location. So if the original file is "index5.html" and it's been moved to "index.html" then they will be in an array and "index5.html" will be in an index 1 before "index.html"
I'm also just testing this on my own machine so I'm using localhost for the URL and using port 9012.
Here is my code:
import java.io.*;
import java.net.*;
import java.util.*;
public final class HttpRequest implements Runnable {
final static String CarrLine = "\r\n";
Socket clientSocket;
// A list of files that have been moved.
// Even indexes (0, 2, 4, ...) are the original file names.
// Odd indexes (1, 3, 5, ...) are where the files of previous indexes moved to.
static String movedFiles[] = {"index5.html", "index.html", "page.html", "homepage.html"};
// This sets the Httprequest object socket equal to
// the socket the client comes in through
public HttpRequest(Socket socket) throws Exception {
this.clientSocket = socket;
}
// Here we define a new method that overwrites the
// previous method in the Runnables class. This is done
// so that when an Http request is attempted, and
// something goes wrong, our whole web server will
// not fail and crash.
#Override
public void run(){
try {
// This is where the method to actually start the Http request starts.
requestProcessing();
} catch (Exception ex) { System.out.print(ex); }
}
// This is our main processing method to take in out Http request
// and spit out a reponse header along with the requested data,
// if there is any.
void requestProcessing() throws Exception {
Boolean fileExists = false;
String CarrLine = "\r\n";
String statusCode = null;
String responseHeader = "HTTP/1.1 ";
String fileName, line = null;
String clientSentence = null;
ArrayList<String> records = new ArrayList<String>();
FileInputStream requestedFileStream = null;
File requestedFile;
// Starts input from client and establishes filters
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
// Starts output stream for output to client through socket
DataOutputStream outToClient = new DataOutputStream(clientSocket.getOutputStream());
/*
// Reads in GET from client BufferedReader
while ( (line = inFromClient.readLine()) != null){
records.add(line);
break;
}*/
clientSentence = inFromClient.readLine();
// Parses and stores file name the client wants in a string
fileName = parseGET(clientSentence);
if (!existingFile(fileName)){
// Here is where the 301 response message is generated and
// retrieve the correct filename.
if (hasMoved(fileName) != -1){
statusCode = "301";
responseHeader = responseHeader + statusCode + " Moved Permanently\n";
responseHeader = responseHeader + "Location: localhost:9012/"
+ movedFiles[hasMoved(fileName)] + CarrLine;
}
// This generates the response header for the client
// if the file the client is looking for is not there (404).
else {
statusCode = "404";
responseHeader = responseHeader + statusCode + " Not Found: \n";
responseHeader = responseHeader + "Content-Type: text/html" + CarrLine;
}
}
// This generates the 200 status code response header
// to send to the client saying the file was found.
if (existingFile(fileName)) {
statusCode = "200";
responseHeader = responseHeader + statusCode + " OK: \n";
responseHeader = responseHeader + "Content-Type: " + fileType(fileName) + CarrLine;
requestedFileStream = openFileStream(fileName);
}
// Outputs the response message to the client through a data stream
outToClient.writeBytes(responseHeader);
outToClient.writeBytes(CarrLine);
// If the file the client is requesting exists,
// begin writing file out to client.
if (existingFile(fileName)){
fileWriteOut(requestedFileStream, outToClient);
requestedFileStream.close();
}
else if(hasMoved(fileName) != -1){
outToClient.writeBytes("File Moved");
}
// If the file the client is requesting does not exist,
// return a 404 message.
else {
outToClient.writeBytes("404: File not found!");
}
// Closes all open streams and sockets to the client.
inFromClient.close();
outToClient.close();
clientSocket.close();
}
// This parses the GET line from the client to get the filename the client is requesting
String parseGET(String clientString){
String temp[] = clientString.split(" /");
temp = temp[1].split(" ");
return temp[0];
}
// This is used to find the file the client is requesting.
// It will return null if no file was found/opened.
FileInputStream openFileStream(String file){
FileInputStream fileStream = null;
// Opening the file stream is in a try catch statment so that
// incase there was no file, the program doesn't crash
// and it'll alert the user on the console.
try {
fileStream = new FileInputStream(file);
} catch (FileNotFoundException e) {
System.out.println(e);
return null;
}
return fileStream;
}
// Determines the file type that is being sent to the client
// and returns the appropriate string
String fileType(String clientRequestFile){
// If the file ends in .html or .htm, it will return "text/html"
// so that it can be added to the response message.
if (clientRequestFile.endsWith(".html") || clientRequestFile.endsWith(".htm")){
return "text/html";
}
// If the file ends in .jpg, it will return "text/jpeg"
// so that it can be added to the response message.
if (clientRequestFile.endsWith(".jpg")){
return "text/jpg";
}
// If the file ends in .css, it will return "text/css"
// so that it can be added to the response message.
if (clientRequestFile.endsWith(".css")){
return "text/css";
}
// Returns this by default, if none of the above.
return "application/octet-stream";
}
// This creates a 2k buffer and writes out
// requested filed to the client.
static void fileWriteOut(FileInputStream clientStream, OutputStream toClient) throws Exception{
byte[] buffer = new byte[2048];
int bytes = 0;
while ((bytes = clientStream.read(buffer)) != -1){
toClient.write(buffer, 0, bytes);
}
}
// This determines whether or not a file that
// the client has requested exists or not.
// Returns a Boolean value.
static Boolean existingFile(String fileName){
File file = new File(fileName);
if (file.exists() && !file.isDirectory()){
return true;
}
return false;
}
// Determines if a file has been moved and if so,
// returns the index of the NEW file. Else it
// returns -1.
static int hasMoved(String fileName){
int i = 0;
for (i = 0; i < movedFiles.length; i=i+2){
if (movedFiles[i].equals(fileName)){
return i+1;
}
}
return -1;
}
}
Could someone point me in the right direction to doing this correctly?
Thank you!

Okay, I figured it out.
It was because I was trying to define the entire "URL" in the 301 response messages.
So it should have been:
responseHeader = responseHeader + "Location: /" + movedFiles[hasMoved(fileName)] + CarrLine;
Instead of:
responseHeader = responseHeader + "Location: localhost:9012/" + movedFiles[hasMoved(fileName)] + CarrLine;

Related

BufferReader stuck in readline()

I am making an HTTP server and HTTP web client for simple Http request and response.
This is the code for Server
import java.io.*;
import java.net.*;
import java.util.*;
public final class WebServer{
public static void main(String[] args) throws Exception{
//storing port number
int port = 2048;
//open socket and wait for TCP connection
ServerSocket serverConnect = new ServerSocket(port);
System.out.println("Server started.\nListening for connections on port : " + port + " ...\n");
// we listen until user halts server execution
while (true) {
//Construct an object to process the HTTP request message.
//This will call another class where we do everything else
HttpRequest request = new HttpRequest(serverConnect.accept());
//create a new thread to process the request
Thread thread = new Thread(request);
thread.start();
} //end of while
}//end of main
}//end of the class webServer
The code for HttpRequest class is as follow:
import java.io.*;
import java.net.*;
import java.util.*;
final class HttpRequest implements Runnable{
final static String CRLF = "\r\n";
Socket socket;
//start of constructor
public HttpRequest(Socket socket) throws Exception{
this.socket=socket;
}//end of constructor
//Implement the run() method of the Runnable interface.
public void run(){
try{
processRequest();
}
catch(Exception e){
System.out.println(e);
}
}//end of run
private void processRequest() throws Exception{
//Get a reference to the scoket's input and output streams.
InputStream is = socket.getInputStream();
DataOutputStream os = new DataOutputStream(socket.getOutputStream());
//set up the stream filters
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//Get the request line of the HTTP request message.
String requestLine = br.readLine();
//Display the request line
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);
}
//System.out.println(requestLine);
//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;
//printing for test
//System.out.println(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 = tokens.nextToken();
contentTypeLine = "Content-type: " + contentType(fileName) + CRLF;
}
else{
statusLine = "HTTP/1.1 404 File Not Found";
contentTypeLine = "Content-type: " + "text/html" + CRLF;
entityBody = "<html><head><title>Not Found </title></head>" +
"<BODY>Not Found</body></html>";
}
//send the status line
os.writeBytes(statusLine);
//send the content Type
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);
os.writeBytes(CRLF);
}
//Close scokets and streams.
fis.close();
os.close();
br.close();
socket.close();
}//end of processRequest
private static String contentType(String fileName){
if(fileName.endsWith(".htm") || fileName.endsWith(".html")){
return "text/html";
}
if(fileName.endsWith(".gif")){
return "image/gif";
}
if(fileName.endsWith(".jpeg") || fileName.endsWith(".jpg")){
return "image/jpeg";
}
return "application/octet-stream";
}// end of contentType
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 scoket's output stream.
while((bytes = fis.read(buffer)) != -1){
os.write(buffer, 0, bytes);
}//end of while
}//end of sendBytes
} // end of the class
The Code works fine when I make a request from Chrome webbrowser. However, I made WebClient as well. When I make request from WebClient, I am stuck as the program runs forever.
As far I have tracked, the pointer does not move from the br.readline on the while loops on the Server Side.
The code for my client is as follow.
import java.io.*;
import java.net.*;
import java.util.*;
public class WebClient{
final static String CRLF = "\r\n";
public static void main(String [] args) {
String serverName = args[0];
int port = Integer.parseInt(args[1]);
try {
// System.out.println("Connecting to " + serverName + " on port " + port);
Socket client = new Socket(serverName, port);
System.out.println("Just connected to " + client.getRemoteSocketAddress());
OutputStream outToServer = client.getOutputStream();
DataOutputStream out = new DataOutputStream(outToServer);
out.writeUTF("GET /" +args[2] +" HTTP/1.1");
out.writeUTF(CRLF);
out.writeUTF("Host: "+client.getLocalSocketAddress());
out.writeUTF(CRLF);
out.writeUTF("Connection: close" + CRLF);
out.writeUTF("User-agent: close" + CRLF);
out.writeUTF(CRLF);
//Cache-Control: max-age=0
System.out.println("Just connected to 1 ");
InputStream inFromServer = client.getInputStream();
System.out.println("Just connected to 2 ");
BufferedReader br = new BufferedReader(new InputStreamReader(inFromServer));
System.out.println("Just connected to 3 ");
String headerLine = null;
while((headerLine = br.readLine()).length()!=0){
System.out.println("asd"+headerLine);
}
System.out.println("Just connected to 4 ");
client.close();
System.out.println("Just connected to 5 ");
} catch (IOException e) {
e.printStackTrace();
}
}
}//end of the class WebClient
Can anyone help me figure out the problem.
Thanks.
First of all, you have to remove line fis.close(); (right before os.close();) in your HttpRequest class: if no file exists, this line raises NullPointerException because fis is null, so after sending Not Found response to the browser, your server does not close the socket accepted from that browser, that's why even though you see Not Found in your browser, your request never ends.
Secondly, the reason of why your client gets stuck is writeUTF() method that you used for sending request header. Seems that this line out.writeUTF(CRLF); does not really send an empty string but adds some other UTF-related character(s) (you may notice that in your server's console output), so your server gets stuck at while((headerLine = br.readLine()).length()!=0) waiting for the client to send an empty string, but never receives it. You need to replace out.writeUTF(CRLF); with out.writeBytes(CRLF);.
Also, it makes little sense to use BufferedReader for receiving binary files from socket. Reader in general is used with character-input stream, so it is not applicable for your case. You may use InputStream instead, by replacing this fragment:
String headerLine = null;
while((headerLine = br.readLine()).length()!=0){
System.out.println("asd"+headerLine);
}
with this (I chose buffer size of 4096, you may replace it with your preferred value):
int readBytes;
byte[] cbuf = new byte[4096];
while((readBytes=inFromServer.read(cbuf, 0, 4096))>-1){
System.out.println("read: " + readBytes);
}
Note: You may easily notice here that InputStream.read() will fetch not only the file itself but also statusLine, contentTypeLine and two CRLFs, so in case if you would like to separate them from the file, you may read them first, by issuing two "readLines" and then fetch the file only by read()
In your server, you use writeBytes()
Writes out the string to the underlying output stream as a sequence of bytes. Each character in the string is written out, in sequence, by discarding its high eight bits. If no exception is thrown, the counter written is incremented by the length of s.
While you may worry about non-ASCII text, generally this is what you need.
In your client you attempt to use writeUTF()
First, two bytes are written to the output stream as if by the writeShort method giving the number of bytes to follow. This value is the number of bytes actually written out, not the length of the string. Following the length, each character of the string is output, in sequence, using the modified UTF-8 encoding for the character. If no exception is thrown, the counter written is incremented by the total number of bytes written to the output stream. This will be at least two plus the length of str, and at most two plus thrice the length of str.
While that 2-byte length in the beginning can be useful in other cases, it is not what web servers expect, including yours (and that is correct). So use writeBytes() everywhere in your client, and it will suddenly work:
out.writeBytes("GET /" +args[2] +" HTTP/1.1");
out.writeBytes(CRLF);
out.writeBytes("Host: "+client.getLocalSocketAddress());
out.writeBytes(CRLF);
out.writeBytes("Connection: close" + CRLF);
out.writeBytes("User-agent: close" + CRLF);
out.writeBytes(CRLF);
In fact those extra bytes may be visible in your server output, at least when I ran it in Eclipse, I saw garbage characters, as a combination of mysterious empty space and a tiny question mark in a rectangle (note how they also appear at the end of the lines when CRLF is sent separately):
(The first request is the one issued with writeUTF, and the second one comes from Chrome)

Sending HTTP request's

I am writing a web client. I have the following code.
public class Connection extends Thread{
public final static int PORT = 1337;
private ServerSocket svrSocket = null;
private Socket con = null;
public Connection(){
try{
svrSocket = new ServerSocket(PORT);
System.out.println("Conected to: " + PORT);
}catch(IOException ex)
{
System.err.println(ex);
System.out.println("Unable to attach to port");
}
}
public void run(){
while(true)
{
try{
con = svrSocket.accept();//on this part the program stops
System.out.println("Client request accepted");
PrintWriter out = new PrintWriter(con.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
out.println("GET /<index.html> HTTP/1.1");
out.println("***CLOSE***");
System.out.println(in.readLine());
/*
String s;
while((s = in.readLine()) != null)
{
System.out.println(s);
}*/
out.flush();
out.close();
in.close();
con.close();
System.out.println("all closed");
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
}
}
The run method will be used latter on. That I have is a file called index.html. This file is in the same file as the java code. What I am trying to do with the request is send the HTML file. But if I run this program on a web browser localhost:1337 the following gets displayed.
GET /<index.html> HTTP/1.1
***CLOSE***
This should not get displayed. The page that results of the HTML code in the index.html should get displayed.
Index.html code:
<html>
<head>
<title> </title>
</head>
<body bgcolor = "#ffffcc" text = "#000000">
<h1>Hello</h1>
<p>This is a simple web page</p>
</body>
</html>
How do I get this html page to display in the browser?
Thank you
t seems that all is good on your code, it seems you need to read the HTTP header from the input stream so you can get the requested file name and then use the Socket output stream to write the response from the file.
OutputStream output = con.getOutputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String fileName = readHeader(in);
String baseDir = System.getProperty("my.base.dir", "/home/myname/httpserver");
boolean exist = true;
InputStream fileIn = null;
try {
File requestedFile = new File(baseDir, fileName);
fileIn = new FileInputStream(requestedFile);
} catch(Exception e){
exist = false;
}
String server = "Java Http Server";
String statusLine = null;
String typeLine = null;
String body = null;
String lengthLine = "error";
if (exist) {
statusLine = "HTTP/1.0 200 OK" + "\r\n";
//get content type by extension
typeLine = "Content-type: html/text \r\n";
lengthLine = "Content-Length: " + (new Integer(fileIn.available())).toString() + "\r\n";
} else {
statusLine = "HTTP/1.0 404 Not Found" + CRLF;
typeLine = "text/html";
body = "<HTML>" + "<HEAD><TITLE>404</TITLE></HEAD>" + "<BODY>404 Not Found"+"</BODY></HTML>";
}
output.write(statusLine.getBytes());
output.write(server.getBytes());
output.write(typeLine.getBytes());
output.write(lengthLine.getBytes());
output.write("\r\n".getBytes());
if (exist) {
byte[] buffer = new byte[1024];
int bytes = 0;
while ((bytes = fileIn.read(buffer)) != -1) {
output.write(buffer, 0, bytes);
}
} else {
output.write(body.getBytes());
}
//close sreams
You are confusing a couple of things. First of all: what you are writing is a server, not a client.
Second: You are not following the HTT Protocol.
The line GET /<index.html> HTTP/1.1 (which is wrong, it should be GET /index.html HTTP/1.1) is a request that is sent by the client (like a web browser). Instead, it is your server sending this.
A quick solution:
Instead of sending this static text (the line with the GET and the one with the ***CLOSE***), read the content of your index.html file and print it to your out stream.
EDIT: Here's a quick overview of the http data flow:
The client (e.g. a browser) connects to the server
The client sends it's request, something like
GET /theFileIWant.html HTTP/1.1\r\n
Host: localhost\r\n
\r\n
at this point, the client usually stops sending anything and waits for the server to respond. That is called the "request/response" model.
The server reads the request data and finds out what it has to do.
The output (in this case: a file's content) is sent to the client, preceded by HTTP response headers.
The connection can be kept open or closed, depending on the HTTP headers of both client's request and server's response.

Passing value from applet to PHP

I want to send values of two variables to a PHP file from a Java applet), and I tried the following code.
try {
URL url = new URL(getCodeBase(),"abc.php");
URLConnection con = url.openConnection();
con.setDoOutput(true);
PrintStream ps = new PrintStream(con.getOutputStream());
ps.print("score="+score);
ps.print("username="+username);
con.getInputStream();
ps.close();
} catch (Exception e) {
g.drawString(""+e, 200,100);
}
I got the following error:
java.net.UnknownServiceException:protocol doesn't support output
java.net.UnknownServiceException:protocol doesn't support output
Means that you are using a protocol that doesn't support output.
getCodeBase() refers to a file url, so something like
file:/path/to/the/applet
The protocol is file, which doesn't support outout. You are looking for a http protocol, which supports output.
Maybe you wanted getDocumentBase(), which actually returns the web page where the applet is, i.e.
http://www.path.to/the/applet
Here's some code I used with my own applet, to send values (via POST) to a PHP script on my server:
I would use it like this:
String content = "";
content = content + "a=update&gid=" + gid + "&map=" + getMapString();
content = content + "&left_to_deploy=" + leftToDeploy + "&playerColor=" + playerColor;
content = content + "&uid=" + uid + "&player_won=" + didWin;
content = content + "&last_action=" + lastActionCode + "&appletID=" + appletID;
String result = "";
try {
result = requestFromDB(content);
System.out.println("Sending - " + content);
} catch (Exception e) {
status = e.toString();
}
As you can see, I am adding up all my values to send into a "content" string, then calling my requestFromDB method (which posts my "request" values, and returns the server's response) :
public String requestFromDB(String request) throws Exception
{
// This will accept a formatted request string, send it to the
// PHP script, then collect the response and return it as a String.
URL url;
URLConnection urlConn;
DataOutputStream printout;
DataInputStream input;
// URL of CGI-Bin script.
url = new URL ("http://" + siteRoot + "/globalconquest/applet-update.php");
// URL connection channel.
urlConn = url.openConnection();
// Let the run-time system (RTS) know that we want input.
urlConn.setDoInput (true);
// Let the RTS know that we want to do output.
urlConn.setDoOutput (true);
// No caching, we want the real thing.
urlConn.setUseCaches (false);
// Specify the content type.
urlConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
// Send POST output.
printout = new DataOutputStream (urlConn.getOutputStream ());
printout.writeBytes (request);
printout.flush ();
printout.close ();
// Get response data.
input = new DataInputStream (urlConn.getInputStream ());
String str;
String a = "";
while (null != ((str = input.readLine())))
{
a = a + str;
}
input.close ();
System.out.println("Got " + a);
if (a.trim().equals("1")) {
// Error!
mode = "error";
}
return a;
} // requestFromDB
In my PHP script, I would only need to look at $_POST for my values. Then I would just print a response.
Note! Your PHP script MUST be on the same server as the applet for security reasons, or this will not work.

Http client 408 status code

I am working on building my own http client. I got it working but tried to clean up the code and make it more efficient. No syntax errors or run time errors. However for some reason when I run the program it hangs when it tries to send the first GET request and ends up timing out with this message:
408 Request Time-out: Server timeout waiting for the HTTP request from the client.
This is my entire class.
public class MyHttpClient {
//Variables
String host;//Host name
int port; //port number to connect to
String path; //Path of resource being requested
String method; //Type of method (GET or POST)
String blankLine = "\r\n"; //Carriage return
String line; //Hold Strings returned from server
int status; //Hold the response code
String description; //Hold the response code description
String name; //Hold name of NameValuePair
String value;//Hold value of NameValuePair
String body; //Hold the body of the response
String queryString;//Hold the query string of the request
int length; //Hold the content length being sent to server
public MyHttpResponse execute(MyHttpRequest request) throws IOException {
//Create the Http response object
MyHttpResponse response = new MyHttpResponse();
//Establish a connection to the server
//Get host and port
host = request.getHost();
port = request.getPort();
Socket connectionSocket = new Socket(host,port);
//Create I/O streams
//input
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
//output
DataOutputStream outToServer = new DataOutputStream(connectionSocket.getOutputStream());
//Get the file path
path = request.getPath();
//Get the type of method
method = request.getMethod();
//Handle GET request
if(method.equalsIgnoreCase("GET")){
System.out.println(host + " " + port + " " + path);
//REQUEST
//Construct the GET request and send to server via output stream
outToServer.writeBytes("GET " + path + " HTTP/1.0" + "\r\n"); //Request line
outToServer.writeBytes("Host: localhost.com" + "\r\n"); //GET request headers
outToServer.flush();
//RESPONSE
//Read in the response from the server
line = inFromServer.readLine();
//Check the status code & assign to response - if not 200 throw error!
status = Integer.parseInt(line.substring(9,12));
response.setStatus(status);
//Get the status code description & assign to response - if 200 should be OK.
description = line.substring(13);
response.setDescription(description);
//Get the response headers
do{
line = inFromServer.readLine();
if(line != null){
name = line.substring(0, line.indexOf(":"));//Key
value = line.substring(line.indexOf(":"));//Value
response.addHeader(name, value);//Add to response object
}
}while(line != null && line.length() == 0);
//Do the above loop until a blank line is reached. This indicates
//the end of the headers and the start of the content.
//Get the body (content) - After a blank line
StringBuilder sb = new StringBuilder();
do{
line = inFromServer.readLine();
if(line != null){
sb.append(line).append("\n");
}
}while(line != null);
//Loop until there is no more lines left.
//Convert the data to a string and set it as the response object's body.
body = sb.toString();
response.setBody(body);
}
//Handle POST request
if(method.equalsIgnoreCase("POST")){
//REQUEST
//Get the query string from request and it's length
queryString = request.getQueryString();
length = queryString.length();
//Construct the POST request and send to the server via the output stream
outToServer.writeBytes("POST: " + path + " HTTP/1.0" + blankLine);//Request line
outToServer.writeBytes("Host: localhost.com" + blankLine);//Header lines
outToServer.writeBytes("Content-Type: application/x-www-form-urlencoded" + blankLine);
outToServer.writeBytes("Content-Length: " + String.valueOf(length) + blankLine);
outToServer.writeBytes(blankLine); //blank line to indicate end of headers and start of body
outToServer.writeBytes(queryString);//query string "hidden" in POST request body, in GET this query string is "visible",added to the url.
outToServer.flush();
//RESPONSE
//read the response and get the status code and assign to the response
line = inFromServer.readLine();
status = Integer.parseInt(line.substring(9,12));
response.setStatus(status);
//get the response status description and assign to response
description = line.substring(13);
response.setDescription(description);
//read the response headers
do{
line = inFromServer.readLine();
if(line != null){
name = line.substring(0, line.indexOf(":"));
value = line.substring(line.indexOf(":"));
response.addHeader(name, value);
}
}while(line != null && line.length() == 0);
//(above)Same as GET - loop through the headers until blank line reached
//indicating the start of the response body.
//read the response body (content)
StringBuilder sb = new StringBuilder();
do{
line = inFromServer.readLine();
if(line != null){
sb.append(line).append("\n");
}
}while(line != null && line.length() == 0);
//(above)Loop through until there is a blank line - end of the content
//Convert to string and assign as response body.
body = sb.toString();
response.setBody(body);
}
//Close the connection to the server
connectionSocket.close();
//Return the response
return response;
}
}//END OF CLASS
Can anyone see what might be causing it? The one thing I changed from my original working code was the output stream from:
s.getOutputStream().write(("GET " + path + " HTTP/1.0\r\n").getBytes("ASCII"));
to use a DataOutputStream
outToServer.writeBytes("GET " + path + " HTTP/1.0" + "\r\n");
As soon as I posted the question I realised my error. I forgot to put a blank line after the GET request headers.
This fixed it:
//Construct the GET request and send to server via output stream
outToServer.writeBytes("GET " + path + " HTTP/1.0" + "\r\n"); //Request line
outToServer.writeBytes("Host: localhost.com" + "\r\n"); //GET request headers
outToServer.writeBytes(blankLine);
outToServer.flush();

How-to Test/"Drive" HttpRequest.java (Web Server)?

I am writing simple, unsophisticated web-server code in java. It seems to be finished, but I'm not quite sure how to test it. Could someone point me in the right direction? All the coding is finished, I just need to test the code. I tried running it from the terminal, and then connecting to localhost with a specified port, but I only get 404 NOT FOUNDs. I reiterate, I don't think this is a problem with the code, but with my guessing at methods by which to test drive said code. Ideas?
import java.io.*;
import java.net.*;
import java.util.*;
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 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(".jpeg") || fileName.endsWith(".jpg")) {
return "image/jpeg";
}
if(fileName.endsWith(".gif")) {
return "image/gif";
}
return "application/octet-stream";
}
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 = new String(br.readLine());
// Display the request line.
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);
}
// 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 = "200 OK" + CRLF;
contentTypeLine = "Content-type: " +
contentType( fileName ) + CRLF;
} else {
statusLine = "404 NOT FOUND" + CRLF;
contentTypeLine = "Content Not Found!" + CRLF;
entityBody = "<HTML>" +
"<HEAD><TITLE>Not Found</TITLE></HEAD>" +
"<BODY>Not Found</BODY></HTML>";
}
// 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("File DNE: Content Not Found!");
}
// Close streams and socket.
os.close();
br.close();
socket.close();
}
public static void main(String[] args) throws Exception {
final ServerSocket ss = new ServerSocket(8080);
while (true)
new HttpRequest(ss.accept()).run();
}
}
Solution:
SOLVED. It turns out, to test it, all you need to do is:
1) run the program from the terminal as per usual,
2) place the file you want to try to retrieve (lets say "example.html") into the same folder as your .java file(s),
3) in a separate terminal, run the command $ wget localhost:PORT/FILE.EXTENSION
(I used port 8080 here, so $ wget localhost:8080/example.html)
You should now see, in the folder you are currently sending the wget command from, an html response file "200 OK" or "404 File Not Server", along with the contents of the file if the former is true.
I was over-complicating this, as were the comments/replies... But it's done.
Guessing and checking ftw.
SOLVED. It turns out, to test it, all you need to do is:
1) run the program from the terminal as per usual,
2) place the file you want to try to retrieve (lets say "example.html") into the same folder as your .java file(s),
3) in a separate terminal, run the command $ wget localhost:PORT/FILE.EXTENSION
(I used port 8080 here, so $ wget localhost:8080/example.html)
You should now see, in the folder you are currently sending the wget command from, a response file "200 OK" or "404 File Not Server", along with the contents of the file if the former is true.
I was over-complicating this, as were the comments/replies... But it's done.
Guessing and checking ftw.

Categories