Working on a HTTP client program using Netbeans.
So far I have gotten to here in my HttpClient class:
public class MyHttpClient {
MyHttpRequest request;
String host;
public MyHttpResponse execute(MyHttpRequest request) throws IOException {
//Creating the response object
MyHttpResponse response = new MyHttpResponse();
//Get web server host and port from request.
String host = request.getHost();
int port = request.getPort();
//Check 1: HOST AND PORT NAME CORRECT!
System.out.println("host: " + host + " port: " + String.valueOf(port));
//Get resource path on web server from requests.
String path = request.getPath();
//Check 2: ENSURE PATH IS CORRECT!
System.out.println("path: " + path);
//Open connection to the web server
Socket s = new Socket(host, port);
//Get Socket input stream and wrap it in Buffered Reader so it can be read line by line.
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(s.getInputStream()));
//Get Socket output stream and wrap it in a DataOutputStream so it can be written to line by line.
DataOutputStream outToServer = new DataOutputStream(s.getOutputStream());
//Get request method
String method = request.getMethod();
//Check 3: ENSURE REQUEST IS CORRECT GET/POST!
System.out.println("Method: " + method);
//GET REQUEST
if(method.equalsIgnoreCase("GET")){
//Send request to server
outToServer.writeChars("GET " + path + " HTTP/1.0");
//HTTP RESPONSE
System.out.println("WAITING FOR RESPONSE!");
String line = inFromServer.readLine();
System.out.println("Line: " + line);
}
//Returning the response
return response;
}
}
I have checked to ensure my request line is constructed correctly, as seen in the print statements throughout. However when I get to this line the program hangs:
System.out.println("WAITING FOR RESPONSE!");
String line = inFromServer.readLine();
I have no idea why... My server is localhost WAMP. It is up and running correctly. I have the file I am requesting stored on the localhost. I can access it through browser.
Any ideas what might be going wrong??
No CR or LF is one of your problems. You should be writing ASCII characters and may be a Host header.
outToServer.write(("GET " + path + " HTTP/1.0\r\n").getBytes("ASCII"));
outToServer.write("Host: myhost.com\r\n\r\n".getBytes("ASCII"));
outToServer.flush();
Related
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)
Sorry if this seems like a dumb question, but I just start the ftp and webserver thing so I get a little bit confused about it, particularly about the InputStream, fileInputStream and outputStream etc this kind of concepts. So I try to extend the program I write called web server and make it act as a FTP client that request txt file only. So when request a text file (.txt) from within my web browser, the web server will not have a copy of this file. It will instantiate an FtpClient, retrieve the text file from your local FTP server and then send it back to your web browser as an HTTP response.
My code works fine for web server part, following is part of my code:
// 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));
...
// Extract the filename from the request line.
StringTokenizer tokens = new StringTokenizer(requestLine);
// skip over the method, which should be "GET"
tokens.nextToken();
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 = "HTTP/1.1 200 OK" + CRLF;
contentTypeLine = "Content-type: " + contentType(fileName) + CRLF;
}
// file doesn't exist
else {
// if the file requested is any type other than a text (.txt) file,
// report // error to the web client
if (!contentType(fileName).equalsIgnoreCase("text/plain")) {
statusLine = "404 Not Found" + CRLF;
contentTypeLine = "no content" + CRLF;
entityBody = "<HTML>" + "<HEAD><TITLE>Not Found</TITLE></HEAD>" + "<BODY>Not Found</BODY></HTML>";
} else {
String server = "127.0.0.1";
// else retrieve the text (.txt) file from your local FTP server
statusLine = "200 OK" + CRLF;
contentTypeLine = "Content-type: " + contentType(fileName) + CRLF;
// create an instance of ftp client
FTPClient ftp = new FTPClient();
// connect to the ftp server
ftp.connect(server);
ftp.login(userName, password);
// retrieve the file from the ftp server, remember you need to
// // first upload this file to the ftp server under your user
// ftp directory
ftp.retrieveFile("/folder1/"+ fileName.substring(1), os);
// disconnect from ftp server
ftp.disconnect();
// assign input stream to read the recently ftp-downloaded file
fis = new FileInputStream(fileName);
}
}
// 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(entityBody);
}
os.close();
br.close();
socket.close();
where things get confusing is that in the ftp retrieve part, I don't know if I use the correct method and if I should using "os" the DataOutputStream as argument or something else. Not fully understand the input and output stream thing. what I'm sure is that I want to use
fis = new FileInputStream(fileName);
after I retrieve the file from ftp server.
So can anyone tell me what should I use in the retrieve part?
Thanks!
I have a java program which accepts a http request from web browser and in response, program sends a text file contents to display in web browser. The program is working fine when I make request from browser which is installed on the same machine in which java code is running but when I make request from some other web browser which is not on the same machine as in which java code running, the program does not get any request.
This is how I make request from my web browser:-
http://localhost:port_number/
This is working fine...
This is how I make request from some other web browser which is not on my machine:
http://my_ip_address:port_number/
This is not working...
And this is my java code:-
while (true) {
ServerSocket serverSocket = null;
Socket clientSocket = null;
try {
serverSocket = new ServerSocket(32768);
clientSocket = serverSocket.accept();
InetAddress ia = clientSocket.getInetAddress();
jTextArea1.append("Connected to : " + ia + "\n");
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
String inputLine, outputLine;
String s = (String) JOptionPane.showInputDialog(this, "Enter File Name : ");
File f = new File(s);
if (f.exists()) {
out.println("http/1.1 200 ok\r");
out.println("Mime version 1.1");
out.println("Content-Type: text/html\r");
out.println("Content-Length: " + f.length() + "\r");
out.println("\r");
BufferedReader d = new BufferedReader(new FileReader(s));
String line = " ", a;
while ((a = d.readLine()) != null) {
line = line + a;
}
out.write(line);
out.flush();
jTextArea1.append("File Delivered.\n");
d.close();
}
out.close();
clientSocket.close();
serverSocket.close();
} catch (IOException e) {
jTextArea1.append("Accept failed.");
System.exit(1);
}
}
This is not related to the code that you've written. You need to make your IP address publicly accessible. Here's is a related thread.
Check that you are indeed listening on 0.0.0.0:32768 and not 127.0.0.1:32768 or any other particulat IP (specially if you are connected to several network). Start a shell and use netstat -ano on Windows and netstat -anp on Unix or Mac.
Check that your firewall allows remote connection to the port 32768
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();
I asked a similar question in another thread but I think I'm just having trouble getting the syntax right at this point. I basically want to open a socket in Java, send a HTTP request message to get the header fields of a specific web page. My program looks like this so far:
String server = "www.w3.org";
int port = 80;
String uri = "/Protocols/rfc2616/rfc2616-sec5.html#sec5.1"
Socket socket = new Socket(server, port);
PrintStream output = new PrintStream(socket.getOutputStream());
BufferedReader socketInput = new BufferedReader(new InputStreamReader(socket.getInputStream()));
output.println("HEAD " + uri + " HTTP/1.1");
//String response = "";
String line = "";
while((line = socketInput.readLine()) != null){
System.out.println(line);
}
socketInput.close();
socket.close();
It doesn't really work. Or it doesn't work for all websites. If someone could just tell me the immediate problems with what I'm doing, that would be great. Thank you!
Change
output.println("HEAD " + uri + " HTTP/1.1");
to
output.println("HEAD " + uri + " HTTP/1.1");
output.println("Host: " + server);
output.println();
You have to send the Host header because usually there are more than one virtual host on one IP address. If you use HTTP/1.0 it works without the Host header.
I would use some higher-level component, like HttpURLConnection (see here) or apache http components.