@@ -72,52 +72,99 @@ local function parse_headers(req_node, source, context)
7272 return setmetatable (headers , nil )
7373end
7474
75+ --- @param str string
76+ --- @return boolean
77+ local function validate_json (str )
78+ local ok , _ = pcall (vim .json .decode , str )
79+ return ok
80+ end
81+
82+ --- @param str string
83+ --- @return boolean
84+ local function validate_xml (str )
85+ local xml2lua = require (" xml2lua" )
86+ local handler = require (" xmlhandler.tree" ):new ()
87+ local xml_parser = xml2lua .parser (handler )
88+ local ok = pcall (function (t ) return xml_parser :parse (t ) end , str )
89+ return ok
90+ end
91+
92+ --- @param str string
93+ --- @return table<string,string> ?
94+ local function parse_urlencoded_form (str )
95+ local form = {}
96+ local query_pairs = vim .split (str , " &" )
97+ for _ , query in ipairs (query_pairs ) do
98+ local key , value = query :match (" ([^=]+)=?(.*)" )
99+ if not key then
100+ -- TODO: error
101+ return nil
102+ end
103+ form [vim .trim (key )] = vim .trim (value )
104+ end
105+ return form
106+ end
107+
108+ --- @param content_type string ?
75109--- @param body_node TSNode
76110--- @param source Source
77111--- @param context rest.Context
78- --- @return rest.Request.Body | nil
79- function parser .parse_body (body_node , source , context )
112+ --- @return rest.Request.Body ?
113+ function parser .parse_body (content_type , body_node , source , context )
80114 local body = {}
81- body . __TYPE = body_node :type (): gsub ( " _%w+ " , " " )
115+ local node_type = body_node :type ()
82116 --- @cast body rest.Request.Body
83- if body .__TYPE == " json" then
117+ if node_type == " external_body" then
118+ body .__TYPE = " external"
119+ local path = assert (get_node_field_text (body_node , " path" , source ))
120+ if type (source ) ~= " number" then
121+ logger .error (" can't parse external body on non-existing http file" )
122+ return
123+ end
124+ --- @cast source integer
125+ local basepath = vim .api .nvim_buf_get_name (source ):match (" (.*)/.*" )
126+ path = vim .fs .normalize (vim .fs .joinpath (basepath , path ))
127+ body .data = {
128+ name = get_node_field_text (body_node , " name" , source ),
129+ path = path ,
130+ }
131+ elseif node_type == " json_body" or content_type == " application/json" then
132+ body .__TYPE = " json"
84133 body .data = vim .trim (vim .treesitter .get_node_text (body_node , source ))
85134 body .data = expand_variables (body .data , context )
86- local ok , _ = pcall ( vim . json . decode , body .data )
135+ local ok = validate_json ( body .data )
87136 if not ok then
88137 logger .warn (" invalid json: '" .. body .data .. " '" )
89138 return nil
90139 end
91- elseif body .__TYPE == " xml" then
140+ elseif node_type == " xml_body" or content_type == " application/xml" then
141+ body .__TYPE = " xml"
92142 body .data = vim .trim (vim .treesitter .get_node_text (body_node , source ))
93143 body .data = expand_variables (body .data , context )
94- local xml2lua = require (" xml2lua" )
95- local handler = require (" xmlhandler.tree" ):new ()
96- local xml_parser = xml2lua .parser (handler )
97- local ok = pcall (function (t ) return xml_parser :parse (t ) end , body .data )
144+ local ok = validate_xml (body .data )
98145 if not ok then
99146 logger .warn (" invalid xml: '" .. body .data .. " '" )
100147 return nil
101148 end
102- elseif body . __TYPE == " form " then
103- body . data = {}
104- for pair , _ in body_node : iter_children () do
105- if pair : type () == " query " then
106- local key = assert ( get_node_field_text ( pair , " key " , source ))
107- local value = assert ( get_node_field_text ( pair , " value " , source ) )
108- key = expand_variables ( key , context )
109- value = expand_variables ( value , context )
110- body . data [ key ] = value
149+ elseif node_type == " raw_body " then
150+ -- TODO: exclude comments from text
151+ local text = vim . treesitter . get_node_text ( body_node , source )
152+ if content_type and vim . startswith ( content_type , " application/x-www-form-urlencoded " ) then
153+ body . __TYPE = " form "
154+ body . data = parse_urlencoded_form ( text )
155+ if not body . data then
156+ -- TODO: parsing urlencoded form failed
157+ return nil
111158 end
159+ else
160+ body .__TYPE = " raw"
161+ body .data = text
112162 end
113- elseif body .__TYPE == " external" then
114- local path = assert (get_node_field_text (body_node , " path" , source ))
115- path = vim .fs .normalize (vim .fs .joinpath (vim .fn .expand (" %:h" ), path ))
116- body .data = {
117- name = get_node_field_text (body_node , " name" , source ),
118- path = path ,
119- }
120- elseif body .__TYPE == " graphql" then
163+ elseif node_type == " multipart_form_data" then
164+ body .__TYPE = " multipart_form_data"
165+ -- TODO:
166+ logger .error (" multipart form data is not supported yet" )
167+ elseif node_type == " graphql_body" then
121168 logger .error (" graphql body is not supported yet" )
122169 end
123170 return body
@@ -273,15 +320,6 @@ function parser.parse(node, source, ctx)
273320 logger .error (" request section doesn't have request node" )
274321 return nil
275322 end
276- local body
277- local body_node = req_node :field (" body" )[1 ]
278- if body_node then
279- body = parser .parse_body (body_node , source , ctx )
280- if not body then
281- logger .error (" parsing body failed" )
282- return nil
283- end
284- end
285323 local method = get_node_field_text (req_node , " method" , source )
286324 if not method then
287325 logger .info (" no method provided, falling back to 'GET'" )
@@ -334,6 +372,23 @@ function parser.parse(node, source, ctx)
334372 url = host .. url
335373 table.remove (headers [" host" ], 1 )
336374 end
375+
376+ --- @type string ?
377+ local content_type
378+ if headers [" content-type" ] then
379+ content_type = headers [" content-type" ][1 ]:match (" ([^;]+)" )
380+ end
381+ local body
382+ local body_node = req_node :field (" body" )[1 ]
383+ if body_node then
384+ body = parser .parse_body (content_type , body_node , source , ctx )
385+ if not body then
386+ logger .error (" parsing body failed" )
387+ vim .notify (" [rest.nvim] parsing request body failed. See `:Rest logs` for more info." , vim .log .levels .ERROR )
388+ return nil
389+ end
390+ end
391+
337392 --- @type rest.Request
338393 local req = {
339394 name = name ,
0 commit comments