package com.mindprod.http;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.Locale;
/**
* base class to Post, Get, Probe to send/receive HTTP messages.
* <p/>
* Originally based on work by Jonathan Revusky
*
* @author Roedy Green, Canadian Mind Products
* @version 2.0 2009-02-20 - major refactoring. separate setParms and setPostParms. new send method. Post can have both types of parm.
* @since 1998
*/
abstract class Http
{
/**
* true if want extra debugging output
*/
static final boolean DEBUGGING = false;
/**
* message length to presume when no length given
*/
static final int DEFAULT_LENGTH = 32 * 1024;
/**
* responseCode to give if is no proper one
*/
static final int DEFAULT_RESPONSE_CODE = -1;
/**
* Accept-Charset for header
*/
private static final String ACCEPT_CHARSET = "iso-8859-1, utf-8, utf-16, *;q=0.1";
/**
* Accept-Encoding for header
*/
private static final String ACCEPT_ENCODING = "gzip, x-gzip, identity, *;q=0";
/**
* Accept property for header
*/
private static final String ACCEPT_PROPERTY = "text/html, image/png, image/jpeg, image/gif, application/x-java-serialized-object, " +
"text/x-java-source, text/xml, application/xml, text/css, application/x-java-jnlp-file, text/plain, " +
"application/zip, application/octet-stream, *; q=.2, */*; q=.2";
/**
* responseMessage to give if is no proper one. Might mean for example that you tried to use http: on https: URL.
*/
static final String DEFAULT_RESPONSE_MESSAGE = "no connect";
/**
* parameters we send with the command. c.f. PostParms sent in message body with a post
*/
private String[] parms;
/**
* the page containing the URL we pretend to be.
* By default null, for none.
*/
private String referer = null;
/**
* responseCode in words from most recent post
*/
String responseMessage;
/**
* the browser we pretend to be, by default Firefox 3.5.4
*
* @see <a href="http://mindprod.com/jgloss/http.html">details on User-Agent</a>
*/
private String userAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.4) Gecko/20091016 Firefox/3.5.4 (.NET CLR 3.5.30729)";
/**
* Allow 50 seconds to connect
*/
private int connectTimeout = 50 * 1000;
/**
* Allow 40 seconds for a read to go without progress
*/
int readTimeout = 40 * 1000;
/**
* responseCode from most recent post
*/
int responseCode;
/**
* encode a set of parms for the command, separated with ? = & = *
*
* @param encoding for URLEncoder
* @param parms 0..n strings to be send as parameter, alternating keyword/value
*
* @return all the parms in one string encoded with lead ?
* @throws java.io.UnsupportedEncodingException
* if bad encoding
*/
public static String encodeParms( String encoding, String... parms ) throws UnsupportedEncodingException
{
if ( parms == null || parms.length == 0 )
{
return "";
}
assert ( parms.length & 1 ) == 0 : "must have an even number of parms, keyword=value";
int estLength = 10;
for ( String p : parms )
{
estLength += p.length() + 1;
}
final StringBuilder sb = new StringBuilder( estLength );
for ( int i = 0; i < parms.length - 1; i += 2 )
{
sb.append( i == 0 ? "?" : "&" );
sb.append( URLEncoder.encode( parms[ i ], encoding
) );
sb.append( '=' );
sb.append( URLEncoder.encode( parms[ i + 1 ], encoding
) );
}
return sb.toString();
}
/**
* ges the Referrer ie. the name of a web page this request ostensibly came from.
*
* @return referrer e.g "http://mindprod.com/index.html", null for none.
* @see <a href="http://mindprod.com/jgloss/http.html">details on Referrer</a>
*/
public String getReferer()
{
return referer;
}
/**
* set the Referrer ie. the name of a web page this request ostensibly came from.
* Note that the word Referrer is spelled incorrectly as Referer the HTTP spec.
*
* @param referer e.g "http://mindprod.com/index.html", null for none.
*
* @see <a href="http://mindprod.com/jgloss/http.html">details on Referrer</a>
*/
public void setReferer( String referer )
{
this.referer = referer;
}
/**
* responseCode from most recent post/get
* Meaning of various codes are described at HttpURLConnection and at http://mindprod.com/jgloss/http.html
*
* @return responseCode
* @see java.net.HttpURLConnection
*/
public int getResponseCode()
{
return responseCode;
}
/**
* responseCode from most recent post/get
*
* @return responseCode
*/
public String getResponseMessage()
{
return responseMessage;
}
/**
* override the default connect timeout of 50 seconds
*
* @param connectTimeout timeout to connect in ms. Note int, not long.
*/
public void setConnectTimeout( int connectTimeout )
{
this.connectTimeout = connectTimeout;
}
/**
* set the parms that will be send with the initial command
*
* @param parms 0..n strings to be send as parameter, alternating keyword/value
*/
public void setParms( final String... parms )
{
assert ( parms.length & 1 ) == 0 : "must have an even number of parms, keyword=value";
this.parms = parms;
}
/**
* override the default read timeout of 40 seconds
*
* @param readTimeout timeout to connect int ms. Note int, not long.
*/
public void setReadTimeout( int readTimeout )
{
this.readTimeout = readTimeout;
}
/**
* override the default User-Agent
*
* @param userAgent User-Agent a browser uses in an HTTP header to identify itself.
* null for no User Agent. By default you get Firefox.
*
* @see <a href="http://mindprod.com/jgloss/http.html">details on User-Agent</a>
*/
public void setUserAgent( String userAgent )
{
this.userAgent = userAgent;
}
/**
* no public instantiation. Just a base class.
*/
Http()
{
}
/**
* get the parms for the command encoded, separated with ? = & = *
*
* @param encoding for URLEncoder
*
* @return all the parms in one string encoded with lead ?
* @throws java.io.UnsupportedEncodingException
* if bad encoding
*/
String getEncodedParms( String encoding ) throws UnsupportedEncodingException
{
return encodeParms( encoding, this.parms );
}
/**
* process the response from the request we sent the server
*
* @param encoding Encoding to use to interpret the result.
* @param urlc the HttpURLConnection, all ready to go but for the connect.
*
* @return content of the response, decompressed, decoded.
* @throws java.io.IOException if trouble reading the stream.
*/
String processResponse( String encoding, HttpURLConnection urlc )
throws IOException
{
urlc.connect();
responseCode = urlc.getResponseCode();
responseMessage = urlc.getResponseMessage();
int estimatedLength = urlc.getContentLength();
if ( estimatedLength < 0 )
{
estimatedLength = DEFAULT_LENGTH;
}
final InputStream is = urlc.getInputStream();
final String contentType = urlc.getContentType();
int place = contentType.lastIndexOf( "charset=" );
final String revisedEncoding;
if ( place >= 0 )
{
revisedEncoding = contentType.substring( place + "charset=".length() ).trim().toUpperCase();
}
else
{
revisedEncoding = encoding;
}
final boolean gzipped = "gzip".equals( urlc.getContentEncoding() )
|| "x-gzip".equals( urlc.getContentEncoding() );
String result = Read.readStringBlocking( is,
estimatedLength,
readTimeout,
gzipped,
revisedEncoding );
if ( DEBUGGING )
{
System.out.println( "--------------------------------" );
System.out.println( "ResponseCode:" + responseCode );
System.out.println( "ResponseMessage:" + responseMessage );
System.out.println( "ContentType:" + contentType );
System.out.println( "CharSet:" + revisedEncoding );
System.out.println( "ContentEncoding:" + urlc.getContentEncoding() );
System.out.println( "Result:" + ( result == null ? "null" : result.substring( 0, Math.min( result.length(), 300 ) ) ) );
}
is.close();
urlc.disconnect();
return result;
}
/**
* set up the standard properties on the connection
*
* @param urlc Connection we are setting up.
*/
protected void setStandardProperties( URLConnection urlc )
{
urlc.setConnectTimeout( connectTimeout );
urlc.setReadTimeout( readTimeout );
if ( userAgent != null )
{
urlc.setRequestProperty( "User-Agent", userAgent );
}
if ( referer != null )
{
urlc.setRequestProperty( "Referer", referer );
}
urlc.setRequestProperty( "Accept", ACCEPT_PROPERTY );
urlc.setRequestProperty( "Accept-Charset", ACCEPT_CHARSET );
urlc.setRequestProperty( "Accept-Encoding", ACCEPT_ENCODING );
final Locale locale = Locale.getDefault();
urlc.setRequestProperty( "Accept-Language", locale.toString() + "," + locale.getLanguage() + ";q=0.9" );
}
}