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.util.HashMap;
021import java.util.List;
022import java.util.Map;
023import java.util.Set;
024
025import org.apache.avalon.framework.configuration.Configurable;
026import org.apache.avalon.framework.configuration.Configuration;
027import org.apache.avalon.framework.configuration.ConfigurationException;
028import org.apache.cocoon.util.StringUtils;
029import org.apache.commons.lang3.ArrayUtils;
030
031import org.ametys.core.util.HttpUrlUtils;
032import org.ametys.runtime.model.checker.ItemChecker;
033import org.ametys.runtime.model.checker.ItemCheckerTestFailureException;
034
035/**
036 * Checks if the url written is correct and if it allows to establish a connection with the given configuration. 
037 */
038public class HttpUrlChecker implements ItemChecker, Configurable
039{
040    /** The user agent */
041    protected String _userAgent;
042    
043    /** The method */
044    protected String _method;
045    
046    /** The timeout */
047    protected int _timeout;
048    
049    /** The acceptable response codes */
050    protected String _okCodes;
051    
052    /** The values the header must have */
053    protected Map<String, String> _requestHeaderValues;
054
055    /** The values the header must have */
056    protected Map<String, String> _responseHeaderValues;
057
058    /** Something to add to the parameter */
059    protected String _additionnalURL;
060
061    public void configure(Configuration configuration) throws ConfigurationException
062    {
063        Configuration config = configuration.getChild("configuration");
064        Configuration requestConfig = config.getChild("request");
065        Configuration responseConfig = config.getChild("response");
066        
067        Configuration timeoutConfig = requestConfig.getChild("timeout", false);
068        
069        _timeout = timeoutConfig != null ? timeoutConfig.getValueAsInteger() : -1;
070        _userAgent = requestConfig.getChild("user-agent").getValue(null);
071        _method = requestConfig.getChild("method").getValue(null);
072        _additionnalURL = requestConfig.getChild("additionnal-url").getValue("");
073        _requestHeaderValues = new HashMap<> ();
074        for (Configuration headerChildConfig : requestConfig.getChild("header").getChildren())
075        {
076            _requestHeaderValues.put(headerChildConfig.getName(), headerChildConfig.getValue());
077        }
078        
079        _okCodes = responseConfig.getChild("code").getValue(null);
080        
081        _responseHeaderValues = new HashMap<> ();
082        for (Configuration headerChildConfig : responseConfig.getChild("header").getChildren())
083        {
084            _responseHeaderValues.put(headerChildConfig.getName(), headerChildConfig.getValue());
085        }
086    }
087    
088    @Override
089    public void check(List<String> values) throws ItemCheckerTestFailureException
090    {
091        String configUrl = values.get(0);
092        
093        try
094        {
095            HttpURLConnection httpUrlConnection = HttpUrlUtils.prepareConnection(configUrl + _additionnalURL, _userAgent, _method, _timeout, _timeout, false, _requestHeaderValues);
096            
097            // Do the connection
098            int responseCode = httpUrlConnection.getResponseCode();
099            
100            _testResponseCode(httpUrlConnection, responseCode);
101            _testHeaders(httpUrlConnection);
102        }
103        catch (IOException e)
104        {
105            throw new ItemCheckerTestFailureException("Unable to contact '" + configUrl + _additionnalURL + "' (" + e.getMessage() + ")", e);
106        }
107    }
108    
109    private void _testHeaders(HttpURLConnection httpUrlConnection) throws ItemCheckerTestFailureException
110    {
111        Set<String> keys = _responseHeaderValues.keySet();
112        for (String key : keys)
113        {
114            if (httpUrlConnection.getHeaderField(key) == null)
115            {
116                throw new ItemCheckerTestFailureException("The header field '" + key + "' does not exist");
117            }
118            
119            if (!httpUrlConnection.getHeaderField(key).equals(_responseHeaderValues.get(key)))
120            {
121                throw new ItemCheckerTestFailureException("The header field '" + key + "' does not have the expected value '" + _responseHeaderValues.get(key) + "', found '" + httpUrlConnection.getHeaderField(key) + "' instead.");
122            }
123        }
124    }
125
126    private void _testResponseCode(HttpURLConnection httpUrlConnection, int responseCode) throws ItemCheckerTestFailureException, IOException
127    {
128        String[] okCodes = {Integer.toString(HttpURLConnection.HTTP_OK)};
129        if (_okCodes != null)
130        {
131            okCodes = StringUtils.split(_okCodes, ",");
132        }
133        if (!ArrayUtils.contains(okCodes, Integer.toString(responseCode)))
134        {
135            throw new ItemCheckerTestFailureException("Error code " + responseCode + ". Message: " + httpUrlConnection.getResponseMessage());
136        }
137    }
138}