Http Request never ends

Hi,

Well I had a few minutes on my hand and decided to build a simple socket application that handles a browser request with a 揾ello? Then I decided to complicate that a little and to actually send back what I receive. However the while loop that checked the input from the browser never ends (that is I never get a ? from inputStream.read() method).

Could someone please explain me why this happens? And how this could be solved? I mean how to detect that the request is over and it is time to respond. (In other words how can I base my response according to the request if I never know when the request is over!).

Here is the code I usedimport java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.net.ServerSocket;

import java.net.Socket;

publicclass Test7{

publicstaticvoid main(String[] args){

try{

ServerSocket serverSocket =new ServerSocket(9989);

while(true){

Socket socket = serverSocket.accept();

new Thread(new SimpleHttpHandler(socket)).run();

}

}

catch (Exception e){

e.printStackTrace();

}

}

}

class SimpleHttpHandlerimplements Runnable{

private Socket client;

public SimpleHttpHandler(Socket client){

this.client = client;

}

publicvoid run(){

try{

BufferedOutputStream outputStream =new BufferedOutputStream(

this.client.getOutputStream()

);

BufferedInputStream inputStream =new BufferedInputStream(

this.client.getInputStream()

);

int in = 0;

while((in = inputStream.read()) != -1){

System.out.print((char)in);

outputStream.write(in);

}

outputStream.close();

outputStream.flush();

}

catch(Exception e){

e.printStackTrace();

}

}

}

Regards,

Sim085

[3439 byte] By [sim085a] at [2007-11-27 5:07:47]
# 1
How about reading RFC? :)Request is over then header and content (if any) is over. Header stops with empty line and content length (if any) specified in header.
Michael.Nazarov@sun.coma at 2007-7-12 10:27:01 > top of Java-index,Java Essentials,Java Programming...
# 2

You are dealing with the HTTP protocol, which defines specific rules about request headers and optional content. For GET requests you have to read til a blank line "\r\n\r\n". For POST, you need to read from the blank line through the content length in the header.

So basically you could generalize that to read the header up to the blank line. Then parse that to see if there's more to read (if POST, read content-length bytes) and read through that.

But it's more complex in that there is a notion of Keep-Alive connections, which means the browser might send another request again after the response. In which case you have to account for that.

Web servers are not as simple internally as most people believe.

bsampieria at 2007-7-12 10:27:01 > top of Java-index,Java Essentials,Java Programming...
# 3

> Web servers are not as simple internally as most

> people believe.

No no, do not believe they are simple :) Just wanted to test a little with sockets :) Handling of Http Requests goes beyong to what I had in mind, but once I hit it, I actually wanted to solve it.

I am now using the following code to check if the request is ready:while(!(in = reader.readLine()).trim().equals("")){

However when I close the outputStream I get an exception:java.net.SocketException: Socket closed

at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:99)

at java.net.SocketOutputStream.write(SocketOutputStream.java:136)

at sun.nio.cs.StreamEncoder$CharsetSE.writeBytes(StreamEncoder.java:336)

at sun.nio.cs.StreamEncoder$CharsetSE.implClose(StreamEncoder.java:427)

at sun.nio.cs.StreamEncoder.close(StreamEncoder.java:160)

at java.io.OutputStreamWriter.close(OutputStreamWriter.java:222)

at java.io.BufferedWriter.close(BufferedWriter.java:250)

at SimpleHttpHandler.run(Test7.java:54)

at java.lang.Thread.run(Thread.java:595)

at Test7.main(Test7.java:17)

However if I do not close the connection, then the browser still waits for the response! I would really like to know how a true web server would handle this!

Btw - if I do not use the InputStream then I can close the OutputStream without any problem!

Regards,

Sim085

sim085a at 2007-7-12 10:27:01 > top of Java-index,Java Essentials,Java Programming...
# 4
Header end works for other side as well so you need to send empty line from server to client.Actually it's much better to act like normal server not stupid echo. Read complete request then send simple correct server header specifying text/plain content then received client header.
Michael.Nazarov@sun.coma at 2007-7-12 10:27:01 > top of Java-index,Java Essentials,Java Programming...
# 5

> Header end works for other side as well so you need

> to send empty line from server to client.

> Actually it's much better to act like normal server

> not stupid echo. Read complete request then send

> simple correct server header specifying text/plain

> content then received client header.

mmmm ... I understand, therefore the client needs to inform the server that he is ready to termine the connection or something like that right!?

I still did not read that RFC document coz I am on work! So sorry the assumptions I am making.

Regards,

Sim085

sim085a at 2007-7-12 10:27:01 > top of Java-index,Java Essentials,Java Programming...
# 6

A plain echo is probably not sufficient in that the browser is then looking for a proper response header and content. All the more reason to read the RFC and understand it if you really want to continue down the HTTP server route.

If you are just doing plain sockets for your own protocol, then your server is a reasonable start, and maybe just create another app that opens a socket to it and writes out to it.

bsampieria at 2007-7-12 10:27:01 > top of Java-index,Java Essentials,Java Programming...
# 7
> I still did not read that RFC document coz I am on work!So you can't read RFC but can read forums? :)Well if you want simplest way then just send header, data and close connection that's enough.
Michael.Nazarov@sun.coma at 2007-7-12 10:27:01 > top of Java-index,Java Essentials,Java Programming...
# 8
but your original check for -1 would mean your client would have to terminate the socket connection to get the server to end.
bsampieria at 2007-7-12 10:27:01 > top of Java-index,Java Essentials,Java Programming...
# 9

> So you can't read RFC but can read forums? :)

Can you imagine reading documentation about something by continuously minimizing and maximizing the browser window? (which I do when at work so to attract less attention) :)

> Well if you want simplest way then just send header,

> data and close connection that's enough.

Thanks :) I understand that now :)

@bsamperi & Michael.Nazarov@sun.com

The code I provided above was not correct. I fixed it and posted it again just in case someone else comes across this post. As already said this was not what I had in mind to do in the first place, but it was fun :) Anyways here is the working code! (Although naturally not good for anything)import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.OutputStreamWriter;

import java.net.ServerSocket;

import java.net.Socket;

public class Test7 {

public static void main(String[] args) {

try {

ServerSocket serverSocket = new ServerSocket(8871);

while(true){

System.out.println("Waiting for request");

Socket socket = serverSocket.accept();

new Thread(new SimpleHttpHandler(socket)).run();

}

}

catch (Exception e) {

e.printStackTrace();

}

}

}

class SimpleHttpHandler implements Runnable{

private final static String CLRF = "\r\n";

private Socket client;

private BufferedWriter writer;

private BufferedReader reader;

public SimpleHttpHandler(Socket client){

this.client = client;

}

public void run(){

try{

this.writer = new BufferedWriter(

new OutputStreamWriter(

this.client.getOutputStream()

)

);

this.reader = new BufferedReader(

new InputStreamReader(

this.client.getInputStream()

)

);

System.out.println("-- IN --\n" + this.read() + "\n");

System.out.println("-- OUT --\n" + this.write("Thank You"));

this.writer.close();

this.reader.close();

this.client.close();

System.out.println("Completed response");

System.out.println("--\n");

}

catch(Exception e){

e.printStackTrace();

}

}

private String read() throws IOException{

String in = "";

StringBuffer buffer = new StringBuffer();

while(!(in = this.reader.readLine()).trim().equals("")){

buffer.append(in + "\n");

}

return buffer.toString();

}

private String write(String out) throws IOException{

StringBuffer buffer = new StringBuffer();

buffer.append("HTTP/1.0 200 OK" + CLRF);

buffer.append("Content-Type: text/html" + CLRF);

buffer.append(CLRF);

buffer.append(out);

buffer.append(CLRF);

writer.write(buffer.toString());

return buffer.toString();

}

}

The output of this code is: Waiting for request

-- IN --

GET / HTTP/1.1

Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg,

application/vnd.ms-powerpoint, application/vnd.ms-excel,

application/msword, application/x-shockwave-flash, */*

Accept-Language: en-us

UA-CPU: x86

Accept-Encoding: gzip, deflate

User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2;

.NET CLR 1.1.4322; .NET CLR 2.0.50727)

Host: localhost:8871

Connection: Keep-Alive

-- OUT --

HTTP/1.0 200 OK

Content-Type: text/html

Thank You

Completed response

--

Waiting for request

-- IN --

GET /favicon.ico HTTP/1.1

Accept: */*

UA-CPU: x86

Accept-Encoding: gzip, deflate

User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2;

.NET CLR 1.1.4322; .NET CLR 2.0.50727)

Host: localhost:8871

Connection: Keep-Alive

-- OUT --

HTTP/1.0 200 OK

Content-Type: text/html

Thank You

Completed response

--

Waiting for request

...

Which shows that this application will handle any web request with a 揟hank You?since I am not basing the response on the request. However that should not be hard once the request and response are handled ok.

Thank to both of you for your help :)

Regards,

Sim085

sim085a at 2007-7-12 10:27:01 > top of Java-index,Java Essentials,Java Programming...