HttpRequest
The main method is parse_http_request
.
nitcorn :: HttpRequestParser :: _first_line
Words of the first linenitcorn :: HttpRequestParser :: _header_fields
Lines of the headernitcorn :: HttpRequestParser :: _http_request
The currentHttpRequest
under construction
nitcorn :: HttpRequestParser :: first_line
Words of the first linenitcorn :: HttpRequestParser :: first_line=
Words of the first linenitcorn :: HttpRequestParser :: header_fields
Lines of the headernitcorn :: HttpRequestParser :: header_fields=
Lines of the headernitcorn :: HttpRequestParser :: http_request
The currentHttpRequest
under construction
nitcorn :: HttpRequestParser :: http_request=
The currentHttpRequest
under construction
nitcorn :: HttpRequestParser :: parse_http_request
Parse thefirst_line
, header_fields
and body
of full_request
.
nitcorn $ HttpRequestParser :: SELF
Type of this instance, automatically specialized in every classnitcorn :: sessions $ HttpRequestParser :: parse_http_request
Parse thefirst_line
, header_fields
and body
of full_request
.
nitcorn :: HttpRequestParser :: _first_line
Words of the first linenitcorn :: HttpRequestParser :: _header_fields
Lines of the headernitcorn :: HttpRequestParser :: _http_request
The currentHttpRequest
under construction
core :: Object :: class_factory
Implementation used byget_class
to create the specific class.
core :: Object :: defaultinit
nitcorn :: HttpRequestParser :: first_line
Words of the first linenitcorn :: HttpRequestParser :: first_line=
Words of the first linenitcorn :: HttpRequestParser :: header_fields
Lines of the headernitcorn :: HttpRequestParser :: header_fields=
Lines of the headernitcorn :: HttpRequestParser :: http_request
The currentHttpRequest
under construction
nitcorn :: HttpRequestParser :: http_request=
The currentHttpRequest
under construction
core :: Object :: is_same_instance
Return true ifself
and other
are the same instance (i.e. same identity).
core :: Object :: is_same_serialized
Isself
the same as other
in a serialization context?
core :: Object :: is_same_type
Return true ifself
and other
have the same dynamic type.
core :: Object :: native_class_name
The class name of the object in CString format.core :: Object :: output_class_name
Display class name on stdout (debug only).nitcorn :: HttpRequestParser :: parse_http_request
Parse thefirst_line
, header_fields
and body
of full_request
.
# Utility class to parse a request string and build a `HttpRequest`
#
# The main method is `parse_http_request`.
class HttpRequestParser
# The current `HttpRequest` under construction
private var http_request: HttpRequest is noinit
# Untreated body
private var body = ""
# Lines of the header
private var header_fields = new Array[String]
# Words of the first line
private var first_line = new Array[String]
# Parse the `first_line`, `header_fields` and `body` of `full_request`.
fun parse_http_request(full_request: String): nullable HttpRequest
do
clear_data
var http_request = new HttpRequest
self.http_request = http_request
segment_http_request(full_request)
# Parse first line, looks like "GET dir/index.html?user=xymus HTTP/1.0"
if first_line.length < 3 then
print "HTTP error: request first line apprears invalid: {first_line}"
return null
end
http_request.method = first_line[0]
http_request.url = first_line[1]
http_request.http_version = first_line[2]
# GET args
if http_request.url.has('?') then
http_request.uri = first_line[1].substring(0, first_line[1].index_of('?'))
http_request.query_string = first_line[1].substring_from(first_line[1].index_of('?')+1)
var parse_url = parse_url
http_request.get_args = parse_url
http_request.all_args.add_all parse_url
else
http_request.uri = first_line[1]
end
# POST args
if http_request.method == "POST" or http_request.method == "PUT" then
http_request.body = body
var lines = body.split_with('&')
for line in lines do if not line.trim.is_empty then
var parts = line.split_once_on('=')
if parts.length > 1 then
var decoded = parts[1].replace('+', " ").from_percent_encoding
http_request.post_args[parts[0]] = decoded
http_request.all_args[parts[0]] = decoded
end
end
end
# Headers
for i in header_fields do
var temp_field = i.split_with(": ")
if temp_field.length == 2 then
http_request.header[temp_field[0]] = temp_field[1]
end
end
# Cookies
if http_request.header.keys.has("Cookie") then
var cookie = http_request.header["Cookie"]
for couple in cookie.split_with(';') do
var words = couple.trim.split_with('=')
if words.length != 2 then continue
http_request.cookie[words[0]] = words[1]
end
end
return http_request
end
private fun clear_data
do
first_line.clear
header_fields.clear
end
private fun segment_http_request(http_request: String): Bool
do
var header_end = http_request.search("\r\n\r\n")
if header_end == null then
header_fields = http_request.split_with("\r\n")
else
header_fields = http_request.substring(0, header_end.from).split_with("\r\n")
body = http_request.substring(header_end.after, http_request.length-1)
end
# If a line of the http_request is long it may change line, it has " " at the
# end to indicate this. This section turns them into 1 line.
if header_fields.length > 1 and header_fields[0].has_suffix(" ") then
var temp_req = header_fields[0].substring(0, header_fields[0].length-1) + header_fields[1]
first_line = temp_req.split_with(' ')
header_fields.shift
header_fields.shift
if first_line.length != 3 then return false
else
first_line = header_fields[0].split_with(' ')
header_fields.shift
if first_line.length != 3 then return false
end
# Cut off the header in lines
var pos = 0
while pos < header_fields.length do
if pos < header_fields.length-1 and header_fields[pos].has_suffix(" ") then
header_fields[pos] = header_fields[pos].substring(0, header_fields[pos].length-1) + header_fields[pos+1]
header_fields.remove_at(pos+1)
pos = pos-1
end
pos = pos+1
end
return true
end
# Extract args from the URL
private fun parse_url: HashMap[String, String]
do
var query_strings = new HashMap[String, String]
if http_request.url.has('?') then
var get_args = http_request.query_string.split_with("&")
for param in get_args do
var key_value = param.split_with("=")
if key_value.length < 2 then continue
var key = key_value[0].from_percent_encoding
var value = key_value[1].from_percent_encoding
query_strings[key] = value
end
end
return query_strings
end
end
lib/nitcorn/http_request.nit:101,1--251,3
redef class HttpRequestParser
redef fun parse_http_request(text)
do
var request = super
if request != null then
if request.cookie.keys.has("nitcorn_session") then
var id_hash = request.cookie["nitcorn_session"]
if sys.sessions.keys.has(id_hash) then
# Restore the session
request.session = sys.sessions[id_hash]
end
end
end
return request
end
end
lib/nitcorn/sessions.nit:78,1--94,3