Skip to content
Permalink
Browse files Browse the repository at this point in the history
Merge pull request from GHSA-xmw9-q7x9-j5qc
Fix GHSA-xmw9-q7x9-j5qc by limiting accepted connections
  • Loading branch information
rossabaker committed Feb 2, 2021
2 parents 06f42dd + 626c4dd commit 4f78617
Show file tree
Hide file tree
Showing 14 changed files with 296 additions and 75 deletions.
8 changes: 6 additions & 2 deletions build.sbt
Expand Up @@ -15,7 +15,7 @@ lazy val commonSettings = Seq(
description := "NIO Framework for Scala",
crossScalaVersions := Seq("2.11.12", "2.12.12", "2.13.3"),
scalaVersion := crossScalaVersions.value.filter(_.startsWith("2.")).last,
scalacOptions in Test ~= (_.filterNot(Set("-Ywarn-dead-code", "-Wdead-code"))), // because mockito
scalacOptions in Test ~= (_.filterNot(Set("-Ywarn-dead-code", "-Wdead-code", "-Xfatal-warnings"))), // because mockito
scalacOptions in (Compile, doc) += "-no-link-warnings",
unmanagedSourceDirectories in Compile ++= {
(unmanagedSourceDirectories in Compile).value.map { dir =>
Expand Down Expand Up @@ -79,7 +79,11 @@ lazy val core = Project("blaze-core", file("core"))
scalaVersion,
git.gitHeadCommit
),
buildInfoOptions += BuildInfoOption.BuildTime
buildInfoOptions += BuildInfoOption.BuildTime,
mimaBinaryIssueFilters ++= Seq(
// private constructor for which there are no sensible defaults
ProblemFilters.exclude[DirectMissingMethodProblem]("org.http4s.blaze.channel.nio1.NIO1SocketServerGroup.this")
)
)

lazy val http = Project("blaze-http", file("http"))
Expand Down
@@ -1,7 +1,17 @@
/*
* Copyright 2014-2020 http4s.org
* Copyright 2014 http4s.org
*
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.http4s.blaze.internal
Expand Down
@@ -0,0 +1,69 @@
/*
* Copyright 2014 http4s.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.http4s.blaze.channel.nio1

import org.http4s.blaze.channel.{ChannelOptions, OptionValue}

import java.net.SocketAddress
import java.nio.ByteBuffer
import java.nio.channels.{SelectableChannel, SocketChannel}
import java.util.concurrent.atomic.AtomicBoolean

private[blaze] final class NIO1ClientChannel(
private[this] val underlying: SocketChannel,
private[this] val onClose: () => Unit)
extends NIO1Channel {

private[this] val closed = new AtomicBoolean(false)

override val selectableChannel: SelectableChannel = underlying

def configureBlocking(block: Boolean): Unit = {
underlying.configureBlocking(block)
()
}

def getRemoteAddress: SocketAddress =
underlying.getRemoteAddress

def getLocalAddress: SocketAddress =
underlying.getLocalAddress

def configureOptions(options: ChannelOptions): Unit =
options.options.foreach { case OptionValue(k, v) =>
underlying.setOption(k, v)
}

def read(dst: ByteBuffer): Int =
underlying.read(dst)

def write(src: ByteBuffer): Int =
underlying.write(src)

def write(srcs: Array[ByteBuffer]): Long =
underlying.write(srcs)

def isOpen: Boolean =
underlying.isOpen

override def close(): Unit =
try underlying.close()
finally if (closed.compareAndSet(false, true)) {
onClose()
}

}
Expand Up @@ -20,7 +20,6 @@ import java.io.IOException
import java.nio.ByteBuffer
import java.nio.channels._
import java.util.concurrent.RejectedExecutionException

import org.http4s.blaze.channel.ChannelHead
import org.http4s.blaze.pipeline.Command.{Disconnected, EOF}
import org.http4s.blaze.util
Expand All @@ -46,7 +45,7 @@ private[nio1] object NIO1HeadStage {
* @return a `Try` representing successfully loading data into `scratch`, or
* the failure cause.
*/
private def performRead(ch: SocketChannel, scratch: ByteBuffer, size: Int): Try[Unit] =
private def performRead(ch: NIO1ClientChannel, scratch: ByteBuffer, size: Int): Try[Unit] =
try {
scratch.clear()
if (size >= 0 && size < scratch.remaining)
Expand All @@ -69,7 +68,7 @@ private[nio1] object NIO1HeadStage {
* @return a WriteResult that is one of Complete, Incomplete or WriteError(e: Exception)
*/
private def performWrite(
ch: SocketChannel,
ch: NIO1ClientChannel,
scratch: ByteBuffer,
buffers: Array[ByteBuffer]): WriteResult =
try if (BufferTools.areDirectOrEmpty(buffers)) {
Expand Down Expand Up @@ -116,13 +115,26 @@ private[nio1] object NIO1HeadStage {
}

private[nio1] final class NIO1HeadStage(
ch: SocketChannel,
ch: NIO1ClientChannel,
selectorLoop: SelectorLoop,
key: SelectionKey
) extends ChannelHead
with Selectable {
import NIO1HeadStage._

@deprecated(
"Binary compatibility shim. This one can leak connection acceptance permits.",
"0.14.15")
private[NIO1HeadStage] def this(
ch: SocketChannel,
selectorLoop: SelectorLoop,
key: SelectionKey
) = this(
new NIO1ClientChannel(ch, () => ()),
selectorLoop: SelectorLoop,
key
)

override def name: String = "NIO1 ByteBuffer Head Stage"

// State of the HeadStage. These should only be accessed from the SelectorLoop thread
Expand Down
Expand Up @@ -36,6 +36,14 @@ object NIO1Connection {
override def isOpen: Boolean = connection.isOpen
}
}

private[blaze] def apply(channel: NIO1ClientChannel): SocketConnection =
new SocketConnection {
override def remote: SocketAddress = channel.getRemoteAddress
override def local: SocketAddress = channel.getLocalAddress
override def isOpen: Boolean = channel.isOpen
override def close(): Unit = channel.close()
}
}

private case class NIO1SocketConnection(connection: SocketChannel) extends SocketConnection {
Expand Down

0 comments on commit 4f78617

Please sign in to comment.