@@ -435,34 +435,41 @@ pub fn parse_request_head(mut reader io.BufferedReader) !Request {
435435
436436// parse_request_head parses *only* the header of a raw HTTP request into a Request object
437437pub fn parse_request_head_str (s string ) ! Request {
438- // TODO called by veb twice!?
439- pos0 := s.index ('\n ' ) or { 0 }
440- lines := s.split ('\n ' )
438+ pos0 := s.index ('\n ' ) or { return error ('malformed request: no request line found' ) }
441439 line0 := s[..pos0 ].trim_space ()
442-
443440 method , target , version := parse_request_line (line0 )!
444441
445442 // headers
446443 mut header := new_header ()
447- for i := 1 ; i < lines.len; i++ {
448- mut line := lines[i].trim_right ('\r ' )
444+ // split by newline and skip the first line (request line)
445+ lines := s[pos0 + 1 ..].split ('\n ' )
446+
447+ for line_raw in lines {
448+ line := line_raw.trim_right ('\r ' )
449+
450+ // IMPORTANT: HTTP headers end at the first empty line.
451+ // If we hit this, we are now at the body, so we stop parsing headers.
452+ if line == '' {
453+ break
454+ }
455+
449456 if ! line.contains (':' ) {
450457 continue
451458 }
452- // key, value := parse_header(line)!
459+
453460 mut pos := parse_header_fast (line)!
454461 key := line.substr_unsafe (0 , pos)
455- for pos < line.len - 1 && line[pos + 1 ].is_space () {
456- // Skip space or tab in value name
457- pos++
462+
463+ // Skip space or tab after the colon
464+ mut val_start := pos + 1
465+ for val_start < line.len && line[val_start].is_space () {
466+ val_start++
458467 }
459- if pos + 1 < line.len {
460- value := line.substr_unsafe (pos + 1 , line.len)
461- _ , _ = key, value
462- // println('key,value=${key},${value}')
468+
469+ if val_start < line.len {
470+ value := line.substr_unsafe (val_start, line.len)
463471 header.add_custom (key, value)!
464472 }
465- // header.coerce(canonicalize: true)
466473 }
467474
468475 mut request_cookies := map [string ]string {}
@@ -480,6 +487,20 @@ pub fn parse_request_head_str(s string) !Request {
480487 }
481488}
482489
490+ // parse_request_str parses a raw HTTP request string into a Request object.
491+ pub fn parse_request_str (s string ) ! Request {
492+ mut request := parse_request_head_str (s)!
493+
494+ delim := '\r\n\r\n '
495+ body_pos := s.index (delim) or { - 1 }
496+
497+ if body_pos != - 1 {
498+ request.data = s[body_pos + delim.len..]
499+ }
500+
501+ return request
502+ }
503+
483504fn parse_request_line (line string ) ! (Method, urllib.URL, Version) {
484505 // println('S=${s}')
485506 words := line.split (' ' )
0 commit comments