diff --git a/src/Messaging/MessageBuffer.php b/src/Messaging/MessageBuffer.php
index c70d52c..07ff4f1 100644
--- a/src/Messaging/MessageBuffer.php
+++ b/src/Messaging/MessageBuffer.php
@@ -55,17 +55,23 @@ class MessageBuffer {
         $this->onControl = $onControl ?: function() {};
     }
 
+    public function onData($data) {
+        while (strlen($data) > 0) {
+            $data = $this->processData($data);
+        }
+    }
+
     /**
      * @param string $data
      * @return null
      */
-    public function onData($data) {
+    private function processData($data) {
         $this->messageBuffer ?: $this->messageBuffer = $this->newMessage();
         $this->frameBuffer   ?: $this->frameBuffer   = $this->newFrame();
 
         $this->frameBuffer->addBuffer($data);
         if (!$this->frameBuffer->isCoalesced()) {
-            return;
+            return '';
         }
 
         $onMessage = $this->onMessage;
@@ -82,7 +88,7 @@ class MessageBuffer {
             $onControl($this->frameBuffer);
 
             if (Frame::OP_CLOSE === $opcode) {
-                return;
+                return '';
             }
         } else {
             $this->messageBuffer->addFrame($this->frameBuffer);
@@ -101,9 +107,7 @@ class MessageBuffer {
             $this->messageBuffer = null;
         }
 
-        if (strlen($overflow) > 0) {
-            $this->onData($overflow); // PHP doesn't do tail recursion  :(
-        }
+        return $overflow;
     }
 
     /**
diff --git a/tests/unit/Messaging/MessageBufferTest.php b/tests/unit/Messaging/MessageBufferTest.php
new file mode 100644
index 0000000..c33ff0c
--- /dev/null
+++ b/tests/unit/Messaging/MessageBufferTest.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace Ratchet\RFC6455\Test\Unit\Messaging;
+
+use Ratchet\RFC6455\Messaging\CloseFrameChecker;
+use Ratchet\RFC6455\Messaging\Frame;
+use Ratchet\RFC6455\Messaging\Message;
+use Ratchet\RFC6455\Messaging\MessageBuffer;
+
+class MessageBufferTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * This is to test that MessageBuffer can handle a large receive
+     * buffer with many many frames without blowing the stack (pre-v0.4 issue)
+     */
+    public function testProcessingLotsOfFramesInASingleChunk() {
+        $frame = new Frame('a', true, Frame::OP_TEXT);
+
+        $frameRaw = $frame->getContents();
+
+        $data = str_repeat($frameRaw, 1000);
+
+        $messageCount = 0;
+
+        $messageBuffer = new MessageBuffer(
+            new CloseFrameChecker(),
+            function (Message $message) use (&$messageCount) {
+                $messageCount++;
+                $this->assertEquals('a', $message->getPayload());
+            },
+            null,
+            false
+        );
+
+        $messageBuffer->onData($data);
+
+        $this->assertEquals(1000, $messageCount);
+    }
+}
\ No newline at end of file