52

When I send a normal HTTP request via a socket, the server does not respond with an OK response. I copied the HTTP header from Firefox. Here is the code:

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

However, here is the response I received:

HTTP/1.0 408 Request Time-out
Cache-Control: no-cache
Connection: close
Content-Type: text/html

<html><body><h1>408 Request Time-out</h1>
Your browser didn't send a complete request in time.
</body></html>

I know that I can do this by using URL.openStream(), but why doesn't the server identify the HTTP request when I send it manually?

Matthias Braun
  • 24,493
  • 16
  • 114
  • 144
Eng.Fouad
  • 107,075
  • 62
  • 298
  • 390

4 Answers4

48

Two things:

  1. You should use println instead of print to print your entries to separate lines.
  2. HTTP request should end in a blank line (link). So add pw.println("");
Lycha
  • 9,108
  • 1
  • 33
  • 43
  • Perfect. Adding the blank line is important! – asgs Dec 31 '14 at 12:40
  • 4
    This only works on Windows machines. On linux, it will only print LF instead of CRLF which is needed for the HTTP spec. See the other answers. – Xiv Aug 05 '15 at 17:20
  • why does it give and `HTTP/1.1 400 Bad Request` when I changed the host to `pw.println("Host: httpstackoverflow.com/questions/10673684/send-http-request-manually-via-socket");` – beginner Nov 03 '16 at 15:24
22

You don't follow the HTTP RFC.

  • Header lines are always ended by a CR LF (i.e. 0x0d plus 0x0a).
  • The header ends after the first double-newline. In your case, you don't include the trailing newline so the server doesn't recognize the end of the request headers.

Generally, you should always try to use existing HTTP libraries. Although HTTP seems to be a simple protocol (and it is compared to others), it has rather strict syntactic and semantic rules. If you try to implement this yourself, you should have read and understand the relevant parts of RFC 2616 (and related).

Sadly, there are already too many crappy HTTP implementations not following the standards out there making the life for everyone miserable. Save yourself the hassle and use the HTTP libraries of your chosen language.

Holger Just
  • 45,586
  • 14
  • 98
  • 114
12

The correct fix which really works and it is cross platform:

    pw.print("GET / HTTP/1.1\r\n");
    pw.print("Host: stackoverflow.com\r\n\r\n");
TadejP
  • 782
  • 10
  • 18
  • 1
    I used `Host : ` instead of `Host: ` and all getting Bad Request (400) and it took a day to realize that, it really sucks. –  Jul 29 '16 at 06:08
4

The following fix, as mentioned by the previous answers, solves the problem;

pw.print("GET / HTTP/1.1\n\r\n");
pw.print("Host: stackoverflow.com\n\r\n");
Aimar Hassano
  • 49
  • 1
  • 1