11local utils = require (' dap.utils' )
22local M = {}
33
4- -- Copied from neovim rpc.lua
54--- @param header string
6- local function parse_headers (header )
7- local headers = {}
8- for line in vim .gsplit (header , ' \r\n ' , {plain = true }) do
9- if line == ' ' then
10- break
11- end
12- local key , value = line :match (' ^%s*(%S+)%s*:%s*(.+)%s*$' )
13- if key then
14- key = key :lower ():gsub (' %-' , ' _' )
15- headers [key ] = value
16- else
17- error (string.format (" Invalid header line %q" , line ))
5+ --- @return integer ?
6+ local function get_content_length (header )
7+ for line in header :gmatch (" (.-)\r\n " ) do
8+ local key , value = line :match (' ^%s*(%S+)%s*:%s*(%d+)%s*$' )
9+ if key and key :lower () == " content-length" then
10+ return tonumber (value )
1811 end
1912 end
20- headers .content_length = tonumber (headers .content_length )
21- or error (string.format (" Content-Length not found in headers. %q" , header ))
22- return headers
2313end
2414
2515
26- -- Mostly copied from neovim rpc.lua
27- local header_start_pattern = (" content" ):gsub (" %w" , function (c ) return " [" .. c .. c :upper ().. " ]" end )
28- local function parse_chunk_loop ()
29- local buffer = ' '
30- while true do
31- local start , finish = buffer :find (' \r\n\r\n ' , 1 , true )
32- if start then
33- local buffer_start = buffer :find (header_start_pattern )
34- if not buffer_start then
35- error (string.format (
36- " Headers were expected but debug adapter sent: %s" ,
37- buffer
38- ))
39- end
40- local headers = parse_headers (buffer :sub (buffer_start , start - 1 ))
41- local content_length = headers .content_length
42- local body_chunks = {buffer :sub (finish + 1 )}
43- local body_length = # body_chunks [1 ]
44- while body_length < content_length do
16+ local parse_chunk_loop
17+ local has_strbuffer , strbuffer = pcall (require , " string.buffer" )
18+
19+ if has_strbuffer then
20+ parse_chunk_loop = function ()
21+ local buf = strbuffer .new ()
22+ while true do
23+ local msg = buf :tostring ()
24+ local header_end = msg :find (' \r\n\r\n ' , 1 , true )
25+ if header_end then
26+ local header = buf :get (header_end + 1 )
27+ buf :skip (2 ) -- skip past header boundary
28+ local content_length = get_content_length (header )
29+ if not content_length then
30+ error (" Content-Length not found in headers: " .. header )
31+ end
32+ while # buf < content_length do
33+ local chunk = coroutine.yield ()
34+ buf :put (chunk )
35+ end
36+ local body = buf :get (content_length )
37+ coroutine.yield (body )
38+ else
4539 local chunk = coroutine.yield ()
46- or error (" Expected more data for the body. The server may have died." )
47- table.insert (body_chunks , chunk )
48- body_length = body_length + # chunk
40+ buf :put (chunk )
4941 end
50- local last_chunk = body_chunks [# body_chunks ]
42+ end
43+ end
44+ else
45+ parse_chunk_loop = function ()
46+ local buffer = ' '
47+ while true do
48+ local header_end , body_start = buffer :find (' \r\n\r\n ' , 1 , true )
49+ if header_end then
50+ local header = buffer :sub (1 , header_end + 1 )
51+ local content_length = get_content_length (header )
52+ if not content_length then
53+ error (" Content-Length not found in headers: " .. header )
54+ end
55+ local body_chunks = {buffer :sub (body_start + 1 )}
56+ local body_length = # body_chunks [1 ]
57+ while body_length < content_length do
58+ local chunk = coroutine.yield ()
59+ or error (" Expected more data for the body. The server may have died." )
60+ table.insert (body_chunks , chunk )
61+ body_length = body_length + # chunk
62+ end
63+ local last_chunk = body_chunks [# body_chunks ]
5164
52- body_chunks [# body_chunks ] = last_chunk :sub (1 , content_length - body_length - 1 )
53- local rest = ' '
54- if body_length > content_length then
55- rest = last_chunk :sub (content_length - body_length )
65+ body_chunks [# body_chunks ] = last_chunk :sub (1 , content_length - body_length - 1 )
66+ local rest = ' '
67+ if body_length > content_length then
68+ rest = last_chunk :sub (content_length - body_length )
69+ end
70+ local body = table.concat (body_chunks )
71+ buffer = rest .. (coroutine.yield (body )
72+ or error (" Expected more data for the body. The server may have died." ))
73+ else
74+ buffer = buffer .. (coroutine.yield ()
75+ or error (" Expected more data for the header. The server may have died." ))
5676 end
57- local body = table.concat (body_chunks )
58- buffer = rest .. (coroutine.yield (headers , body )
59- or error (" Expected more data for the body. The server may have died." ))
60- else
61- buffer = buffer .. (coroutine.yield ()
62- or error (" Expected more data for the header. The server may have died." ))
6377 end
6478 end
6579end
@@ -80,10 +94,10 @@ function M.create_read_loop(handle_body, on_no_chunk)
8094 return
8195 end
8296 while true do
83- local headers , body = parse_chunk (chunk )
84- if headers then
97+ local body = parse_chunk (chunk )
98+ if body then
8599 handle_body (body )
86- chunk = ' '
100+ chunk = " "
87101 else
88102 break
89103 end
0 commit comments