001/*
002 * nimbus-jose-jwt
003 *
004 * Copyright 2012-2016, Connect2id Ltd.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
007 * this file except in compliance with the License. You may obtain a copy of the
008 * License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software distributed
013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
015 * specific language governing permissions and limitations under the License.
016 */
017
018package com.nimbusds.jose.util;
019
020
021import java.io.IOException;
022import java.io.InputStream;
023import java.net.HttpURLConnection;
024import java.net.URL;
025
026import net.jcip.annotations.ThreadSafe;
027import org.apache.commons.io.IOUtils;
028import org.apache.commons.io.input.BoundedInputStream;
029
030
031/**
032 * The default retriever of resources specified by URL. Provides setting of
033 * HTTP connect and read timeouts as well as a size limit of the retrieved
034 * entity. Caching header directives are not honoured.
035 */
036@ThreadSafe
037public class DefaultResourceRetriever extends AbstractRestrictedResourceRetriever implements RestrictedResourceRetriever {
038        
039        
040        /**
041         * Creates a new resource retriever. The HTTP timeouts and entity size
042         * limit are set to zero (infinite).
043         */
044        public DefaultResourceRetriever() {
045        
046                this(0, 0);     
047        }
048        
049        
050        /**
051         * Creates a new resource retriever. The HTTP entity size limit is set
052         * to zero (infinite).
053         *
054         * @param connectTimeout The HTTP connects timeout, in milliseconds, 
055         *                       zero for infinite. Must not be negative.
056         * @param readTimeout    The HTTP read timeout, in milliseconds, zero 
057         *                       for infinite. Must not be negative.
058         */
059        public DefaultResourceRetriever(final int connectTimeout, final int readTimeout) {
060
061                this(connectTimeout, readTimeout, 0);
062        }
063
064
065        /**
066         * Creates a new resource retriever.
067         *
068         * @param connectTimeout The HTTP connects timeout, in milliseconds,
069         *                       zero for infinite. Must not be negative.
070         * @param readTimeout    The HTTP read timeout, in milliseconds, zero
071         *                       for infinite. Must not be negative.
072         * @param sizeLimit      The HTTP entity size limit, in bytes, zero for
073         *                       infinite. Must not be negative.
074         */
075        public DefaultResourceRetriever(final int connectTimeout, final int readTimeout, final int sizeLimit) {
076        
077                super(connectTimeout, readTimeout, sizeLimit);
078        }
079
080
081        @Override
082        public Resource retrieveResource(final URL url)
083                throws IOException {
084                
085                HttpURLConnection con;
086                try {
087                        con = (HttpURLConnection)url.openConnection();
088                } catch (ClassCastException e) {
089                        throw new IOException("Couldn't open HTTP(S) connection: " + e.getMessage(), e);
090                }
091
092                con.setConnectTimeout(getConnectTimeout());
093                con.setReadTimeout(getReadTimeout());
094
095                InputStream inputStream = con.getInputStream();
096
097                if (getSizeLimit() > 0) {
098                        inputStream = new BoundedInputStream(inputStream, getSizeLimit());
099                }
100
101                final String content = IOUtils.toString(inputStream);
102
103                // Check HTTP code + message
104                final int statusCode = con.getResponseCode();
105                final String statusMessage = con.getResponseMessage();
106
107                // Ensure 2xx status code
108                if (statusCode > 299 || statusCode < 200) {
109                        throw new IOException("HTTP " + statusCode + ": " + statusMessage);
110                }
111
112                return new Resource(content, con.getContentType());
113        }
114}