Parse an HTTP request from browser on local server : Java - java

I'm trying to make a simple HTML server that will read a request from my browser, parse the requested file from the request, then serve the appropriate HTML back to the browser. I need to be able to handle multiple requests, so I currently have a Server class acting as a parent of another runnable class RequestHandler. Each time a connection is made on the server, a new instance of the runnable class RequestHandler is run.
package server;
import java.io.IOException;
import java.net.ServerSocket;
public class Server {
public static void main(String[] args){
try{
ServerSocket serverSocket = new ServerSocket(8000);
for(;;){
Object block = new Object();
RequestHandler handler = new RequestHandler(block, serverSocket);
handler.start();
try{
synchronized(block){
System.out.println("Server thread paused...");
block.wait();
System.out.println("Server thread creating new RequestHandler...");
}
}catch(InterruptedException e){
System.out.println("Can't be interrupted!");
e.printStackTrace();
}
}
}catch(IOException e){
System.out.println("IOException!");
e.printStackTrace();
}
}
}
package server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class RequestHandler extends Thread {
Object block;
ServerSocket serverSocket;
BufferedReader socketReader;
PrintWriter socketWriter;
public RequestHandler(Object block, ServerSocket serverSocket){
this.block = block;
this.serverSocket = serverSocket;
}
#Override
public void run() {
try{
System.out.println("Waiting for request...");
Socket clientSocket = serverSocket.accept();
System.out.println("Connection made.");
synchronized(block){
System.out.print("Notifying server thread...");
block.notify();
System.out.println("...done");
}
socketReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
socketWriter = new PrintWriter(clientSocket.getOutputStream(), true);
String input;
while((input = socketReader.readLine()) != null){
System.out.println(input);
}
}catch(IOException e){
System.out.println("IOException!");
e.printStackTrace();
}
}
}
The problem I'm running into is that I'm not sure how to combine all the lines of the request so that I can parse the requested file. If it's just constantly waiting on request input, I'll never get to a point where I can parse the entirety of the request. How can I solve this problem?

your while loop will only break once the connection between the client and the server is closed. Since the client is waiting on the same connection for a response after sending the request the connection will remain open, so your readline() will block. In your while loop you have to check after every line whether you have reached the end of the request data. For GET requests, you have to look for a blank line following HTTP headers. For POST requests, you have to parse incoming headers looking for <Content-Length: N>. THen process the remaining headers looking for the blank line (just like in the GET case). Once you find the blank like, you have to read <N> bytes. At this point you know you've finished processing request data and should break out of the read loop.
Read the HTTP spec for details.

The first line gives you the request method as well as the requested path, the following lines are the request headers, the header block ends with a blank line.
That said, you are reinventing the wheel: you could use com.sun.net.httpserver.HttpServer

Related

File upload using ServerSocket & HTML Client. Stuck at InputStream.read()

To understand the concept of socket programming, I created a server and a client. The client will send a file and server should save it some location. (ie. a file upload).
Server:
package com.test.socket.server;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class WebServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8081);
Socket socket = serverSocket.accept();
System.out.println("Received request");
InputStream inputStream = socket.getInputStream();
OutputStream out = new FileOutputStream("yoyo.png");
System.out.println("Reading....");
byte[] bytes = new byte[16 * 1024];
int count = 0;
while((count = inputStream.read(bytes)) > 0){
System.out.print(". ");
out.write(bytes,0,count);
System.out.println("Some bytes are written");
}
System.out.println("written....");
socket.getOutputStream().write("Written.....".getBytes());
out.close();
inputStream.close();
socket.close();
serverSocket.close();
}
}
Java client follows:
package com.test.socket.client;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class WebClient {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = null;
String host = "127.0.0.1";
socket = new Socket(host, 8081);
///home/renju/Desktop/frame.png
File file = new File("/home/renju/Desktop/frame.png");
InputStream inputStream = new FileInputStream(file);
OutputStream os = socket.getOutputStream();
byte[] bytes = new byte[16 * 1024];
int count = 0;
while((count = inputStream.read(bytes)) > 0){
os.write(bytes);
}
System.out.println("Sending....");
os.close();
inputStream.close();
socket.close();
}
}
This works fine and writes the uploaded file to my projects root folder.
Now I changed the client to an HTML page.
HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="http://127.0.0.1:8081/" method="POST">
<input type="file" name="file" />
<button type="submit" name="submit">Upload</button>
</form>
</body>
</html>
This is not working in the same fashion as the Java client. For some reason, the execution does not go beyond the out.write(bytes); of server code.
Console log..
Received request
Reading....
. Some bytes are written
What can be the possible reason?
One more question...
Ultimately what I am trying to understand is the purpose of 'multipart/form-data' while uploading a file(once I got the above code working, that is what I am planning to experiment). If someone could give me a hint on that, it will be really helpful.
This works fine.
No it doesn't. It writes junk at the end of the file, and possibly in other places as well. Your copy loop should be:
while((count = inputStream.read(bytes)) > 0){
System.out.print(". ");
out.write(bytes, 0, count);
}
in both server and client.
For some reason, the execution does not go beyond the out.write(bytes); of server code.
Actually it is blocking in read(), not write(). That is because you are now getting an HTTP request, and specifically it is because of HTTP keepalive. See RFC 2616 and successors. The server code you've written will write all the HTTP headers to the target file and then block until the client browser releases the connection, which can take an arbitrary amount of time. You need to read and parse the headers, specifically the Content-length and Content-encoding headers, and process the body of the request accordingly, which means only trying to read the number of bytes given in Content-length, not read to end of stream, and if the Content-encoding is chunked, you need to write some unchunking code.
From oracle docs:
A socket is one end-point of a two-way communication link between two
programs running on the network. Socket classes are used to represent
the connection between a client program and a server program. The
java.net package provides two classes--Socket and ServerSocket--that
implement the client side of the connection and the server side of the
connection, respectively.
Simple socket client is :
Socket echoSocket = new Socket(hostName, portNumber);
PrintWriter out =
new PrintWriter(echoSocket.getOutputStream(), true);
BufferedReader in =
new BufferedReader(
new InputStreamReader(echoSocket.getInputStream()));
The Socket constructor used here requires the name of the computer and the port number to which you want to connect.
Simple socket server is:
ServerSocket serverSocket = new ServerSocket(portNumber);
Socket clientSocket = serverSocket.accept();
PrintWriter out =
new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
ServerSocket is a java.net class that provides a system-independent implementation of the server side. To accept connection from client ServerSocket does:
clientSocket = serverSocket.accept();

Read server response using Java Sockets API

I have created a simple class which sends a string to a server, both communicate using Java Sockets API. The server reads what the client have sent, and responds with another string. But the client can not read that response.
This is the client class:
import java.io.IOException;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("localhost", 8181);
socket.getOutputStream().write("Hello".getBytes());
int read;
while ((read = socket.getInputStream().read()) > -1) {
System.out.print((char) read);
}
socket.close();
}
}
And this is the server class:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8181);
while (true) {
Socket socket = serverSocket.accept();
int read;
while ((read = socket.getInputStream().read()) > -1) {
System.out.print((char) read);
}
socket.getOutputStream().write("Hi!".getBytes());
}
}
}
I imagine that the problem may be in the client execution flow, because I don`t know how canI do it wait for a server response. In other words, how to implement a client able to read the server response?
You aren't closing the sockets.
The server is attempting to read until end of stream and then send a reply. End of stream only happens when the peer closes the connection, so it won't be possible to send a reply even after you fix (1). You need to read a message, whatever that means in your application protocol.
You need to flush or close the outputstream.

ServerSocket on port 80 is it correct?

I read some materials about ServerSocket and tried to listen on port 80 and print for example InetAddress of website which I was opening in web browser but my program couldn't do this. My code:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Site implements Runnable {
private int port;
Site(int port){
this.port = port;
}
public void run() {
try {
ServerSocket server = new ServerSocket(port);
while(true){
Socket socket = server.accept();
System.out.println(socket.getInetAddress());
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String args[]){
Thread thread = new Thread(new Site(80));
thread.start();
}
}
When I run my program I am only one time in the while loop and the program doesn't print System.out.println(socket.getInetAddress()) and as the result when I open my web browser and visit http sites I don't see any output. Do you know what I am doing wrong? Do you know any other ways to print InetAddress for currently open website? Any materials will by appreciate.
I can't comment without proper reputation so forgive me for throwing everything out here:
you might already have something listening on port 80
you might be running on a version of linux that restricts non root process binding to ports above 1024
you might be blocked by a software firewall

java Connection reset error

I am quite a newbie to Java. Please excuse me if you find this as a very basic question.There are many answers available already in stack overflow about this and I went through almost all the possible helps i can get in Stack overflow and also in some other forums. Unfortunately none of them helped me.
I have client/server program in which the client send a string to server and server just attaches another string to the string sent by client and sends it back to the client.
Server program looks like this.
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class server {
public static void main(String[] args) {
try
{
ServerSocket server = new ServerSocket(7300);
Socket s = server.accept();
DataInputStream inp = new DataInputStream(s.getInputStream());
DataOutputStream out = new DataOutputStream(s.getOutputStream());
String str =inp.readUTF();
str = str+" buddy!";
out.writeUTF(str);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
Client looks like This.
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.*;
public class client {
public static void main(String[] args) {
try
{
Socket s = new Socket("192.168.1.3",7300);
DataInputStream inp = new DataInputStream(s.getInputStream());
DataOutputStream out = new DataOutputStream(s.getOutputStream());
out.writeUTF("hi");
System.out.println(inp.readUTF());
Thread.sleep(2000);
out.writeUTF("hello");
System.out.println(inp.readUTF());
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
Everything works fine while client writes "hi" and when client starts sending "hello" i am getting Connection reset error. I am not getting what mistake am i doing please help me in resolving this.
The output with the error i am getting looks like this.
hi buddy!
java.net.SocketException: Connection reset by peer: socket write error
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(Unknown Source)
at java.net.SocketOutputStream.write(Unknown Source)
at java.io.DataOutputStream.write(Unknown Source)
at java.io.DataOutputStream.writeUTF(Unknown Source)
at java.io.DataOutputStream.writeUTF(Unknown Source)
at sokry.client.main(client.java:18)
In your server example, readUTF is only called once on the DataInputStream, even though the client wrote to the DataOutputStream twice. Thus, simply adding
str = inp.readUTF();
str = str + " buddy!";
out.writeUTF(str);
to your server example, after the last out.writeUTF(str), will solve your problem.
do comment on following line of your client.java file and try.it will work
Thread.sleep(2000);
`//out.writeUTF("hello");;
//System.out.println(inp.readUTF());
because when you are sending "hi" from client to server and server gives reply then it finished it work and it stop connection but in client.java you sending another request to server but server is at rest.
you should start server until client finish it work..
hope it will wait

Sending keyboard presses to another computer?

I was wondering if i could get help making or finding a program that has the ability to send keyboard presses and receive them on another computer. I want to use this to play multiplayer flash-player games with friends across computers. I know there are some programs out there like "logmein" but both users cannot use the keyboard at the same time. (When i press a key the computer user cannot press a key at the same time because it wont respond.) I only know java and I am quite novice at it. Im guessing if i need to write it ill have to send the information through a port or onto a web-server. I would like to know your opinions and suggestions for this program, thanks guys.
Basically what you are looking for is a chatroom program? Have you tried looking into mIRC?
mIRC is a free internet relay chat. What exactly are the requirements for the program? Is there a certain size that it must be? Are these flash games that you and your friends are playing taking up your full computer screen?
Building a program would require a web-server(any computer with internet access would do), and you would have to open the ports on your network to allow the traffic to go through.
A basic server in java would look something like this:
Please note that after the first connection this "server" will close the connection.
import java.net.ServerSocket;
import java.net.Socket;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class Server
{
private static ServerSocket serverSocket;
private static Socket clientSocket;
private static BufferedReader bufferedReader;
private static String inputLine;
public static void main(String[] args)
{
// Wait for client to connect on 63400
try
{
serverSocket = new ServerSocket(63400);
while(true){
clientSocket = serverSocket.accept();
// Create a reader
bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
// Get the client message
while((inputLine = bufferedReader.readLine()) != null)
{System.out.println(inputLine);}
serverSocket.close();
System.out.println("close");
}
}
catch(IOException e)
{
System.out.println(e);
}
}
}
And a client would almost be the same:
import java.net.Socket;
import java.io.PrintWriter;
public class client
{
private static Socket socket;
private static PrintWriter printWriter;
public static void main(String[] args)
{
try
{
//change "localhost" to the ip address that the client is on, and this number to the port
socket = new Socket("localhost",63400);
printWriter = new PrintWriter(socket.getOutputStream(),true);
printWriter.println("Hello Socket");
}
catch(Exception e)
{
System.out.println(e);
}
}
}
If I am not mistaken printWriter is a 16-bit operation, and in order to reduce lag, if you were just sending text then you might want to use printStream(). I believe that this might be a bit quicker.

Categories