misc/vim: inform the user when no results are found
[nit.git] / lib / nitcorn / http_request_parser.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Http request parsing for bufferized inputs.
16 module http_request_parser
17
18 intrude import libevent
19
20 redef class Connection
21
22 private var in_request = false
23 private var in_header = false
24 private var in_body = false
25 private var current_header: FlatBuffer
26 private var current_body: FlatBuffer
27 private var content_length = 0
28 private var current_length = 0
29
30 # FIXME will not work if the header/body delimiter fall between two watermarks windows.
31 redef fun read_callback_native(cstr, len)
32 do
33 # is this the start of a request?
34 if not in_request then
35 parse_start
36 end
37 var str = cstr.to_s_with_length(len)
38 var body: String
39 # parsing header
40 if in_header then
41 body = parse_header(str)
42 else
43 body = str
44 end
45 # parsing body
46 if in_body then
47 parse_body(body)
48 end
49 end
50
51
52 # We have a new request entering
53 private fun parse_start do
54 in_request = true
55 # reset values
56 current_header = new FlatBuffer
57 current_body = new FlatBuffer
58 current_length = 0
59 content_length = 0
60 # next step is to find the header part
61 in_header = true
62 in_body = false
63 end
64
65 # We are receiving the header of a request
66 #
67 # Return parsed body foud in header window
68 private fun parse_header(str: String): String do
69 # split in CRLF
70 var parts = str.split("\r\n\r\n")
71 # first part go in the header
72 current_header.append parts.shift
73
74 # if there is more part we are done with headers
75 if not parts.is_empty then
76 # get content-length
77 parse_content_length(current_header.write_to_string)
78 # next step if to parse body
79 in_header = false
80 in_body = true
81 # return rest of the body
82 return parts.join("\r\n")
83 end
84 return ""
85 end
86
87 # Extract and set `content_length` from header.
88 private fun parse_content_length(head: String) do
89 var hlines = head.split("\r\n")
90 for hline in hlines do
91 var hparts = hline.split(": ")
92 if hparts.first == "Content-Length" then
93 content_length = hparts[1].to_i
94 end
95 end
96 end
97
98 # We are receiving body parts.
99 private fun parse_body(str: String) do
100 current_length += str.length
101 current_body.append str
102 if current_length >= content_length then
103 parse_end
104 end
105 end
106
107 # We have reached the end of the body
108 private fun parse_end do
109 var res = new FlatBuffer
110 res.append current_header
111 res.append "\r\n\r\n"
112 res.append current_body
113 read_callback(res.write_to_string)
114 in_request = false
115 end
116 end