package org.scribe.model;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.TimeUnit;
import org.scribe.exceptions.*;
import org.scribe.utils.*;
/**
* Represents an HTTP Request object
*
* @author Pablo Fernandez
*/
class Request
{
private static final String CONTENT_LENGTH = "Content-Length";
private String url;
private Verb verb;
private Map<String, String> querystringParams;
private Map<String, String> bodyParams;
private Map<String, String> headers;
private String payload = null;
private HttpURLConnection connection;
/**
* Creates a new Http Request
*
* @param verb Http Verb (GET, POST, etc)
* @param url url with optional querystring parameters.
*/
public Request(Verb verb, String url)
{
this.verb = verb;
this.url = url;
this.querystringParams = new HashMap<String, String>();
this.bodyParams = new HashMap<String, String>();
this.headers = new HashMap<String, String>();
}
/**
* Execute the request and return a {@link Response}
*
* @return Http Response
* @throws RuntimeException
* if the connection cannot be created.
*/
public Response send()
{
try
{
createConnection();
return doSend();
} catch (IOException ioe)
{
throw new OAuthException("Problems while creating connection", ioe);
}
}
private void createConnection() throws IOException
{
String effectiveUrl = URLUtils.appendParametersToQueryString(url, querystringParams);
if (connection == null)
{
connection = (HttpURLConnection) new URL(effectiveUrl).openConnection();
}
}
Response doSend() throws IOException
{
connection.setRequestMethod(this.verb.name());
addHeaders(connection);
if (verb.equals(Verb.PUT) || verb.equals(Verb.POST))
{
addBody(connection, getBodyContents());
}
return new Response(connection);
}
void addHeaders(HttpURLConnection conn)
{
for (String key : headers.keySet())
conn.setRequestProperty(key, headers.get(key));
}
void addBody(HttpURLConnection conn, String content) throws IOException
{
conn.setRequestProperty(CONTENT_LENGTH, String.valueOf(content.getBytes().length));
conn.setDoOutput(true);
conn.getOutputStream().write(content.getBytes());
}
/**
* Add an HTTP Header to the Request
*
* @param key the header name
* @param value the header value
*/
public void addHeader(String key, String value)
{
this.headers.put(key, value);
}
/**
* Add a body Parameter (for POST/ PUT Requests)
*
* @param key the parameter name
* @param value the parameter value
*/
public void addBodyParameter(String key, String value)
{
this.bodyParams.put(key, value);
}
/**
* Add a QueryString parameter
*
* @param key the parameter name
* @param value the parameter value
*/
public void addQuerystringParameter(String key, String value)
{
this.querystringParams.put(key, value);
}
/**
* Add body payload.
*
* This method is used when the HTTP body is not a form-url-encoded string,
* but another thing. Like for example XML.
*
* Note: The contents are not part of the OAuth signature
*
* @param payload the body of the request
*/
public void addPayload(String payload)
{
this.payload = payload;
}
/**
* Get a {@link Map} of the query string parameters.
*
* @return a map containing the query string parameters
*/
public Map<String, String> getQueryStringParams()
{
try
{
Map<String, String> params = new HashMap<String, String>();
String query = new URL(url).getQuery();
if (query != null)
{
for (String param : query.split("&"))
{
String pair[] = param.split("=");
params.put(pair[0], pair[1]);
}
}
params.putAll(querystringParams);
return params;
}
catch (MalformedURLException mue)
{
throw new OAuthException("Malformed URL", mue);
}
}
/**
* Obtains a {@link Map} of the body parameters.
*
* @return a map containing the body parameters.
*/
public Map<String, String> getBodyParams()
{
return bodyParams;
}
/**
* Obtains the URL of the HTTP Request.
*
* @return the original URL of the HTTP Request
*/
public String getUrl()
{
return url;
}
/**
* Returns the URL without the port and the query string part.
*
* @return the OAuth-sanitized URL
*/
public String getSanitizedUrl()
{
return url.replaceAll("\\?.*", "").replace("\\:\\d{4}", "");
}
/**
* Returns the body of the request
*
* @return form encoded string
*/
public String getBodyContents()
{
return (payload != null) ? payload : URLUtils.formURLEncodeMap(bodyParams);
}
/**
* Returns the HTTP Verb
*
* @return the verb
*/
public Verb getVerb()
{
return verb;
}
/**
* Returns the connection headers as a {@link Map}
*
* @return map of headers
*/
public Map<String, String> getHeaders()
{
return headers;
}
/**
* Sets the connect timeout for the underlying {@link HttpURLConnection}
*
* @param duration duration of the timeout
*
* @param unit unit of time (milliseconds, seconds, etc)
*/
public void setConnectTimeout(int duration, TimeUnit unit)
{
this.connection.setConnectTimeout((int) unit.toMillis(duration));
}
/**
* Sets the read timeout for the underlying {@link HttpURLConnection}
*
* @param duration duration of the timeout
*
* @param unit unit of time (milliseconds, seconds, etc)
*/
public void setReadTimeout(int duration, TimeUnit unit)
{
this.connection.setReadTimeout((int) unit.toMillis(duration));
}
/*
* We need this in order to stub the connection object for test cases
*/
void setConnection(HttpURLConnection connection)
{
this.connection = connection;
}
@Override
public String toString()
{
return String.format("@Request(%s %s)", getVerb(), getUrl());
}
}