1

Tried this code from this question. When just requesting stackoverflow.com, it gives the correct reply but when i try https://stackoverflow.com/questions/10673684/send-http-request-manually-via-socket, it returns HTTP/1.1 400 Bad Request. What causes this problem?

Here is the working code i got from the above link which gives that correct response from the server.

Socket s = new Socket(InetAddress.getByName("stackoverflow.com"), 80);
PrintWriter pw = new PrintWriter(s.getOutputStream());
pw.println("GET / HTTP/1.1");
pw.println("Host: stackoverflow.com");
pw.println("");
pw.flush();
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String t;
while ((t = br.readLine()) != null) {
    System.out.println(t);
}
br.close();

Tried to change it to the following...

Socket s = new Socket(InetAddress.getByName("stackoverflow.com"), 80);
PrintWriter pw = new PrintWriter(s.getOutputStream());
pw.println("GET / HTTP/1.1");
pw.println("Host: https://stackoverflow.com/questions/10673684/send-http-request-manually-via-socket");
pw.println("");
pw.flush();
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String t;
while ((t = br.readLine()) != null) {
    System.out.println(t);
}

Then the response is HTTP/1.1 400 Bad Request.

P.S. I am not planning to use any http libraries.

Community
  • 1
  • 1
beginner
  • 2,024
  • 5
  • 43
  • 76
  • 3
    The Host should stay like in the working code, but you must change the line above the host to `GET /questions/10673684/send-http-request-manually-via-socket HTTP/1.1` – Alex Nov 03 '16 at 15:47
  • 1
    @Alex you should put that comment as an answer – tddmonkey Nov 03 '16 at 15:51
  • Hi @Alex. You are right. Thank you so much. If you'll place an answer I'll mark it. – beginner Nov 03 '16 at 15:55
  • 3
    Also you should use `\r\n` as line end instead of `\n` and you should not expect the server to close the connection after the response since you've implicitly requested persistent connection by use of HTTP version 1.1. For the same reason you also need to be able to deal with chunked transfer encoding of the data. It is recommend to have a look at the appropriate standards when implementing a protocol and not just guess the behavior. – Steffen Ullrich Nov 03 '16 at 16:17

1 Answers1

1

The problem lies within your request, which is not correct. If you replace your call to the PrintWriter with

pw.println ("GET /questions/10673684/send-http-request-manually-via-socket HTTP/1.1");
pw.println ("Host: stackoverflow.com");

it should work.


EDIT: As EJP pointed out in a comment to this answer, you should make sure the line ending is always \r\n. You could either ditch the println-function and instead use

pw.print ("Host: stackoverflow.com\r\n");

or you could change the default line ending to make sure println works correctly, however, this could influence other parts of your program as well.


Furthermore, you could use a try-with-resources to make sure your socket gets closed after you finish reading, which addresses one of Steffen Ullrichs concerns in his comment to your question.

However, in your first example you call br.close();, which should close the underlying input stream, which in turn closes the socket, so that should work too. However, in my opinion it's better to do that explicitly.

Community
  • 1
  • 1
Alex
  • 1,175
  • 1
  • 8
  • 25
  • 3
    Not unless you fix the line termination at least, which is a matter of *not* using `println()`. You might get lucky with a series of tolerant HTTP servers, but any HTTP server is entitled to ignore/reject the request based on that alone. – user207421 Nov 07 '16 at 08:54
  • I tried to address your concern in my edit. You still can use `println()` if you want, you just have to set the line.separator property before creating the PrintWriter instance. – Alex Nov 07 '16 at 10:36
  • If I hadn't seen the 400 Bad Request from Apache with my own eyes, I wouldn't have believed that the SSLSocketClient.java example code at https://docs.oracle.com/javase/10/security/sample-code-illustrating-secure-socket-connection-client-and-server.htm#JSSEC-GUID-AA1C27A1-2CA8-4309-B281-D6199F60E666 was missing your \r insight too. Sun/Oracle only tested on Windows? How are the mighty fallen! – Martin Dorey Aug 12 '20 at 21:14