10

Is there any way to get raw response http header?

The getHeaderField() method doesn't work for me, because server spits multiple 'Set-Cookie' and some of them get lost.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
p4553d
  • 818
  • 1
  • 7
  • 17
  • It sounds like you are using a library like Apache HTTP Client? Would be useful to state that if so, since I assume you're asking if that particular library has such a method. – Sean Owen Feb 21 '10 at 20:36
  • Would be helpful, but I think he's not using apache client but Java standard library: http://docs.oracle.com/javase/6/docs/api/java/net/URLConnection.html#getHeaderField(java.lang.String) – thermz Feb 10 '14 at 10:30

4 Answers4

34

The getHeaderField() method doesn't work for me

You're asking this in the context of java.net.URLConnection, is it? No, obtaining the raw HTTP response headers is not possible with URLconnection. You'll need to fall back to low-level Socket programming. Here's an SSCCE, just copy'n'paste'n'run it.

package com.stackoverflow.q2307291;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;

public class Test {

    public static void main(String[] args) throws IOException {
        String hostname = "stackoverflow.com";
        int port = 80;

        Socket socket = null;
        PrintWriter writer = null;
        BufferedReader reader = null;

        try {
            socket = new Socket(hostname, port);
            writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
            writer.println("GET / HTTP/1.1");
            writer.println("Host: " + hostname);
            writer.println("Accept: */*");
            writer.println("User-Agent: Java"); // Be honest.
            writer.println(""); // Important, else the server will expect that there's more into the request.
            writer.flush();

            reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            for (String line; (line = reader.readLine()) != null;) {
                if (line.isEmpty()) break; // Stop when headers are completed. We're not interested in all the HTML.
                System.out.println(line);
            }
        } finally {
            if (reader != null) try { reader.close(); } catch (IOException logOrIgnore) {} 
            if (writer != null) { writer.close(); }
            if (socket != null) try { socket.close(); } catch (IOException logOrIgnore) {} 
        }
    }

}

To avoid SO being overloaded by everyone trying this snippet, here's how the output will look like:

HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html; charset=utf-8
Expires: Sun, 21 Feb 2010 20:39:08 GMT
Server: Microsoft-IIS/7.5
Date: Sun, 21 Feb 2010 20:39:07 GMT
Connection: close
Content-Length: 208969

To learn more about sending HTTP requests the low-level way, read the HTTP specification.

However, you probably want to make use of getHeaderFields() method instead to retrieve a header with multiple values. The getHeaderField() namely only returns the last value, as per the linked API doc.

List<String> cookies = connection.getHeaderFields().get("Set-Cookie");
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Heys are you saying that `java.net.URLConnection` is built on top of these methods? – Pacerier Jan 17 '12 at 06:37
  • "Obtaining the raw HTTP response headers is not possible with `URLConnection`"? What does `getHeaderField(int)` return? – erickson Feb 19 '12 at 01:13
  • @erickson: it parses the raw response headers and returns the value for the header on the given index. It doesn't return the raw response headers exactly as shown in the quote in my answer. I believe you're misinterpreting "raw" in the context of this question. Have you by the way read the `getHeaderFields()` hint at the bottom of my answer? Btw: I didn't downvote your answer :) – BalusC Feb 19 '12 at 01:27
  • 1
    I don't see a difference in the "raw" values. Can you provide an example where the "raw" value is different than that returned by the `URLConnection` API? – erickson Feb 19 '12 at 01:33
  • @erickson: there are no differences in the obtained values. Raw just means unparsed, plain, exactly as shown in the output as quoted in my answer. The OP has most likely the intent to manually parse it further in order to retrieve multiple values. – BalusC Feb 19 '12 at 01:35
  • I can see that the `URLConnection` API discards the white space between the header name and value, while you preserve it. Otherwise, the index-based API seems to return the "raw", unprocessed values verbatim. Do you know of any further processing that is performed (decoding quoted-printable or something)? The `URLConnection` definitely supports retrieving multiple values for a single header name. – erickson Feb 19 '12 at 02:27
  • @erickson: Yes, the `getHeaderFields()` was what the OP really needed (that's also why I mentioned it in my answer), but not what the OP initially asked :) – BalusC Feb 19 '12 at 02:36
  • why you don't write caret return ("\r") symbol in your request ? – Lev Jan 16 '15 at 21:26
  • But it may not work with all servers, cause you violating rfc: http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.htm in your request. – Lev Jan 19 '15 at 17:57
  • @BalusC: There is no guarantee that "\r" will be added: http://docs.oracle.com/javase/7/docs/api/java/io/PrintWriter.html#println() – Lev Jan 19 '15 at 18:30
  • I wouldn't suggest to implement HTTP protocol, depending on system-dependent property – Lev Jan 19 '15 at 18:47
  • How would I read the HTTP Request parameters if I send an HTTP Request from a Java Servlet and receive it on a raw port using ServerSocket. Can anyone please help me on this? – Hiren Feb 11 '15 at 01:00
6

Not exactly 'raw' but concise:

for (Map.Entry<String, List<String>> k : myHttpURLConnection.getHeaderFields().entrySet()) {
    System.out.println(k.toString());
}

IF you worry that some of the headers are getting lost use:

for (Map.Entry<String, List<String>> k : myHttpURLConnection.getHeaderFields().entrySet()) {
    for (String v : k.getValue()){
         System.out.println(k.getKey() + ":" + v);
    }
}

PS: Better late than never. :)

ostergaard
  • 3,377
  • 2
  • 30
  • 40
  • 1
    I didn't test your example, but I believe getHeaderFields returns only one value for a field. This leads to troubles, if you get multiple fields with equal name, for example "Set-Cookies" is one of them. – p4553d Sep 17 '13 at 09:56
  • 2
    @p4553d - that's why entrySet returns a List as the value ... Me thinks. – ostergaard Sep 18 '13 at 04:05
2

The easy way is to use the getHeaderFields() method of URLConnection. Here is some code that does something equivalent.

static String[] getHeaders(HttpURLConnection con, String header) {
  List<String> values = new ArrayList<String>();
  int idx = (con.getHeaderFieldKey(0) == null) ? 1 : 0;
  while (true) {
    String key = con.getHeaderFieldKey(idx);
    if (key == null)
      break;
    if (header.equalsIgnoreCase(key))
      values.add(con.getHeaderField(idx));
    ++idx;
  }
  return values.toArray(new String[values.size()]);
}
erickson
  • 265,237
  • 58
  • 395
  • 493
  • 3
    @Pacerier Have you tried it? What did you find to be incorrect? – erickson Feb 19 '12 at 00:58
  • I'm getting empty `Set-Cookie` headers. Two or three of them, depending on what the other party sends. Other headers work fine. The problem doesn't seem to lie in printing as `connection.getRequestProperties()` shows `Set-Cookies=[ , ]`. The cookies are `Secure; HTTPOnly`, but this shouldn't matter in Java. Strange, isn't it? – maaartinus May 30 '17 at 03:03
1

Late to the party, but here's the simplest solution. Just implement CookieStore. (or use the default implementation and let it take care of adding the cookies to your subsequent calls.)

http://docs.oracle.com/javase/7/docs/api/java/net/CookieStore.html

Set your cookie store as the default cookie manager

CookieManager cookieManager = new CookieManager(new MyCookieStore(), CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(cookieManager);

And every new cookie will appear to you in add() in your CookieStore. I had the same problem with params being overwritten by having the same name "Set-Cookie" in a single request, and now I get both the cookie and the sessionId.

accordionfolder
  • 573
  • 4
  • 17