Handle repeated NNTP command whitespace (#20)

This commit is contained in:
phucnguyen1707 2026-06-15 10:25:04 +07:00 committed by GitHub
parent 0944fa2cb4
commit 36c6e0e275
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 96 additions and 5 deletions

View file

@ -142,12 +142,16 @@ func (s *Server) Process(nc net.Conn) {
if err != nil { if err != nil {
return return
} }
cmd := strings.Split(l, " ") fields := strings.Fields(l)
args := []string{} if len(fields) == 0 {
if len(cmd) > 1 { err = handleDefault(nil, sess, c)
args = cmd[1:] } else {
args := []string{}
if len(fields) > 1 {
args = fields[1:]
}
err = sess.dispatchCommand(fields[0], args, c)
} }
err = sess.dispatchCommand(cmd[0], args, c)
if err != nil { if err != nil {
if _, isNNTPError := err.(*NNTPError); err == io.EOF { if _, isNNTPError := err.(*NNTPError); err == io.EOF {
return return

View file

@ -0,0 +1,87 @@
package nntpd
import (
"errors"
"net"
"net/textproto"
"strings"
"testing"
"time"
"github.com/dustin/go-nntp"
)
type whitespaceBackend struct {
group *nntp.Group
}
func (b *whitespaceBackend) ListGroups(max int) ([]*nntp.Group, error) {
return []*nntp.Group{b.group}, nil
}
func (b *whitespaceBackend) GetGroup(name string) (*nntp.Group, error) {
if name == b.group.Name {
return b.group, nil
}
return nil, ErrNoSuchGroup
}
func (b *whitespaceBackend) GetArticle(group *nntp.Group, id string) (*nntp.Article, error) {
return nil, ErrInvalidArticleNumber
}
func (b *whitespaceBackend) GetArticles(group *nntp.Group, from, to int64) ([]NumberedArticle, error) {
return nil, nil
}
func (b *whitespaceBackend) Authorized() bool { return true }
func (b *whitespaceBackend) Authenticate(user, pass string) (Backend, error) {
return b, nil
}
func (b *whitespaceBackend) AllowPost() bool { return false }
func (b *whitespaceBackend) Post(article *nntp.Article) error {
return errors.New("posting disabled")
}
func TestProcessCollapsesRepeatedCommandWhitespace(t *testing.T) {
backend := &whitespaceBackend{
group: &nntp.Group{Name: "pfs.general", Count: 1, Low: 1, High: 1, Posting: nntp.PostingPermitted},
}
server := NewServer(backend)
clientConn, serverConn := net.Pipe()
defer clientConn.Close()
done := make(chan struct{})
go func() {
server.Process(serverConn)
close(done)
}()
client := textproto.NewConn(clientConn)
defer client.Close()
if line, err := client.ReadLine(); err != nil || !strings.HasPrefix(line, "200 ") {
t.Fatalf("greeting = %q, %v", line, err)
}
if err := client.PrintfLine("GROUP pfs.general"); err != nil {
t.Fatalf("send GROUP: %v", err)
}
if line, err := client.ReadLine(); err != nil || !strings.HasPrefix(line, "211 ") {
t.Fatalf("GROUP with repeated spaces = %q, %v; want 211", line, err)
}
if err := client.PrintfLine("QUIT"); err != nil {
t.Fatalf("send QUIT: %v", err)
}
if line, err := client.ReadLine(); err != nil || !strings.HasPrefix(line, "205 ") {
t.Fatalf("QUIT = %q, %v; want 205", line, err)
}
select {
case <-done:
case <-time.After(time.Second):
t.Fatal("server did not close after QUIT")
}
}