View Javadoc
1   package emissary.util.web;
2   
3   import org.slf4j.Logger;
4   import org.slf4j.LoggerFactory;
5   
6   import java.io.BufferedReader;
7   import java.io.IOException;
8   import java.io.InputStreamReader;
9   import java.io.OutputStream;
10  import java.net.HttpURLConnection;
11  import java.net.MalformedURLException;
12  import java.net.URL;
13  import java.util.ArrayList;
14  import java.util.HashMap;
15  import java.util.List;
16  import java.util.Map;
17  import javax.annotation.Nullable;
18  
19  public class Url {
20  
21      private static final Logger logger = LoggerFactory.getLogger(Url.class);
22  
23      public static final int UNINITIALIZED = 0;
24      public static final int GET = 1;
25      public static final int POST = 2;
26      public static final int HEAD = 3;
27  
28      static final String[] theMethodString = {"GET", "POST", "HEAD"};
29  
30      /**
31       * process a url depending on the method specified
32       * 
33       * @param toProcess the URL resource to process with GET HEAD or POST
34       */
35      public static UrlData doUrl(final UrlData toProcess) {
36          if (toProcess == null) {
37              throw new IllegalArgumentException("Url.doUrl: null UrlData arg");
38          }
39  
40          final int method = toProcess.getTheMethod();
41  
42          if (method == Url.GET) {
43              return getUrl(toProcess);
44          }
45  
46          if (method == Url.POST) {
47              return postUrl(toProcess);
48          }
49  
50          throw new IllegalArgumentException("UrlData method " + method + " not implemented in UrlData.doUrl");
51      }
52  
53      /**
54       * get a url
55       * 
56       * @param toGet describe where to GET from
57       */
58      public static UrlData getUrl(final UrlData toGet) {
59          return getUrl(toGet.getTheUrl(), toGet.getProps());
60      }
61  
62      /**
63       * get a Url without any extra properties
64       * 
65       * @param urlString the URL resource to GET
66       */
67      public static UrlData getUrl(final String urlString) {
68          return getUrl(urlString, null);
69      }
70  
71      /**
72       * Get a url, specifying additional header properties
73       * 
74       * @param urlString the URL resource
75       * @param props properties to use on the connection
76       */
77      public static UrlData getUrl(final String urlString, @Nullable final List<UrlRequestProperty> props) {
78          return processUrl(urlString, props, null, Url.GET);
79      }
80  
81      /**
82       * post to a url
83       * 
84       * @param toPost descript where to POST
85       */
86      public static UrlData postUrl(final UrlData toPost) {
87          return postUrl(toPost.getTheUrl(), toPost.getProps(), null);
88      }
89  
90      /**
91       * post to a url
92       * 
93       * @param toPost describe where to POST
94       * @param parms the POST data
95       */
96      public static UrlData postUrl(final UrlData toPost, final HttpPostParameters parms) {
97          return postUrl(toPost.getTheUrl(), toPost.getProps(), parms);
98      }
99  
100     /**
101      * post a Url without any extra properties
102      * 
103      * @param urlString the URL resource to POST on
104      */
105     public static UrlData postUrl(final String urlString) {
106         return postUrl(urlString, null, null);
107     }
108 
109     /**
110      * Post on a url, specifying additional header properties and params
111      * 
112      * @param urlString the URL resource
113      * @param props array of properties to use
114      * @param parms the POST data
115      */
116     public static UrlData postUrl(final String urlString, @Nullable final List<UrlRequestProperty> props, @Nullable final HttpPostParameters parms) {
117 
118         // props.addProp(new UrlRequestProperty("Content-length",parms.length()));
119 
120         final UrlData u = new UrlData(urlString);
121         u.setTheMethod(Url.POST);
122         if (props != null) {
123             u.setProps(props);
124         }
125         if (parms != null) {
126             u.addProp(new UrlRequestProperty("Content-length", parms.length()));
127         }
128 
129         return processUrl(u.getTheUrl(), u.getProps(), parms, u.getTheMethod());
130     }
131 
132     /**
133      * process (GET|POST|HEAD) a Url
134      * 
135      * @param urlString the URL resource
136      * @param props array of properties to use as headers, must have Content-length if POSTing
137      * @param parms parameters to use when POSTing
138      * @param method GET, HEAD, POST
139      */
140     private static UrlData processUrl(final String urlString, @Nullable final List<UrlRequestProperty> props,
141             @Nullable final HttpPostParameters parms,
142             final int method) {
143         final UrlData response = new UrlData(urlString);
144 
145         final StringBuilder theOutput = new StringBuilder();
146         OutputStream os = null;
147         BufferedReader dis = null;
148         try {
149             final URL theUrl = new URL(urlString);
150             final HttpURLConnection conn = (HttpURLConnection) theUrl.openConnection();
151 
152             // Set up for POST or other
153             conn.setDoOutput(method == Url.POST);
154             conn.setDoInput(true);
155             conn.setUseCaches(false);
156 
157 
158             // Set user requested properties
159             if (props != null) {
160                 for (UrlRequestProperty prop : props) {
161                     conn.setRequestProperty(prop.getKey(), prop.getValue());
162                 }
163             }
164 
165 
166             // Write post data if POSTing
167             if (method == Url.POST && parms != null) {
168                 os = conn.getOutputStream();
169                 os.write(parms.toPostString().getBytes());
170                 os.flush();
171             }
172 
173             // Get response code
174             response.setResponseCode(conn.getResponseCode());
175 
176             // Get the headers
177             final Map<String, String> headers = new HashMap<>();
178             String s;
179             int hdr = 0;
180             while ((s = conn.getHeaderField(hdr)) != null) {
181                 final String key = conn.getHeaderFieldKey(hdr);
182                 if (key != null) {
183                     headers.put(key, s);
184                 } else {
185                     headers.put("", s);
186                 }
187                 hdr++;
188             }
189 
190             // Load headers into properties array
191             final List<UrlRequestProperty> theProps = new ArrayList<>(headers.size());
192             for (final Map.Entry<String, String> entry : headers.entrySet()) {
193                 theProps.add(new UrlRequestProperty(entry.getKey(), entry.getValue()));
194             }
195             response.setProps(theProps);
196 
197             // Get page unless HEADing
198             if (method != Url.HEAD) {
199                 dis = new BufferedReader(new InputStreamReader(conn.getInputStream()));
200 
201                 // Get the content
202                 String line;
203                 while ((line = dis.readLine()) != null) {
204                     theOutput.append(line).append(System.getProperty("line.separator", "\n"));
205                 }
206 
207                 response.setTheContent(theOutput.toString().getBytes());
208             }
209         } catch (MalformedURLException e) {
210             logger.warn("Bad URL " + urlString, e);
211         } catch (IOException e) {
212             logger.warn("Read error on " + urlString, e);
213         } catch (OutOfMemoryError e) {
214             logger.warn("Not enough space for read on " + urlString, e);
215         } finally {
216             if (os != null) {
217                 try {
218                     os.close();
219                 } catch (IOException ioe) {
220                     logger.warn("Unable to close stream", ioe);
221                 }
222             }
223             if (dis != null) {
224                 try {
225                     dis.close();
226                 } catch (IOException ioe) {
227                     logger.warn("Unable to close stream", ioe);
228                 }
229             }
230         }
231 
232         return response;
233     }
234 
235     /** This class is not meant to be instantiated. */
236     private Url() {}
237 }