webcrystal/src/http/message.cr

143 lines
3.6 KiB
Crystal

require "./message"
require "./method"
require "uri"
require "json"
class Message
@@status_line_regex = /(?'method'[A-Z]+) (?'uri'[^ ]+) (?'protocol'(?'protocol_name'[^ ]+)\/(?'protocol_version'[0-9]+.[0-9]+))/
@@header_line_regex = /^(?'name'[^:]+): (?'values'.+)/
@protocol_name = "HTTP"
@protocol_version = "1.0"
@method : Method = Method::NON_STANDARD
@uri : String = "/"
@headers : Hash(String, String) = {} of String => String
@body : String = ""
def parse_message(request : String)
protocol_name = Nil
protocol_version = Nil
method = Method::NON_STANDARD
uri = "/"
headers = {} of String => String
body = ""
current_header = ""
is_body = false
is_status_line = true
request.chars.each do |char|
if is_body
body += char
next
end
current_header += char
if current_header == "\r\n"
is_body = true
next
end
if current_header.ends_with?("\r\n") # End of header
if !is_status_line
regexified_header = @@header_line_regex.match(current_header)
if regexified_header.nil?
raise "Header regex is broken :aie:"
end
headers[regexified_header["name"]] = regexified_header["values"].gsub({"\r": "", "\n": ""})
else
is_status_line = false
regexified_status_line = @@status_line_regex.match(current_header)
if regexified_status_line.nil?
raise "Status line regex is broken :aie:"
end
method = Method.parse?(regexified_status_line["method"])
uri = regexified_status_line["uri"]
protocol_name = regexified_status_line["protocol_name"]
protocol_version = regexified_status_line["protocol_version"]
end
current_header = ""
end
end
return {
"protocol_name" => protocol_name,
"protocol_version" => protocol_version,
"method" => method,
"uri" => uri,
"headers" => headers,
"body" => body
}
end
def parse_form_body(body : String)
form_body = Hash(String, String).new()
key = ""
value = ""
is_key = true
body.chars.each do |char|
if char == '='
is_key = false
next
end
if char == '&'
form_body[key] = value[0, value.size - 1]
key = ""
value = ""
next
end
if is_key
key += char
else
value += char
end
end
form_body[key] = value
return form_body
end
def is_form_body
return "application/x-www-form-urlencoded" == @headers["Content-Type"]?
end
def is_json_body
return "application/json" == @headers["Content-Type"]?
end
def get_body
if is_json_body
return Hash(String, JSON::Any).from_json @body
elsif is_form_body
return parse_form_body @body
end
end
def header(header : String)
return @headers[header]?
end
def headers
return @headers
end
def body : String
return @body
end
def method : Method
return @method
end
def uri: String
return @uri
end
end