Read and write on single socket in java - java

I have a socket server which accepts only one client socket connection. It will remember the connection and send response on the same. If client opens one more connection to the server with same host and port, then server will accept it but send response on last remembered socket connection. I don't know how server is able to do it as it is not in my control.
Below is code i tried. In my code, I am first creating Socket connection with server and storing it in Spring application context. For every request, I am getting it and using Input and Output Stream.
I am able to send one request and receive one response. But when i send second request, I do not get any response from server.
Please make a note that, server sends message length in first two bytes and appends the rest of the response.
For second response, I get header as 0000 and response as null.
Can somebody point me to example where client is creating only one socket with server and use its input and output stream for every request. Below is code i tried.
SocketConnector.java
public class SocketConnector {
LoggerUtil log = LoggerUtil.getInstance();
final String className = "SocketConnector";
#Value("${socket.host}")
String socketHost;
#Value("${socket.port}")
int socketPort;
#Value("${socket.connection.timeout}")
int socketConnectionTimeout;
#Value("${socket.read.timeout}")
int socketReadTimeout;
#Bean
Socket socketSocket(){
Socket s = new Socket();
final String methodName = "socketSocket";
try {
s.connect(new InetSocketAddress(socketHost, socketPort), socketConnectionTimeout); // Connection timeout set to 5 seconds with socket.
s.setSoTimeout(socketReadTimeout); // Read timeout set to 2 seconds. This means socket should send response in maximum of 2 second for every request.
log.doLog(3, className, methodName, "Created Socket Connection");
} catch (IOException e) {
log.doLog(3, className, methodName, LoggerUtil.getExStackTrace(e));
}
return s;
};
}
LogonScheduler.java
#Configuration
#EnableScheduling
public class LogonScheduler {
#Autowired
#Qualifier("socketSocket")
private Socket socketSocket;
private DataInputStream socketInputStream;
private OutputStream socketOutputStream;
static LoggerUtil log = LoggerUtil.getInstance();
final static String className = "LogonScheduler";
String logonResponse = null;
byte[] reqMsg = null;
byte[] msgLen = null;
byte[] header = null;
byte[] buf = null;
byte[] response = null;
int messageLen = -1;
/*#Scheduled(fixedDelay = 17500)*/
#Scheduled(fixedDelay = 10000)
public void logonSender(){
final String methodName = "logonSender";
try {
socketInputStream = new DataInputStream(socketSocket.getInputStream());
socketOutputStream = socketSocket.getOutputStream();
/*
* Created a byte array named buf and writing to socketOutputStream
* buf = createRequest();
*/
socketOutputStream.write(buf);
header = new byte[2];
socketInputStream.read(header, 0, 2);
messageLen = Integer.parseInt(bytetoHex(header), 16);
log.doLog(4, className, methodName, "Message length received :" + messageLen);
logonResponse = bytetoHex(header);
response = new byte[messageLen];
socketInputStream.readFully(response, 0, messageLen);
logonResponse += bytetoHex(response);
log.doLog(4, className, methodName, "Response Message with header : " + logonResponse);
logonResponse = logonResponse.substring(4);
log.doLog(4, className, methodName, "Response Message without header : " + logonResponse);
} catch (Exception e) {
e.printStackTrace();
}finally{
Utils.closeResources(logonResponse, reqMsg, msgLen, header, buf, response, messageLen);
}
}
public String bytetoHex(byte[] b) {
if (isEmpty(b)) {
return null;
}
String hex = "";
for (int i = 0; i < b.length; i++) {
hex += byteToHex(b[i]);
}
return hex;
}
// Returns hex String representation of byte b
public String byteToHex(byte b) {
char[] array = {hexDigit[(b >> 4) & 0x0f], hexDigit[b & 0x0f]};
return new String(array);
}
}

Related

Java - read register value by OBIS code with TCP client

I have connection to TCP server (ip,port) to which meter is connected. I'd like to read the specified data from this port because when I'm using standard read method it sends me the whole data stream which takes about 15 minutes to read. So my question: is there any method I can use to get one specified register's value using his OBIS code (1.1.1.8.0.255 - active energy taken) in java via TCP server?
import java.net.*;
import java.io.*;
public class scratch {
public static void main(String[] args) {
String hostname = "ip (hidden)";
int port = port (hidden);
try (Socket socket = new Socket(hostname, port)) {
OutputStream out = socket.getOutputStream();
InputStream input = socket.getInputStream();
InputStreamReader reader = new InputStreamReader(input);
int character;
StringBuilder data = new StringBuilder();
String test = "/?!\r\n";
byte[] req = test.getBytes();
out.write(req);
while ((character = reader.read()) != '\n') {
data.append((char) character);
}
System.out.println(data);
} catch (UnknownHostException ex) {
System.out.println("Server not found: " + ex.getMessage());
} catch (IOException ex) {
System.out.println("I/O error: " + ex.getMessage());
}
}
}
The message "test" send initiation request to meter and his respond is correct but I dont' know how to put flags (ACK STX ETX) in my request, I've tried something like this:
String test2 = (char)0x6 + "051\r\n";
byte[] req2 = test2.getBytes("ASCII");
out.write(req2);
But meter doesn't recognize it.

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)

Send DHT queries to "router.bittorrent.com" response garbled text

I read the DHT Protocol in bep_0005 page.
But when I send a ping query or a find_node query, the server response a garbled text (both of router.bittorrent.com:6881 or dht.transmissionbt.com:6881)
Here is the Java source code bellow
public String ping(final String id) {
System.out.println("Start ping:" + id);
Bencode bencode = new Bencode();
byte[] encoded = bencode.encode(new HashMap<Object, Object>() {
private static final long serialVersionUID = 4225164001818744013L;
{
put("t", "tr");
put("y", "q");
put("q", "ping");
put("a", new HashMap<Object, Object>() {
private static final long serialVersionUID = -6092073963971093460L;
{
put("id", id);
}
});
}
});
byte[] result = client.send(new String(encoded, bencode.getCharset()));
Map<String, Object> dict = bencode.decode(result, Type.DICTIONARY);
System.out.println("Bdecoded Data:" + dict);
return "";
}
Send Packets
ping Query = {"t":"aa", "y":"q", "q":"ping", "a":{"id":"abcdefghij0123456789"}}
bencoded = d1:ad2:id20:abcdefghij0123456789e1:q4:ping1:t2:aa1:y1:qe
Acrodding to the bep_0005 protocol the response with be like:
Response = {"t":"aa", "y":"r", "r": {"id":"mnopqrstuvwxyz123456"}}
bencoded = d1:rd2:id20:mnopqrstuvwxyz123456e1:t2:aa1:y1:re
But my response is:
Response = {ip=��P���, r={id=2�NisQ�J�)ͺ����F|�g}, t=tr, y=r}
bencoded = d2:ip6:��P���1:rd2:id20:2�NisQ�J�)ͺ����F|�ge1:t2:tr1:y1:re
Send udp part Java code is:
public byte[] send(String sendData) {
DatagramSocket client;
try {
client = new DatagramSocket();
client.setSoTimeout(5000);
byte[] sendBuffer;
sendBuffer = sendData.getBytes();
InetAddress addr = InetAddress.getByName("router.bittorrent.com");
int port = 6881;
DatagramPacket sendPacket = new DatagramPacket(sendBuffer, sendBuffer.length, addr, port);
client.send(sendPacket);
byte[] receiveBuf = new byte[512];
DatagramPacket receivePacket = new DatagramPacket(receiveBuf, receiveBuf.length);
client.receive(receivePacket);
System.out.println("Client Source Data:" + Arrays.toString(receivePacket.getData()));
String receiveData = new String(receivePacket.getData(), "UTF-8");
System.out.println("Client String Data:" + receiveData);
client.close();
return receivePacket.getData();
} catch (SocketException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
read the response in UTF-8 , but the iso-8859-1 is also a garbled text.
who can help me,thanks!
the server response a garbled text
No, the response is bencoded and contains raw binary data.
It CAN NOT be treated as text.
In BEP5, to make the raw binary node_id in the examples printable,
it has cleverly been chosen to consist of only alphanumeric characters.
See:
Bittorrent KRPC - Why are node ID's half the size of an info_hash and use every character a-z?
The ip key is a extension explained in: BEP42 - DHT Security extension
The received response is fully valid.
TODO: Working Java code
Map<String, Object> dict = bencode.decode(result, Type.DICTIONARY);
This gives you the decoded root dictionary of the message as Map. Within that you should find the r dictionary as another map and with in that map the id value. What type the id has will depend on the bedecoding library you are using.
If it is ByteBuffer or byte[] then you should have 20 bytes that you can hexencode (to 40 characters) if you need it to be human-readable. The DHT protocol deals in raw hashes, not hex values.
If it is a String then you will have to convert the string back into byte[] before hex-encoding it. That is only possible when the bdecoder used ISO 8859-1 to decode because that charset is roundtrip-safe while utf-8 is not for arbitrary byte sequences.

Java Proxy is not sending anything back to browser

I have created a proxy server in Java, (See code below), the thing is, I'm getting response back from the web-server however my client-side of the proxy which handles the connections between clients(browser) and the web-server after a socket has been created with the server side of the proxy. The server side creates a client and sends the request and socket and this is then handled in a new thread.
I have a few questions:
First Code is of the Client-side of the proxy second code part is of the Server-side of the proxy
What type of streams should I use when sending data between browser/proxy/webserver?
Is it fine to use a String or should I use some type of byte array when sending and receiving from streams?
Why is the browser not receiving anything from the proxy? Since I can print it out from the console but when writing to the stream nothing happens in the browser.
Also, why do I need to click "enter" twice in the browser for the proxy to react?
public class Client implements Runnable {
private String request;
private String response;
private Socket browserSocket;
public Client(String request, Socket browserSocket) {
this.request = request;
this.response = "";
this.browserSocket = browserSocket;
}
#Override
public void run() {
/* Send request to web server and get the response. */
this.request = Client.modifyHttpHeader("Connection", "close", this.request);
String hostName = Client.getHttpHeader("Host", this.request);
if (!hostName.isEmpty()) {
try {
/* Send request to the web-server. */
Socket socket = new Socket(hostName, 80);
OutputStreamWriter osw = new OutputStreamWriter(socket.getOutputStream());
PrintWriter pw = new PrintWriter(osw);
pw.write(this.request);
pw.flush();
System.out.println("---S:REQUEST---");
System.out.println(this.request);
System.out.println("---S:REQUEST---");
/* Receive the response from the web-server. */
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String response = "";
int tmpData;
while ((tmpData = br.read()) != -1) {
response += (char)tmpData;
}
this.response = response;
socket.close(); /* Close the socket between client-side and web-server. */
/* Send the response back to the browser. */
OutputStreamWriter oswbrowser = new OutputStreamWriter(this.browserSocket.getOutputStream());
PrintWriter pwBrowser = new PrintWriter(oswbrowser);
pwBrowser.write(this.response);
pwBrowser.flush();
pwBrowser.close();
this.browserSocket.close(); /* Close the socket between client-side and browser. */
System.out.println("---C:RESPONSE---");
System.out.println(this.response);
System.out.println("---C:RESPONSE---");
} catch (Exception e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
}
}
public String getHttpResponse() {
return this.response;
}
/**
*
* #param header
* The name of the HTTP header. Example: "GET".
* Note: Header name is case sensitive.
* #param request
* The HTTP message.
* #return
* On success: The value following the HTTP header ": " (colon and whitespace).
* On failure: Empty string.
*/
public static String getHttpHeader(String header, String request) {
int startHeaderIndex = request.indexOf(header) + header.length();
int endHeaderIndex = request.indexOf('\n', startHeaderIndex);
/* Could not find the searched header. */
if (startHeaderIndex == -1 || endHeaderIndex == -1)
return "";
/* Add 2 to remove ':' and ' '(white space). Decrement 1 to exclude '\r' and '\n' */
return request.substring(startHeaderIndex + 2, endHeaderIndex - 1);
}
/**
*
* #param header
* The name of the HTTP header. Example: "Connection"
* Note: The header is case sensitive.
* #param value
* The new value you want to put. Example: "Close"
* #param request
* The HTTP message.
* #return
* On success: A new HTTP request with the modified header value.
* On failure: Empty string.
*
*/
public static String modifyHttpHeader(String header, String value, String request) {
int startHeaderIndex = request.indexOf(header) + header.length();
int endHeaderIndex = request.indexOf('\n', startHeaderIndex);
/* Could not find the searched header. */
if (startHeaderIndex == -1 || endHeaderIndex == -1)
return "";
String newRequest = "";
/* Copy all characters including ':' and ' ' (whitespace) */
for (int i = 0; i < startHeaderIndex + 2; i++) {
newRequest += request.charAt(i);
}
newRequest += value;
newRequest += "\r\n";
/* Add the rest of the request. */
for (int i = endHeaderIndex + 1; i < request.length(); i++) {
newRequest += request.charAt(i);
}
return newRequest;
}
}
public class Server {
public static void main(String[] args) throws Exception{
/* Receiving and parsing port number from command line arguments. */
int ssPort = 0;
if (args.length > 1 || args.length == 0){
System.err.println("Only one argument allowed; port number (int).");
System.exit(1);
} else {
try {
ssPort = Integer.parseInt(args[0]);
} catch(NumberFormatException exception) {
System.err.println("Argument \"" + args[0] + "\" must be a number.");
System.exit(1);
}
}
ServerSocket serverSocket = new ServerSocket(ssPort); /* Creating the server socket. */
System.out.println("Proxy running on port: " + ssPort);
while(true) {
System.out.println("Waiting for client...");
Socket clientSocket = serverSocket.accept(); /* Listening for connections. */
BufferedReader bReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String request = "";
int tmpData;
while ((tmpData = bReader.read()) != -1) {
request += (char)tmpData;
}
Client clientObject = new Client(request, clientSocket);
Thread clientThread = new Thread(clientObject);
clientThread.start(); /* Start the client thread. */
}
}
}
Throw it all away. This isn't how proxies are written. An HTTP proxy should:
Read one line from the downstream client, to determine whom to connect to upstream, without buffering.
Connect upstream.
If (2) fails, send an appropriate HTTP response downstream and close the connection.
Otherwise, start copying bytes, in both directions, simultaneously.
You should not attempt to assemble the entire request, or even the headers, and the words 'bytes' and 'simultaneously' above are critical. Note that you don't have to do anything about HTTP keep-alive, Connection headers, HTTPS, etc.

Generating Http 301 Response Message

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;

Categories