diff --git a/response.go b/response.go index c87d756..1d177be 100644 --- a/response.go +++ b/response.go @@ -35,6 +35,16 @@ type Response struct { func (or *Response) readSGMLHeaders(r *bufio.Reader) error { var seenHeader, seenVersion bool = false, false for { + // Some financial institutions do not properly leave an empty line after the last header. + // Avoid attempting to read another header in that case. + next, err := r.Peek(1) + if err != nil { + return err + } + if next[0] == '<' { + break + } + line, err := r.ReadString('\n') if err != nil { return err diff --git a/response_test.go b/response_test.go index 49659b7..1018002 100644 --- a/response_test.go +++ b/response_test.go @@ -140,10 +140,9 @@ func TestValidSamples(t *testing.T) { fn := func(path string, info os.FileInfo, err error) error { if info.IsDir() { return nil - } else if filepath.Ext(path) != ".ofx" { + } else if ext := filepath.Ext(path); ext != ".ofx" && ext != ".qfx" { return nil } - file, err := os.Open(path) if err != nil { t.Fatalf("Unexpected error opening %s: %s\n", path, err) @@ -155,4 +154,5 @@ func TestValidSamples(t *testing.T) { return nil } filepath.Walk("samples/valid_responses", fn) + filepath.Walk("samples/busted_responses", fn) } diff --git a/samples/busted_responses/bmo_v102__no_header_newline.qfx b/samples/busted_responses/bmo_v102__no_header_newline.qfx new file mode 100644 index 0000000..e9f946a --- /dev/null +++ b/samples/busted_responses/bmo_v102__no_header_newline.qfx @@ -0,0 +1,59 @@ +OFXHEADER:100 +DATA:OFXSGML +VERSION:102 +SECURITY:NONE +ENCODING:USASCII +CHARSET:1252 +COMPRESSION:NONE +OLDFILEUID:NONE +NEWFILEUID:NONE + + + + +0 +INFO +OK + +20181202184906.217[-5:EDT] +SJLDF802DV09DF80 +ENG +00017 + + + + +1 + +0 +INFO +OK + + +CAD + +2380370270281083 + + +20181202184905.909[-5:EDT] +20181202184905.909[-5:EDT] + +CREDIT +20181030000000.000[-5:EDT] +2042.24 +2380370270281083201810302054456 +PAYMENT RECEIVED - THANK YOU + + + +-552.63 +20181202184906.217[-5:EDT] + + +-552.63 +20181202184906.217[-5:EDT] + + + + +