Merge: Added contributing guidelines and link from readme
[nit.git] / lib / nitcorn / http_request.nit
index 6431ace..1833fca 100644 (file)
@@ -3,6 +3,7 @@
 # Copyright 2013 Frederic Sevillano
 # Copyright 2013 Jean-Philippe Caissy <jpcaissy@piji.ca>
 # Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+# Copyright 2014 Alexandre Terrasa <alexandre@moz-code.org>
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # Provides the `HttpRequest` class and services to create it
 module http_request
 
-import standard
+import core
 
 # A request received over HTTP, is build by `HttpRequestParser`
 class HttpRequest
-       private init do end
+       private init is old_style_init do end
 
        # HTTP protocol version
        var http_version: String
@@ -46,6 +47,9 @@ class HttpRequest
        # 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]
 
@@ -54,6 +58,44 @@ class HttpRequest
 
        # 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 a number.
+       #
+       # 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_numeric 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`
@@ -61,7 +103,7 @@ end
 # The main method is `parse_http_request`.
 class HttpRequestParser
        # The current `HttpRequest` under construction
-       private var http_request: HttpRequest
+       private var http_request: HttpRequest is noinit
 
        # Untreated body
        private var body = ""
@@ -72,8 +114,7 @@ class HttpRequestParser
        # Words of the first line
        private var first_line = new Array[String]
 
-       init do end
-
+       # Parse the `first_line`, `header_fields` and `body` of `full_request`.
        fun parse_http_request(full_request: String): nullable HttpRequest
        do
                clear_data
@@ -84,6 +125,10 @@ class HttpRequestParser
                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]
@@ -92,23 +137,24 @@ class HttpRequestParser
                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" then
+                       http_request.body = body
                        var lines = body.split_with('&')
-                       for line in lines do
+                       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
-                                       if decoded == null then
-                                               print "decode error"
-                                               continue
-                                       end
                                        http_request.post_args[parts[0]] = decoded
+                                       http_request.all_args[parts[0]] = decoded
                                else
                                        print "POST Error: {line} format error on {line}"
                                end