Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Adding HTTP protocol version to the response table #934

Closed
nnposter opened this Issue Jul 7, 2017 · 1 comment

Comments

Projects
None yet
2 participants

nnposter commented Jul 7, 2017

Library http.lua is already parsing the status line of HTTP responses, including the HTTP protocol version. This information should be captured so that other code does not need to re-implement the version extraction.

I am proposing version as a new member of the response table. The value is a string, as extracted from the status line. A consuming code could use it as follows:

if response.version >= "1.1" then

The actual patch follows:

--- a/nselib/http.lua
+++ b/nselib/http.lua
@@ -13,6 +13,7 @@
 -- These functions return a table of values, including:
 -- * <code>status-line</code> - A string representing the status, such as "HTTP/1.1 200 OK". In case of an error, a description will be provided in this line.
 -- * <code>status</code> - The HTTP status value; for example, "200". If an error occurs during a request, then this value is going to be nil.
+-- * <code>version</code> - HTTP protocol version string, as stated in the status line. Example: "1.1"
 -- * <code>header</code> - An associative array representing the header. Keys are all lowercase, and standard headers, such as 'date', 'content-length', etc. will typically be present.
 -- * <code>rawheader</code> - A numbered array of the headers, exactly as the server sent them. While header['content-type'] might be 'text/html', rawheader[3] might be 'Content-type: text/html'.
 -- * <code>cookies</code> - A numbered array of the cookies the server sent. Each cookie is a table with the following keys: <code>name</code>, <code>value</code>, <code>path</code>, <code>domain</code>, and <code>expires</code>.
@@ -54,6 +55,7 @@
 -- The response to each function is typically a table with the following keys:
 -- * <code>status-line</code>: The HTTP status line; for example, "HTTP/1.1 200 OK" (note: this is followed by a newline). In case of an error, a description will be provided in this line.
 -- * <code>status</code>: The HTTP status value; for example, "200". If an error occurs during a request, then this value is going to be nil.
+-- * <code>version</code>: HTTP protocol version string, as stated in the status line. Example: "1.1"
 -- * <code>header</code>: A table of header values, where the keys are lowercase and the values are exactly what the server sent
 -- * <code>rawheader</code>: A list of header values as "name: value" strings, in the exact format and order that the server sent them
 -- * <code>cookies</code>: A list of cookies that the server is sending. Each cookie is a table containing the keys <code>name</code>, <code>value</code>, and <code>path</code>. This table can be sent to the server in subsequent responses in the <code>options</code> table to any function (see below).
@@ -567,7 +569,6 @@
 -- and the status code of the response.
 local function recv_body(s, response, method, partial)
   local connection_close, connection_keepalive
-  local version_major, version_minor
   local transfer_encoding
   local content_length
   local err
@@ -594,9 +595,6 @@
     end
   end
 
-  -- The HTTP version may also affect our decisions.
-  version_major, version_minor = string.match(response["status-line"], "^HTTP/(%d+)%.(%d+)")
-
   -- See RFC 2616, section 4.4 "Message Length".
 
   -- 1. Any response message which "MUST NOT" include a message-body (such as
@@ -610,7 +608,7 @@
   if string.upper(method) == "HEAD"
     or (response.status >= 100 and response.status <= 199)
     or response.status == 204 or response.status == 304 then
-    if connection_close or (version_major == "1" and version_minor == "0" and not connection_keepalive) then
+    if connection_close or (response.version == "1.0" and not connection_keepalive) then
       return recv_all(s, partial)
     else
       return "", partial
@@ -657,7 +655,7 @@
   return recv_all(s, partial)
 end
 
--- Sets response["status-line"] and response.status.
+-- Sets response["status-line"], response.status, and response.version.
 local function parse_status_line(status_line, response)
   response["status-line"] = status_line
   local version, status, reason_phrase = string.match(status_line,
@@ -665,7 +663,8 @@
   if not version then
     return nil, string.format("Error parsing status-line %q.", status_line)
   end
-  -- We don't have a use for the version or the reason_phrase; ignore them.
+  -- We don't have a use for the reason_phrase; ignore it.
+  response.version = version
   response.status = tonumber(status)
   if not response.status then
     return nil, string.format("Status code is not numeric: %s", status)

Please let me know if you have any questions or concerns.

cldrn commented Jul 9, 2017

Sounds good to me!

@nmap-bot nmap-bot closed this in 06b8430 Jul 21, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment