From: Alexandre Terrasa Date: Wed, 17 Dec 2014 21:05:13 +0000 (-0500) Subject: lib/nitcorn: handles bufferized request content X-Git-Tag: v0.7~18^2 X-Git-Url: http://nitlanguage.org?ds=sidebyside lib/nitcorn: handles bufferized request content Partially fixes #1027 Signed-off-by: Alexandre Terrasa --- diff --git a/lib/nitcorn/http_request_parser.nit b/lib/nitcorn/http_request_parser.nit new file mode 100644 index 0000000..20598a6 --- /dev/null +++ b/lib/nitcorn/http_request_parser.nit @@ -0,0 +1,116 @@ +# 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 diff --git a/lib/nitcorn/reactor.nit b/lib/nitcorn/reactor.nit index 48084e0..8124f97 100644 --- a/lib/nitcorn/reactor.nit +++ b/lib/nitcorn/reactor.nit @@ -2,6 +2,7 @@ # # Copyright 2013 Jean-Philippe Caissy # Copyright 2014 Alexis Laferrière +# Copyright 2014 Alexandre Terrasa # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,7 +20,7 @@ module reactor import more_collections -import libevent +import http_request_parser import vararg_routes import http_request @@ -41,10 +42,7 @@ class HttpServer redef fun read_callback(str) do - # TODO support bigger inputs (such as big forms and file upload) - var request_object = parser.parse_http_request(str.to_s) - if request_object != null then delegate_answer request_object end