mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-31 21:52:59 +00:00 
			
		
		
		
	Make many more http options domain-specific
timetout, max_upload, max_download and max_websocket_message may now be
configured on a domain-by-domain basis. This uses the same system that
we use for the block/allow-list from before:
Example:
    [[http.rules]]
        host = "*"
        action = "allow"
	max_upload = 4194304
	max_download = 16777216
	timeout = 30000
			
			
This commit is contained in:
		| @@ -6,7 +6,8 @@ | ||||
| package dan200.computercraft; | ||||
|  | ||||
| import dan200.computercraft.api.turtle.event.TurtleAction; | ||||
| import dan200.computercraft.core.apis.http.AddressRule; | ||||
| import dan200.computercraft.core.apis.http.options.Action; | ||||
| import dan200.computercraft.core.apis.http.options.AddressRule; | ||||
| import dan200.computercraft.shared.Config; | ||||
| import dan200.computercraft.shared.computer.blocks.BlockComputer; | ||||
| import dan200.computercraft.shared.computer.core.ClientComputerRegistry; | ||||
| @@ -70,7 +71,7 @@ public final class ComputerCraft | ||||
|     public static boolean disable_lua51_features = false; | ||||
|     public static String default_computer_settings = ""; | ||||
|     public static boolean debug_enable = true; | ||||
|     public static boolean logPeripheralErrors = true; | ||||
|     public static boolean logComputerErrors = true; | ||||
|     public static boolean commandRequireCreative = true; | ||||
|  | ||||
|     public static int computer_threads = 1; | ||||
| @@ -80,16 +81,16 @@ public final class ComputerCraft | ||||
|     public static boolean httpEnabled = true; | ||||
|     public static boolean httpWebsocketEnabled = true; | ||||
|     public static List<AddressRule> httpRules = Collections.unmodifiableList( Stream.concat( | ||||
|         Stream.of( DEFAULT_HTTP_DENY ).map( x -> AddressRule.parse( x, AddressRule.Action.DENY ) ).filter( Objects::nonNull ), | ||||
|         Stream.of( DEFAULT_HTTP_ALLOW ).map( x -> AddressRule.parse( x, AddressRule.Action.ALLOW ) ).filter( Objects::nonNull ) | ||||
|         Stream.of( DEFAULT_HTTP_DENY ) | ||||
|             .map( x -> AddressRule.parse( x, Action.DENY.toPartial() ) ) | ||||
|             .filter( Objects::nonNull ), | ||||
|         Stream.of( DEFAULT_HTTP_ALLOW ) | ||||
|             .map( x -> AddressRule.parse( x, Action.ALLOW.toPartial() ) ) | ||||
|             .filter( Objects::nonNull ) | ||||
|     ).collect( Collectors.toList() ) ); | ||||
|  | ||||
|     public static int httpTimeout = 30000; | ||||
|     public static int httpMaxRequests = 16; | ||||
|     public static long httpMaxDownload = 16 * 1024 * 1024; | ||||
|     public static long httpMaxUpload = 4 * 1024 * 1024; | ||||
|     public static int httpMaxWebsockets = 4; | ||||
|     public static int httpMaxWebsocketMessage = 128 * 1024; | ||||
|  | ||||
|     public static boolean enableCommandBlock = false; | ||||
|     public static int modem_range = 64; | ||||
|   | ||||
| @@ -119,12 +119,6 @@ public class HTTPAPI implements ILuaAPI | ||||
|             URI uri = HttpRequest.checkUri( address ); | ||||
|             HttpRequest request = new HttpRequest( requests, m_apiEnvironment, address, postString, headers, binary, redirect ); | ||||
|  | ||||
|             long requestBody = request.body().readableBytes() + HttpRequest.getHeaderSize( headers ); | ||||
|             if( ComputerCraft.httpMaxUpload != 0 && requestBody > ComputerCraft.httpMaxUpload ) | ||||
|             { | ||||
|                 throw new HTTPRequestException( "Request body is too large" ); | ||||
|             } | ||||
|  | ||||
|             // Make the request | ||||
|             request.queue( r -> r.request( uri, httpMethod ) ); | ||||
|  | ||||
|   | ||||
| @@ -7,6 +7,7 @@ package dan200.computercraft.core.apis.http; | ||||
|  | ||||
| import dan200.computercraft.core.apis.IAPIEnvironment; | ||||
|  | ||||
| import java.net.InetSocketAddress; | ||||
| import java.net.URI; | ||||
| import java.util.concurrent.Future; | ||||
|  | ||||
| @@ -46,7 +47,9 @@ public class CheckUrl extends Resource<CheckUrl> | ||||
|  | ||||
|         try | ||||
|         { | ||||
|             NetworkUtils.getAddress( host, 80, false ); | ||||
|             InetSocketAddress address = NetworkUtils.getAddress( host, 80, false ); | ||||
|             NetworkUtils.getOptions( host, address ); | ||||
|  | ||||
|             if( tryClose() ) environment.queueEvent( EVENT, address, true ); | ||||
|         } | ||||
|         catch( HTTPRequestException e ) | ||||
|   | ||||
| @@ -6,6 +6,9 @@ | ||||
| package dan200.computercraft.core.apis.http; | ||||
|  | ||||
| import dan200.computercraft.ComputerCraft; | ||||
| import dan200.computercraft.core.apis.http.options.Action; | ||||
| import dan200.computercraft.core.apis.http.options.AddressRule; | ||||
| import dan200.computercraft.core.apis.http.options.Options; | ||||
| import dan200.computercraft.shared.util.ThreadUtils; | ||||
| import io.netty.buffer.ByteBuf; | ||||
| import io.netty.channel.EventLoopGroup; | ||||
| @@ -15,7 +18,6 @@ import io.netty.handler.ssl.SslContextBuilder; | ||||
|  | ||||
| import javax.net.ssl.SSLException; | ||||
| import javax.net.ssl.TrustManagerFactory; | ||||
| import java.net.InetAddress; | ||||
| import java.net.InetSocketAddress; | ||||
| import java.security.KeyStore; | ||||
| import java.util.concurrent.ExecutorService; | ||||
| @@ -106,24 +108,31 @@ public final class NetworkUtils | ||||
|      * @param port The port, or -1 if not defined. | ||||
|      * @param ssl  Whether to connect with SSL. This is used to find the default port if not otherwise specified. | ||||
|      * @return The resolved address. | ||||
|      * @throws HTTPRequestException If the host is not permitted. | ||||
|      * @throws HTTPRequestException If the host is not malformed. | ||||
|      */ | ||||
|     public static InetSocketAddress getAddress( String host, int port, boolean ssl ) throws HTTPRequestException | ||||
|     { | ||||
|         if( port < 0 ) port = ssl ? 443 : 80; | ||||
|  | ||||
|         InetSocketAddress socketAddress = new InetSocketAddress( host, port ); | ||||
|         if( socketAddress.isUnresolved() ) throw new HTTPRequestException( "Unknown host" ); | ||||
|  | ||||
|         InetAddress address = socketAddress.getAddress(); | ||||
|         if( AddressRule.apply( ComputerCraft.httpRules, host, address ) == AddressRule.Action.DENY ) | ||||
|         { | ||||
|             throw new HTTPRequestException( "Domain not permitted" ); | ||||
|         } | ||||
|  | ||||
|         return socketAddress; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get options for a specific domain. | ||||
|      * | ||||
|      * @param host    The host to resolve. | ||||
|      * @param address The address, resolved by {@link #getAddress(String, int, boolean)}. | ||||
|      * @return The options for this host. | ||||
|      * @throws HTTPRequestException If the host is not permitted | ||||
|      */ | ||||
|     public static Options getOptions( String host, InetSocketAddress address ) throws HTTPRequestException | ||||
|     { | ||||
|         Options options = AddressRule.apply( ComputerCraft.httpRules, host, address.getAddress() ); | ||||
|         if( options.action == Action.DENY ) throw new HTTPRequestException( "Domain not permitted" ); | ||||
|         return options; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Read a {@link ByteBuf} into a byte array. | ||||
|      * | ||||
|   | ||||
| @@ -0,0 +1,23 @@ | ||||
| /* | ||||
|  * This file is part of ComputerCraft - http://www.computercraft.info | ||||
|  * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. | ||||
|  * Send enquiries to dratcliffe@gmail.com | ||||
|  */ | ||||
|  | ||||
| package dan200.computercraft.core.apis.http.options; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| public enum Action | ||||
| { | ||||
|     ALLOW, | ||||
|     DENY; | ||||
|  | ||||
|     private final PartialOptions partial = new PartialOptions( this, null, null, null, null ); | ||||
|  | ||||
|     @Nonnull | ||||
|     public PartialOptions toPartial() | ||||
|     { | ||||
|         return partial; | ||||
|     } | ||||
| } | ||||
| @@ -3,11 +3,12 @@ | ||||
|  * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. | ||||
|  * Send enquiries to dratcliffe@gmail.com | ||||
|  */ | ||||
| package dan200.computercraft.core.apis.http; | ||||
| package dan200.computercraft.core.apis.http.options; | ||||
| 
 | ||||
| import com.google.common.net.InetAddresses; | ||||
| import dan200.computercraft.ComputerCraft; | ||||
| 
 | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
| import java.net.Inet6Address; | ||||
| import java.net.InetAddress; | ||||
| @@ -18,6 +19,11 @@ import java.util.regex.Pattern; | ||||
|  */ | ||||
| public final class AddressRule | ||||
| { | ||||
|     public static final long MAX_DOWNLOAD = 16 * 1024 * 1024; | ||||
|     public static final long MAX_UPLOAD = 4 * 1024 * 1024; | ||||
|     public static final int TIMEOUT = 30_000; | ||||
|     public static final int WEBSOCKET_MESSAGE = 128 * 1024; | ||||
| 
 | ||||
|     private static final class HostRange | ||||
|     { | ||||
|         private final byte[] min; | ||||
| @@ -44,25 +50,19 @@ public final class AddressRule | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public enum Action | ||||
|     { | ||||
|         ALLOW, | ||||
|         DENY, | ||||
|     } | ||||
| 
 | ||||
|     private final HostRange ip; | ||||
|     private final Pattern domainPattern; | ||||
|     private final Action action; | ||||
|     private final PartialOptions partial; | ||||
| 
 | ||||
|     private AddressRule( HostRange ip, Pattern domainPattern, Action action ) | ||||
|     private AddressRule( @Nullable HostRange ip, @Nullable Pattern domainPattern, @Nonnull PartialOptions partial ) | ||||
|     { | ||||
|         this.ip = ip; | ||||
|         this.domainPattern = domainPattern; | ||||
|         this.action = action; | ||||
|         this.partial = partial; | ||||
|     } | ||||
| 
 | ||||
|     @Nullable | ||||
|     public static AddressRule parse( String filter, Action action ) | ||||
|     public static AddressRule parse( String filter, @Nonnull PartialOptions partial ) | ||||
|     { | ||||
|         int cidr = filter.indexOf( '/' ); | ||||
|         if( cidr >= 0 ) | ||||
| @@ -117,12 +117,12 @@ public final class AddressRule | ||||
|                 size -= 8; | ||||
|             } | ||||
| 
 | ||||
|             return new AddressRule( new HostRange( minBytes, maxBytes ), null, action ); | ||||
|             return new AddressRule( new HostRange( minBytes, maxBytes ), null, partial ); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             Pattern pattern = Pattern.compile( "^\\Q" + filter.replaceAll( "\\*", "\\\\E.*\\\\Q" ) + "\\E$" ); | ||||
|             return new AddressRule( null, pattern, action ); | ||||
|             return new AddressRule( null, pattern, partial ); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @@ -133,7 +133,7 @@ public final class AddressRule | ||||
|      * @param address The address to check. | ||||
|      * @return Whether it matches any of these patterns. | ||||
|      */ | ||||
|     public boolean matches( String domain, InetAddress address ) | ||||
|     private boolean matches( String domain, InetAddress address ) | ||||
|     { | ||||
|         if( domainPattern != null ) | ||||
|         { | ||||
| @@ -155,13 +155,32 @@ public final class AddressRule | ||||
|         return ip != null && ip.contains( address ); | ||||
|     } | ||||
| 
 | ||||
|     public static Action apply( Iterable<? extends AddressRule> rules, String domain, InetAddress address ) | ||||
|     public static Options apply( Iterable<? extends AddressRule> rules, String domain, InetAddress address ) | ||||
|     { | ||||
|         PartialOptions options = null; | ||||
|         boolean hasMany = false; | ||||
| 
 | ||||
|         for( AddressRule rule : rules ) | ||||
|         { | ||||
|             if( rule.matches( domain, address ) ) return rule.action; | ||||
|             if( !rule.matches( domain, address ) ) continue; | ||||
| 
 | ||||
|             if( options == null ) | ||||
|             { | ||||
|                 options = rule.partial; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
| 
 | ||||
|                 if( !hasMany ) | ||||
|                 { | ||||
|                     options = options.copy(); | ||||
|                     hasMany = true; | ||||
|                 } | ||||
| 
 | ||||
|                 options.merge( rule.partial ); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return Action.DENY; | ||||
|         return (options == null ? PartialOptions.DEFAULT : options).toOptions(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,132 @@ | ||||
| /* | ||||
|  * This file is part of ComputerCraft - http://www.computercraft.info | ||||
|  * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. | ||||
|  * Send enquiries to dratcliffe@gmail.com | ||||
|  */ | ||||
|  | ||||
| package dan200.computercraft.core.apis.http.options; | ||||
|  | ||||
| import com.electronwill.nightconfig.core.CommentedConfig; | ||||
| import com.electronwill.nightconfig.core.Config; | ||||
| import com.electronwill.nightconfig.core.InMemoryCommentedFormat; | ||||
| import com.electronwill.nightconfig.core.UnmodifiableConfig; | ||||
| import dan200.computercraft.ComputerCraft; | ||||
|  | ||||
| import javax.annotation.Nullable; | ||||
| import java.util.Locale; | ||||
| import java.util.Optional; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
|  | ||||
| /** | ||||
|  * Parses, checks and generates {@link Config}s for {@link AddressRule}. | ||||
|  */ | ||||
| public class AddressRuleConfig | ||||
| { | ||||
|     public static UnmodifiableConfig makeRule( String host, Action action ) | ||||
|     { | ||||
|         CommentedConfig config = InMemoryCommentedFormat.defaultInstance().createConfig( ConcurrentHashMap::new ); | ||||
|         config.add( "host", host ); | ||||
|         config.add( "action", action.name().toLowerCase( Locale.ROOT ) ); | ||||
|  | ||||
|         if( host.equals( "*" ) && action == Action.ALLOW ) | ||||
|         { | ||||
|             config.setComment( "timeout", "The period of time (in milliseconds) to wait before a HTTP request times out. Set to 0 for unlimited." ); | ||||
|             config.add( "timeout", AddressRule.TIMEOUT ); | ||||
|  | ||||
|             config.setComment( "max_download", "The maximum size (in bytes) that a computer can download in a single request. Note that responses may receive more data than allowed, but this data will not be returned to the client." ); | ||||
|             config.set( "max_download", AddressRule.MAX_DOWNLOAD ); | ||||
|  | ||||
|             config.setComment( "max_upload", "The maximum size (in bytes) that a computer can upload in a single request. This includes headers and POST text." ); | ||||
|             config.set( "max_upload", AddressRule.MAX_UPLOAD ); | ||||
|  | ||||
|             config.setComment( "max_websocket_message", "The maximum size (in bytes) that a computer can send or receive in one websocket packet." ); | ||||
|             config.set( "max_websocket_message", AddressRule.WEBSOCKET_MESSAGE ); | ||||
|         } | ||||
|  | ||||
|         return config; | ||||
|     } | ||||
|  | ||||
|     public static boolean checkRule( UnmodifiableConfig builder ) | ||||
|     { | ||||
|         String hostObj = get( builder, "host", String.class ).orElse( null ); | ||||
|         return hostObj != null && checkEnum( builder, "action", Action.class ) | ||||
|             && check( builder, "timeout", Number.class ) | ||||
|             && check( builder, "max_upload", Number.class ) | ||||
|             && check( builder, "max_download", Number.class ) | ||||
|             && check( builder, "websocket_message", Number.class ) | ||||
|             && AddressRule.parse( hostObj, PartialOptions.DEFAULT ) != null; | ||||
|     } | ||||
|  | ||||
|     @Nullable | ||||
|     public static AddressRule parseRule( UnmodifiableConfig builder ) | ||||
|     { | ||||
|         String hostObj = get( builder, "host", String.class ).orElse( null ); | ||||
|         if( hostObj == null ) return null; | ||||
|  | ||||
|         Action action = getEnum( builder, "action", Action.class ).orElse( null ); | ||||
|         Integer timeout = get( builder, "timeout", Number.class ).map( Number::intValue ).orElse( null ); | ||||
|         Long maxUpload = get( builder, "max_upload", Number.class ).map( Number::longValue ).orElse( null ); | ||||
|         Long maxDownload = get( builder, "max_download", Number.class ).map( Number::longValue ).orElse( null ); | ||||
|         Integer websocketMessage = get( builder, "websocket_message", Number.class ).map( Number::intValue ).orElse( null ); | ||||
|  | ||||
|         PartialOptions options = new PartialOptions( | ||||
|             action, | ||||
|             maxUpload, | ||||
|             maxDownload, | ||||
|             timeout, | ||||
|             websocketMessage | ||||
|         ); | ||||
|  | ||||
|         return AddressRule.parse( hostObj, options ); | ||||
|     } | ||||
|  | ||||
|     private static <T> boolean check( UnmodifiableConfig config, String field, Class<T> klass ) | ||||
|     { | ||||
|         Object value = config.get( field ); | ||||
|         if( value == null || klass.isInstance( value ) ) return true; | ||||
|  | ||||
|         ComputerCraft.log.warn( "HTTP rule's {} is not a {}.", field, klass.getSimpleName() ); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     private static <T extends Enum<T>> boolean checkEnum( UnmodifiableConfig config, String field, Class<T> klass ) | ||||
|     { | ||||
|         Object value = config.get( field ); | ||||
|         if( value == null ) return true; | ||||
|  | ||||
|         if( !(value instanceof String) ) | ||||
|         { | ||||
|             ComputerCraft.log.warn( "HTTP rule's {} is not a string", field ); | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         if( parseEnum( klass, (String) value ) == null ) | ||||
|         { | ||||
|             ComputerCraft.log.warn( "HTTP rule's {} is not a known option", field ); | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     private static <T> Optional<T> get( UnmodifiableConfig config, String field, Class<T> klass ) | ||||
|     { | ||||
|         Object value = config.get( field ); | ||||
|         return klass.isInstance( value ) ? Optional.of( klass.cast( value ) ) : Optional.empty(); | ||||
|     } | ||||
|  | ||||
|     private static <T extends Enum<T>> Optional<T> getEnum( UnmodifiableConfig config, String field, Class<T> klass ) | ||||
|     { | ||||
|         return get( config, field, String.class ).map( x -> parseEnum( klass, x ) ); | ||||
|     } | ||||
|  | ||||
|     @Nullable | ||||
|     private static <T extends Enum<T>> T parseEnum( Class<T> klass, String x ) | ||||
|     { | ||||
|         for( T value : klass.getEnumConstants() ) | ||||
|         { | ||||
|             if( value.name().equalsIgnoreCase( x ) ) return value; | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,31 @@ | ||||
| /* | ||||
|  * This file is part of ComputerCraft - http://www.computercraft.info | ||||
|  * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. | ||||
|  * Send enquiries to dratcliffe@gmail.com | ||||
|  */ | ||||
|  | ||||
| package dan200.computercraft.core.apis.http.options; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| /** | ||||
|  * Options about a specific domain. | ||||
|  */ | ||||
| public final class Options | ||||
| { | ||||
|     @Nonnull | ||||
|     public final Action action; | ||||
|     public final long maxUpload; | ||||
|     public final long maxDownload; | ||||
|     public final int timeout; | ||||
|     public final int websocketMessage; | ||||
|  | ||||
|     Options( @Nonnull Action action, long maxUpload, long maxDownload, int timeout, int websocketMessage ) | ||||
|     { | ||||
|         this.action = action; | ||||
|         this.maxUpload = maxUpload; | ||||
|         this.maxDownload = maxDownload; | ||||
|         this.timeout = timeout; | ||||
|         this.websocketMessage = websocketMessage; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,59 @@ | ||||
| /* | ||||
|  * This file is part of ComputerCraft - http://www.computercraft.info | ||||
|  * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. | ||||
|  * Send enquiries to dratcliffe@gmail.com | ||||
|  */ | ||||
|  | ||||
| package dan200.computercraft.core.apis.http.options; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| public final class PartialOptions | ||||
| { | ||||
|     static final PartialOptions DEFAULT = new PartialOptions( null, null, null, null, null ); | ||||
|  | ||||
|     Action action; | ||||
|     Long maxUpload; | ||||
|     Long maxDownload; | ||||
|     Integer timeout; | ||||
|     Integer websocketMessage; | ||||
|  | ||||
|     Options options; | ||||
|  | ||||
|     PartialOptions( Action action, Long maxUpload, Long maxDownload, Integer timeout, Integer websocketMessage ) | ||||
|     { | ||||
|         this.action = action; | ||||
|         this.maxUpload = maxUpload; | ||||
|         this.maxDownload = maxDownload; | ||||
|         this.timeout = timeout; | ||||
|         this.websocketMessage = websocketMessage; | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     Options toOptions() | ||||
|     { | ||||
|         if( options != null ) return options; | ||||
|  | ||||
|         return options = new Options( | ||||
|             action == null ? Action.DENY : action, | ||||
|             maxUpload == null ? AddressRule.MAX_UPLOAD : maxUpload, | ||||
|             maxDownload == null ? AddressRule.MAX_DOWNLOAD : maxDownload, | ||||
|             timeout == null ? AddressRule.TIMEOUT : timeout, | ||||
|             websocketMessage == null ? AddressRule.WEBSOCKET_MESSAGE : websocketMessage | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     void merge( @Nonnull PartialOptions other ) | ||||
|     { | ||||
|         if( action == null && other.action != null ) action = other.action; | ||||
|         if( maxUpload == null && other.maxUpload != null ) maxUpload = other.maxUpload; | ||||
|         if( maxDownload == null && other.maxDownload != null ) maxDownload = other.maxDownload; | ||||
|         if( timeout == null && other.timeout != null ) timeout = other.timeout; | ||||
|         if( websocketMessage == null && other.websocketMessage != null ) websocketMessage = other.websocketMessage; | ||||
|     } | ||||
|  | ||||
|     PartialOptions copy() | ||||
|     { | ||||
|         return new PartialOptions( action, maxUpload, maxDownload, timeout, websocketMessage ); | ||||
|     } | ||||
| } | ||||
| @@ -11,6 +11,7 @@ import dan200.computercraft.core.apis.http.HTTPRequestException; | ||||
| import dan200.computercraft.core.apis.http.NetworkUtils; | ||||
| import dan200.computercraft.core.apis.http.Resource; | ||||
| import dan200.computercraft.core.apis.http.ResourceGroup; | ||||
| import dan200.computercraft.core.apis.http.options.Options; | ||||
| import dan200.computercraft.core.tracking.TrackingField; | ||||
| import io.netty.bootstrap.Bootstrap; | ||||
| import io.netty.buffer.ByteBuf; | ||||
| @@ -136,16 +137,24 @@ public class HttpRequest extends Resource<HttpRequest> | ||||
|         { | ||||
|             boolean ssl = uri.getScheme().equalsIgnoreCase( "https" ); | ||||
|             InetSocketAddress socketAddress = NetworkUtils.getAddress( uri.getHost(), uri.getPort(), ssl ); | ||||
|             Options options = NetworkUtils.getOptions( uri.getHost(), socketAddress ); | ||||
|             SslContext sslContext = ssl ? NetworkUtils.getSslContext() : null; | ||||
|  | ||||
|             // getAddress may have a slight delay, so let's perform another cancellation check. | ||||
|             if( isClosed() ) return; | ||||
|  | ||||
|             long requestBody = getHeaderSize( headers ) + postBuffer.capacity(); | ||||
|             if( options.maxUpload != 0 && requestBody > options.maxUpload ) | ||||
|             { | ||||
|                 failure( "Request body is too large" ); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             // Add request size to the tracker before opening the connection | ||||
|             environment.addTrackingChange( TrackingField.HTTP_REQUESTS, 1 ); | ||||
|             environment.addTrackingChange( TrackingField.HTTP_UPLOAD, getHeaderSize( headers ) + postBuffer.capacity() ); | ||||
|             environment.addTrackingChange( TrackingField.HTTP_UPLOAD, requestBody ); | ||||
|  | ||||
|             HttpRequestHandler handler = currentRequest = new HttpRequestHandler( this, uri, method ); | ||||
|             HttpRequestHandler handler = currentRequest = new HttpRequestHandler( this, uri, method, options ); | ||||
|             connectFuture = new Bootstrap() | ||||
|                 .group( NetworkUtils.LOOP_GROUP ) | ||||
|                 .channelFactory( NioSocketChannel::new ) | ||||
| @@ -155,9 +164,9 @@ public class HttpRequest extends Resource<HttpRequest> | ||||
|                     protected void initChannel( SocketChannel ch ) | ||||
|                     { | ||||
|  | ||||
|                         if( ComputerCraft.httpTimeout > 0 ) | ||||
|                         if( options.timeout > 0 ) | ||||
|                         { | ||||
|                             ch.config().setConnectTimeoutMillis( ComputerCraft.httpTimeout ); | ||||
|                             ch.config().setConnectTimeoutMillis( options.timeout ); | ||||
|                         } | ||||
|  | ||||
|                         ChannelPipeline p = ch.pipeline(); | ||||
| @@ -166,9 +175,9 @@ public class HttpRequest extends Resource<HttpRequest> | ||||
|                             p.addLast( sslContext.newHandler( ch.alloc(), uri.getHost(), socketAddress.getPort() ) ); | ||||
|                         } | ||||
|  | ||||
|                         if( ComputerCraft.httpTimeout > 0 ) | ||||
|                         if( options.timeout > 0 ) | ||||
|                         { | ||||
|                             p.addLast( new ReadTimeoutHandler( ComputerCraft.httpTimeout, TimeUnit.MILLISECONDS ) ); | ||||
|                             p.addLast( new ReadTimeoutHandler( options.timeout, TimeUnit.MILLISECONDS ) ); | ||||
|                         } | ||||
|  | ||||
|                         p.addLast( | ||||
| @@ -194,7 +203,7 @@ public class HttpRequest extends Resource<HttpRequest> | ||||
|         catch( Exception e ) | ||||
|         { | ||||
|             failure( "Could not connect" ); | ||||
|             if( ComputerCraft.logPeripheralErrors ) ComputerCraft.log.error( "Error in HTTP request", e ); | ||||
|             if( ComputerCraft.logComputerErrors ) ComputerCraft.log.error( "Error in HTTP request", e ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -12,6 +12,7 @@ import dan200.computercraft.core.apis.handles.EncodedReadableHandle; | ||||
| import dan200.computercraft.core.apis.handles.HandleGeneric; | ||||
| import dan200.computercraft.core.apis.http.HTTPRequestException; | ||||
| import dan200.computercraft.core.apis.http.NetworkUtils; | ||||
| import dan200.computercraft.core.apis.http.options.Options; | ||||
| import dan200.computercraft.core.tracking.TrackingField; | ||||
| import io.netty.buffer.ByteBuf; | ||||
| import io.netty.buffer.CompositeByteBuf; | ||||
| @@ -45,18 +46,20 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<HttpOb | ||||
|  | ||||
|     private final URI uri; | ||||
|     private final HttpMethod method; | ||||
|     private final Options options; | ||||
|  | ||||
|     private Charset responseCharset; | ||||
|     private final HttpHeaders responseHeaders = new DefaultHttpHeaders(); | ||||
|     private HttpResponseStatus responseStatus; | ||||
|     private CompositeByteBuf responseBody; | ||||
|  | ||||
|     HttpRequestHandler( HttpRequest request, URI uri, HttpMethod method ) | ||||
|     HttpRequestHandler( HttpRequest request, URI uri, HttpMethod method, Options options ) | ||||
|     { | ||||
|         this.request = request; | ||||
|  | ||||
|         this.uri = uri; | ||||
|         this.method = method; | ||||
|         this.options = options; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
| @@ -153,7 +156,7 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<HttpOb | ||||
|             if( partial.isReadable() ) | ||||
|             { | ||||
|                 // If we've read more than we're allowed to handle, abort as soon as possible. | ||||
|                 if( ComputerCraft.httpMaxDownload != 0 && responseBody.readableBytes() + partial.readableBytes() > ComputerCraft.httpMaxDownload ) | ||||
|                 if( options.maxDownload != 0 && responseBody.readableBytes() + partial.readableBytes() > options.maxDownload ) | ||||
|                 { | ||||
|                     closed = true; | ||||
|                     ctx.close(); | ||||
| @@ -185,7 +188,7 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<HttpOb | ||||
|     @Override | ||||
|     public void exceptionCaught( ChannelHandlerContext ctx, Throwable cause ) | ||||
|     { | ||||
|         if( ComputerCraft.logPeripheralErrors ) ComputerCraft.log.error( "Error handling HTTP response", cause ); | ||||
|         if( ComputerCraft.logComputerErrors ) ComputerCraft.log.error( "Error handling HTTP response", cause ); | ||||
|         request.failure( cause ); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -12,6 +12,7 @@ import dan200.computercraft.core.apis.http.HTTPRequestException; | ||||
| import dan200.computercraft.core.apis.http.NetworkUtils; | ||||
| import dan200.computercraft.core.apis.http.Resource; | ||||
| import dan200.computercraft.core.apis.http.ResourceGroup; | ||||
| import dan200.computercraft.core.apis.http.options.Options; | ||||
| import dan200.computercraft.shared.util.IoUtil; | ||||
| import io.netty.bootstrap.Bootstrap; | ||||
| import io.netty.channel.Channel; | ||||
| @@ -130,6 +131,7 @@ public class Websocket extends Resource<Websocket> | ||||
|             boolean ssl = uri.getScheme().equalsIgnoreCase( "wss" ); | ||||
|  | ||||
|             InetSocketAddress socketAddress = NetworkUtils.getAddress( uri.getHost(), uri.getPort(), ssl ); | ||||
|             Options options = NetworkUtils.getOptions( uri.getHost(), socketAddress ); | ||||
|             SslContext sslContext = ssl ? NetworkUtils.getSslContext() : null; | ||||
|  | ||||
|             // getAddress may have a slight delay, so let's perform another cancellation check. | ||||
| @@ -151,14 +153,14 @@ public class Websocket extends Resource<Websocket> | ||||
|  | ||||
|                         WebSocketClientHandshaker handshaker = WebSocketClientHandshakerFactory.newHandshaker( | ||||
|                             uri, WebSocketVersion.V13, null, true, headers, | ||||
|                             ComputerCraft.httpMaxWebsocketMessage == 0 ? MAX_MESSAGE_SIZE : ComputerCraft.httpMaxWebsocketMessage | ||||
|                             options.websocketMessage <= 0 ? MAX_MESSAGE_SIZE : options.websocketMessage | ||||
|                         ); | ||||
|  | ||||
|                         p.addLast( | ||||
|                             new HttpClientCodec(), | ||||
|                             new HttpObjectAggregator( 8192 ), | ||||
|                             WebSocketClientCompressionHandler.INSTANCE, | ||||
|                             new WebsocketHandler( Websocket.this, handshaker ) | ||||
|                             new WebsocketHandler( Websocket.this, handshaker, options ) | ||||
|                         ); | ||||
|                     } | ||||
|                 } ) | ||||
| @@ -178,15 +180,15 @@ public class Websocket extends Resource<Websocket> | ||||
|         catch( Exception e ) | ||||
|         { | ||||
|             failure( "Could not connect" ); | ||||
|             if( ComputerCraft.logPeripheralErrors ) ComputerCraft.log.error( "Error in websocket", e ); | ||||
|             if( ComputerCraft.logComputerErrors ) ComputerCraft.log.error( "Error in websocket", e ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void success( Channel channel ) | ||||
|     void success( Channel channel, Options options ) | ||||
|     { | ||||
|         if( isClosed() ) return; | ||||
|  | ||||
|         WebsocketHandle handle = new WebsocketHandle( this, channel ); | ||||
|         WebsocketHandle handle = new WebsocketHandle( this, options, channel ); | ||||
|         environment().queueEvent( SUCCESS_EVENT, address, handle ); | ||||
|         websocketHandle = createOwnerReference( handle ); | ||||
|  | ||||
|   | ||||
| @@ -6,8 +6,8 @@ | ||||
| package dan200.computercraft.core.apis.http.websocket; | ||||
|  | ||||
| import com.google.common.base.Objects; | ||||
| import dan200.computercraft.ComputerCraft; | ||||
| import dan200.computercraft.api.lua.*; | ||||
| import dan200.computercraft.core.apis.http.options.Options; | ||||
| import dan200.computercraft.core.tracking.TrackingField; | ||||
| import dan200.computercraft.shared.util.StringUtil; | ||||
| import io.netty.buffer.Unpooled; | ||||
| @@ -28,13 +28,15 @@ import static dan200.computercraft.core.apis.http.websocket.Websocket.MESSAGE_EV | ||||
| public class WebsocketHandle implements Closeable | ||||
| { | ||||
|     private final Websocket websocket; | ||||
|     private final Options options; | ||||
|     private boolean closed = false; | ||||
|  | ||||
|     private Channel channel; | ||||
|  | ||||
|     public WebsocketHandle( Websocket websocket, Channel channel ) | ||||
|     public WebsocketHandle( Websocket websocket, Options options, Channel channel ) | ||||
|     { | ||||
|         this.websocket = websocket; | ||||
|         this.options = options; | ||||
|         this.channel = channel; | ||||
|     } | ||||
|  | ||||
| @@ -55,7 +57,7 @@ public class WebsocketHandle implements Closeable | ||||
|         checkOpen(); | ||||
|  | ||||
|         String text = StringUtil.toString( args.get( 0 ) ); | ||||
|         if( ComputerCraft.httpMaxWebsocketMessage != 0 && text.length() > ComputerCraft.httpMaxWebsocketMessage ) | ||||
|         if( options.websocketMessage != 0 && text.length() > options.websocketMessage ) | ||||
|         { | ||||
|             throw new LuaException( "Message is too large" ); | ||||
|         } | ||||
|   | ||||
| @@ -7,6 +7,7 @@ package dan200.computercraft.core.apis.http.websocket; | ||||
|  | ||||
| import dan200.computercraft.core.apis.http.HTTPRequestException; | ||||
| import dan200.computercraft.core.apis.http.NetworkUtils; | ||||
| import dan200.computercraft.core.apis.http.options.Options; | ||||
| import dan200.computercraft.core.tracking.TrackingField; | ||||
| import io.netty.channel.ChannelHandlerContext; | ||||
| import io.netty.channel.ConnectTimeoutException; | ||||
| @@ -23,11 +24,13 @@ public class WebsocketHandler extends SimpleChannelInboundHandler<Object> | ||||
| { | ||||
|     private final Websocket websocket; | ||||
|     private final WebSocketClientHandshaker handshaker; | ||||
|     private final Options options; | ||||
|  | ||||
|     public WebsocketHandler( Websocket websocket, WebSocketClientHandshaker handshaker ) | ||||
|     public WebsocketHandler( Websocket websocket, WebSocketClientHandshaker handshaker, Options options ) | ||||
|     { | ||||
|         this.handshaker = handshaker; | ||||
|         this.websocket = websocket; | ||||
|         this.options = options; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
| @@ -52,7 +55,7 @@ public class WebsocketHandler extends SimpleChannelInboundHandler<Object> | ||||
|         if( !handshaker.isHandshakeComplete() ) | ||||
|         { | ||||
|             handshaker.finishHandshake( ctx.channel(), (FullHttpResponse) msg ); | ||||
|             websocket.success( ctx.channel() ); | ||||
|             websocket.success( ctx.channel(), options ); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -518,7 +518,7 @@ public final class ComputerThread | ||||
|  | ||||
|     private static void timeoutTask( ComputerExecutor executor, Thread thread, long time ) | ||||
|     { | ||||
|         if( !ComputerCraft.logPeripheralErrors ) return; | ||||
|         if( !ComputerCraft.logComputerErrors ) return; | ||||
|  | ||||
|         StringBuilder builder = new StringBuilder() | ||||
|             .append( "Terminating computer #" ).append( executor.getComputer().getID() ) | ||||
|   | ||||
| @@ -54,7 +54,7 @@ class BasicFunction extends VarArgFunction | ||||
|         } | ||||
|         catch( Throwable t ) | ||||
|         { | ||||
|             if( ComputerCraft.logPeripheralErrors ) | ||||
|             if( ComputerCraft.logComputerErrors ) | ||||
|             { | ||||
|                 ComputerCraft.log.error( "Error calling " + name + " on " + instance, t ); | ||||
|             } | ||||
|   | ||||
| @@ -323,7 +323,7 @@ public class CobaltLuaMachine implements ILuaMachine | ||||
|             return wrapped; | ||||
|         } | ||||
|  | ||||
|         if( ComputerCraft.logPeripheralErrors ) | ||||
|         if( ComputerCraft.logComputerErrors ) | ||||
|         { | ||||
|             ComputerCraft.log.warn( "Received unknown type '{}', returning nil.", object.getClass().getName() ); | ||||
|         } | ||||
| @@ -532,7 +532,7 @@ public class CobaltLuaMachine implements ILuaMachine | ||||
|                 } | ||||
|                 catch( Throwable t ) | ||||
|                 { | ||||
|                     if( ComputerCraft.logPeripheralErrors ) ComputerCraft.log.error( "Error running task", t ); | ||||
|                     if( ComputerCraft.logComputerErrors ) ComputerCraft.log.error( "Error running task", t ); | ||||
|                     m_computer.queueEvent( "task_complete", new Object[] { | ||||
|                         taskID, false, "Java Exception Thrown: " + t, | ||||
|                     } ); | ||||
|   | ||||
| @@ -64,7 +64,7 @@ class ResultInterpreterFunction extends ResumableVarArgFunction<ResultInterprete | ||||
|         } | ||||
|         catch( Throwable t ) | ||||
|         { | ||||
|             if( ComputerCraft.logPeripheralErrors ) | ||||
|             if( ComputerCraft.logComputerErrors ) | ||||
|             { | ||||
|                 ComputerCraft.log.error( "Error calling " + name + " on " + instance, t ); | ||||
|             } | ||||
| @@ -95,7 +95,7 @@ class ResultInterpreterFunction extends ResumableVarArgFunction<ResultInterprete | ||||
|         } | ||||
|         catch( Throwable t ) | ||||
|         { | ||||
|             if( ComputerCraft.logPeripheralErrors ) | ||||
|             if( ComputerCraft.logComputerErrors ) | ||||
|             { | ||||
|                 ComputerCraft.log.error( "Error calling " + name + " on " + container.callback, t ); | ||||
|             } | ||||
|   | ||||
| @@ -12,8 +12,8 @@ import com.google.common.base.CaseFormat; | ||||
| import com.google.common.base.Converter; | ||||
| import dan200.computercraft.ComputerCraft; | ||||
| import dan200.computercraft.api.turtle.event.TurtleAction; | ||||
| import dan200.computercraft.core.apis.http.AddressRule; | ||||
| import dan200.computercraft.core.apis.http.websocket.Websocket; | ||||
| import dan200.computercraft.core.apis.http.options.Action; | ||||
| import dan200.computercraft.core.apis.http.options.AddressRuleConfig; | ||||
| import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; | ||||
| import net.minecraftforge.common.ForgeConfigSpec; | ||||
| import net.minecraftforge.eventbus.api.SubscribeEvent; | ||||
| @@ -21,7 +21,6 @@ import net.minecraftforge.fml.ModLoadingContext; | ||||
| import net.minecraftforge.fml.common.Mod; | ||||
| import net.minecraftforge.fml.config.ModConfig; | ||||
|  | ||||
| import javax.annotation.Nullable; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
| import java.util.Objects; | ||||
| @@ -55,12 +54,8 @@ public final class Config | ||||
|     private static final ConfigValue<Boolean> httpWebsocketEnabled; | ||||
|     private static final ConfigValue<List<? extends UnmodifiableConfig>> httpRules; | ||||
|  | ||||
|     private static final ConfigValue<Integer> httpTimeout; | ||||
|     private static final ConfigValue<Integer> httpMaxRequests; | ||||
|     private static final ConfigValue<Integer> httpMaxDownload; | ||||
|     private static final ConfigValue<Integer> httpMaxUpload; | ||||
|     private static final ConfigValue<Integer> httpMaxWebsockets; | ||||
|     private static final ConfigValue<Integer> httpMaxWebsocketMessage; | ||||
|  | ||||
|     private static final ConfigValue<Boolean> commandBlockEnabled; | ||||
|     private static final ConfigValue<Integer> modemRange; | ||||
| @@ -121,7 +116,7 @@ public final class Config | ||||
|             logComputerErrors = builder | ||||
|                 .comment( "Log exceptions thrown by peripherals and other Lua objects.\n" + | ||||
|                     "This makes it easier for mod authors to debug problems, but may result in log spam should people use buggy methods." ) | ||||
|                 .define( "log_computer_errors", ComputerCraft.logPeripheralErrors ); | ||||
|                 .define( "log_computer_errors", ComputerCraft.logComputerErrors ); | ||||
|         } | ||||
|  | ||||
|         { | ||||
| @@ -164,42 +159,25 @@ public final class Config | ||||
|                 .define( "websocket_enabled", ComputerCraft.httpWebsocketEnabled ); | ||||
|  | ||||
|             httpRules = builder | ||||
|                 .comment( "A list of rules which control which domains or IPs are allowed through the \"http\" API on computers.\n" + | ||||
|                     "Each rule is an item with a 'host' to match against, and an action. " + | ||||
|                 .comment( "A list of rules which control behaviour of the \"http\" API for specific domains or IPs.\n" + | ||||
|                     "Each rule is an item with a 'host' to match against, and a series of properties. " + | ||||
|                     "The host may be a domain name (\"pastebin.com\"),\n" + | ||||
|                     "wildcard (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\"). 'action' maybe 'allow' or 'block'. If no rules" + | ||||
|                     "match, the domain will be blocked." ) | ||||
|                     "wildcard (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\"). If no rules, the domain is blocked." ) | ||||
|                 .defineList( "rules", | ||||
|                     Stream.concat( | ||||
|                         Stream.of( ComputerCraft.DEFAULT_HTTP_DENY ).map( x -> makeRule( x, "deny" ) ), | ||||
|                         Stream.of( ComputerCraft.DEFAULT_HTTP_ALLOW ).map( x -> makeRule( x, "allow" ) ) | ||||
|                         Stream.of( ComputerCraft.DEFAULT_HTTP_DENY ).map( x -> AddressRuleConfig.makeRule( x, Action.DENY ) ), | ||||
|                         Stream.of( ComputerCraft.DEFAULT_HTTP_ALLOW ).map( x -> AddressRuleConfig.makeRule( x, Action.ALLOW ) ) | ||||
|                     ).collect( Collectors.toList() ), | ||||
|                     x -> x instanceof UnmodifiableConfig && parseRule( (UnmodifiableConfig) x ) != null ); | ||||
|  | ||||
|             httpTimeout = builder | ||||
|                 .comment( "The period of time (in milliseconds) to wait before a HTTP request times out. Set to 0 for unlimited." ) | ||||
|                 .defineInRange( "timeout", ComputerCraft.httpTimeout, 0, Integer.MAX_VALUE ); | ||||
|                     x -> x instanceof UnmodifiableConfig && AddressRuleConfig.checkRule( (UnmodifiableConfig) x ) ); | ||||
|  | ||||
|             httpMaxRequests = builder | ||||
|                 .comment( "The number of http requests a computer can make at one time. Additional requests will be queued, and sent when the running requests have finished. Set to 0 for unlimited." ) | ||||
|                 .defineInRange( "max_requests", ComputerCraft.httpMaxRequests, 0, Integer.MAX_VALUE ); | ||||
|  | ||||
|             httpMaxDownload = builder | ||||
|                 .comment( "The maximum size (in bytes) that a computer can download in a single request. Note that responses may receive more data than allowed, but this data will not be returned to the client." ) | ||||
|                 .defineInRange( "max_download", (int) ComputerCraft.httpMaxDownload, 0, Integer.MAX_VALUE ); | ||||
|  | ||||
|             httpMaxUpload = builder | ||||
|                 .comment( "The maximum size (in bytes) that a computer can upload in a single request. This includes headers and POST text." ) | ||||
|                 .defineInRange( "max_upload", (int) ComputerCraft.httpMaxUpload, 0, Integer.MAX_VALUE ); | ||||
|  | ||||
|             httpMaxWebsockets = builder | ||||
|                 .comment( "The number of websockets a computer can have open at one time. Set to 0 for unlimited." ) | ||||
|                 .defineInRange( "max_websockets", ComputerCraft.httpMaxWebsockets, 1, Integer.MAX_VALUE ); | ||||
|  | ||||
|             httpMaxWebsocketMessage = builder | ||||
|                 .comment( "The maximum size (in bytes) that a computer can send or receive in one websocket packet." ) | ||||
|                 .defineInRange( "max_websocket_message", ComputerCraft.httpMaxWebsocketMessage, 0, Websocket.MAX_MESSAGE_SIZE ); | ||||
|  | ||||
|             builder.pop(); | ||||
|         } | ||||
|  | ||||
| @@ -291,7 +269,7 @@ public final class Config | ||||
|         ComputerCraft.default_computer_settings = defaultComputerSettings.get(); | ||||
|         ComputerCraft.debug_enable = debugEnabled.get(); | ||||
|         ComputerCraft.computer_threads = computerThreads.get(); | ||||
|         ComputerCraft.logPeripheralErrors = logComputerErrors.get(); | ||||
|         ComputerCraft.logComputerErrors = logComputerErrors.get(); | ||||
|  | ||||
|         // Execution | ||||
|         ComputerCraft.computer_threads = computerThreads.get(); | ||||
| @@ -302,14 +280,10 @@ public final class Config | ||||
|         ComputerCraft.httpEnabled = httpEnabled.get(); | ||||
|         ComputerCraft.httpWebsocketEnabled = httpWebsocketEnabled.get(); | ||||
|         ComputerCraft.httpRules = Collections.unmodifiableList( httpRules.get().stream() | ||||
|             .map( Config::parseRule ).filter( Objects::nonNull ).collect( Collectors.toList() ) ); | ||||
|             .map( AddressRuleConfig::parseRule ).filter( Objects::nonNull ).collect( Collectors.toList() ) ); | ||||
|  | ||||
|         ComputerCraft.httpTimeout = httpTimeout.get(); | ||||
|         ComputerCraft.httpMaxRequests = httpMaxRequests.get(); | ||||
|         ComputerCraft.httpMaxDownload = httpMaxDownload.get(); | ||||
|         ComputerCraft.httpMaxUpload = httpMaxUpload.get(); | ||||
|         ComputerCraft.httpMaxWebsockets = httpMaxWebsockets.get(); | ||||
|         ComputerCraft.httpMaxWebsocketMessage = httpMaxWebsocketMessage.get(); | ||||
|  | ||||
|         // Peripheral | ||||
|         ComputerCraft.enableCommandBlock = commandBlockEnabled.get(); | ||||
| @@ -362,28 +336,4 @@ public final class Config | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static UnmodifiableConfig makeRule( String host, String action ) | ||||
|     { | ||||
|         com.electronwill.nightconfig.core.Config config = com.electronwill.nightconfig.core.Config.inMemory(); | ||||
|         config.add( "host", host ); | ||||
|         config.add( "action", action ); | ||||
|         return config; | ||||
|     } | ||||
|  | ||||
|     @Nullable | ||||
|     private static AddressRule parseRule( UnmodifiableConfig builder ) | ||||
|     { | ||||
|         Object hostObj = builder.get( "host" ); | ||||
|         Object actionObj = builder.get( "action" ); | ||||
|         if( !(hostObj instanceof String) || !(actionObj instanceof String) ) return null; | ||||
|  | ||||
|         String host = (String) hostObj, action = (String) actionObj; | ||||
|         for( AddressRule.Action candiate : AddressRule.Action.values() ) | ||||
|         { | ||||
|             if( candiate.name().equalsIgnoreCase( action ) ) return AddressRule.parse( host, candiate ); | ||||
|         } | ||||
|  | ||||
|         return null; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -64,7 +64,7 @@ public class CommandAPI implements ILuaAPI | ||||
|         } | ||||
|         catch( Throwable t ) | ||||
|         { | ||||
|             if( ComputerCraft.logPeripheralErrors ) ComputerCraft.log.error( "Error running command.", t ); | ||||
|             if( ComputerCraft.logComputerErrors ) ComputerCraft.log.error( "Error running command.", t ); | ||||
|             return new Object[] { false, createOutput( "Java Exception Thrown: " + t ) }; | ||||
|         } | ||||
|     } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 SquidDev
					SquidDev