/* * Copyright 2012 Nodeable Inc * * Licensed 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 com.streamreduce.util; import com.streamreduce.Constants; import com.streamreduce.core.model.ConnectionCredentials; import com.streamreduce.core.service.exception.InvalidCredentialsException; import org.apache.commons.io.IOUtils; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.params.ClientPNames; import org.apache.http.client.params.CookiePolicy; import org.apache.http.client.protocol.ClientContext; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.PoolingClientConnectionManager; import org.apache.http.message.BasicHeader; import org.apache.http.params.CoreProtocolPNames; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HttpContext; import org.apache.http.util.EntityUtils; import org.scribe.model.OAuthRequest; import org.scribe.model.Response; import org.scribe.model.Token; import org.scribe.model.Verb; import org.scribe.oauth.OAuthService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils; import javax.annotation.Nullable; import java.io.IOException; import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; /** * Simple class that provides helper methods for HTTP-related work. */ public final class HTTPUtils { public static Logger LOGGER = LoggerFactory.getLogger(HTTPUtils.class); private static HttpClient httpClient; static { PoolingClientConnectionManager connectionManager = new PoolingClientConnectionManager(); connectionManager.setMaxTotal(200); connectionManager.setDefaultMaxPerRoute(20); httpClient = new DefaultHttpClient(connectionManager); } public static String openOAuthUrl(String url, String method, String data, String mediaType, OAuthService oAuthService, ConnectionCredentials credentials, @Nullable List<Header> requestHeaders, List<Header> responseHeaders) throws InvalidCredentialsException, IOException { String oAuthToken = credentials.getOauthToken(); String oAuthSecret = credentials.getOauthTokenSecret(); Token token; if (StringUtils.hasText(oAuthSecret)) { token = new Token(oAuthToken, oAuthSecret); } else { token = new Token(oAuthToken, ""); } OAuthRequest request = new OAuthRequest(Verb.valueOf(method.toUpperCase()), url); if (data != null) { request.addPayload(data); } if (requestHeaders == null) { requestHeaders = new ArrayList<>(); } for (Header header : requestHeaders) { request.addHeader(header.getName(), header.getValue()); } if (mediaType != null) { request.addHeader("Content-Type", mediaType); } oAuthService.signRequest(token, request); Response response = request.send(); if (response.getCode() == 401 || response.getCode() == 403) { throw new InvalidCredentialsException("The OAuth Token is invalid, or has been revoked"); } else if (response.getCode() != 200) { throw new IOException("Unexpected status code of " + response.getCode() + ": " + response.getBody() + " for a " + method + " request to" + url); } if (response.getHeaders() != null) { for (Map.Entry<String, String> headerKeyValue : response.getHeaders().entrySet()) { if (headerKeyValue.getKey() != null) { Header h = new BasicHeader(headerKeyValue.getKey(), headerKeyValue.getValue()); responseHeaders.add(h); } } } if (response.getBody() == null) { StringWriter writer = new StringWriter(); IOUtils.copy(response.getStream(), writer); return writer.toString(); } else { return response.getBody(); } } /** * Opens a connection to the specified URL with the supplied username and password, * if supplied, and then reads the contents of the URL. * * @param url the url to open and read from * @param method the method to use for the request * @param data the request body as string * @param mediaType the media type of the request * @param username the username, if any * @param password the password, if any * @param requestHeaders the special request headers to send * @param responseHeaders save response headers * @return the read string from the * @throws InvalidCredentialsException if the connection credentials are invalid * @throws IOException if there is a problem with the request */ public static String openUrl(String url, String method, String data, String mediaType, @Nullable String username, @Nullable String password, @Nullable List<Header> requestHeaders, @Nullable List<Header> responseHeaders) throws InvalidCredentialsException, IOException { String response = null; /* Set the cookie policy */ httpClient.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY); /* Set the user agent */ httpClient.getParams().setParameter(CoreProtocolPNames.USER_AGENT, Constants.NODEABLE_HTTP_USER_AGENT); HttpContext context = new BasicHttpContext(); HttpRequestBase httpMethod; if (method.equals("DELETE")) { httpMethod = new HttpDelete(url); } else if (method.equals("GET")) { httpMethod = new HttpGet(url); } else if (method.equals("POST")) { httpMethod = new HttpPost(url); } else if (method.equals("PUT")) { httpMethod = new HttpPut(url); } else { throw new IllegalArgumentException("The method you specified is not supported."); } // Put data into the request for POST and PUT requests if (method.equals("POST") || method.equals("PUT") && data != null) { HttpEntityEnclosingRequestBase eeMethod = (HttpEntityEnclosingRequestBase) httpMethod; eeMethod.setEntity(new StringEntity(data, ContentType.create(mediaType, "UTF-8"))); } /* Set the username/password if any */ if (username != null) { CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); credentialsProvider.setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT), new UsernamePasswordCredentials(username, password)); context.setAttribute(ClientContext.CREDS_PROVIDER, credentialsProvider); } /* Add request headers if need be */ if (requestHeaders != null) { for (Header header : requestHeaders) { httpMethod.addHeader(header); } } LOGGER.debug("Making HTTP request as " + (username != null ? username : "anonymous") + ": " + method + " - " + url); /* Make the request and read the response */ try { HttpResponse httpResponse = httpClient.execute(httpMethod); HttpEntity entity = httpResponse.getEntity(); if (entity != null) { response = EntityUtils.toString(entity); } int responseCode = httpResponse.getStatusLine().getStatusCode(); if (responseCode == 401 || responseCode == 403) { throw new InvalidCredentialsException("The connection credentials are invalid."); } else if (responseCode < 200 || responseCode > 299) { throw new IOException("Unexpected status code of " + responseCode + " for a " + method + " request to " + url); } if (responseHeaders != null) { responseHeaders.addAll(Arrays.asList(httpResponse.getAllHeaders())); } } catch (IOException e) { httpMethod.abort(); throw e; } return response; } }