Java's HttpURLConnection doesn't support R

2020-07-11 04:37发布

问题:

HttpURLConnection does only support things like GET, POST and HEAD - but no REPORT/PROPFIND. I'm going to implement a CalDAV-Client but without theese operations (if I want to use them I get a ProtocolException) I have to write/deliver a complete and huge HTTP library with auth and so on.

"Overkill".

How do I send requests with PROPFIND and REPORT?

回答1:

I had similar problem on WebDav for PROPFIND method.

Solved the problem by implementing this solution: https://java.net/jira/browse/JERSEY-639

    try {
            httpURLConnection.setRequestMethod(method);
        } catch (final ProtocolException pe) {
            try {
                final Class<?> httpURLConnectionClass = httpURLConnection
                        .getClass();
                final Class<?> parentClass = httpURLConnectionClass
                        .getSuperclass();
                final Field methodField;
                // If the implementation class is an HTTPS URL Connection, we
                // need to go up one level higher in the heirarchy to modify the
                // 'method' field.
                if (parentClass == HttpsURLConnection.class) {
                    methodField = parentClass.getSuperclass().getDeclaredField(
                            "method");
                } else {
                    methodField = parentClass.getDeclaredField("method");
                }
                methodField.setAccessible(true);
                methodField.set(httpURLConnection, method);
            } catch (final Exception e) {
                throw new RuntimeException(e);

            }
     }


回答2:

You'd probably want to look for a WebDAV libary, not an HTTP library, for this one.

Maybe take a look at Apache Jackrabbit.



回答3:

Either you can use https://github.com/square/okhttp

Sample Code

    // using OkHttp
    public class PropFindExample {        
    private final OkHttpClient client = new OkHttpClient();
    String run(String url) throws IOException {
        String credential = Credentials.basic(userName, password);
        // body
        String body = "<d:propfind xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\">\n" +
                "  <d:prop>\n" +
                "     <d:displayname />\n" +
                "     <d:getetag />\n" +
                "  </d:prop>\n" +
                "</d:propfind>";
        Request request = new Request.Builder()
                .url(url)
                .method("PROPFIND", RequestBody.create(MediaType.parse(body), body))
                .header("DEPTH", "1")
                .header("Authorization", credential)
                .header("Content-Type", "text/xml")
                .build();

        Response response = client.newCall(request).execute();
        return response.body().string();
    }
 }

Or play with Sockets

Sample Code

String host = "example.com";
int port = 443;
String path = "/placeholder";
String userName = "username";
String password = "password";

SSLSocketFactory ssf = (SSLSocketFactory) SSLSocketFactory.getDefault();
Socket socket = ssf.createSocket(host, port);
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())));

// xml data to be sent in body
String xmlData = "<?xml version=\"1.0\"?> <d:propfind xmlns:d=\"DAV:\" xmlns:cs=\"http://calendarserver.org/ns/\"> <d:prop> <d:displayname /> <d:getetag /> </d:prop> </d:propfind>";
// append headers
out.println("PROPFIND path HTTP/1.1");
out.println("Host: "+host);
String userCredentials = username+":"+password;
String basicAuth = "Basic " + new String(Base64.encode(userCredentials.getBytes(), Base64.DEFAULT));
String authorization = "Authorization: " + basicAuth;
out.println(authorization.trim());
out.println("Content-Length: "+ xmlData.length());
out.println("Content-Type: text/xml");
out.println("Depth: 1");
out.println();
// append body
out.println(xmlData);
out.flush();

// get response
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String inputLine;

System.out.println("--------------------------------------------------------");
System.out.println("---------------Printing response--------------------------");
System.out.println("--------------------------------------------------------");
while ((inputLine = in.readLine()) != null) {
    System.out.println(inputLine);
}

in.close();


回答4:

You could try to use another HTTP library, such as Apache HTTP client and extend its HttpRequestBase (see HttpGet and HttpPost for example).

Alternatively, you could use a WebDAV client library directly.



回答5:

Consider using Caldav4j

It supports:

  • easy generation of report requests
  • based on httpclient 3.0
  • android app
  • currently migrating to jackrabbit


回答6:

private static void setRequestMethod(HttpURLConnection conn, String method) throws Throwable {
    try {
        conn.setRequestMethod(method);
    } catch (ProtocolException e) {
        Class<?> c = conn.getClass();
        Field methodField = null;
        Field delegateField = null;
        try {
            delegateField = c.getDeclaredField("delegate");
        } catch (NoSuchFieldException nsfe) {

        }
        while (c != null && methodField == null) {
            try {
                methodField = c.getDeclaredField("method");
            } catch (NoSuchFieldException nsfe) {

            }
            if (methodField == null) {
                c = c.getSuperclass();
            }
        }
        if (methodField != null) {
            methodField.setAccessible(true);
            methodField.set(conn, method);
        }

        if (delegateField != null) {
            delegateField.setAccessible(true);
            HttpURLConnection delegate = (HttpURLConnection) delegateField.get(conn);
            setRequestMethod(delegate, method);
        }
    }
}


标签: java caldav