From c2e379a7572af54640cbe17e1110e72214b69e49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Bru=CC=88ckner?= Date: Sat, 12 Dec 2015 21:38:12 +0100 Subject: [PATCH] Added support for HTTP request headers. --- src/main/resources/application.conf | 3 +++ .../lua/component/internet/lib/internet.lua | 5 +++-- src/main/scala/li/cil/oc/Settings.scala | 1 + .../cil/oc/server/component/InternetCard.scala | 18 +++++++++++++----- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 540daf5bd..ca4f0c98a 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -892,6 +892,9 @@ opencomputers { # the `request` method on internet card components becomes available. enableHttp: true + # Whether to allow adding custom headers to HTTP requests. + enableHttpHeaders: true + # Whether to allow TCP connections via internet cards. When enabled, # the `connect` method on internet card components becomes available. enableTcp: true diff --git a/src/main/resources/assets/opencomputers/lua/component/internet/lib/internet.lua b/src/main/resources/assets/opencomputers/lua/component/internet/lib/internet.lua index cfd927598..dabff53f0 100644 --- a/src/main/resources/assets/opencomputers/lua/component/internet/lib/internet.lua +++ b/src/main/resources/assets/opencomputers/lua/component/internet/lib/internet.lua @@ -6,9 +6,10 @@ local internet = {} ------------------------------------------------------------------------------- -function internet.request(url, data) +function internet.request(url, data, headers) checkArg(1, url, "string") checkArg(2, data, "string", "table", "nil") + checkArg(3, headers, "table", "nil") local inet = component.internet if not inet then @@ -25,7 +26,7 @@ function internet.request(url, data) end end - local request, reason = inet.request(url, post) + local request, reason = inet.request(url, post, headers) if not request then error(reason, 2) end diff --git a/src/main/scala/li/cil/oc/Settings.scala b/src/main/scala/li/cil/oc/Settings.scala index 2b38fa04f..82ef081f4 100644 --- a/src/main/scala/li/cil/oc/Settings.scala +++ b/src/main/scala/li/cil/oc/Settings.scala @@ -273,6 +273,7 @@ class Settings(val config: Config) { // ----------------------------------------------------------------------- // // internet val httpEnabled = config.getBoolean("internet.enableHttp") + val httpHeadersEnabled = config.getBoolean("internet.enableHttpHeaders") val tcpEnabled = config.getBoolean("internet.enableTcp") val httpHostBlacklist = Array(config.getStringList("internet.blacklist").map(new Settings.AddressValidator(_)): _*) val httpHostWhitelist = Array(config.getStringList("internet.whitelist").map(new Settings.AddressValidator(_)): _*) diff --git a/src/main/scala/li/cil/oc/server/component/InternetCard.scala b/src/main/scala/li/cil/oc/server/component/InternetCard.scala index 64c3fb7b1..a1d91179d 100644 --- a/src/main/scala/li/cil/oc/server/component/InternetCard.scala +++ b/src/main/scala/li/cil/oc/server/component/InternetCard.scala @@ -16,6 +16,7 @@ import li.cil.oc.util.ThreadPoolFactory import net.minecraft.nbt.NBTTagCompound import net.minecraft.server.MinecraftServer +import scala.collection.convert.WrapAsScala._ import scala.collection.mutable class InternetCard extends prefab.ManagedEnvironment { @@ -35,7 +36,7 @@ class InternetCard extends prefab.ManagedEnvironment { @Callback(direct = true, doc = """function():boolean -- Returns whether HTTP requests can be made (config setting).""") def isHttpEnabled(context: Context, args: Arguments): Array[AnyRef] = result(Settings.get.httpEnabled) - @Callback(doc = """function(url:string[, postData:string]):userdata -- Starts an HTTP request. If this returns true, further results will be pushed using `http_response` signals.""") + @Callback(doc = """function(url:string[, postData:string[, headers:table]]):userdata -- Starts an HTTP request. If this returns true, further results will be pushed using `http_response` signals.""") def request(context: Context, args: Arguments): Array[AnyRef] = this.synchronized { checkOwner(context) val address = args.checkString(0) @@ -46,7 +47,13 @@ class InternetCard extends prefab.ManagedEnvironment { throw new IOException("too many open connections") } val post = if (args.isString(1)) Option(args.checkString(1)) else None - val request = new InternetCard.HTTPRequest(this, checkAddress(address), post) + val headers = if (args.isTable(2)) args.checkTable(2).collect { + case (key: String, value: AnyRef) => (key, value.toString) + }.toMap else Map.empty[String, String] + if (!Settings.get.httpHeadersEnabled && headers.size > 0) { + return result(Unit, "http request headers are unavailable") + } + val request = new InternetCard.HTTPRequest(this, checkAddress(address), post, headers) connections += request result(request) } @@ -276,10 +283,10 @@ object InternetCard { } class HTTPRequest extends AbstractValue with Closable { - def this(owner: InternetCard, url: URL, post: Option[String]) { + def this(owner: InternetCard, url: URL, post: Option[String], headers: Map[String, String]) { this() this.owner = Some(owner) - this.stream = threadPool.submit(new RequestSender(url, post)) + this.stream = threadPool.submit(new RequestSender(url, post, headers)) } private var owner: Option[InternetCard] = None @@ -378,13 +385,14 @@ object InternetCard { } // This one doesn't (see comment in TCP socket), but I like to keep it consistent. - private class RequestSender(val url: URL, val post: Option[String]) extends Callable[InputStream] { + private class RequestSender(val url: URL, val post: Option[String], val headers: Map[String, String]) extends Callable[InputStream] { override def call() = try { checkLists(InetAddress.getByName(url.getHost), url.getHost) val proxy = Option(MinecraftServer.getServer.getServerProxy).getOrElse(java.net.Proxy.NO_PROXY) url.openConnection(proxy) match { case http: HttpURLConnection => try { http.setDoInput(true) + headers.foreach(Function.tupled(http.setRequestProperty _)) if (post.isDefined) { http.setRequestMethod("POST") http.setDoOutput(true)