--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.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.
+
+# Http request parsing for bufferized inputs.
+module http_request_parser
+
+intrude import libevent
+
+redef class Connection
+
+ private var in_request = false
+ private var in_header = false
+ private var in_body = false
+ private var current_header: FlatBuffer
+ private var current_body: FlatBuffer
+ private var content_length = 0
+ private var current_length = 0
+
+ # FIXME will not work if the header/body delimiter fall between two watermarks windows.
+ redef fun read_callback_native(cstr, len)
+ do
+ # is this the start of a request?
+ if not in_request then
+ parse_start
+ end
+ var str = cstr.to_s_with_length(len)
+ var body: String
+ # parsing header
+ if in_header then
+ body = parse_header(str)
+ else
+ body = str
+ end
+ # parsing body
+ if in_body then
+ parse_body(body)
+ end
+ end
+
+
+ # We have a new request entering
+ private fun parse_start do
+ in_request = true
+ # reset values
+ current_header = new FlatBuffer
+ current_body = new FlatBuffer
+ current_length = 0
+ content_length = 0
+ # next step is to find the header part
+ in_header = true
+ in_body = false
+ end
+
+ # We are receiving the header of a request
+ #
+ # Return parsed body foud in header window
+ private fun parse_header(str: String): String do
+ # split in CRLF
+ var parts = str.split("\r\n\r\n")
+ # first part go in the header
+ current_header.append parts.shift
+
+ # if there is more part we are done with headers
+ if not parts.is_empty then
+ # get content-length
+ parse_content_length(current_header.write_to_string)
+ # next step if to parse body
+ in_header = false
+ in_body = true
+ # return rest of the body
+ return parts.join("\r\n")
+ end
+ return ""
+ end
+
+ # Extract and set `content_length` from header.
+ private fun parse_content_length(head: String) do
+ var hlines = head.split("\r\n")
+ for hline in hlines do
+ var hparts = hline.split(": ")
+ if hparts.first == "Content-Length" then
+ content_length = hparts[1].to_i
+ end
+ end
+ end
+
+ # We are receiving body parts.
+ private fun parse_body(str: String) do
+ current_length += str.length
+ current_body.append str
+ if current_length >= content_length then
+ parse_end
+ end
+ end
+
+ # We have reached the end of the body
+ private fun parse_end do
+ var res = new FlatBuffer
+ res.append current_header
+ res.append "\r\n\r\n"
+ res.append current_body
+ read_callback(res.write_to_string)
+ in_request = false
+ end
+end