mirror of
https://github.com/golang/go
synced 2024-11-24 22:57:57 -07:00
textproto: parse RFC 959 multiline responses correctly
Fixes #2218 R=golang-dev, rsc CC=golang-dev https://golang.org/cl/5037041
This commit is contained in:
parent
e30b9fd87e
commit
f5181ae9d7
@ -11,6 +11,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BUG(rsc): To let callers manage exposure to denial of service
|
// BUG(rsc): To let callers manage exposure to denial of service
|
||||||
@ -182,6 +183,10 @@ func (r *Reader) readCodeLine(expectCode int) (code int, continued bool, message
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
return parseCodeLine(line, expectCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseCodeLine(line string, expectCode int) (code int, continued bool, message string, err os.Error) {
|
||||||
if len(line) < 4 || line[3] != ' ' && line[3] != '-' {
|
if len(line) < 4 || line[3] != ' ' && line[3] != '-' {
|
||||||
err = ProtocolError("short response: " + line)
|
err = ProtocolError("short response: " + line)
|
||||||
return
|
return
|
||||||
@ -224,15 +229,20 @@ func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err os.
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadResponse reads a multi-line response of the form
|
// ReadResponse reads a multi-line response of the form:
|
||||||
|
//
|
||||||
// code-message line 1
|
// code-message line 1
|
||||||
// code-message line 2
|
// code-message line 2
|
||||||
// ...
|
// ...
|
||||||
// code message line n
|
// code message line n
|
||||||
// where code is a 3-digit status code. Each line should have the same code.
|
//
|
||||||
// The response is terminated by a line that uses a space between the code and
|
// where code is a 3-digit status code. The first line starts with the
|
||||||
// the message line rather than a dash. Each line in message is separated by
|
// code and a hyphen. The response is terminated by a line that starts
|
||||||
// a newline (\n).
|
// with the same code followed by a space. Each line in message is
|
||||||
|
// separated by a newline (\n).
|
||||||
|
//
|
||||||
|
// See page 36 of RFC 959 (http://www.ietf.org/rfc/rfc959.txt) for
|
||||||
|
// details.
|
||||||
//
|
//
|
||||||
// If the prefix of the status does not match the digits in expectCode,
|
// If the prefix of the status does not match the digits in expectCode,
|
||||||
// ReadResponse returns with err set to &Error{code, message}.
|
// ReadResponse returns with err set to &Error{code, message}.
|
||||||
@ -244,11 +254,18 @@ func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err os.
|
|||||||
func (r *Reader) ReadResponse(expectCode int) (code int, message string, err os.Error) {
|
func (r *Reader) ReadResponse(expectCode int) (code int, message string, err os.Error) {
|
||||||
code, continued, message, err := r.readCodeLine(expectCode)
|
code, continued, message, err := r.readCodeLine(expectCode)
|
||||||
for err == nil && continued {
|
for err == nil && continued {
|
||||||
|
line, err := r.ReadLine()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var code2 int
|
var code2 int
|
||||||
var moreMessage string
|
var moreMessage string
|
||||||
code2, continued, moreMessage, err = r.readCodeLine(expectCode)
|
code2, continued, moreMessage, err = parseCodeLine(line, expectCode)
|
||||||
if code != code2 {
|
if err != nil || code2 != code {
|
||||||
err = ProtocolError("status code mismatch: " + strconv.Itoa(code) + ", " + strconv.Itoa(code2))
|
message += "\n" + strings.TrimRight(line, "\r\n")
|
||||||
|
continued = true
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
message += "\n" + moreMessage
|
message += "\n" + moreMessage
|
||||||
}
|
}
|
||||||
|
@ -138,3 +138,56 @@ func TestReadMIMEHeader(t *testing.T) {
|
|||||||
t.Fatalf("ReadMIMEHeader: %v, %v; want %v", m, err, want)
|
t.Fatalf("ReadMIMEHeader: %v, %v; want %v", m, err, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type readResponseTest struct {
|
||||||
|
in string
|
||||||
|
inCode int
|
||||||
|
wantCode int
|
||||||
|
wantMsg string
|
||||||
|
}
|
||||||
|
|
||||||
|
var readResponseTests = []readResponseTest{
|
||||||
|
{"230-Anonymous access granted, restrictions apply\n" +
|
||||||
|
"Read the file README.txt,\n" +
|
||||||
|
"230 please",
|
||||||
|
23,
|
||||||
|
230,
|
||||||
|
"Anonymous access granted, restrictions apply\nRead the file README.txt,\n please",
|
||||||
|
},
|
||||||
|
|
||||||
|
{"230 Anonymous access granted, restrictions apply\n",
|
||||||
|
23,
|
||||||
|
230,
|
||||||
|
"Anonymous access granted, restrictions apply",
|
||||||
|
},
|
||||||
|
|
||||||
|
{"400-A\n400-B\n400 C",
|
||||||
|
4,
|
||||||
|
400,
|
||||||
|
"A\nB\nC",
|
||||||
|
},
|
||||||
|
|
||||||
|
{"400-A\r\n400-B\r\n400 C\r\n",
|
||||||
|
4,
|
||||||
|
400,
|
||||||
|
"A\nB\nC",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// See http://www.ietf.org/rfc/rfc959.txt page 36.
|
||||||
|
func TestRFC959Lines(t *testing.T) {
|
||||||
|
for i, tt := range readResponseTests {
|
||||||
|
r := reader(tt.in + "\nFOLLOWING DATA")
|
||||||
|
code, msg, err := r.ReadResponse(tt.inCode)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("#%d: ReadResponse: %v", i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if code != tt.wantCode {
|
||||||
|
t.Errorf("#%d: code=%d, want %d", i, code, tt.wantCode)
|
||||||
|
}
|
||||||
|
if msg != tt.wantMsg {
|
||||||
|
t.Errorf("%#d: msg=%q, want %q", i, msg, tt.wantMsg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user