org.apache.sling.testing.tools.http.RequestExecutor.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.sling.testing.tools.http.RequestExecutor.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements. See the NOTICE file distributed with this
 * work for additional information regarding copyright ownership. The ASF
 * licenses this file to You under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package org.apache.sling.testing.tools.http;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.regex.Pattern;

import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

/** Executes a Request and provides convenience methods
 *  to validate the results.
 */
public class RequestExecutor {
    private final DefaultHttpClient httpClient;
    private HttpUriRequest request;
    private HttpResponse response;
    private HttpEntity entity;
    private String content;

    /**
     * HttpRequestInterceptor for preemptive authentication, based on httpclient
     * 4.0 example
     */
    private static class PreemptiveAuthInterceptor implements HttpRequestInterceptor {

        public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {

            AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
            CredentialsProvider credsProvider = (CredentialsProvider) context
                    .getAttribute(ClientContext.CREDS_PROVIDER);
            HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);

            // If not auth scheme has been initialized yet
            if (authState.getAuthScheme() == null) {
                AuthScope authScope = new AuthScope(targetHost.getHostName(), targetHost.getPort());

                // Obtain credentials matching the target host
                Credentials creds = credsProvider.getCredentials(authScope);

                // If found, generate BasicScheme preemptively
                if (creds != null) {
                    authState.setAuthScheme(new BasicScheme());
                    authState.setCredentials(creds);
                }
            }
        }
    }

    public RequestExecutor(DefaultHttpClient client) {
        httpClient = client;
    }

    public String toString() {
        if (request == null) {
            return "Request";
        }
        return request.getMethod() + " request to " + request.getURI();
    }

    public RequestExecutor execute(Request r) throws ClientProtocolException, IOException {
        clear();
        r.customizeIfNeeded();
        request = r.getRequest();

        // Optionally setup for basic authentication
        if (r.getUsername() != null) {
            httpClient.getCredentialsProvider().setCredentials(AuthScope.ANY,
                    new UsernamePasswordCredentials(r.getUsername(), r.getPassword()));

            // And add request interceptor to have preemptive authentication
            httpClient.addRequestInterceptor(new PreemptiveAuthInterceptor(), 0);
        } else {
            // Make sure existing credentials are not reused - but looks like we
            // cannot set null as credentials
            httpClient.getCredentialsProvider().setCredentials(AuthScope.ANY,
                    new UsernamePasswordCredentials(getClass().getName(), getClass().getSimpleName()));
            httpClient.removeRequestInterceptorByClass(PreemptiveAuthInterceptor.class);
        }

        // Setup redirects
        httpClient.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, r.getRedirects());

        // Execute request
        response = httpClient.execute(request);
        entity = response.getEntity();
        if (entity != null) {
            consumeEntity();
        }
        return this;
    }

    /** Can be overridden to consume in a different way, or not at all */
    protected void consumeEntity() throws ParseException, IOException {
        content = EntityUtils.toString(entity);
        entity.consumeContent();
    }

    protected void clear() {
        request = null;
        entity = null;
        response = null;
        content = null;
    }

    /** Verify that response matches supplied status */
    public RequestExecutor assertStatus(int expected) {
        assertNotNull(this.toString(), response);
        assertEquals(this + ": expecting status " + expected, expected, response.getStatusLine().getStatusCode());
        return this;
    }

    /** Verify that response matches supplied content type */
    public RequestExecutor assertContentType(String expected) {
        assertNotNull(this.toString(), response);
        if (entity == null) {
            fail(this + ": no entity in response, cannot check content type");
        }

        // Remove whatever follows semicolon in content-type
        String contentType = entity.getContentType().getValue();
        if (contentType != null) {
            contentType = contentType.split(";")[0].trim();
        }

        // And check for match
        assertEquals(this + ": expecting content type " + expected, expected, contentType);
        return this;
    }

    /** For each supplied regexp, fail unless content contains at 
     *  least one line that matches.
     *  Regexps are automatically prefixed/suffixed with .* so as
     *  to have match partial lines.
     */
    public RequestExecutor assertContentRegexp(String... regexp) throws IOException {
        assertNotNull(this.toString(), response);
        nextPattern: for (String expr : regexp) {
            final Pattern p = Pattern.compile(".*" + expr + ".*");
            final BufferedReader br = new BufferedReader(new StringReader(content));
            String line = null;
            while ((line = br.readLine()) != null) {
                if (p.matcher(line).matches()) {
                    continue nextPattern;
                }
            }
            fail(this + ": no match for regexp '" + expr + "', content=\n" + content);
        }
        return this;
    }

    /** For each supplied string, fail unless content contains it */
    public RequestExecutor assertContentContains(String... expected) throws ParseException, IOException {
        assertNotNull(this.toString(), response);
        for (String exp : expected) {
            if (!content.contains(exp)) {
                fail(this + ": content does not contain '" + exp + "', content=\n" + content);
            }
        }
        return this;
    }

    public void generateDocumentation(RequestDocumentor documentor, String... metadata) throws IOException {
        documentor.generateDocumentation(this, metadata);
    }

    public HttpUriRequest getRequest() {
        return request;
    }

    public HttpResponse getResponse() {
        return response;
    }

    public HttpEntity getEntity() {
        return entity;
    }

    public String getContent() {
        return content;
    }
}