From 2779fe7c10c172281e18e5133c4fb23634e62b2a Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Thu, 14 May 2020 12:58:49 -0400 Subject: [PATCH 1/2] fix #1005 --- irc/client.go | 11 ++++++++--- irc/handlers.go | 36 +++++++++++++++++++----------------- irc/utils/text.go | 14 ++++++++++++++ 3 files changed, 41 insertions(+), 20 deletions(-) diff --git a/irc/client.go b/irc/client.go index 8465fa6b..a5cc0f8f 100644 --- a/irc/client.go +++ b/irc/client.go @@ -175,7 +175,7 @@ func (s *Session) EndMultilineBatch(label string) (batch MultilineBatch, err err } s.deferredFakelagCount = fakelagBill - if batch.label == "" || batch.label != label || batch.message.LenLines() == 0 { + if batch.label == "" || batch.label != label || !batch.message.ValidMultiline() { err = errInvalidMultilineBatch return } @@ -1357,9 +1357,14 @@ func (session *Session) sendSplitMsgFromClientInternal(blocking bool, nickmask, session.SendRawMessage(msg, blocking) } } else { - for i, messagePair := range message.Split { + msgidSent := false // send msgid on the first nonblank line + for _, messagePair := range message.Split { + if len(messagePair.Message) == 0 { + continue + } var msgid string - if i == 0 { + if !msgidSent { + msgidSent = true msgid = message.Msgid } session.sendFromClientInternal(blocking, message.Time, msgid, nickmask, accountName, tags, command, target, messagePair.Message) diff --git a/irc/handlers.go b/irc/handlers.go index 4427bdf9..c6745d95 100644 --- a/irc/handlers.go +++ b/irc/handlers.go @@ -1793,33 +1793,35 @@ func nickHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Resp // helper to store a batched PRIVMSG in the session object func absorbBatchedMessage(server *Server, client *Client, msg ircmsg.IrcMessage, batchTag string, histType history.ItemType, rb *ResponseBuffer) { + var errorCode, errorMessage string + defer func() { + if errorCode != "" { + if histType != history.Notice { + rb.Add(nil, server.name, "FAIL", "BATCH", errorCode, errorMessage) + } + rb.session.EndMultilineBatch("") + } + }() + if batchTag != rb.session.batch.label { - if histType != history.Notice { - rb.Add(nil, server.name, "FAIL", "BATCH", "MULTILINE_INVALID", client.t("Incorrect batch tag sent")) - } - rb.session.EndMultilineBatch("") + errorCode, errorMessage = "MULTILINE_INVALID", client.t("Incorrect batch tag sent") return - } else if len(msg.Params) < 2 || msg.Params[1] == "" { - if histType != history.Notice { - rb.Add(nil, server.name, "FAIL", "BATCH", "MULTILINE_INVALID", client.t("Invalid multiline batch")) - } - rb.session.EndMultilineBatch("") + } else if len(msg.Params) < 2 { + errorCode, errorMessage = "MULTILINE_INVALID", client.t("Invalid multiline batch") return } rb.session.batch.command = msg.Command isConcat, _ := msg.GetTag(caps.MultilineConcatTag) + if isConcat && len(msg.Params[1]) == 0 { + errorCode, errorMessage = "MULTILINE_INVALID", client.t("Cannot send a blank line with the multiline concat tag") + return + } rb.session.batch.message.Append(msg.Params[1], isConcat) config := server.Config() if config.Limits.Multiline.MaxBytes < rb.session.batch.message.LenBytes() { - if histType != history.Notice { - rb.Add(nil, server.name, "FAIL", "BATCH", "MULTILINE_MAX_BYTES", strconv.Itoa(config.Limits.Multiline.MaxBytes)) - } - rb.session.EndMultilineBatch("") + errorCode, errorMessage = "MULTILINE_MAX_BYTES", strconv.Itoa(config.Limits.Multiline.MaxBytes) } else if config.Limits.Multiline.MaxLines != 0 && config.Limits.Multiline.MaxLines < rb.session.batch.message.LenLines() { - if histType != history.Notice { - rb.Add(nil, server.name, "FAIL", "BATCH", "MULTILINE_MAX_LINES", strconv.Itoa(config.Limits.Multiline.MaxLines)) - } - rb.session.EndMultilineBatch("") + errorCode, errorMessage = "MULTILINE_MAX_LINES", strconv.Itoa(config.Limits.Multiline.MaxLines) } } diff --git a/irc/utils/text.go b/irc/utils/text.go index 5d46b140..d77b88d4 100644 --- a/irc/utils/text.go +++ b/irc/utils/text.go @@ -73,10 +73,24 @@ func (sm *SplitMessage) LenBytes() (result int) { } for i := 0; i < len(sm.Split); i++ { result += len(sm.Split[i].Message) + // bill for the joining newline if necessary + if i != 0 && !sm.Split[i].Concat { + result += 1 + } } return } +func (sm *SplitMessage) ValidMultiline() bool { + // must contain at least one nonblank line + for i := 0; i < len(sm.Split); i++ { + if len(sm.Split[i].Message) != 0 { + return true + } + } + return false +} + func (sm *SplitMessage) IsRestrictedCTCPMessage() bool { if IsRestrictedCTCPMessage(sm.Message) { return true From 8efbc4bc329b4063f26132760e81a784580963f7 Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Thu, 14 May 2020 22:16:34 -0400 Subject: [PATCH 2/2] maintain lenBytes as a running count --- irc/client.go | 3 ++- irc/handlers.go | 6 +++++- irc/utils/text.go | 14 -------------- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/irc/client.go b/irc/client.go index a5cc0f8f..b5204b3d 100644 --- a/irc/client.go +++ b/irc/client.go @@ -146,6 +146,7 @@ type MultilineBatch struct { target string responseLabel string // this is the value of the labeled-response tag sent with BATCH message utils.SplitMessage + lenBytes int tags map[string]string } @@ -168,7 +169,7 @@ func (s *Session) EndMultilineBatch(label string) (batch MultilineBatch, err err s.fakelag.Unsuspend() // heuristics to estimate how much data they used while fakelag was suspended - fakelagBill := (batch.message.LenBytes() / 512) + 1 + fakelagBill := (batch.lenBytes / 512) + 1 fakelagBillLines := (batch.message.LenLines() * 60) / 512 if fakelagBill < fakelagBillLines { fakelagBill = fakelagBillLines diff --git a/irc/handlers.go b/irc/handlers.go index c6745d95..467881e8 100644 --- a/irc/handlers.go +++ b/irc/handlers.go @@ -1816,9 +1816,13 @@ func absorbBatchedMessage(server *Server, client *Client, msg ircmsg.IrcMessage, errorCode, errorMessage = "MULTILINE_INVALID", client.t("Cannot send a blank line with the multiline concat tag") return } + if !isConcat && len(rb.session.batch.message.Split) != 0 { + rb.session.batch.lenBytes++ // bill for the newline + } rb.session.batch.message.Append(msg.Params[1], isConcat) + rb.session.batch.lenBytes += len(msg.Params[1]) config := server.Config() - if config.Limits.Multiline.MaxBytes < rb.session.batch.message.LenBytes() { + if config.Limits.Multiline.MaxBytes < rb.session.batch.lenBytes { errorCode, errorMessage = "MULTILINE_MAX_BYTES", strconv.Itoa(config.Limits.Multiline.MaxBytes) } else if config.Limits.Multiline.MaxLines != 0 && config.Limits.Multiline.MaxLines < rb.session.batch.message.LenLines() { errorCode, errorMessage = "MULTILINE_MAX_LINES", strconv.Itoa(config.Limits.Multiline.MaxLines) diff --git a/irc/utils/text.go b/irc/utils/text.go index d77b88d4..62c49eb5 100644 --- a/irc/utils/text.go +++ b/irc/utils/text.go @@ -67,20 +67,6 @@ func (sm *SplitMessage) LenLines() int { return len(sm.Split) } -func (sm *SplitMessage) LenBytes() (result int) { - if sm.Split == nil { - return len(sm.Message) - } - for i := 0; i < len(sm.Split); i++ { - result += len(sm.Split[i].Message) - // bill for the joining newline if necessary - if i != 0 && !sm.Split[i].Concat { - result += 1 - } - } - return -} - func (sm *SplitMessage) ValidMultiline() bool { // must contain at least one nonblank line for i := 0; i < len(sm.Split); i++ {