Provides the HttpRequest class and services to create it

Introduced classes

class HttpRequest

nitcorn :: HttpRequest

A request received over HTTP, is build by HttpRequestParser
class HttpRequestParser

nitcorn :: HttpRequestParser

Utility class to parse a request string and build a HttpRequest

Redefined classes

redef abstract class Deserializer

nitcorn :: http_request $ Deserializer

Abstract deserialization service

All class definitions

redef abstract class Deserializer

nitcorn :: http_request $ Deserializer

Abstract deserialization service
class HttpRequest

nitcorn $ HttpRequest

A request received over HTTP, is build by HttpRequestParser
class HttpRequestParser

nitcorn $ HttpRequestParser

Utility class to parse a request string and build a HttpRequest
package_diagram nitcorn::http_request http_request serialization serialization nitcorn::http_request->serialization poset poset serialization->poset meta meta serialization->meta json json serialization->json ...poset ... ...poset->poset ...meta ... ...meta->meta ...json ... ...json->json nitcorn::vararg_routes vararg_routes nitcorn::vararg_routes->nitcorn::http_request nitcorn::sessions sessions nitcorn::sessions->nitcorn::http_request nitcorn::reactor reactor nitcorn::reactor->nitcorn::vararg_routes nitcorn::reactor... ... nitcorn::reactor...->nitcorn::reactor nitcorn::file_server file_server nitcorn::file_server->nitcorn::sessions nitcorn::file_server... ... nitcorn::file_server...->nitcorn::file_server

Ancestors

module abstract_collection

core :: abstract_collection

Abstract collection classes and services.
module abstract_text

core :: abstract_text

Abstract class for manipulation of sequences of characters
module array

core :: array

This module introduces the standard array structure.
module bitset

core :: bitset

Services to handle BitSet
module bytes

core :: bytes

Services for byte streams and arrays
module caching

serialization :: caching

Services for caching serialization engines
module circular_array

core :: circular_array

Efficient data structure to access both end of the sequence.
module codec_base

core :: codec_base

Base for codecs to use with streams
module codecs

core :: codecs

Group module for all codec-related manipulations
module collection

core :: collection

This module define several collection classes.
module core

core :: core

Standard classes and methods used by default by Nit programs and libraries.
module engine_tools

serialization :: engine_tools

Advanced services for serialization engines
module environ

core :: environ

Access to the environment variables of the process
module error

core :: error

Standard error-management infrastructure.
module exec

core :: exec

Invocation and management of operating system sub-processes.
module file

core :: file

File manipulations (create, read, write, etc.)
module fixed_ints

core :: fixed_ints

Basic integers of fixed-precision
module fixed_ints_text

core :: fixed_ints_text

Text services to complement fixed_ints
module flat

core :: flat

All the array-based text representations
module gc

core :: gc

Access to the Nit internal garbage collection mechanism
module hash_collection

core :: hash_collection

Introduce HashMap and HashSet.
module inspect

serialization :: inspect

Refine Serializable::inspect to show more useful information
module iso8859_1

core :: iso8859_1

Codec for ISO8859-1 I/O
module kernel

core :: kernel

Most basic classes and methods.
module list

core :: list

This module handle double linked lists
module math

core :: math

Mathematical operations
module meta

meta :: meta

Simple user-defined meta-level to manipulate types of instances as object.
module native

core :: native

Native structures for text and bytes
module numeric

core :: numeric

Advanced services for Numeric types
module protocol

core :: protocol

module queue

core :: queue

Queuing data structures and wrappers
module range

core :: range

Module for range of discrete objects.
module re

core :: re

Regular expression support for all services based on Pattern
module ropes

core :: ropes

Tree-based representation of a String.
module serialization_core

serialization :: serialization_core

Abstract services to serialize Nit objects to different formats
module sorter

core :: sorter

This module contains classes used to compare things and sorts arrays.
module stream

core :: stream

Input and output streams of characters
module text

core :: text

All the classes and methods related to the manipulation of text entities
module time

core :: time

Management of time and dates
module union_find

core :: union_find

union–find algorithm using an efficient disjoint-set data structure
module utf8

core :: utf8

Codec for UTF-8 I/O

Parents

module serialization

serialization :: serialization

General serialization services

Children

module sessions

nitcorn :: sessions

Automated session management
module vararg_routes

nitcorn :: vararg_routes

Routes with parameters.

Descendants

module a_star-m

a_star-m

module example_angular

popcorn :: example_angular

This is an example of how to use angular.js with popcorn
module file_server

nitcorn :: file_server

Provides the FileServer action, which is a standard and minimal file server
module hooks

github :: hooks

Github hook event listening with nitcorn.
module htcpcp_server

nitcorn :: htcpcp_server

A server that implements HTCPCP. At the moment there are no additions.
module loader

github :: loader

module log

nitcorn :: log

Services inserting a timestamp in all prints and to log each requests
module nitcorn

nitcorn :: nitcorn

The nitcorn Web server framework creates server-side Web apps in Nit
module nitcorn_hello_world

nitcorn :: nitcorn_hello_world

Hello World Web server example
module nitcorn_reverse_proxy

nitcorn :: nitcorn_reverse_proxy

Minimal example using a ProxyAction
module pop_auth

popcorn :: pop_auth

Authentification handlers.
module pop_handlers

popcorn :: pop_handlers

Route handlers.
module pop_json

popcorn :: pop_json

Introduce useful services for JSON REST API handlers.
module pop_routes

popcorn :: pop_routes

Internal routes representation.
module pop_sessions

popcorn :: pop_sessions

Session handlers
module pop_tasks

popcorn :: pop_tasks

Popcorn threaded tasks
module pop_templates

popcorn :: pop_templates

Template rendering for popcorn
module pop_tests

popcorn :: pop_tests

Popcorn testing services
module popcorn

popcorn :: popcorn

Application server abstraction on top of nitcorn.
module proxy

nitcorn :: proxy

Provides the ProxyAction action, which redirects requests to another interface
module pthreads

nitcorn :: pthreads

Activate the use of pthreads with nitcorn
module reactor

nitcorn :: reactor

Core of the nitcorn project, provides HttpFactory and Action
module restful

nitcorn :: restful

Support module for the nitrestful tool and the restful annotation
module restful_annot

nitcorn :: restful_annot

Example for the restful annotation documented at lib/nitcorn/restful.nit
module signal_handler

nitcorn :: signal_handler

Handle SIGINT and SIGTERM to close the server after all active events
module simple_file_server

nitcorn :: simple_file_server

Basic file server on port 80 by default, may require root to execute
# Provides the `HttpRequest` class and services to create it
module http_request

import core
import serialization

# A request received over HTTP, is build by `HttpRequestParser`
class HttpRequest
	serialize

	private init is old_style_init do end

	# HTTP protocol version
	var http_version: String

	# Method of this request (GET or POST)
	var method: String

	# The full URL requested by the client (including the `query_string`)
	var url: String

	# The resource requested by the client (only the page, not the `query_string`)
	var uri: String

	# The string following `?` in the requested URL
	var query_string = ""

	# The header of this request
	var header = new HashMap[String, String]

	# The raw body of the request.
	var body = ""

	# The content of the cookie of this request
	var cookie = new HashMap[String, String]

	# The arguments passed with the GET method,
	var get_args = new HashMap[String, String]

	# The arguments passed with the POST method
	var post_args = new HashMap[String, String]

	# The arguments passed with the POST or GET method (with a priority on POST)
	var all_args = new HashMap[String, String]

	# Returns argument `arg_name` in the request as a String
	# or null if it was not found.
	# Also cleans the String by trimming it.
	# If the Strings happens to be empty after trimming,
	# the method will return `null`
	#
	# NOTE: Prioritizes POST before GET
	fun string_arg(arg_name: String): nullable String do
		if not all_args.has_key(arg_name) then return null
		var s = all_args[arg_name].trim
		if s.is_empty then return null
		return s
	end

	# Returns argument `arg_name` as an Int or `null` if not found or not an integer.
	#
	# NOTE: Prioritizes POST before GET
	fun int_arg(arg_name: String): nullable Int do
		if not all_args.has_key(arg_name) then return null
		var i = all_args[arg_name]
		if not i.is_int then return null
		return i.to_i
	end

	# Returns argument `arg_name` as a Bool or `null` if not found or not a boolean.
	#
	# NOTE: Prioritizes POST before GET
	fun bool_arg(arg_name: String): nullable Bool do
		if not all_args.has_key(arg_name) then return null
		var i = all_args[arg_name]
		if i == "true" then return true
		if i == "false" then return false
		return null
	end
end

# 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:20,1--251,3