001 package com.nimbusds.openid.connect.sdk.util; 002 003 004 import java.io.BufferedReader; 005 import java.io.InputStreamReader; 006 import java.io.IOException; 007 import java.net.HttpURLConnection; 008 import java.net.URL; 009 010 import javax.mail.internet.ContentType; 011 import javax.mail.internet.ParseException; 012 013 import net.jcip.annotations.ThreadSafe; 014 015 016 /** 017 * The default retriever of resources specified by URL. Provides setting of 018 * HTTP connect and read timeouts. Caching header directives are not honoured. 019 * This class is thread-safe. 020 * 021 * @author Vladimir Dzhuvinov 022 */ 023 @ThreadSafe 024 public class DefaultResourceRetriever implements ResourceRetriever { 025 026 027 /** 028 * The system line separator. 029 */ 030 private final String lineSeparator; 031 032 033 /** 034 * The HTTP connect timeout, in milliseconds. 035 */ 036 private int connectTimeout; 037 038 039 /** 040 * The HTTP read timeout, in milliseconds. 041 */ 042 private int readTimeout; 043 044 045 /** 046 * Creates a new resource retriever. The HTTP connect and read timeouts 047 * are set to zero (infinite). 048 */ 049 public DefaultResourceRetriever() { 050 051 this(0, 0); 052 } 053 054 055 /** 056 * Creates a new resource retriever. 057 * 058 * @param connectTimeout The HTTP connects timeout, in milliseconds, 059 * zero for infinite. Must not be negative. 060 * @param readTimeout The HTTP read timeout, in milliseconds, zero 061 * for infinite. Must not be negative. 062 */ 063 public DefaultResourceRetriever(final int connectTimeout, final int readTimeout) { 064 065 setConnectTimeout(connectTimeout); 066 setReadTimeout(readTimeout); 067 068 lineSeparator = System.getProperty("line.separator"); 069 } 070 071 072 /** 073 * Gets the HTTP connect timeout. 074 * 075 * @return The HTTP connect timeout, in milliseconds, zero for 076 * infinite. 077 */ 078 public int getConnectTimeout() { 079 080 return connectTimeout; 081 } 082 083 084 /** 085 * Sets the HTTP connect timeout. 086 * 087 * @param connectTimeout The HTTP connect timeout, in milliseconds, 088 * zero for infinite. Must not be negative. 089 */ 090 public void setConnectTimeout(final int connectTimeout) { 091 092 if (connectTimeout < 0) 093 throw new IllegalArgumentException("The connect timeout must not be negative"); 094 095 this.connectTimeout = connectTimeout; 096 } 097 098 099 /** 100 * Gets the HTTP read timeout. 101 * 102 * @return The HTTP read timeout, in milliseconds, zero for infinite. 103 */ 104 public int getReadTimeout() { 105 106 return readTimeout; 107 } 108 109 110 /** 111 * Sets the HTTP read timeout. 112 * 113 * @param readTimeout The HTTP read timeout, in milliseconds, zero for 114 * infinite. Must not be negative. 115 */ 116 public void setReadTimeout(final int readTimeout) { 117 118 if (readTimeout < 0) 119 throw new IllegalArgumentException("The read timeout must not be negative"); 120 121 this.readTimeout = readTimeout; 122 } 123 124 125 @Override 126 public Resource retrieveResource(final URL url) 127 throws IOException { 128 129 HttpURLConnection con; 130 131 try { 132 con = (HttpURLConnection)url.openConnection(); 133 134 } catch (ClassCastException e) { 135 136 throw new IOException("Couldn't open HTTP(S) connection: " + e.getMessage(), e); 137 } 138 139 con.setConnectTimeout(connectTimeout); 140 con.setReadTimeout(readTimeout); 141 142 StringBuilder sb = new StringBuilder(); 143 144 BufferedReader input = new BufferedReader(new InputStreamReader(con.getInputStream())); 145 146 String line = null; 147 148 while ((line = input.readLine()) != null) { 149 150 sb.append(line); 151 sb.append(lineSeparator); 152 } 153 154 input.close(); 155 156 // Check HTTP code + message 157 final int statusCode = con.getResponseCode(); 158 final String statusMessage = con.getResponseMessage(); 159 160 if (statusCode != HttpURLConnection.HTTP_OK) { 161 162 throw new IOException("HTTP " + statusCode + ": " + statusMessage); 163 } 164 165 // Parse the Content-Type header 166 ContentType contentType = null; 167 168 if (con.getContentType() != null) { 169 170 try { 171 contentType = new ContentType(con.getContentType()); 172 173 } catch (ParseException e) { 174 175 throw new IOException("Couldn't parse Content-Type header: " + e.getMessage(), e); 176 } 177 } 178 179 180 return new Resource(sb.toString(), contentType); 181 } 182 }