CC-Tweaked/src/main/java/dan200/computercraft/core/apis/HTTPRequest.java

304 lines
9.7 KiB
Java

/**
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.apis;
import dan200.computercraft.ComputerCraft;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
class HTTPRequestException extends Exception {
public HTTPRequestException( String s ) {
super( s );
}
}
public class HTTPRequest
{
public static URL checkURL( String urlString ) throws HTTPRequestException
{
URL url;
try
{
url = new URL( urlString );
}
catch( MalformedURLException e )
{
throw new HTTPRequestException( "URL malformed" );
}
// Validate the URL
String protocol = url.getProtocol().toLowerCase();
if( !protocol.equals("http") && !protocol.equals("https") )
{
throw new HTTPRequestException( "URL not http" );
}
// Compare the URL to the whitelist
boolean allowed = false;
String whitelistString = ComputerCraft.http_whitelist;
String[] allowedURLs = whitelistString.split( ";" );
for( int i=0; i<allowedURLs.length; ++i )
{
String allowedURL = allowedURLs[i];
Pattern allowedURLPattern = Pattern.compile( "^\\Q" + allowedURL.replaceAll( "\\*", "\\\\E.*\\\\Q" ) + "\\E$" );
if( allowedURLPattern.matcher( url.getHost() ).matches() )
{
allowed = true;
break;
}
}
if( !allowed )
{
throw new HTTPRequestException( "Domain not permitted" );
}
return url;
}
public HTTPRequest( String url, final String postText, final Map<String, String> headers ) throws HTTPRequestException
{
// Parse the URL
m_urlString = url;
m_url = checkURL( m_urlString );
// Start the thread
m_cancelled = false;
m_complete = false;
m_success = false;
m_result = null;
m_responseCode = -1;
Thread thread = new Thread( new Runnable() {
@Override
public void run()
{
try
{
// Connect to the URL
HttpURLConnection connection = (HttpURLConnection)m_url.openConnection();
if( postText != null )
{
connection.setRequestMethod( "POST" );
connection.setDoOutput( true );
}
else
{
connection.setRequestMethod( "GET" );
}
// Set headers
connection.setRequestProperty( "accept-charset", "UTF-8" );
if( postText != null )
{
connection.setRequestProperty( "content-type", "application/x-www-form-urlencoded; charset=utf-8" );
connection.setRequestProperty( "content-encoding", "UTF-8" );
}
if( headers != null )
{
for( Map.Entry<String, String> header : headers.entrySet() )
{
connection.setRequestProperty( header.getKey(), header.getValue() );
}
}
// Send POST text
if( postText != null )
{
OutputStream os = connection.getOutputStream();
OutputStreamWriter osw;
try
{
osw = new OutputStreamWriter( os, "UTF-8" );
}
catch( UnsupportedEncodingException e )
{
osw = new OutputStreamWriter( os );
}
BufferedWriter writer = new BufferedWriter( osw );
writer.write( postText, 0, postText.length() );
writer.close();
}
// Read response
InputStream is;
int code = connection.getResponseCode();
boolean responseSuccess;
if (code >= 200 && code < 400) {
is = connection.getInputStream();
responseSuccess = true;
} else {
is = connection.getErrorStream();
responseSuccess = false;
}
InputStreamReader isr;
try
{
String contentEncoding = connection.getContentEncoding();
if( contentEncoding != null )
{
try
{
isr = new InputStreamReader( is, contentEncoding );
}
catch( UnsupportedEncodingException e )
{
isr = new InputStreamReader( is, "UTF-8" );
}
}
else
{
isr = new InputStreamReader( is, "UTF-8" );
}
}
catch( UnsupportedEncodingException e )
{
isr = new InputStreamReader( is );
}
// Download the contents
BufferedReader reader = new BufferedReader( isr );
StringBuilder result = new StringBuilder();
while( true )
{
synchronized( m_lock )
{
if( m_cancelled )
{
break;
}
}
String line = reader.readLine();
if( line == null )
{
break;
}
result.append( line );
result.append( '\n' );
}
reader.close();
synchronized( m_lock )
{
if( m_cancelled )
{
// We cancelled
m_complete = true;
m_success = false;
m_result = null;
}
else
{
// We completed
m_complete = true;
m_success = responseSuccess;
m_result = result.toString();
m_responseCode = connection.getResponseCode();
Map<String, Map<Integer, String>> headers = m_responseHeaders = new HashMap<String, Map<Integer, String>>();
for (Map.Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
Map<Integer, String> values = new HashMap<Integer, String>();
int i = 0;
for (String value : header.getValue()) {
values.put(++i, value);
}
headers.put(header.getKey(), values);
}
}
}
connection.disconnect(); // disconnect
}
catch( IOException e )
{
synchronized( m_lock )
{
// There was an error
m_complete = true;
m_success = false;
m_result = null;
}
}
}
} );
thread.start();
}
public String getURL() {
return m_urlString;
}
public void cancel()
{
synchronized(m_lock) {
m_cancelled = true;
}
}
public boolean isComplete()
{
synchronized(m_lock) {
return m_complete;
}
}
public int getResponseCode() {
synchronized(m_lock) {
return m_responseCode;
}
}
public Map<String, Map<Integer, String>> getResponseHeaders() {
synchronized (m_lock) {
return m_responseHeaders;
}
}
public boolean wasSuccessful()
{
synchronized(m_lock) {
return m_success;
}
}
public BufferedReader getContents()
{
String result = null;
synchronized(m_lock) {
result = m_result;
}
if( result != null ) {
return new BufferedReader( new StringReader( result ) );
}
return null;
}
private Object m_lock = new Object();
private URL m_url;
private final String m_urlString;
private boolean m_complete;
private boolean m_cancelled;
private boolean m_success;
private String m_result;
private int m_responseCode;
private Map<String, Map<Integer, String>> m_responseHeaders;
}