Writing a simple HTTP server to accept GET requests - java

I'm trying to create a simple server that accepts a request, and then writes the content of a file to the browser that sent the request. The server connects and writes to the socket. However my browser says
no data received
and doesn't display anything.
public class Main {
/**
* #param args
*/
public static void main(String[] args) throws IOException{
while(true){
ServerSocket serverSock = new ServerSocket(6789);
Socket sock = serverSock.accept();
System.out.println("connected");
InputStream sis = sock.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(sis));
String request = br.readLine(); // Now you get GET index.html HTTP/1.1`
String[] requestParam = request.split(" ");
String path = requestParam[1];
System.out.println(path);
PrintWriter out = new PrintWriter(sock.getOutputStream(), true);
File file = new File(path);
BufferedReader bfr = null;
String s = "Hi";
if (!file.exists() || !file.isFile()) {
System.out.println("writing not found...");
out.write("HTTP/1.0 200 OK\r\n");
out.write(new Date() + "\r\n");
out.write("Content-Type: text/html");
out.write("Content length: " + s.length() + "\r\n");
out.write(s);
}else{
FileReader fr = new FileReader(file);
bfr = new BufferedReader(fr);
String line;
while ((line = bfr.readLine()) != null) {
out.write(line);
}
}
if(bfr != null){
bfr.close();
}
br.close();
out.close();
serverSock.close();
}
}
}

Your code works for me (data shows up in the browser), if I use
http://localhost:6789/etc/hosts
and there is a file /etc/hosts (Linux filesystem notation).
If the file does not exist, this snippet
out.write("HTTP/1.0 200 OK\r\n");
out.write(new Date() + "\r\n");
out.write("Content-Type: text/html\r\n");
out.write("\r\n");
out.write("File " + file + " not found\r\n");
out.flush();
will return data that shows up in the browser: Note that I have explicitly added a call to flush() here. Make sure that out is flushed in the other case as well.
The other possibility is to reorder your close statements.
A quote from EJP's answer on How to close a socket:
You should close the outermost output stream you have created from the socket. That will flush it.
This is especially the case if the outermost output stream is (another quote from the same source):
a buffered output stream, or a stream wrapped around one. If you don't close that, it won't be flushed.
So out.close() should be called before br.close().

Related

How do I send htm file to socket

I am trying to send this htm file to a web browser and have the browser display the contents of the file. When I run my code, all that happens is the browsers displays the name of the htm file and nothing else.
try
{
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
String input = in.readLine();
while (!input.isEmpty())
{
System.out.println("\tserver read a line: " + input);
input = in.readLine();
}
System.out.println("");
File myFile = new File ("hello.htm");
out.println("HTTP/1.1 200 OK");
out.println("Content-Type: text/html");
out.println("\r\n");
out.write(myFile);
out.flush();
out.close();
}
catch(Exception e)
{
System.out.println("\ncaught exeception: " + e + "\n");
}
You need to actually write the contents of the file to the stream:
...
BufferedReader in2 = new BufferedReader(new FileReader(myFile));
out.write("HTTP/1.1 200 OK\r\n");
out.write("Content-Type: text/html\r\n");
//Tell the end user how much data you are sending
out.write("Content-Length: " + myFile.length() + "\r\n");
//Indicates end of headers
out.write("\r\n");
String line;
while((line = in2.readLine()) != null) {
//Not sure if you should use out.println or out.write, play around with it.
out.write(line + "\r\n");
}
//out.write(myFile); Remove this
out.flush();
out.close();
...
The above code is just an idea of what you really should be doing. It takes into account the HTTP protocol.

The DataOutputStream text from Server to Client is indented weird and produces a 4

Right now, I'm trying to make a server that can display messages to the client when they connect (through localhost). When I connect through telnet, it gives me weird indentation. The code for the server is:
private ServerSocket middleman;
private int port = 8080;
private Socket client;
protected void createSocketServer()
{
try
{
while (true){
middleman = new ServerSocket(port);
client = middleman.accept();
middleman.close();
PrintWriter out = new PrintWriter(client.getOutputStream(),true);
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
String line;
//Client stuff
DataOutputStream dOut = new DataOutputStream(client.getOutputStream());
while((line = in.readLine()) != null)
{
System.out.println("echo: " + line);
dOut.writeByte(1);
dOut.writeUTF("Good day to you user. Here is a selection of poems " + "\n");
dOut.writeUTF("1. Cupcake Poem" + "\n");
dOut.flush();
//Response
if(line.equals("cupcake")){
try{
FileReader fileReader = new FileReader(poem);
BufferedReader bufferedReader = new BufferedReader(fileReader);
StringBuffer stringBuffer = new StringBuffer();
String poemLine;
while((poemLine = bufferedReader.readLine()) != null){
stringBuffer.append(poemLine);
stringBuffer.append("\n");
}
fileReader.close();
System.out.println("Contents of file:");
//System.out.println(stringBuffer.toString());
dOut.writeUTF(stringBuffer.toString());
dOut.flush();
} catch(IOException e){
e.printStackTrace();
}
}
else{
System.out.println("wrong!, the line is:" + line);
}
}
}
}
catch(IOException e)
{
System.out.println(e);
}
}
On the client side, I'll open the command prompt and type telnet localhost 8080 then I'll type something like "fish". It will print
[?]Good day to you user. here is a selection of poems
1. Cupcake Poem
Why does it do this? If I type "cupcake" on client, it will read the file, but have weird spacing. Is this something to do with Telnet?
For telnet the correct end-of-line sequence is "\r\n". Newline by itself will only go down to the next line, but it will not back up to the first column, which what the carriage-return does.
Also note that the order matters, the telnet specifications says that it has to be "\r\n", in that order.
Also, you don't have to append the output with the newline-sequence like you do. You can write it all as a single string:
dOut.writeUTF("1. Cupcake Poem\r\n");

Socket HTTP request returning invalid GZIP

I am teaching myself more about HTTP requests and such, so I wrote a simple POST request using Java's HttpURLConnection class and it returns compressed data which is easily decompress. I decided to go a lower level and send the HTTP request with sockets (for practice). I figured it out after a series of google searches, but there is one issue. When the server respondes with compressed data it isn't valid. Here is an image of a bit of debugging.
http://i.imgur.com/KfAcero.png
The portion below the "=" separator line is the response when using a HttpURLConnection instance, but the portion above it is the response when using sockets. I'm not too sure what is going on here. The bottom part is valid, while the top is not.
The HttpParameter and header classes simply store a key and value.
public String sendPost(String host, String path, List<HttpParameter> parameters, List<HttpHeader> headers) throws UnknownHostException, IOException {
String data = this.encodeParameters(parameters);
Socket socket = new Socket(host, 80);
PrintWriter writer = new PrintWriter(socket.getOutputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
writer.println("POST " + path + " HTTP/1.1");
for(HttpHeader header : headers) {
writer.println(header.getField() + ": " + header.getValue());
}
writer.println();
writer.println(data);
writer.flush();
StringBuilder contentBuilder = new StringBuilder();
for(String line; (line = reader.readLine()) != null;) {
contentBuilder.append(line + "\n");
}
reader.close();
writer.close();
return contentBuilder.toString();
}
Your problem is that you are using Readers and Writers for something that is not text.
InputStream and OutputStream work with bytes; Reader and Writer work with encoded text. If you try to use Reader and Writer with something that is not encoded text, you will mangle it.
Sending the request with a Writer is fine.
You want to do something like this instead:
InputStream in = socket.getInputStream();
// ...
ByteArrayOutputStream contentBuilder = new ByteArrayOutputStream();
byte[] buffer = new byte[32768]; // the size of this doesn't matter too much
int num_read;
while(true) {
num_read = in.read(buffer);
if(num_read < 0)
break;
contentBuilder.write(buffer, 0, num_read);
}
in.close();
writer.close();
return contentBuilder.toByteArray();
and make sendPost return a byte array.

How to receive plain Text through Socket in Java

I was trying to send plain text through Socket. So I found a post in StackOverflow, I followed it and I guess it that I did it write However, How can I accept that plain text as string in the client?
I used BufferedReader() and InputStreamReader() class, but exception has been thrown.
Exception : exception java.net.SocketException: Broken pipe
Here is the code:
Server:
OutputStreamWriter osw = new OutputStreamWriter(socket.getOutputStream(), "UTF-8");
osw.write(fileName, 0, fileName.length());
Client:
InputStream in = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String fileName = br.readLine();
br.close();
Some help would be great. :) Thank you.
Client side code:
public void soc_client() throws Exception {
long time = System.currentTimeMillis();
long totalRecieved = 0;
try {
Socket sock = new Socket("172.16.27.106", 55000);
System.out.println("Hello Client");
InputStream in = sock.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String fileName = br.readLine();
File outputFile = new File(fileName + "");
br.close(); // CLOSING BufferedReader
FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
byte[] buffer = new byte[100 * 1024];
int bytesRead = 0;
while ((bytesRead = in.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, bytesRead);
totalRecieved += bytesRead;
System.out.println("Recieved " + (totalRecieved / 1024)
+ " kilobytes in "
+ ((System.currentTimeMillis() - time) / 1000)
+ " seconds");
}
fileOutputStream.close();
sock.close();
} catch (Exception e) {
System.out.println("Exception " + e);
} finally {
System.out.println("Recieved " + totalRecieved + " bytes in "
+ (System.currentTimeMillis() - time) + "ms.");
}
}
You're reading a line but you aren't sending a line, and you aren't closing the OutputWriter either. So readLine() will block forever waiting for a line terminator or an EOS that is never coming.
Add a newline to the message.
Close the OutputWriter.
Well to use sockets to send and transfer text in client server fashion , i'm posting a simple basic code , which upon running send a HELLO WORLD response to client.
//Server Side
ServerSocket server= new ServerSocket(1166); // //1166 -port no. u can use any other too.
Socket s= server.accept(); // makes a connection whenever a client requests.
OutputStream os= socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
dos.writeUTF("Hello World");
dos.close();
// Client Side
Socket socket= new Socket("Ip address of you server" , 1166) ;
InputStream is= new InputStream();
DataInputStream dis = new DataInputStream(is);
String msg=dis.readUTF();
System.out.println(msg);
dis.close();
now after you run the code once on server computer , then run the client side code and the server will now respond you with Hello World.

How to use FileReader not to use BufferReader

How to use FileReader not to use BufferReader i want to use File,FileReader for this program of file reading from ftp
public class FileReader {
public final static String SERVER = "ftp://server.com";
public final static String USER_NAME = "user";
public final static String PASSWORD = "password";
public final static String FILE_NAME = "Sorting Cloumns Dynamically - Java Scripts.txt";
public static void main(String[] args) {
System.out.println("Connecting to FTP server...");
// Connection String
URL url;
try {
url = new URL("ftp://" + USER_NAME + ":" + PASSWORD + "#" + SERVER+ "/study/" + FILE_NAME +";type=i");
URLConnection con = url.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
System.out.println("Reading file start.");
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
}
catch (FileNotFoundException e) {
System.out.println("File not find on server.");
System.exit(0);
}catch (Exception e) {
e.printStackTrace();
}
System.out.println("Read File Complete.");
}
}
this code for i have created
You can't. A FileReader reads a file from the file system. It doesn't read from an FTP connection.
You have to convert the input stream into a file and then use File Reader.
URL url;
try {
url = new URL("ftp://" + USER_NAME + ":" + PASSWORD + "#" + SERVER
+ "/study/" + FILE_NAME + ";type=i");
URLConnection con = url.openConnection();
File tmpFile = new File("tmpFile.java");
OutputStream out = new FileOutputStream(f);
InputStream inputStream = con.getInputStream();
byte buf[] = new byte[1024];
int len;
while ((len = inputStream.read(buf)) > 0)
out.write(buf, 0, len);
out.close();
inputStream.close();
} catch (IOException e) {
}
The obove code creats a file object tmpFile from the input stream. You can use Filereader on this file object.
FileReader fileReader=new FileReader(tmpFile);
int ch= fileReader.read();
while(ch != -1){
System.out.print((char)ch);
ch = fileReader.read();
}
fileReader.close();
Notice that File Reader reads character by character.Thats why people prefer BufferedReader over it.
In general, each read request made of a Reader causes a corresponding read request to be made of the underlying character or byte stream. It is therefore advisable to wrap a BufferedReader around any Reader whose read() operations may be costly, such as FileReaders and InputStreamReaders. For example,
BufferedReader in
= new BufferedReader(new FileReader("foo.in"));
will buffer the input from the specified file. Without buffering, each invocation of read() or readLine() could cause bytes to be read from the file, converted into characters, and then returned, which can be very inefficient.
Why? The input isn't a file. You could write all the input to a file and then open a FileReader and try to remember to delete the file when finished, but what a colossal waste of time: reading the data twice. Simpler to adjust your API so you can supply a Reader or an InputStream.

Categories

Resources