File: HttpClient.java

package info (click to toggle)
libglazedlists-java 1.8.0.dfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 3,016 kB
  • sloc: java: 21,991; xml: 860; sh: 48; makefile: 5
file content (131 lines) | stat: -rw-r--r-- 5,286 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/* Glazed Lists                                                 (c) 2003-2006 */
/* http://publicobject.com/glazedlists/                      publicobject.com,*/
/*                                                     O'Dell Engineering Ltd.*/
package ca.odell.glazedlists.impl;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Overcome flaws in {@link HttpURLConnection} to download files from http://java.net,
 * which requires cookies to be passed between redirects for downloads to work.
 *
 * @author <a href="jesse@swank.ca">Jesse Wilson</a>
 */
public class HttpClient {

    public static final int MAX_REDIRECTS = 20;

    public static void main(String[] args) throws Exception {
        // expect a single argument starting with "http" or "https"
        if(args.length != 2 || !args[0].startsWith("http")) {
            System.out.println("Usage: HttpClient <url> <filename>");
            System.out.println();
            System.out.println("This program demonstrates how to download from java.net's");
            System.out.println("Documents & Files area using URLConnection");
            return;
        }

        // fast fail if the file already exists
        File targetFile = new File(args[1]);
        if(targetFile.exists()) {
            System.out.println("Skipping " + args[0] + ", file already exists");
            return;
        }

        // read from the webserver specified
        InputStream httpIn = getInputStream(args[0]);

        // write from the stream to our target file
        System.out.println("Downloading " + args[0]);
        OutputStream fileOut = new BufferedOutputStream(new FileOutputStream(args[1]));
        pushStreams(httpIn, fileOut);
        fileOut.close();
    }

    /**
     * Move bytes from the specified input stream to the specified output
     * stream until the input stream is exhaused.
     *
     * <p>We could optimize this to use byte buffers if it ever became a bottleneck.
     */
    private static void pushStreams(InputStream source, OutputStream target) throws IOException {
        while(true) {
            int aByte = source.read();
            if(aByte < 0) break;
            target.write(aByte);
        }
    }

    /**
     * Follow redirects as necessary to get an InputStream from the specified URL.
     */
    private static InputStream getInputStream(String url) throws IOException {
        List cookies = new ArrayList();

        for(int i = 0; i < MAX_REDIRECTS; i++) {
            // prepare the connection
            HttpURLConnection urlConnection = (HttpURLConnection)new URL(url).openConnection();
            urlConnection.setInstanceFollowRedirects(false);
            writeCookies(cookies, urlConnection);
            urlConnection.connect();

            // if this is a redirect, keep the cookies
            // and load the next location
            if(urlConnection.getResponseCode() == HttpURLConnection.HTTP_MOVED_TEMP
                    || urlConnection.getResponseCode() == HttpURLConnection.HTTP_MOVED_PERM) {
                url = urlConnection.getHeaderField("Location");
                acceptCookies(cookies, urlConnection);

            // success!
            } else {
                return urlConnection.getInputStream();
            }
        }

        throw new IOException("Max redirects " + MAX_REDIRECTS + " exceeded!");
    }

    /**
     * Accept all cookies provided by the HTTP response.
     *
     * <p>This method fails to perform some important aspects of cookie management,
     * and is potentially dangerous for all but the most basic of cookie problems.
     * This method fails at:
     * <li>Ensuring cookie names are unique
     * <li>Handling cookie expiry dates
     * <li>Keeping cookies private to the hosts that provide them
     * <li>Verifying the hosts specified match the hosts providing the cookies
     */
    private static void acceptCookies(List cookies, HttpURLConnection urlConnection) {
        for(Iterator i = urlConnection.getHeaderFields().entrySet().iterator(); i.hasNext(); ) {
            Map.Entry entry = (Map.Entry)i.next();
            String key = (String)entry.getKey();
            if(!"Set-Cookie".equalsIgnoreCase(key)) continue;

            List values = (List)entry.getValue();
            for(Iterator v = values.iterator(); v.hasNext(); ) {
                String value = (String)v.next();
                String cookie = value.split(";")[0];
                cookies.add(cookie);
            }
        }
    }

    /**
     * Encode the cookie header for the specified connection.
     */
    private static void writeCookies(List cookies, HttpURLConnection urlConnection) {
        StringBuffer cookiesString = new StringBuffer();
        for(Iterator i = cookies.iterator(); i.hasNext(); ) {
            if(cookiesString.length() > 0) cookiesString.append("; ");
            cookiesString.append(i.next());
        }
        if(cookiesString.length() > 0) urlConnection.addRequestProperty("Cookie", cookiesString.toString());
    }
}