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