001/*
002 *  Copyright 2016 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.core.impl.checker;
017
018import java.io.IOException;
019import java.net.HttpURLConnection;
020import java.net.MalformedURLException;
021import java.net.ProtocolException;
022import java.net.URL;
023import java.util.HashMap;
024import java.util.List;
025import java.util.Map;
026import java.util.Map.Entry;
027import java.util.Set;
028
029import org.apache.avalon.framework.configuration.Configurable;
030import org.apache.avalon.framework.configuration.Configuration;
031import org.apache.avalon.framework.configuration.ConfigurationException;
032import org.apache.cocoon.util.StringUtils;
033import org.apache.commons.lang.ArrayUtils;
034
035import org.ametys.runtime.model.checker.ItemChecker;
036import org.ametys.runtime.model.checker.ItemCheckerTestFailureException;
037
038/**
039 * Checks if the url written is correct and if it allows to establish a connection with the given configuration. 
040 */
041public class HttpUrlChecker implements ItemChecker, Configurable
042{
043    /** The user agent */
044    protected String _userAgent;
045    
046    /** The method */
047    protected String _method;
048    
049    /** The timeout */
050    protected int _timeout;
051    
052    /** The acceptable response codes */
053    protected String _okCodes;
054    
055    /** The values the header must have */
056    protected Map<String, String> _requestHeaderValues;
057
058    /** The values the header must have */
059    protected Map<String, String> _responseHeaderValues;
060
061    /** Something to add to the parameter */
062    protected String _additionnalURL;
063    
064    public void configure(Configuration configuration) throws ConfigurationException
065    {
066        Configuration config = configuration.getChild("configuration");
067        Configuration requestConfig = config.getChild("request");
068        Configuration responseConfig = config.getChild("response");
069        
070        Configuration timeoutConfig = requestConfig.getChild("timeout", false);
071        
072        _timeout = timeoutConfig != null ? timeoutConfig.getValueAsInteger() : -1;
073        _userAgent = requestConfig.getChild("user-agent").getValue(null);
074        _method = requestConfig.getChild("method").getValue(null);
075        _additionnalURL = requestConfig.getChild("additionnal-url").getValue("");
076        _requestHeaderValues = new HashMap<> ();
077        for (Configuration headerChildConfig : requestConfig.getChild("header").getChildren())
078        {
079            _requestHeaderValues.put(headerChildConfig.getName(), headerChildConfig.getValue());
080        }
081        
082        _okCodes = responseConfig.getChild("code").getValue(null);
083        
084        _responseHeaderValues = new HashMap<> ();
085        for (Configuration headerChildConfig : responseConfig.getChild("header").getChildren())
086        {
087            _responseHeaderValues.put(headerChildConfig.getName(), headerChildConfig.getValue());
088        }
089    }
090    
091    @Override
092    public void check(List<String> values) throws ItemCheckerTestFailureException
093    {
094        String configUrl = values.get(0);
095        
096        try
097        {
098            HttpURLConnection httpUrlConnection = _prepareConnection(configUrl + _additionnalURL);
099            
100            // Do the connection
101            int responseCode = httpUrlConnection.getResponseCode();
102            
103            _testResponseCode(httpUrlConnection, responseCode);
104            _testHeaders(httpUrlConnection);
105        }
106        catch (IOException e)
107        {
108            throw new ItemCheckerTestFailureException("Unable to contact '" + configUrl + _additionnalURL + "' (" + e.getMessage() + ")", e);
109        }
110    }
111
112    private HttpURLConnection _prepareConnection(String configUrl) throws IOException, MalformedURLException, ProtocolException
113    {
114        HttpURLConnection httpUrlConnection = (HttpURLConnection) new URL(configUrl).openConnection();
115        
116        if (_userAgent != null)
117        {
118            httpUrlConnection.setRequestProperty("User-Agent", _userAgent);
119        }
120        if (_method != null)
121        {
122            httpUrlConnection.setRequestMethod(_method);
123        }
124        if (_timeout != -1)
125        {
126            httpUrlConnection.setReadTimeout(_timeout);
127        }
128        for (Entry<String, String> headers : _requestHeaderValues.entrySet())
129        {
130            httpUrlConnection.setRequestProperty(headers.getKey(), headers.getValue());
131        }
132        
133        return httpUrlConnection;
134    }
135    
136    private void _testHeaders(HttpURLConnection httpUrlConnection) throws ItemCheckerTestFailureException
137    {
138        Set<String> keys = _responseHeaderValues.keySet();
139        for (String key : keys)
140        {
141            if (httpUrlConnection.getHeaderField(key) == null)
142            {
143                throw new ItemCheckerTestFailureException("The header field '" + key + "' does not exist");
144            }
145            
146            if (!httpUrlConnection.getHeaderField(key).equals(_responseHeaderValues.get(key)))
147            {
148                throw new ItemCheckerTestFailureException("The header field '" + key + "' does not have the expected value '" + _responseHeaderValues.get(key) + "', found '" + httpUrlConnection.getHeaderField(key) + "' instead.");
149            }
150        }
151    }
152
153    private void _testResponseCode(HttpURLConnection httpUrlConnection, int responseCode) throws ItemCheckerTestFailureException, IOException
154    {
155        String[] okCodes = {Integer.toString(HttpURLConnection.HTTP_OK)};
156        if (_okCodes != null)
157        {
158            okCodes = StringUtils.split(_okCodes, ",");
159        }
160        if (!ArrayUtils.contains(okCodes, Integer.toString(responseCode)))
161        {
162            throw new ItemCheckerTestFailureException("Error code " + responseCode + ". Message: " + httpUrlConnection.getResponseMessage());
163        }
164    }
165}