This is an automated email from the ASF dual-hosted git repository.

fanningpj pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/pekko-http.git


The following commit(s) were added to refs/heads/main by this push:
     new 957f913e8 more performant boundary check (#799)
957f913e8 is described below

commit 957f913e86497e7353b04bfe4441db83f60170bd
Author: PJ Fanning <[email protected]>
AuthorDate: Fri Sep 26 14:22:00 2025 +0100

    more performant boundary check (#799)
    
    * more performant boundary check
    
    * try to fix tests
    
    * Update BodyPartParser.scala
    
    * Update BodyPartParser.scala
    
    * Update BodyPartParser.scala
    
    * Update BodyPartParser.scala
    
    * add HttpConstants
---
 .../http/impl/engine/parsing/BodyPartParser.scala  | 46 ++++++++++++++++------
 .../pekko/http/impl/util/HttpConstants.scala       | 32 +++++++++++++++
 2 files changed, 66 insertions(+), 12 deletions(-)

diff --git 
a/http-core/src/main/scala/org/apache/pekko/http/impl/engine/parsing/BodyPartParser.scala
 
b/http-core/src/main/scala/org/apache/pekko/http/impl/engine/parsing/BodyPartParser.scala
index a1d9dc56f..1ca1f6d54 100644
--- 
a/http-core/src/main/scala/org/apache/pekko/http/impl/engine/parsing/BodyPartParser.scala
+++ 
b/http-core/src/main/scala/org/apache/pekko/http/impl/engine/parsing/BodyPartParser.scala
@@ -16,18 +16,17 @@ package org.apache.pekko.http.impl.engine.parsing
 import org.apache.pekko
 import pekko.NotUsed
 import pekko.annotation.InternalApi
-
-import scala.annotation.tailrec
 import pekko.event.LoggingAdapter
-import org.parboiled2.CharPredicate
+import pekko.http.impl.util._
+import pekko.http.scaladsl.model._
+import pekko.http.scaladsl.model.headers._
+import pekko.stream.{ Attributes, FlowShape, Inlet, Outlet }
 import pekko.stream.scaladsl.Source
 import pekko.stream.stage._
 import pekko.util.ByteString
-import pekko.http.scaladsl.model._
-import pekko.http.impl.util._
-import pekko.stream.{ Attributes, FlowShape, Inlet, Outlet }
-import pekko.http.scaladsl.model.headers._
+import org.parboiled2.CharPredicate
 
+import scala.annotation.tailrec
 import scala.collection.mutable.ListBuffer
 
 /**
@@ -355,15 +354,38 @@ private[http] object BodyPartParser {
   }
 
   case class UndefinedEndOfLineConfiguration(boundary: String) extends 
EndOfLineConfiguration {
+    import HttpConstants._
+
     override def eol: String = "\r\n"
 
     override def defineOnce(byteString: ByteString): EndOfLineConfiguration = {
       // Hypothesis: There is either CRLF or LF as EOL, no mix possible
-      val crLfNeedle = ByteString(s"$boundary\r\n")
-      val lfNeedle = ByteString(s"$boundary\n")
-      if (byteString.containsSlice(crLfNeedle)) 
DefinedEndOfLineConfiguration("\r\n", boundary)
-      else if (byteString.containsSlice(lfNeedle)) 
DefinedEndOfLineConfiguration("\n", boundary)
-      else this
+      checkForBoundary(byteString) match {
+        case CR_BYTE => DefinedEndOfLineConfiguration("\r\n", boundary)
+        case LF_BYTE => DefinedEndOfLineConfiguration("\n", boundary)
+        case _       => this
+      }
+    }
+
+    // returns CR for CRLF, LF for LF, 0 otherwise
+    private def checkForBoundary(byteString: ByteString): Byte = {
+      val check = ByteString(boundary)
+      @tailrec def findBoundary(offset: Int): Byte = {
+        val index = byteString.indexOfSlice(check, offset)
+        if (index != -1) {
+          val newIndex = index + boundary.length
+          byteAt(byteString, newIndex) match {
+            case CR_BYTE =>
+              if (byteAt(byteString, newIndex + 1) == LF_BYTE) CR_BYTE else 
findBoundary(index + 1)
+            case LF_BYTE => LF_BYTE
+            case _       => findBoundary(index + 1)
+          }
+        } else 0
+      }
+      try findBoundary(0)
+      catch {
+        case NotEnoughDataException => 0
+      }
     }
   }
 }
diff --git 
a/http-core/src/main/scala/org/apache/pekko/http/impl/util/HttpConstants.scala 
b/http-core/src/main/scala/org/apache/pekko/http/impl/util/HttpConstants.scala
new file mode 100644
index 000000000..05315f088
--- /dev/null
+++ 
b/http-core/src/main/scala/org/apache/pekko/http/impl/util/HttpConstants.scala
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.pekko.http.impl.util
+
+import org.apache.pekko.annotation.InternalApi
+
+/**
+ * INTERNAL API
+ *
+ * This object contains HTTP related constants that are used in various places.
+ * It is not intended to be used outside of the HTTP implementation.
+ */
+@InternalApi
+private[http] object HttpConstants {
+  final val CR_BYTE: Byte = 13
+  final val LF_BYTE: Byte = 10
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to